963 lines
20 KiB
Text
963 lines
20 KiB
Text
|
|
#IFNDEF __lib_cardrender
|
|
#DEFINE __lib_cardrender 1
|
|
|
|
#INCLUDE "cardconsts.c65"
|
|
|
|
GOTO __skip_lib_cardrender
|
|
|
|
LABEL card_charcode_map
|
|
ASM
|
|
!8 13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
|
|
ENDASM
|
|
|
|
LABEL card_suit_charcode_map
|
|
ASM
|
|
!8 $50, $51, $0e, $0f
|
|
ENDASM
|
|
|
|
LABEL suit_graphic_hearts
|
|
ASM
|
|
!8 $1d+64, $1e+64, $1f+64, $2d+64, $2e+64, $2f+64, 0+64, $3e+64, 0+64
|
|
ENDASM
|
|
|
|
LABEL suit_graphic_diamonds
|
|
ASM
|
|
!8 0+64, $1b+64, 0+64, $2a+64, $2b+64, $2c+64, 0+64, $3b+64, 0+64
|
|
ENDASM
|
|
|
|
LABEL suit_graphic_spades
|
|
ASM
|
|
!8 0, $18, $19, $27, $28, $29, $37, $38, $39
|
|
ENDASM
|
|
|
|
LABEL suit_graphic_clubs
|
|
ASM
|
|
!8 0, $15, 0, $24, $25, $26, 0, $35, $36
|
|
ENDASM
|
|
|
|
// Convert card ID (0-51) to suit and rank
|
|
// 0-12: Hearts, 13-25: Diamonds, 26-38: Spades, 39-51: Clubs
|
|
FUNC card_id_to_suit_rank({BYTE card_id} out:{BYTE card_suit} out:{BYTE card_rank})
|
|
card_rank = card_id
|
|
card_suit = 0
|
|
|
|
IF card_rank >= 13
|
|
card_rank = card_rank - 13
|
|
card_suit = 1
|
|
ENDIF
|
|
|
|
IF card_rank >= 13
|
|
card_rank = card_rank - 13
|
|
card_suit = 2
|
|
ENDIF
|
|
|
|
IF card_rank >= 13
|
|
card_rank = card_rank - 13
|
|
card_suit = 3
|
|
ENDIF
|
|
FEND
|
|
|
|
// ZP usage $fa-$fd
|
|
// Render full card using card_id (0-51)
|
|
FUNC render_card({WORD screen_address} {WORD offset} {BYTE card_id})
|
|
BYTE card_suit
|
|
BYTE card_rank
|
|
|
|
card_id_to_suit_rank(card_id, card_suit, card_rank)
|
|
|
|
// Get rank charcode
|
|
WORD card_charcode_map_ptr @ $fa
|
|
POINTER card_charcode_map_ptr -> card_charcode_map
|
|
|
|
BYTE card_rank_charcode
|
|
card_rank_charcode = PEEK card_charcode_map_ptr[card_rank]
|
|
|
|
// Adjust color for red suit
|
|
IF card_suit < CARD_SUIT_SPADES
|
|
card_rank_charcode = card_rank_charcode + 64 //red color for hearts and diamonds
|
|
ENDIF
|
|
|
|
// Get suit charcode
|
|
WORD card_suit_charcode_map_ptr @ $fa
|
|
POINTER card_suit_charcode_map_ptr -> card_suit_charcode_map
|
|
|
|
BYTE suit_charcode
|
|
suit_charcode = PEEK card_suit_charcode_map_ptr[card_suit]
|
|
|
|
|
|
WORD p2 @ $fa
|
|
SWITCH card_suit
|
|
CASE CARD_SUIT_HEARTS
|
|
POINTER p2 -> suit_graphic_hearts
|
|
CASE CARD_SUIT_DIAMONDS
|
|
POINTER p2 -> suit_graphic_diamonds
|
|
CASE CARD_SUIT_SPADES
|
|
POINTER p2 -> suit_graphic_spades
|
|
CASE CARD_SUIT_CLUBS
|
|
POINTER p2 -> suit_graphic_clubs
|
|
ENDSWITCH
|
|
|
|
WORD p @ $fc
|
|
p = screen_address + offset
|
|
|
|
POKE p[0] , 224 // top left corner
|
|
POKE p[1] , 225
|
|
POKE p[2] , 225
|
|
POKE p[3] , 225
|
|
POKE p[4] , 226
|
|
|
|
p = p + 40
|
|
|
|
POKE p[0] , 240
|
|
POKE p[1] , card_rank_charcode
|
|
POKE p[2] , 0
|
|
POKE p[3] , suit_charcode
|
|
POKE p[4] , 243
|
|
|
|
p = p + 40
|
|
|
|
|
|
// Here we draw the bigger suit graphic in the middle of the card
|
|
BYTE g
|
|
POKE p[0] , 240
|
|
g = PEEK p2[0]
|
|
POKE p[1] , g
|
|
g = PEEK p2[1]
|
|
POKE p[2] , g
|
|
g = PEEK p2[2]
|
|
POKE p[3] , g
|
|
POKE p[4] , 243
|
|
|
|
p = p + 40
|
|
|
|
POKE p[0] , 240
|
|
g = PEEK p2[3]
|
|
POKE p[1] , g
|
|
g = PEEK p2[4]
|
|
POKE p[2] , g
|
|
g = PEEK p2[5]
|
|
POKE p[3] , g
|
|
POKE p[4] , 243
|
|
|
|
p = p + 40
|
|
|
|
POKE p[0] , 240
|
|
g = PEEK p2[6]
|
|
POKE p[1] , g
|
|
g = PEEK p2[7]
|
|
POKE p[2] , g
|
|
g = PEEK p2[8]
|
|
POKE p[3] , g
|
|
POKE p[4] , 243
|
|
|
|
p = p + 40
|
|
|
|
POKE p[0] , 240
|
|
POKE p[1] , suit_charcode
|
|
POKE p[2] , 0
|
|
POKE p[3] , card_rank_charcode
|
|
POKE p[4] , 243
|
|
|
|
p = p + 40
|
|
|
|
POKE p[0] , 241
|
|
POKE p[1] , 227
|
|
POKE p[2] , 227
|
|
POKE p[3] , 227
|
|
POKE p[4] , 242
|
|
|
|
|
|
FEND
|
|
|
|
// Render face-down card stack and top border of visible card
|
|
// Returns number of rows drawn (for offset calculation)
|
|
// n=0: just draws normal top border ($e0)
|
|
// n=1-2: draws modified top border showing stacked cards
|
|
// n=3+: draws multiple rows ending with top border
|
|
FUNC render_facedown_stack({WORD screen_address} {WORD offset} {BYTE num_facedown} out:{BYTE rows_drawn})
|
|
WORD p @ $fc
|
|
p = screen_address + offset
|
|
BYTE middle_rows
|
|
BYTE top_type
|
|
|
|
IF num_facedown == 0
|
|
// Normal top border
|
|
POKE p[0] , $e0
|
|
POKE p[1] , $e1
|
|
POKE p[2] , $e1
|
|
POKE p[3] , $e1
|
|
POKE p[4] , $e2
|
|
rows_drawn = 1
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF num_facedown == 1
|
|
// 1 face-down: $fa row
|
|
POKE p[0] , $fa
|
|
POKE p[1] , $da
|
|
POKE p[2] , $da
|
|
POKE p[3] , $da
|
|
POKE p[4] , $fc
|
|
rows_drawn = 1
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF num_facedown == 2
|
|
// 2 face-down: $fd row
|
|
POKE p[0] , $fd
|
|
POKE p[1] , $dc
|
|
POKE p[2] , $dc
|
|
POKE p[3] , $dc
|
|
POKE p[4] , $ff
|
|
rows_drawn = 1
|
|
EXIT
|
|
ENDIF
|
|
|
|
// 3+ face-down cards
|
|
// Top row based on (num_facedown mod 3)
|
|
top_type = num_facedown
|
|
WHILE top_type >= 3
|
|
top_type = top_type - 3
|
|
WEND
|
|
|
|
// Draw top row
|
|
IF top_type == 0
|
|
POKE p[0] , $e0
|
|
POKE p[1] , $e1
|
|
POKE p[2] , $e1
|
|
POKE p[3] , $e1
|
|
POKE p[4] , $e2
|
|
ENDIF
|
|
IF top_type == 1
|
|
POKE p[0] , $fa
|
|
POKE p[1] , $da
|
|
POKE p[2] , $da
|
|
POKE p[3] , $da
|
|
POKE p[4] , $fc
|
|
ENDIF
|
|
IF top_type == 2
|
|
POKE p[0] , $fd
|
|
POKE p[1] , $dc
|
|
POKE p[2] , $dc
|
|
POKE p[3] , $dc
|
|
POKE p[4] , $ff
|
|
ENDIF
|
|
p = p + 40
|
|
rows_drawn = 1
|
|
|
|
// Calculate middle $d7 rows: (num_facedown - 3) / 3
|
|
middle_rows = num_facedown - 3
|
|
WHILE middle_rows >= 3
|
|
middle_rows = middle_rows - 3
|
|
// Draw $d7 row
|
|
POKE p[0] , $d7
|
|
POKE p[1] , $dc
|
|
POKE p[2] , $dc
|
|
POKE p[3] , $dc
|
|
POKE p[4] , $f4
|
|
p = p + 40
|
|
rows_drawn++
|
|
WEND
|
|
|
|
// Draw card top row: $d7 for all n>=3
|
|
POKE p[0] , $d7
|
|
POKE p[1] , $dc
|
|
POKE p[2] , $dc
|
|
POKE p[3] , $dc
|
|
POKE p[4] , $f4
|
|
rows_drawn++
|
|
FEND
|
|
|
|
// Draw connecting border between stacked face-up cards
|
|
// Used before each face-up card after the first
|
|
FUNC render_connecting_border({WORD screen_address} {WORD offset})
|
|
WORD p @ $fc
|
|
p = screen_address + offset
|
|
|
|
POKE p[0] , $d4
|
|
POKE p[1] , $e1
|
|
POKE p[2] , $e1
|
|
POKE p[3] , $e1
|
|
POKE p[4] , $d6
|
|
FEND
|
|
|
|
// Render just the rank/suit row (no top border)
|
|
// Used for face-up cards in a stack where top border is already drawn
|
|
FUNC render_card_body_partial({WORD screen_address} {WORD offset} {BYTE card_id})
|
|
BYTE card_suit
|
|
BYTE card_rank
|
|
|
|
card_id_to_suit_rank(card_id, card_suit, card_rank)
|
|
|
|
// Get rank charcode
|
|
WORD card_charcode_map_ptr @ $fa
|
|
POINTER card_charcode_map_ptr -> card_charcode_map
|
|
|
|
BYTE card_rank_charcode
|
|
card_rank_charcode = PEEK card_charcode_map_ptr[card_rank]
|
|
|
|
// Adjust color for red suit
|
|
IF card_suit < CARD_SUIT_SPADES
|
|
card_rank_charcode = card_rank_charcode + 64
|
|
ENDIF
|
|
|
|
// Get suit charcode
|
|
WORD card_suit_charcode_map_ptr @ $fa
|
|
POINTER card_suit_charcode_map_ptr -> card_suit_charcode_map
|
|
|
|
BYTE suit_charcode
|
|
suit_charcode = PEEK card_suit_charcode_map_ptr[card_suit]
|
|
|
|
WORD p @ $fc
|
|
p = screen_address + offset
|
|
|
|
// Rank/suit row
|
|
POKE p[0] , $f0
|
|
POKE p[1] , card_rank_charcode
|
|
POKE p[2] , 0
|
|
POKE p[3] , suit_charcode
|
|
POKE p[4] , $f3
|
|
FEND
|
|
|
|
// Render card body without top border (rank/suit + middle + bottom)
|
|
// Used for the last face-up card in a stack
|
|
FUNC render_card_body_full({WORD screen_address} {WORD offset} {BYTE card_id})
|
|
BYTE card_suit
|
|
BYTE card_rank
|
|
|
|
card_id_to_suit_rank(card_id, card_suit, card_rank)
|
|
|
|
// Get rank charcode
|
|
WORD card_charcode_map_ptr @ $fa
|
|
POINTER card_charcode_map_ptr -> card_charcode_map
|
|
|
|
BYTE card_rank_charcode
|
|
card_rank_charcode = PEEK card_charcode_map_ptr[card_rank]
|
|
|
|
// Adjust color for red suit
|
|
IF card_suit < CARD_SUIT_SPADES
|
|
card_rank_charcode = card_rank_charcode + 64
|
|
ENDIF
|
|
|
|
// Get suit charcode
|
|
WORD card_suit_charcode_map_ptr @ $fa
|
|
POINTER card_suit_charcode_map_ptr -> card_suit_charcode_map
|
|
|
|
BYTE suit_charcode
|
|
suit_charcode = PEEK card_suit_charcode_map_ptr[card_suit]
|
|
|
|
// Get suit graphic pointer
|
|
WORD p2 @ $fa
|
|
SWITCH card_suit
|
|
CASE CARD_SUIT_HEARTS
|
|
POINTER p2 -> suit_graphic_hearts
|
|
CASE CARD_SUIT_DIAMONDS
|
|
POINTER p2 -> suit_graphic_diamonds
|
|
CASE CARD_SUIT_SPADES
|
|
POINTER p2 -> suit_graphic_spades
|
|
CASE CARD_SUIT_CLUBS
|
|
POINTER p2 -> suit_graphic_clubs
|
|
ENDSWITCH
|
|
|
|
WORD p @ $fc
|
|
p = screen_address + offset
|
|
WORD CONST SCREEN_MEM_END = $0400+999
|
|
|
|
// Bounds check: skip last 2 rows if they'd overflow screen (compact mode)
|
|
IF p > SCREEN_MEM_END-4
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Row 0: Rank/suit row
|
|
POKE p[0] , $f0
|
|
POKE p[1] , card_rank_charcode
|
|
POKE p[2] , 0
|
|
POKE p[3] , suit_charcode
|
|
POKE p[4] , $f3
|
|
|
|
p = p + 40
|
|
|
|
// Bounds check: skip last 2 rows if they'd overflow screen (compact mode)
|
|
IF p > SCREEN_MEM_END-4
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Rows 1-3: Suit graphic
|
|
BYTE g
|
|
POKE p[0] , $f0
|
|
g = PEEK p2[0]
|
|
POKE p[1] , g
|
|
g = PEEK p2[1]
|
|
POKE p[2] , g
|
|
g = PEEK p2[2]
|
|
POKE p[3] , g
|
|
POKE p[4] , $f3
|
|
|
|
p = p + 40
|
|
|
|
// Bounds check: skip last 2 rows if they'd overflow screen (compact mode)
|
|
IF p > SCREEN_MEM_END-4
|
|
EXIT
|
|
ENDIF
|
|
|
|
POKE p[0] , $f0
|
|
g = PEEK p2[3]
|
|
POKE p[1] , g
|
|
g = PEEK p2[4]
|
|
POKE p[2] , g
|
|
g = PEEK p2[5]
|
|
POKE p[3] , g
|
|
POKE p[4] , $f3
|
|
|
|
p = p + 40
|
|
|
|
// Bounds check: skip last 2 rows if they'd overflow screen (compact mode)
|
|
IF p > SCREEN_MEM_END-4
|
|
EXIT
|
|
ENDIF
|
|
|
|
POKE p[0] , $f0
|
|
g = PEEK p2[6]
|
|
POKE p[1] , g
|
|
g = PEEK p2[7]
|
|
POKE p[2] , g
|
|
g = PEEK p2[8]
|
|
POKE p[3] , g
|
|
POKE p[4] , $f3
|
|
|
|
p = p + 40
|
|
|
|
// Bounds check: skip last 2 rows if they'd overflow screen (compact mode)
|
|
IF p > SCREEN_MEM_END-4
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Row 4: Bottom rank/suit
|
|
POKE p[0] , $f0
|
|
POKE p[1] , suit_charcode
|
|
POKE p[2] , 0
|
|
POKE p[3] , card_rank_charcode
|
|
POKE p[4] , $f3
|
|
|
|
p = p + 40
|
|
|
|
// Bounds check: skip bottom border if it'd overflow (K-2 case)
|
|
IF p > SCREEN_MEM_END-4
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Row 5: Bottom border
|
|
POKE p[0] , $f1
|
|
POKE p[1] , $e3
|
|
POKE p[2] , $e3
|
|
POKE p[3] , $e3
|
|
POKE p[4] , $f2
|
|
FEND
|
|
|
|
// Render a complete tableau pile from pile data
|
|
// Handles face-down stack and all face-up cards
|
|
FUNC render_tableau_pile({WORD screen_address} {WORD offset} {WORD pile_ptr @ $fe})
|
|
BYTE count
|
|
BYTE facedown_count
|
|
BYTE faceup_count
|
|
BYTE faceup_index
|
|
BYTE card
|
|
BYTE card_id
|
|
BYTE i
|
|
BYTE rows
|
|
WORD pos
|
|
BYTE use_compact
|
|
|
|
count = PEEK pile_ptr[0]
|
|
|
|
// Empty pile - nothing to render
|
|
IF count == 0
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Count face-down cards
|
|
facedown_count = 0
|
|
BYTE is_facedown
|
|
FOR i = 1 TO count
|
|
card = PEEK pile_ptr[i]
|
|
is_facedown = card & CARD_FACEDOWN
|
|
IF is_facedown
|
|
facedown_count++
|
|
ENDIF
|
|
NEXT
|
|
|
|
faceup_count = count - facedown_count
|
|
|
|
// Calculate if we need compact mode (total rows > 17)
|
|
BYTE facedown_rows
|
|
BYTE faceup_rows_normal
|
|
BYTE total_rows
|
|
BYTE temp_count
|
|
|
|
// Calculate facedown rows
|
|
IF facedown_count == 0
|
|
facedown_rows = 0
|
|
ELSE
|
|
IF facedown_count <= 2
|
|
facedown_rows = 1
|
|
ELSE
|
|
facedown_rows = 2
|
|
temp_count = facedown_count - 3
|
|
WHILE temp_count >= 3
|
|
temp_count = temp_count - 3
|
|
facedown_rows++
|
|
WEND
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Calculate faceup rows (normal mode)
|
|
IF faceup_count == 0
|
|
faceup_rows_normal = 0
|
|
ELSE
|
|
IF faceup_count == 1
|
|
faceup_rows_normal = 6
|
|
ELSE
|
|
// Normal mode: 4 + 2*N rows
|
|
faceup_rows_normal = faceup_count + faceup_count
|
|
faceup_rows_normal = faceup_rows_normal + 4
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Check if we need compact mode (screen rows 8-24 = 17 rows available)
|
|
total_rows = facedown_rows + faceup_rows_normal
|
|
use_compact = 0
|
|
IF total_rows > 17
|
|
use_compact = 1
|
|
ENDIF
|
|
|
|
// Draw face-down stack + first face-up top border
|
|
pos = offset
|
|
render_facedown_stack(screen_address, pos, facedown_count, rows)
|
|
FOR i = 1 TO rows
|
|
pos = pos + 40
|
|
NEXT
|
|
|
|
// If no face-up cards, we're done (shouldn't happen in valid game)
|
|
IF faceup_count == 0
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Render face-up cards
|
|
faceup_index = 0
|
|
#PRAGMA _P_USE_LONG_JUMP 1
|
|
FOR i = 1 TO count
|
|
#PRAGMA _P_USE_LONG_JUMP 0
|
|
card = PEEK pile_ptr[i]
|
|
|
|
// Skip face-down cards
|
|
is_facedown = card & CARD_FACEDOWN
|
|
IF is_facedown
|
|
// do nothing
|
|
ELSE
|
|
faceup_index++
|
|
card_id = card & CARD_MASK
|
|
|
|
IF faceup_index == 1
|
|
// First face-up: top border already drawn, just body
|
|
IF faceup_count == 1
|
|
// Only one face-up card - render full
|
|
render_card_body_full(screen_address, pos, card_id)
|
|
ELSE
|
|
// More cards follow - render partial
|
|
render_card_body_partial(screen_address, pos, card_id)
|
|
pos = pos + 40
|
|
ENDIF
|
|
ELSE
|
|
// Subsequent face-up cards
|
|
IF use_compact == 0
|
|
// Normal mode: draw connecting border
|
|
render_connecting_border(screen_address, pos)
|
|
pos = pos + 40
|
|
ENDIF
|
|
|
|
IF faceup_index == faceup_count
|
|
// Last face-up card - render full
|
|
render_card_body_full(screen_address, pos, card_id)
|
|
ELSE
|
|
// More cards follow - render partial
|
|
render_card_body_partial(screen_address, pos, card_id)
|
|
pos = pos + 40
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
NEXT
|
|
FEND
|
|
|
|
// Render partial card (top 2 rows only) for stacked display
|
|
// Used for face-up cards underneath the top card
|
|
FUNC render_card_partial({WORD screen_address} {WORD offset} {BYTE card_id})
|
|
BYTE card_suit
|
|
BYTE card_rank
|
|
|
|
card_id_to_suit_rank(card_id, card_suit, card_rank)
|
|
|
|
// Get rank charcode
|
|
WORD card_charcode_map_ptr @ $fa
|
|
POINTER card_charcode_map_ptr -> card_charcode_map
|
|
|
|
BYTE card_rank_charcode
|
|
card_rank_charcode = PEEK card_charcode_map_ptr[card_rank]
|
|
|
|
// Adjust color for red suit
|
|
IF card_suit < CARD_SUIT_SPADES
|
|
card_rank_charcode = card_rank_charcode + 64
|
|
ENDIF
|
|
|
|
// Get suit charcode
|
|
WORD card_suit_charcode_map_ptr @ $fa
|
|
POINTER card_suit_charcode_map_ptr -> card_suit_charcode_map
|
|
|
|
BYTE suit_charcode
|
|
suit_charcode = PEEK card_suit_charcode_map_ptr[card_suit]
|
|
|
|
WORD p @ $fc
|
|
p = screen_address + offset
|
|
|
|
// Row 0: top border
|
|
POKE p[0] , 224
|
|
POKE p[1] , 225
|
|
POKE p[2] , 225
|
|
POKE p[3] , 225
|
|
POKE p[4] , 226
|
|
|
|
p = p + 40
|
|
|
|
// Row 1: rank and suit
|
|
POKE p[0] , 240
|
|
POKE p[1] , card_rank_charcode
|
|
POKE p[2] , 0
|
|
POKE p[3] , suit_charcode
|
|
POKE p[4] , 243
|
|
FEND
|
|
|
|
// Render back side of a card (face-down full card)
|
|
// Same border as face card, middle filled with $52
|
|
FUNC render_card_back({WORD screen_address} {WORD offset})
|
|
WORD p @ $fc
|
|
p = screen_address + offset
|
|
|
|
// Row 0: top border
|
|
POKE p[0] , $e0
|
|
POKE p[1] , $e1
|
|
POKE p[2] , $e1
|
|
POKE p[3] , $e1
|
|
POKE p[4] , $e2
|
|
|
|
p = p + 40
|
|
|
|
// Row 1: side borders + $52 fill
|
|
POKE p[0] , $f0
|
|
POKE p[1] , $52
|
|
POKE p[2] , $52
|
|
POKE p[3] , $52
|
|
POKE p[4] , $f3
|
|
|
|
p = p + 40
|
|
|
|
// Row 2: side borders + $52 fill
|
|
POKE p[0] , $f0
|
|
POKE p[1] , $52
|
|
POKE p[2] , $52
|
|
POKE p[3] , $52
|
|
POKE p[4] , $f3
|
|
|
|
p = p + 40
|
|
|
|
// Row 3: side borders + $52 fill
|
|
POKE p[0] , $f0
|
|
POKE p[1] , $52
|
|
POKE p[2] , $52
|
|
POKE p[3] , $52
|
|
POKE p[4] , $f3
|
|
|
|
p = p + 40
|
|
|
|
// Row 4: side borders + $52 fill
|
|
POKE p[0] , $f0
|
|
POKE p[1] , $52
|
|
POKE p[2] , $52
|
|
POKE p[3] , $52
|
|
POKE p[4] , $f3
|
|
|
|
p = p + 40
|
|
|
|
// Row 5: side borders + $52 fill
|
|
POKE p[0] , $f0
|
|
POKE p[1] , $52
|
|
POKE p[2] , $52
|
|
POKE p[3] , $52
|
|
POKE p[4] , $f3
|
|
|
|
p = p + 40
|
|
|
|
// Row 6: bottom border
|
|
POKE p[0] , $f1
|
|
POKE p[1] , $e3
|
|
POKE p[2] , $e3
|
|
POKE p[3] , $e3
|
|
POKE p[4] , $f2
|
|
FEND
|
|
|
|
// Render empty pile placeholder
|
|
// Same border shape but -$80 for light pink color, interior filled with 0
|
|
FUNC render_empty_pile({WORD screen_address} {WORD offset})
|
|
WORD p @ $fc
|
|
p = screen_address + offset
|
|
|
|
// Row 0: top border (pink)
|
|
POKE p[0] , $60
|
|
POKE p[1] , $61
|
|
POKE p[2] , $61
|
|
POKE p[3] , $61
|
|
POKE p[4] , $62
|
|
|
|
p = p + 40
|
|
|
|
// Row 1: side borders + empty fill
|
|
POKE p[0] , $70
|
|
POKE p[1] , 0
|
|
POKE p[2] , 0
|
|
POKE p[3] , 0
|
|
POKE p[4] , $73
|
|
|
|
p = p + 40
|
|
|
|
// Row 2: side borders + empty fill
|
|
POKE p[0] , $70
|
|
POKE p[1] , 0
|
|
POKE p[2] , 0
|
|
POKE p[3] , 0
|
|
POKE p[4] , $73
|
|
|
|
p = p + 40
|
|
|
|
// Row 3: side borders + empty fill
|
|
POKE p[0] , $70
|
|
POKE p[1] , 0
|
|
POKE p[2] , 0
|
|
POKE p[3] , 0
|
|
POKE p[4] , $73
|
|
|
|
p = p + 40
|
|
|
|
// Row 4: side borders + empty fill
|
|
POKE p[0] , $70
|
|
POKE p[1] , 0
|
|
POKE p[2] , 0
|
|
POKE p[3] , 0
|
|
POKE p[4] , $73
|
|
|
|
p = p + 40
|
|
|
|
// Row 5: side borders + empty fill
|
|
POKE p[0] , $70
|
|
POKE p[1] , 0
|
|
POKE p[2] , 0
|
|
POKE p[3] , 0
|
|
POKE p[4] , $73
|
|
|
|
p = p + 40
|
|
|
|
// Row 6: bottom border (pink)
|
|
POKE p[0] , $71
|
|
POKE p[1] , $63
|
|
POKE p[2] , $63
|
|
POKE p[3] , $63
|
|
POKE p[4] , $72
|
|
FEND
|
|
|
|
// Render foundation pile - shows top card or empty placeholder
|
|
FUNC render_foundation_pile({WORD screen_address} {WORD offset} {WORD pile_ptr @ $fe})
|
|
BYTE count
|
|
BYTE card
|
|
BYTE card_id
|
|
|
|
count = PEEK pile_ptr[0]
|
|
|
|
IF count == 0
|
|
render_empty_pile(screen_address, offset)
|
|
ELSE
|
|
card = PEEK pile_ptr[count]
|
|
card_id = card & CARD_MASK
|
|
render_card(screen_address, offset, card_id)
|
|
ENDIF
|
|
FEND
|
|
|
|
// Render stock pile - shows card back or empty placeholder
|
|
FUNC render_stock_pile({WORD screen_address} {WORD offset} {WORD pile_ptr @ $fe})
|
|
BYTE count
|
|
|
|
count = PEEK pile_ptr[0]
|
|
|
|
IF count == 0
|
|
render_empty_pile(screen_address, offset)
|
|
ELSE
|
|
render_card_back(screen_address, offset)
|
|
ENDIF
|
|
FEND
|
|
|
|
// Render left edge of card (2 columns) for fanned display
|
|
FUNC render_card_left_edge({WORD screen_address} {WORD offset} {BYTE card_id})
|
|
BYTE card_suit
|
|
BYTE card_rank
|
|
|
|
card_id_to_suit_rank(card_id, card_suit, card_rank)
|
|
|
|
// Get rank charcode
|
|
WORD card_charcode_map_ptr @ $fa
|
|
POINTER card_charcode_map_ptr -> card_charcode_map
|
|
|
|
BYTE card_rank_charcode
|
|
card_rank_charcode = PEEK card_charcode_map_ptr[card_rank]
|
|
|
|
// Adjust color for red suit
|
|
IF card_suit < CARD_SUIT_SPADES
|
|
card_rank_charcode = card_rank_charcode + 64
|
|
ENDIF
|
|
|
|
// Get suit charcode
|
|
WORD card_suit_charcode_map_ptr @ $fa
|
|
POINTER card_suit_charcode_map_ptr -> card_suit_charcode_map
|
|
|
|
BYTE suit_charcode
|
|
suit_charcode = PEEK card_suit_charcode_map_ptr[card_suit]
|
|
|
|
// Get suit graphic pointer
|
|
WORD p2 @ $fa
|
|
SWITCH card_suit
|
|
CASE CARD_SUIT_HEARTS
|
|
POINTER p2 -> suit_graphic_hearts
|
|
CASE CARD_SUIT_DIAMONDS
|
|
POINTER p2 -> suit_graphic_diamonds
|
|
CASE CARD_SUIT_SPADES
|
|
POINTER p2 -> suit_graphic_spades
|
|
CASE CARD_SUIT_CLUBS
|
|
POINTER p2 -> suit_graphic_clubs
|
|
ENDSWITCH
|
|
|
|
WORD p @ $fc
|
|
p = screen_address + offset
|
|
|
|
BYTE g
|
|
|
|
// Row 0: top border (2 cols)
|
|
POKE p[0] , $e0
|
|
POKE p[1] , $e1
|
|
|
|
p = p + 40
|
|
|
|
// Row 1: left border + rank
|
|
POKE p[0] , $f0
|
|
POKE p[1] , card_rank_charcode
|
|
|
|
p = p + 40
|
|
|
|
// Row 2: left border + suit graphic
|
|
POKE p[0] , $f0
|
|
g = PEEK p2[0]
|
|
POKE p[1] , g
|
|
|
|
p = p + 40
|
|
|
|
// Row 3: left border + suit graphic
|
|
POKE p[0] , $f0
|
|
g = PEEK p2[3]
|
|
POKE p[1] , g
|
|
|
|
p = p + 40
|
|
|
|
// Row 4: left border + suit graphic
|
|
POKE p[0] , $f0
|
|
g = PEEK p2[6]
|
|
POKE p[1] , g
|
|
|
|
p = p + 40
|
|
|
|
// Row 5: left border + suit
|
|
POKE p[0] , $f0
|
|
POKE p[1] , suit_charcode
|
|
|
|
p = p + 40
|
|
|
|
// Row 6: bottom border (2 cols)
|
|
POKE p[0] , $f1
|
|
POKE p[1] , $e3
|
|
FEND
|
|
|
|
// Render waste pile - draw-3 style fanned display
|
|
// Shows up to 3 cards fanned horizontally (2 col offset per card)
|
|
FUNC render_waste_pile({WORD screen_address} {WORD offset} {WORD pile_ptr @ $fe} {BYTE draw_mode})
|
|
BYTE count
|
|
BYTE card
|
|
BYTE card_id
|
|
WORD off2
|
|
WORD off4
|
|
|
|
count = PEEK pile_ptr[0]
|
|
|
|
// Draw-1 mode: only show top card
|
|
IF draw_mode == 1
|
|
IF count == 0
|
|
render_empty_pile(screen_address, offset)
|
|
ELSE
|
|
card = PEEK pile_ptr[count]
|
|
card_id = card & CARD_MASK
|
|
render_card(screen_address, offset, card_id)
|
|
ENDIF
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Draw-3 mode: fan out top 3 cards
|
|
off2 = offset + 2
|
|
off4 = offset + 4
|
|
|
|
SWITCH count
|
|
CASE 0
|
|
render_empty_pile(screen_address, offset)
|
|
|
|
CASE 1
|
|
card = PEEK pile_ptr[1]
|
|
card_id = card & CARD_MASK
|
|
render_card(screen_address, offset, card_id)
|
|
|
|
CASE 2
|
|
// 2nd from top (left edge)
|
|
card = PEEK pile_ptr[1]
|
|
card_id = card & CARD_MASK
|
|
render_card_left_edge(screen_address, offset, card_id)
|
|
// Top card (full)
|
|
card = PEEK pile_ptr[2]
|
|
card_id = card & CARD_MASK
|
|
render_card(screen_address, off2, card_id)
|
|
|
|
DEFAULT
|
|
// 3+ cards: show top 3 fanned
|
|
BYTE idx
|
|
// 3rd from top (left edge)
|
|
idx = count - 2
|
|
card = PEEK pile_ptr[idx]
|
|
card_id = card & CARD_MASK
|
|
render_card_left_edge(screen_address, offset, card_id)
|
|
|
|
// 2nd from top (left edge)
|
|
idx = count - 1
|
|
card = PEEK pile_ptr[idx]
|
|
card_id = card & CARD_MASK
|
|
render_card_left_edge(screen_address, off2, card_id)
|
|
|
|
// Top card (full)
|
|
card = PEEK pile_ptr[count]
|
|
card_id = card & CARD_MASK
|
|
render_card(screen_address, off4, card_id)
|
|
ENDSWITCH
|
|
FEND
|
|
|
|
LABEL __skip_lib_cardrender
|
|
|
|
#IFEND
|