#IFNDEF __lib_gamemenu #DEFINE __lib_gamemenu 1 #INCLUDE "pileconsts.c65" #INCLUDE "keyboard.c65" #INCLUDE "utils.c65" GOTO __skip_lib_gamemenu // ============================================================================ // GAME MENU SYSTEM // ============================================================================ // Pause game and display menu for configuration and restart // // Usage: // #INCLUDE "gamemenu.c65" // BYTE action // menu_show(action) // Returns MENU_ACTION_* constant // ============================================================================ // Menu action constants BYTE CONST MENU_ACTION_RESUME = 0 BYTE CONST MENU_ACTION_RESTART = 1 // Screen backup buffer (1000 bytes for screen, 1000 for color) // Located at $C000-$C7CF (2000 bytes) WORD CONST SCREEN_BACKUP = $C000 WORD CONST COLOR_BACKUP = $C3E8 // ============================================================================ // FUNC menu_save_screen // Save current screen and color memory to backup buffer // ============================================================================ FUNC menu_save_screen mem_copy_range($0400, SCREEN_BACKUP, 1000) mem_copy_range($D800, COLOR_BACKUP, 1000) FEND // ============================================================================ // FUNC menu_restore_screen // Restore screen and color memory from backup buffer // ============================================================================ FUNC menu_restore_screen mem_copy_range(SCREEN_BACKUP, $0400, 1000) mem_copy_range(COLOR_BACKUP, $D800, 1000) FEND // ============================================================================ // FUNC menu_switch_to_rom_charset // Switch VIC-II to use ROM charset at $1800 (uppercase/lowercase) // ============================================================================ FUNC menu_switch_to_rom_charset set_vic_charmem(3) // $1800 / $0800 = 3 FEND // ============================================================================ // FUNC menu_switch_to_card_charset // Switch VIC-II back to custom card charset at $2000 // ============================================================================ FUNC menu_switch_to_card_charset set_vic_charmem(4) // $2000 / $0800 = 4 FEND // ============================================================================ // FUNC menu_print_string // Print a string at a specific screen position // ============================================================================ FUNC menu_print_string({WORD screen_pos @ $e0} {WORD str_ptr @ $e2}) BYTE char BYTE str_offset str_offset = 0 char = PEEK str_ptr[str_offset] WHILE char != 0 POKE screen_pos[0] , char screen_pos++ str_offset++ char = PEEK str_ptr[str_offset] WEND FEND // ============================================================================ // FUNC menu_render // Render the menu screen with current settings // ============================================================================ FUNC menu_render WORD screen_pos @ $f0 WORD str_ptr @ $f2 BYTE draw_indicator BYTE found_to_tab_indicator // Clear screen fill_mem($0400, $0400+999, 32) // 32 = space character fill_mem($D800, $D800+999, 14) // Light blue text // Title (centered at row 2) screen_pos = 2*40+$0400+8 POINTER str_ptr -> str_title menu_print_string(screen_pos, str_ptr) // Draw mode option (row 6) screen_pos = 6*40+$0400+4 POINTER str_ptr -> str_draw_mode menu_print_string(screen_pos, str_ptr) // Draw mode value screen_pos = 6*40+$0400+24 IF game_draw_mode == 1 POKE screen_pos[0] , 49 // '1' ELSE POKE screen_pos[0] , 51 // '3' ENDIF // Draw mode indicator IF game_draw_mode == 1 draw_indicator = 91 // '[' screen_pos = 6*40+$0400+23 POKE screen_pos[0] , draw_indicator screen_pos = 6*40+$0400+25 POKE screen_pos[0] , 93 // ']' ELSE draw_indicator = 91 // '[' screen_pos = 6*40+$0400+26 POKE screen_pos[0] , draw_indicator screen_pos = 6*40+$0400+28 POKE screen_pos[0] , 93 // ']' ENDIF // Foundation to Tableau option (row 9) screen_pos = 9*40+$0400+4 POINTER str_ptr -> str_found_to_tab menu_print_string(screen_pos, str_ptr) // Foundation to Tableau value screen_pos = 9*40+$0400+28 IF game_allow_found_to_tab == 0 POINTER str_ptr -> str_off ELSE POINTER str_ptr -> str_on ENDIF menu_print_string(screen_pos, str_ptr) // Instructions for resume/restart (row 14+) screen_pos = 14*40+$0400+4 POINTER str_ptr -> str_inst_f7 menu_print_string(screen_pos, str_ptr) screen_pos = 15*40+$0400+4 POINTER str_ptr -> str_inst_f8 menu_print_string(screen_pos, str_ptr) // Set border color to menu color (purple) POKE $d020 , 4 FEND // ============================================================================ // FUNC menu_show // Display menu and handle input, return action to take // ============================================================================ FUNC menu_show(out:{BYTE action}) BYTE key BYTE prev_key action = MENU_ACTION_RESUME prev_key = KEY_NONE // Clear any card selection before entering menu game_selected_pile = PILE_ID_NONE game_selected_card_count = 0 // Save current screen state menu_save_screen() // Disable all sprites POKE $D015 , 0 // Sprite enable register - disable all // Switch to ROM charset and normal character mode menu_switch_to_rom_charset() clear_vic_ecm() // Render menu menu_render() // Wait for key release first (debounce) key_scan(key) WHILE key != KEY_NONE key_scan(key) WEND // Menu loop WHILE 1 key_scan(key) // Only process on key press (transition from NONE to key) IF key != KEY_NONE IF prev_key == KEY_NONE SWITCH key CASE KEY_F1 // Toggle draw mode IF game_draw_mode == 1 game_draw_mode = 3 ELSE game_draw_mode = 1 ENDIF menu_render() CASE KEY_F3 // Toggle foundation to tableau IF game_allow_found_to_tab == 0 game_allow_found_to_tab = 1 ELSE game_allow_found_to_tab = 0 ENDIF menu_render() CASE KEY_F7 // Resume game action = MENU_ACTION_RESUME BREAK CASE KEY_F8 // Restart game (SHIFT+F7) action = MENU_ACTION_RESTART BREAK ENDSWITCH ENDIF ENDIF prev_key = key WEND // Wait for key release before returning WHILE key != KEY_NONE key_scan(key) WEND // Restore screen or clear for restart IF action == MENU_ACTION_RESUME menu_restore_screen() ELSE // Restarting - clear screen and reset colors fill_mem($0400, $0400+999, 0) fill_mem($d800, $d800+999, 1) // White color ENDIF // Switch back to card charset and ECM mode menu_switch_to_card_charset() set_vic_ecm() // Re-enable pointer sprite (game loop will handle card display sprites) pointer_enable(1) // Restore border color POKE $d020 , 1 // White FEND // Menu strings (null-terminated) - Using !scr for screen codes LABEL str_title ASM !scr "Klondike Solitaire Menu", 0 ENDASM LABEL str_draw_mode ASM !scr "F1: Draw mode:", 0 ENDASM LABEL str_found_to_tab ASM !scr "F3: Foundation>Tableau:", 0 ENDASM LABEL str_on ASM !scr "On", 0 ENDASM LABEL str_off ASM !scr "Off", 0 ENDASM LABEL str_inst_f1 ASM !scr "F1: Toggle draw mode (1/3)", 0 ENDASM LABEL str_inst_f3 ASM !scr "F3: Toggle foundation moves", 0 ENDASM LABEL str_inst_f7 ASM !scr "F7: Resume game", 0 ENDASM LABEL str_inst_f8 ASM !scr "F8: Restart game", 0 ENDASM LABEL __skip_lib_gamemenu #IFEND