Tightened up the code with better label and pointer handling. README improved.

This commit is contained in:
Mattias Hansson 2026-01-12 13:39:27 +01:00
parent f4bff18f29
commit 788c6ed60d
5 changed files with 20 additions and 58 deletions

View file

@ -1,26 +1,17 @@
# Solitaire C64 # Solitaire C64
A classic Klondike solitaire card game for the Commodore 64, written in c65gm. A classic Klondike solitaire card game for the Commodore 64.
## Features ## Features
- **Full Klondike Solitaire**: Stock, waste, 7 tableaus, and 4 foundation piles - Full Klondike with draw-1 and draw-3 modes
- **Dual Input Support**: Play with joystick or 1351 mouse - Joystick and 1351 mouse support
- **Draw Modes**: Toggle between draw-1 and draw-3 gameplay - Extended color mode graphics with sprite cursor
- **Custom Graphics**: Character-based card rendering using extended color mode - Hardware-seeded RNG for shuffling
- **Sprite Cursor**: Visual pointer for card selection and movement
- **Smart Shuffling**: Hardware-seeded RNG for true randomness
## Technical Details
**Language**: c65gm (C-like language for 6502/C64)
**Memory Layout**: Code at $3000, custom charset at $2000
**Graphics**: Extended Color Mode (ECM) with custom character set
**Input**: CIA joystick ports + 1351 proportional mouse support
## Building ## Building
Requires the c65gm compiler and ACME assembler: Requires the [c65gm compiler](https://git.techserio.com/mattiashz/c65gm) and ACME assembler:
```bash ```bash
./cm.sh ./cm.sh

View file

@ -95,28 +95,13 @@ FEND
// Tab0=1, Tab1=2, Tab2=3, Tab3=4, Tab4=5, Tab5=6, Tab6=7 cards // Tab0=1, Tab1=2, Tab2=3, Tab3=4, Tab4=5, Tab5=6, Tab6=7 cards
// Top card of each tableau is face up // Top card of each tableau is face up
FUNC deal_tableaus FUNC deal_tableaus
WORD ptr deal_to_tableau(@pile_tab0, 1)
deal_to_tableau(@pile_tab1, 2)
POINTER ptr -> pile_tab0 deal_to_tableau(@pile_tab2, 3)
deal_to_tableau(ptr, 1) deal_to_tableau(@pile_tab3, 4)
deal_to_tableau(@pile_tab4, 5)
POINTER ptr -> pile_tab1 deal_to_tableau(@pile_tab5, 6)
deal_to_tableau(ptr, 2) deal_to_tableau(@pile_tab6, 7)
POINTER ptr -> pile_tab2
deal_to_tableau(ptr, 3)
POINTER ptr -> pile_tab3
deal_to_tableau(ptr, 4)
POINTER ptr -> pile_tab4
deal_to_tableau(ptr, 5)
POINTER ptr -> pile_tab5
deal_to_tableau(ptr, 6)
POINTER ptr -> pile_tab6
deal_to_tableau(ptr, 7)
FEND FEND
// Clear the seen array // Clear the seen array

View file

@ -84,13 +84,7 @@ FUNC main
set_vic_charmem(4) // $2000 set_vic_charmem(4) // $2000
set_vic_ecm() set_vic_ecm()
mem_copy(@card_charset, @card_charset_end, $2000)
WORD charset_ptr
WORD charset_end_ptr
POINTER charset_ptr -> card_charset
POINTER charset_end_ptr -> card_charset_end
mem_copy(charset_ptr, charset_end_ptr, $2000)
//mem_copy_range(charset_ptr, $2000, 512)
fill_mem($d800, $d800+999, color_white) // Fill color mem fill_mem($d800, $d800+999, color_white) // Fill color mem
POKE $d020 , color_white //color_grey POKE $d020 , color_white //color_grey

View file

@ -224,7 +224,7 @@ FEND
// Waste to Tableau // Waste to Tableau
FUNC move_waste_to_tab({WORD tab_ptr} out:{BYTE success}) FUNC move_waste_to_tab({WORD tab_ptr} out:{BYTE success})
WORD waste_ptr @ $8c WORD waste_ptr
POINTER waste_ptr -> pile_waste POINTER waste_ptr -> pile_waste
BYTE card BYTE card
BYTE valid BYTE valid
@ -249,7 +249,7 @@ FEND
// Waste to Foundation // Waste to Foundation
FUNC move_waste_to_found({WORD found_ptr} out:{BYTE success}) FUNC move_waste_to_found({WORD found_ptr} out:{BYTE success})
WORD waste_ptr @ $aa WORD waste_ptr
POINTER waste_ptr -> pile_waste POINTER waste_ptr -> pile_waste
BYTE card BYTE card
BYTE valid BYTE valid
@ -273,7 +273,7 @@ FUNC move_waste_to_found({WORD found_ptr} out:{BYTE success})
FEND FEND
// Tableau to Foundation (top card only) // Tableau to Foundation (top card only)
FUNC move_tab_to_found({WORD tab_ptr @ $8e} {WORD found_ptr} out:{BYTE success}) FUNC move_tab_to_found({WORD tab_ptr} {WORD found_ptr} out:{BYTE success})
BYTE card BYTE card
BYTE valid BYTE valid
BYTE is_facedown BYTE is_facedown
@ -358,7 +358,7 @@ FUNC move_tab_to_tab({WORD src_ptr @ $b0} {WORD dst_ptr} {BYTE card_count} out:{
FEND FEND
// Foundation to Tableau (optional rule - some variants allow this) // Foundation to Tableau (optional rule - some variants allow this)
FUNC move_found_to_tab({WORD found_ptr @ $84} {WORD tab_ptr} out:{BYTE success}) FUNC move_found_to_tab({WORD found_ptr} {WORD tab_ptr} out:{BYTE success})
BYTE card BYTE card
BYTE valid BYTE valid

View file

@ -871,22 +871,14 @@ FUNC game_loop
BYTE button_state BYTE button_state
BYTE clicked BYTE clicked
BYTE is_won BYTE is_won
WORD src_ptr @ $8a
WORD src_end_ptr
WORD dst_ptr
// Copy sprite data to $2200 (sprite block 136) // Copy sprite data to $2200 (sprite block 136)
// $2000-$21FF reserved for charset // $2000-$21FF reserved for charset
POINTER src_ptr -> pointer_sprite_data mem_copy(@pointer_sprite_data, @pointer_sprite_data_end, $2200)
POINTER src_end_ptr -> pointer_sprite_data_end
POINTER dst_ptr -> $2200
mem_copy(src_ptr, src_end_ptr, dst_ptr)
// Copy card sprite data to $2240 (sprite blocks 137+) // Copy card sprite data to $2240 (sprite blocks 137+)
// 26 sprites × 64 bytes = 1664 bytes (includes "RETURN FOR MENU" sprite) // 26 sprites × 64 bytes = 1664 bytes (includes "RETURN FOR MENU" sprite)
POINTER src_ptr -> sprite_rank_ace mem_copy_range(@sprite_rank_ace, $2240, 64*26)
POINTER dst_ptr -> $2240
mem_copy_range(src_ptr, dst_ptr, 64*26)