solitaire-c64/gamemenu.c65

313 lines
7.6 KiB
Text

#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