solitaire-c64/pointer.c65

371 lines
9.8 KiB
Text

#IFNDEF __lib_pointer
#DEFINE __lib_pointer 1
GOTO __skip_lib_pointer
// ============================================================================
// SPRITE POINTER DRIVER FOR COMMODORE 64
// ============================================================================
// This library provides sprite-based pointer/cursor control.
// Can be driven by joystick, mouse, keyboard, or other input methods.
//
// Usage:
// #INCLUDE "pointer.c65"
// pointer_init(100, 50, 1, 192) // Init at x=100, y=50, white color, sprite data block 192
// WHILE 1
// // Read your input device (joystick, mouse, etc.)
// pointer_move(delta_x, delta_y) // Move pointer
// WEND
// ============================================================================
// VIC-II Sprite registers
WORD CONST VIC2 = $D000
BYTE sprite_x0 @ VIC2+0 // Sprite 0 X position
BYTE sprite_y0 @ VIC2+1 // Sprite 0 Y position
BYTE sprite_x_msb @ VIC2+16 // Sprite X MSB (for X > 255)
BYTE sprite_enable @ VIC2+21 // Sprite enable register
BYTE sprite_color0 @ VIC2+39 // Sprite 0 color
BYTE sprite_pointer0 @ $07F8 // Sprite 0 pointer (screen + $3F8)
// Pointer position variables
WORD pointer_x // Current pointer X position (0-511)
BYTE pointer_y // Current pointer Y position
BYTE pointer_speed // Base movement speed
BYTE pointer_accel // Current acceleration counter
BYTE pointer_max_speed // Maximum speed with acceleration
// ============================================================================
// Compact arrow pointer sprite - 7 pixels tall
// Tip at (0,0) for easy pointing at coordinates
// ============================================================================
LABEL pointer_sprite_data
ASM
// Simple compact arrow
!8 $80, $00, $00 // Row 0: *
!8 $C0, $00, $00 // Row 1: **
!8 $E0, $00, $00 // Row 2: ***
!8 $F0, $00, $00 // Row 3: ****
!8 $E0, $00, $00 // Row 4: ***
!8 $C0, $00, $00 // Row 5: **
!8 $80, $00, $00 // Row 6: *
!8 $00, $00, $00 // Row 7-20: blank
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00, $00, $00
!8 $00 // Padding
ENDASM
LABEL pointer_sprite_data_end
// ============================================================================
// FUNC pointer_init
// Initialize sprite 0 as a pointer at given position
// Parameters:
// x_pos: Initial X position (0-255)
// y_pos: Initial Y position (0-250)
// color: Sprite color (0-15)
// sprite_data: Sprite data block number (0-255)
// ============================================================================
FUNC pointer_init({BYTE x_pos} {BYTE y_pos} {BYTE color} {BYTE sprite_data})
BYTE temp
// Set pointer position
pointer_x = x_pos
pointer_y = y_pos
pointer_speed = 1 // Base speed: 1 pixel
pointer_accel = 0 // No acceleration initially
pointer_max_speed = 10 // Max accelerated speed
// Set sprite X position (low byte)
sprite_x0 = x_pos
sprite_y0 = y_pos
// Clear X MSB for sprite 0 (x_pos is < 256)
temp = sprite_x_msb
temp = temp & %11111110 // Clear bit 0
sprite_x_msb = temp
// Set sprite color
sprite_color0 = color
// Set sprite data pointer
sprite_pointer0 = sprite_data
// Enable sprite 0
sprite_enable = 1
FEND
// ============================================================================
// FUNC pointer_move_left
// Move pointer left by speed amount
// ============================================================================
FUNC pointer_move_left({BYTE speed})
// Move left with bounds check
IF pointer_x >= speed
pointer_x = pointer_x - speed
ELSE
pointer_x = 0
ENDIF
IF pointer_x < 24
pointer_x = 24
ENDIF
// Update VIC registers
sprite_x0 = pointer_x
IF pointer_x > 255
sprite_x_msb = sprite_x_msb | %00000001
ELSE
sprite_x_msb = sprite_x_msb & %11111110
ENDIF
FEND
// ============================================================================
// FUNC pointer_move_right
// Move pointer right by speed amount
// ============================================================================
FUNC pointer_move_right({BYTE speed})
// Move right with bounds check
pointer_x = pointer_x + speed
IF pointer_x > 320+20
pointer_x = 320+20
ENDIF
// Update VIC registers
sprite_x0 = pointer_x
IF pointer_x > 255
sprite_x_msb = sprite_x_msb | %00000001
ELSE
sprite_x_msb = sprite_x_msb & %11111110
ENDIF
FEND
// ============================================================================
// FUNC pointer_move_up
// Move pointer up by speed amount
// ============================================================================
FUNC pointer_move_up({BYTE speed})
IF pointer_y >= speed
pointer_y = pointer_y - speed
ENDIF
IF pointer_y < 50
pointer_y = 50 // Stop at top edge, not 0
ENDIF
sprite_y0 = pointer_y
FEND
// ============================================================================
// FUNC pointer_move_down
// Move pointer down by speed amount
// ============================================================================
FUNC pointer_move_down({BYTE speed})
WORD new_y
new_y = pointer_y + speed
// Stop at bottom edge (around Y=229 for NTSC, 249 for PAL)
IF new_y > 247
pointer_y = 247
ELSE
pointer_y = new_y
ENDIF
sprite_y0 = pointer_y
FEND
// ============================================================================
// FUNC pointer_update_joystick
// Update pointer based on joystick input state with acceleration
// Expects joy_state to be set (from joystick.c65 library)
// joy_state bits: UP=bit0, DOWN=bit1, LEFT=bit2, RIGHT=bit3, FIRE=bit4
// ============================================================================
FUNC pointer_update_joystick({BYTE joy_state})
BYTE actual_speed
BYTE any_direction
BYTE test_bit
// Check if any direction is pressed (mask all direction bits)
any_direction = joy_state & %00001111
// Reset acceleration if joystick is neutral
IF any_direction == 0
pointer_accel = 0
ELSE
// Increase acceleration while moving
IF pointer_accel < 255
pointer_accel++
ENDIF
ENDIF
// Calculate actual speed with acceleration
// Divide accel by 8 (shift right 3 times)
actual_speed = pointer_accel
ASM
lda |actual_speed|
;lsr
lsr
lsr
lsr
sta |actual_speed|
ENDASM
actual_speed = pointer_speed + actual_speed
IF actual_speed > pointer_max_speed
actual_speed = pointer_max_speed
ENDIF
// Move in pressed directions
test_bit = joy_state & %00000100 // LEFT mask
IF test_bit
pointer_move_left(actual_speed)
ENDIF
test_bit = joy_state & %00001000 // RIGHT mask
IF test_bit
pointer_move_right(actual_speed)
ENDIF
test_bit = joy_state & %00000001 // UP mask
IF test_bit
pointer_move_up(actual_speed)
ENDIF
test_bit = joy_state & %00000010 // DOWN mask
IF test_bit
pointer_move_down(actual_speed)
ENDIF
FEND
// ============================================================================
// FUNC pointer_update_mouse
// Update pointer based on mouse delta movements
// Expects mouse_delta_x and mouse_delta_y to be set (from mouse.c65 library)
// Mouse deltas are signed 8-bit values
// ============================================================================
FUNC pointer_update_mouse({BYTE delta_x} {BYTE delta_y})
BYTE sign_x
BYTE sign_y
BYTE abs_x
BYTE abs_y
// Handle X movement
sign_x = delta_x & %10000000
IF sign_x
// Negative (moving left)
abs_x = 0 - delta_x // Get absolute value
IF abs_x > 0
pointer_move_left(abs_x)
ENDIF
ELSE
// Positive (moving right)
IF delta_x > 0
pointer_move_right(delta_x)
ENDIF
ENDIF
// Handle Y movement
sign_y = delta_y & %10000000
IF sign_y
// Negative (moving up)
abs_y = 0 - delta_y // Get absolute value
IF abs_y > 0
pointer_move_up(abs_y)
ENDIF
ELSE
// Positive (moving down)
IF delta_y > 0
pointer_move_down(delta_y)
ENDIF
ENDIF
FEND
// ============================================================================
// FUNC pointer_set_speed
// Set pointer movement speed
// Parameters:
// speed: Pixels to move per movement (1-8 recommended)
// ============================================================================
FUNC pointer_set_speed({BYTE speed})
pointer_speed = speed
FEND
// ============================================================================
// FUNC pointer_get_x
// Get current pointer X position
// Parameters:
// out:x_pos: X position (0-511)
// ============================================================================
FUNC pointer_get_x(out:{WORD x_pos})
x_pos = pointer_x
FEND
// ============================================================================
// FUNC pointer_get_y
// Get current pointer Y position
// Returns: Y position in out parameter
// ============================================================================
FUNC pointer_get_y(out:{BYTE y_pos})
y_pos = pointer_y
FEND
// ============================================================================
// FUNC pointer_enable
// Enable or disable pointer sprite
// Parameters:
// enable: 1 to enable, 0 to disable
// ============================================================================
FUNC pointer_enable({BYTE enable})
BYTE temp
temp = sprite_enable
IF enable
temp = temp | %00000001
ELSE
temp = temp & %11111110
ENDIF
sprite_enable = temp
FEND
// ============================================================================
// FUNC pointer_set_color
// Change pointer sprite color
// Parameters:
// color: Color value (0-15)
// ============================================================================
FUNC pointer_set_color({BYTE color})
sprite_color0 = color
FEND
LABEL __skip_lib_pointer
#IFEND