From 9d96e879980df25ad8ff5ecb989be1a80c87407b Mon Sep 17 00:00:00 2001 From: Anderson911114 <110701037@g.nccu.edu.tw> Date: Tue, 21 Jul 2026 17:21:54 +0800 Subject: [PATCH 1/2] fix(solo): sync personal best score and max combo on pregame screen (#4) --- src/App.tsx | 20 +++++++++++--------- src/hooks/useSoloGame.ts | 22 ++++++++++++++++++++++ src/lib/app-helpers.ts | 10 +++++++++- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 2246dd6..824bbfb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -189,7 +189,8 @@ async function syncAuthenticatedLeaderboardProfile({ onPlayerName: (name: string) => void; }) { const userId = currentSession.user.id; - const fallbackHighScore = loadBestScore().score; + const fallbackBest = loadBestScore(); + const fallbackHighScore = fallbackBest.score; const fallbackExperience = loadExperience(); const existingRecordResponse = await authClient .from('combo_leaderboard') @@ -213,6 +214,10 @@ async function syncAuthenticatedLeaderboardProfile({ experience: number; updated_at: string | null; } | null; + const nextMaxCombo = Math.max( + existingRecord?.max_combo ?? 0, + fallbackBest.maxCombo + ); const nextHighScore = Math.max( normalizeHistoricSoloHighScore( existingRecord?.high_score ?? 0, @@ -225,19 +230,15 @@ async function syncAuthenticatedLeaderboardProfile({ fallbackExperience ); - if (nextHighScore > 0) { - saveBestScore(nextHighScore, 0); + if (nextHighScore > 0 || nextMaxCombo > 0) { + saveBestScore(nextHighScore, nextMaxCombo); } - const localBest = loadBestScore(); const stats: ProfileStats = { games_played: existingRecord?.games_played ?? 0, wins: existingRecord?.wins ?? 0, losses: existingRecord?.losses ?? 0, - max_combo: Math.max( - existingRecord?.max_combo ?? 0, - localBest.maxCombo || 0 - ), + max_combo: nextMaxCombo, high_score: nextHighScore, experience: nextExperience, updated_at: existingRecord?.updated_at, @@ -500,7 +501,7 @@ export default function App(): JSX.Element { const soloGame = useSoloGame({ screen, onScreenChange, - onNewBest: (score) => { + onNewBest: (score, maxCombo) => { const userId = session?.user.id; if (!supabaseAuthClient || !userId || !playerName) { return; @@ -512,6 +513,7 @@ export default function App(): JSX.Element { user_id: userId, player_name: playerName, high_score: score, + max_combo: maxCombo, }, { onConflict: 'user_id' } ) diff --git a/src/hooks/useSoloGame.ts b/src/hooks/useSoloGame.ts index 1e62d34..ae9083f 100644 --- a/src/hooks/useSoloGame.ts +++ b/src/hooks/useSoloGame.ts @@ -116,6 +116,28 @@ export function useSoloGame({ isPausedRef.current = isPaused; }, [isPaused]); + useEffect(() => { + function syncBestScore() { + setBestScore(loadBestScore()); + } + + syncBestScore(); + + globalThis.addEventListener( + 'atomize:best-score-updated', + syncBestScore + ); + globalThis.addEventListener('storage', syncBestScore); + + return () => { + globalThis.removeEventListener( + 'atomize:best-score-updated', + syncBestScore + ); + globalThis.removeEventListener('storage', syncBestScore); + }; + }, [screen]); + useEffect(() => { if (screen !== 'single') { return undefined; diff --git a/src/lib/app-helpers.ts b/src/lib/app-helpers.ts index d255f6c..201f469 100644 --- a/src/lib/app-helpers.ts +++ b/src/lib/app-helpers.ts @@ -145,18 +145,26 @@ export function loadBestScore(): BestScoreRecord { export function saveBestScore(score: number, maxCombo: number): boolean { const current = loadBestScore(); const isNewHighScore = score > current.score; + const isNewMaxCombo = maxCombo > current.maxCombo; if (isNewHighScore) { globalThis.localStorage.setItem(bestScoreStorageKey, String(score)); } - if (maxCombo > current.maxCombo) { + if (isNewMaxCombo) { globalThis.localStorage.setItem( bestMaxComboStorageKey, String(maxCombo) ); } + if ( + (isNewHighScore || isNewMaxCombo) && + typeof globalThis.dispatchEvent === 'function' + ) { + globalThis.dispatchEvent(new Event('atomize:best-score-updated')); + } + return isNewHighScore; } From e1672e925cfe719c13344158e66eb3841ad25aa1 Mon Sep 17 00:00:00 2001 From: Anderson911114 <110701037@g.nccu.edu.tw> Date: Tue, 21 Jul 2026 17:32:59 +0800 Subject: [PATCH 2/2] fix(godot): replace invalid accessibility_name property with built-in tooltip_text --- godot/scripts/screens/main.gd | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/godot/scripts/screens/main.gd b/godot/scripts/screens/main.gd index 0aeb1aa..bcd1936 100644 --- a/godot/scripts/screens/main.gd +++ b/godot/scripts/screens/main.gd @@ -2187,7 +2187,7 @@ func _show_player_name_dialog() -> void: player_name_input.text = battle_player_name player_name_input.max_length = SaveManager.PLAYER_NAME_LIMIT player_name_input.placeholder_text = BATTLE_GUEST_NAME - player_name_input.accessibility_name = "Username" + player_name_input.tooltip_text = "Username" player_name_input.position = Vector2(14, 104) player_name_input.size = Vector2(DIALOG_WIDTH - 28.0, 44) player_name_input.alignment = HORIZONTAL_ALIGNMENT_CENTER @@ -4282,7 +4282,7 @@ func _make_home_title() -> HBoxContainer: func _make_home_blob_button(text: String, callback: Callable, color: Color, icon_kind: String) -> Button: var button := Button.new() - button.accessibility_name = text + button.tooltip_text = text button.custom_minimum_size = Vector2(HOME_BLOB_SIZE, HOME_BLOB_SIZE) button.size = Vector2(HOME_BLOB_SIZE, HOME_BLOB_SIZE) button.text = "" @@ -4339,7 +4339,7 @@ func _start_home_blob_idle(button: Button, starts_raised: bool) -> void: func _make_home_menu_button() -> Button: var button := Button.new() - button.accessibility_name = "Close menu" if home_menu_open else "Menu" + button.tooltip_text = "Close menu" if home_menu_open else "Menu" button.size = Vector2(HOME_MENU_BUTTON_SIZE, HOME_MENU_BUTTON_SIZE) button.custom_minimum_size = Vector2(HOME_MENU_BUTTON_SIZE, HOME_MENU_BUTTON_SIZE) button.text = "" @@ -4353,7 +4353,7 @@ func _make_home_menu_button() -> Button: func _make_home_menu_item(icon_kind: String, tooltip: String, callback: Callable) -> Button: var button := Button.new() - button.accessibility_name = tooltip + button.tooltip_text = tooltip button.text = "" button.custom_minimum_size = Vector2(48, 48) button.flat = true @@ -4368,7 +4368,7 @@ func _prefers_reduced_motion() -> bool: func _make_header_icon_button(text: String, callback: Callable) -> Button: var button := Button.new() - button.accessibility_name = "Back" if text == "←" else text + button.tooltip_text = "Back" if text == "←" else text button.text = "" if text == "←" else text button.size = Vector2(44, 44) button.custom_minimum_size = Vector2(44, 44) @@ -4381,7 +4381,7 @@ func _make_header_icon_button(text: String, callback: Callable) -> Button: func _make_page_back_button(callback: Callable) -> Button: var button := Button.new() - button.accessibility_name = "Back" + button.tooltip_text = "Back" button.text = "" button.size = Vector2(44, 44) button.custom_minimum_size = Vector2(44, 44) @@ -4393,7 +4393,7 @@ func _make_page_back_button(callback: Callable) -> Button: func _make_pause_icon_button() -> Button: var button := Button.new() - button.accessibility_name = "Pause" + button.tooltip_text = "Pause" button.size = Vector2(44, 44) button.custom_minimum_size = Vector2(44, 44) button.text = "" @@ -4510,7 +4510,7 @@ func _build_prime_keypad_controls( backspace_button = _make_icon_text_button("", COLOR_PRIMARY_STRONG, COLOR_INK, 28, "backspace") backspace_button.name = "BackspaceButton" - backspace_button.accessibility_name = "Backspace" + backspace_button.tooltip_text = "Backspace" backspace_button.custom_minimum_size = Vector2(SOLO_KEY_SIZE, SOLO_KEY_SIZE) _add_delete_icon(backspace_button, SOLO_KEY_SIZE, SOLO_KEY_SIZE, _get_button_text_color(COLOR_PRIMARY_STRONG)) backspace_button.pressed.connect(backspace_callback) @@ -4518,7 +4518,7 @@ func _build_prime_keypad_controls( submit_button = _make_icon_text_button("", COLOR_PRIMARY_STRONG, COLOR_INK, 34, "submit") submit_button.name = "SubmitButton" - submit_button.accessibility_name = "Submit combo" + submit_button.tooltip_text = "Submit combo" submit_button.custom_minimum_size = Vector2(SOLO_KEY_SIZE, (SOLO_KEY_SIZE * 2.0) + SOLO_KEY_GAP) _add_submit_icon(submit_button, SOLO_KEY_SIZE, (SOLO_KEY_SIZE * 2.0) + SOLO_KEY_GAP, _get_button_text_color(COLOR_PRIMARY_STRONG)) submit_button.pressed.connect(submit_callback) @@ -4560,7 +4560,7 @@ func _animate_tutorial_card(card: Panel) -> void: func _make_prime_key_button(text: String) -> Button: var button := Button.new() - button.accessibility_name = "Prime %s" % text + button.tooltip_text = "Prime %s" % text button.text = text button.custom_minimum_size = Vector2(SOLO_KEY_SIZE, SOLO_KEY_SIZE) _apply_button_theme(button, THEME_BUTTON_KEYPAD)