Score and Turn Display
Count cells, display scores, show whose turn it is. The game gets a proper UI.
Players need to know the score. They need to know whose turn it is.
This unit adds a proper user interface: score display showing how many cells each player owns, and a turn indicator that changes colour with each move. The game starts to feel complete.
Run It
pasmonext --sna inkwar.asm inkwar.sna

Above the board you’ll see:
- P1:00 with a score (red background)
- P2:00 with a score (blue background)
- TURN indicator in the current player’s colour
Claim some cells. Watch the scores update. Watch the turn indicator change colour.
Counting Cells
To display scores, we first need to count them:
; ----------------------------------------------------------------------------
; Count Cells
; ----------------------------------------------------------------------------
; Counts cells owned by each player
count_cells:
xor a
ld (p1_count), a
ld (p2_count), a
ld hl, board_state
ld b, 64 ; 64 cells
.count_loop:
ld a, (hl)
cp STATE_P1
jr nz, .not_p1
ld a, (p1_count)
inc a
ld (p1_count), a
jr .next
.not_p1:
cp STATE_P2
jr nz, .next
ld a, (p2_count)
inc a
ld (p2_count), a
.next:
inc hl
djnz .count_loop
ret
This iterates through all 64 cells of board_state, counting how many belong to each player. The djnz instruction (Decrement and Jump if Not Zero) is perfect for loops - it decrements B and jumps back if B isn’t zero yet.
We store the counts in p1_count and p2_count for display.
Printing Characters
Rather than wrestling with the ROM’s print routines (which need careful system variable setup), we write our own character printing routine. This gives us complete control and teaches more about how the Spectrum works.
; ----------------------------------------------------------------------------
; Print Character
; ----------------------------------------------------------------------------
; A = ASCII character (32-127), B = row (0-23), C = column (0-31)
; Writes character directly to display file using ROM character set
print_char:
push bc
push de
push hl
push af
; Calculate character data address: CHAR_SET + char*8
ld l, a
ld h, 0
add hl, hl
add hl, hl
add hl, hl ; HL = char * 8
ld de, CHAR_SET
add hl, de ; HL = source address
push hl ; Save character data address
; Calculate display file address
; Screen address: high byte varies with row, low byte = column
ld a, b ; A = row (0-23)
and %00011000 ; Get which third (0, 8, 16)
add a, $40 ; Add display file base high byte
ld d, a
ld a, b ; A = row
and %00000111 ; Get line within character row
rrca
rrca
rrca ; Shift to bits 5-7
add a, c ; Add column
ld e, a ; DE = screen address
pop hl ; HL = character data
; Copy 8 bytes (8 pixel rows of character)
ld b, 8
.pc_loop:
ld a, (hl)
ld (de), a
inc hl
inc d ; Next screen line (add 256)
djnz .pc_loop
pop af
pop hl
pop de
pop bc
ret
The routine:
- Looks up the character’s pixel data in the ROM character set at $3C00
- Calculates where on screen to draw it using the Spectrum’s quirky display layout
- Copies 8 bytes (one per pixel row) to the display file
The Spectrum’s Screen Layout
The Spectrum’s display file at $4000 has a complex layout. For each character position at row R, column C:
; High byte = $40 + (row/8)*8 + pixel_line
; Low byte = (row%8)*32 + column
The screen is divided into thirds (rows 0-7, 8-15, 16-23), with each pixel row 256 bytes apart. Our print_char routine handles this complexity.
Converting Numbers to Text
Scores are numbers (0-64), but we print characters. To convert:
; ----------------------------------------------------------------------------
; Print Two Digits
; ----------------------------------------------------------------------------
; A = number (0-99), B = row, C = column (will advance by 2)
; Prints number as two digits
print_two_digits:
push bc
; Calculate tens digit
ld d, 0 ; Tens counter
.ptd_tens:
cp 10
jr c, .ptd_print
sub 10
inc d
jr .ptd_tens
.ptd_print:
push af ; Save units digit
; Print tens digit
ld a, d
add a, '0'
call print_char
inc c
; Print units digit
pop af
add a, '0'
call print_char
inc c
pop bc
ret
The conversion is simple: subtract 10 repeatedly to get the tens digit, then add ASCII ‘0’ (48 decimal) to convert digits to printable characters.
For example, the number 23:
- Subtract 10 twice: 23 → 13 → 3 (tens = 2, remainder = 3)
- Tens digit: 2 + ‘0’ = ‘2’ (ASCII 50)
- Units digit: 3 + ‘0’ = ‘3’ (ASCII 51)
The Turn Indicator
A simple “TURN” label that changes colour based on whose turn it is:
; ----------------------------------------------------------------------------
; Draw Turn Indicator
; ----------------------------------------------------------------------------
; Shows "TURN" with current player's colour
draw_turn_indicator:
; Print "TURN"
ld b, TURN_ROW
ld c, TURN_COL
ld a, 'T'
call print_char
inc c
ld a, 'U'
call print_char
inc c
ld a, 'R'
call print_char
inc c
ld a, 'N'
call print_char
; Set attribute based on current player
ld a, (current_player)
cp 1
jr z, .dti_p1
ld e, P2_TEXT
jr .dti_set
.dti_p1:
ld e, P1_TEXT
.dti_set:
ld a, TURN_ROW
ld c, TURN_COL
ld b, 4 ; "TURN" = 4 chars
call set_attr_range
ret
We print the text first, then set the attributes afterwards. The text stays the same - only the background colour changes.
Setting Attribute Ranges
We colour the text by setting attributes for multiple consecutive cells:
set_attr_range:
; A = row, C = start column, B = count, E = attribute
; Calculate address, then write E to B consecutive bytes
This lets us create coloured “badges” for the score labels - red background for P1, blue for P2.
UI Layout Constants
The display positions are defined as constants at the top:
SCORE_ROW equ 2 ; Score display row
P1_SCORE_COL equ 10 ; "P1: nn" column
P2_SCORE_COL equ 18 ; "P2: nn" column
TURN_ROW equ 4 ; Turn indicator row
TURN_COL equ 14 ; Turn indicator column
Changing these moves the entire UI. Want scores at the bottom? Change SCORE_ROW to 20.
Updating After Claims
When a cell is claimed, we update the display:
try_claim:
; ... claim the cell ...
call draw_ui ; Update scores and turn indicator
call update_border
call draw_cursor
The draw_ui routine calls count_cells to recalculate, then redraws the score display and turn indicator. Every claim triggers an update.
The Complete Code
; ============================================================================
; INK WAR - Unit 4: Score and Turn Display
; ============================================================================
; Adds score display and turn indicator to the game.
; Shows "P1: nn P2: nn" and indicates whose turn it is.
;
; Controls: Q=Up, A=Down, O=Left, P=Right, SPACE=Claim
; ============================================================================
org 32768
; ----------------------------------------------------------------------------
; Constants
; ----------------------------------------------------------------------------
ATTR_BASE equ $5800
DISPLAY_FILE equ $4000
CHAR_SET equ $3C00 ; ROM character set base address
BOARD_ROW equ 8
BOARD_COL equ 12
BOARD_SIZE equ 8
; Display positions
SCORE_ROW equ 2 ; Score display row
P1_SCORE_COL equ 10 ; "P1: nn" column
P2_SCORE_COL equ 18 ; "P2: nn" column
TURN_ROW equ 4 ; Turn indicator row
TURN_COL equ 14 ; Turn indicator column
; Customised colours (from Unit 3)
EMPTY_ATTR equ %01101000 ; Cyan paper + BRIGHT
BORDER_ATTR equ %01110000 ; Yellow paper + BRIGHT
CURSOR_ATTR equ %01111000 ; White paper + BRIGHT
P1_ATTR equ %01010000 ; Red paper + BRIGHT
P2_ATTR equ %01001000 ; Blue paper + BRIGHT
P1_CURSOR equ %01111010 ; White paper + Red ink + BRIGHT
P2_CURSOR equ %01111001 ; White paper + Blue ink + BRIGHT
; Text display attributes
TEXT_ATTR equ %00111000 ; White paper, black ink
P1_TEXT equ %01010111 ; Red paper, white ink + BRIGHT
P2_TEXT equ %01001111 ; Blue paper, white ink + BRIGHT
P1_BORDER equ 2
P2_BORDER equ 1
; Keyboard ports
KEY_PORT equ $fe
ROW_QAOP equ $fb
ROW_ASDF equ $fd
ROW_YUIOP equ $df
ROW_SPACE equ $7f
; Game states
STATE_EMPTY equ 0
STATE_P1 equ 1
STATE_P2 equ 2
; ----------------------------------------------------------------------------
; Entry Point
; ----------------------------------------------------------------------------
start:
call init_screen
call init_game
call draw_board_border
call draw_board
call draw_ui ; Draw score and turn display
call draw_cursor
call update_border
main_loop:
halt
call read_keyboard
call handle_input
jp main_loop
; ----------------------------------------------------------------------------
; Initialise Screen
; ----------------------------------------------------------------------------
init_screen:
xor a
out (KEY_PORT), a
; Clear display file (pixels)
ld hl, DISPLAY_FILE
ld de, DISPLAY_FILE+1
ld bc, 6143
ld (hl), 0
ldir
; Clear all attributes to white paper, black ink
ld hl, ATTR_BASE
ld de, ATTR_BASE+1
ld bc, 767
ld (hl), TEXT_ATTR ; White background for text areas
ldir
ret
; ----------------------------------------------------------------------------
; Draw UI
; ----------------------------------------------------------------------------
; Draws score display and turn indicator
draw_ui:
call draw_scores
call draw_turn_indicator
ret
; ----------------------------------------------------------------------------
; Draw Scores
; ----------------------------------------------------------------------------
; Displays "P1: nn P2: nn" with player colours
draw_scores:
; Count cells for each player
call count_cells
; Draw P1 label "P1:"
ld b, SCORE_ROW
ld c, P1_SCORE_COL
ld a, 'P'
call print_char
inc c
ld a, '1'
call print_char
inc c
ld a, ':'
call print_char
inc c
; Print P1 score
ld a, (p1_count)
call print_two_digits
; Set P1 colour attribute
ld a, SCORE_ROW
ld c, P1_SCORE_COL
ld b, 5 ; "P1:nn" = 5 characters
ld e, P1_TEXT
call set_attr_range
; Draw P2 label "P2:"
ld b, SCORE_ROW
ld c, P2_SCORE_COL
ld a, 'P'
call print_char
inc c
ld a, '2'
call print_char
inc c
ld a, ':'
call print_char
inc c
; Print P2 score
ld a, (p2_count)
call print_two_digits
; Set P2 colour attribute
ld a, SCORE_ROW
ld c, P2_SCORE_COL
ld b, 5
ld e, P2_TEXT
call set_attr_range
ret
; ----------------------------------------------------------------------------
; Draw Turn Indicator
; ----------------------------------------------------------------------------
; Shows "TURN" with current player's colour
draw_turn_indicator:
; Print "TURN"
ld b, TURN_ROW
ld c, TURN_COL
ld a, 'T'
call print_char
inc c
ld a, 'U'
call print_char
inc c
ld a, 'R'
call print_char
inc c
ld a, 'N'
call print_char
; Set attribute based on current player
ld a, (current_player)
cp 1
jr z, .dti_p1
ld e, P2_TEXT
jr .dti_set
.dti_p1:
ld e, P1_TEXT
.dti_set:
ld a, TURN_ROW
ld c, TURN_COL
ld b, 4 ; "TURN" = 4 chars
call set_attr_range
ret
; ----------------------------------------------------------------------------
; Print Character
; ----------------------------------------------------------------------------
; A = ASCII character (32-127), B = row (0-23), C = column (0-31)
; Writes character directly to display file using ROM character set
print_char:
push bc
push de
push hl
push af
; Calculate character data address: CHAR_SET + char*8
ld l, a
ld h, 0
add hl, hl
add hl, hl
add hl, hl ; HL = char * 8
ld de, CHAR_SET
add hl, de ; HL = source address
push hl ; Save character data address
; Calculate display file address
; Screen address: high byte varies with row, low byte = column
ld a, b ; A = row (0-23)
and %00011000 ; Get which third (0, 8, 16)
add a, $40 ; Add display file base high byte
ld d, a
ld a, b ; A = row
and %00000111 ; Get line within character row
rrca
rrca
rrca ; Shift to bits 5-7
add a, c ; Add column
ld e, a ; DE = screen address
pop hl ; HL = character data
; Copy 8 bytes (8 pixel rows of character)
ld b, 8
.pc_loop:
ld a, (hl)
ld (de), a
inc hl
inc d ; Next screen line (add 256)
djnz .pc_loop
pop af
pop hl
pop de
pop bc
ret
; ----------------------------------------------------------------------------
; Print Two Digits
; ----------------------------------------------------------------------------
; A = number (0-99), B = row, C = column (will advance by 2)
; Prints number as two digits
print_two_digits:
push bc
; Calculate tens digit
ld d, 0 ; Tens counter
.ptd_tens:
cp 10
jr c, .ptd_print
sub 10
inc d
jr .ptd_tens
.ptd_print:
push af ; Save units digit
; Print tens digit
ld a, d
add a, '0'
call print_char
inc c
; Print units digit
pop af
add a, '0'
call print_char
inc c
pop bc
ret
; ----------------------------------------------------------------------------
; Count Cells
; ----------------------------------------------------------------------------
; Counts cells owned by each player
count_cells:
xor a
ld (p1_count), a
ld (p2_count), a
ld hl, board_state
ld b, 64 ; 64 cells
.cc_loop:
ld a, (hl)
cp STATE_P1
jr nz, .cc_not_p1
ld a, (p1_count)
inc a
ld (p1_count), a
jr .cc_next
.cc_not_p1:
cp STATE_P2
jr nz, .cc_next
ld a, (p2_count)
inc a
ld (p2_count), a
.cc_next:
inc hl
djnz .cc_loop
ret
; ----------------------------------------------------------------------------
; Set Attribute Range
; ----------------------------------------------------------------------------
; A = row, C = start column, B = count, E = attribute
set_attr_range:
push bc
push de
; Calculate start address: ATTR_BASE + row*32 + col
ld l, a
ld h, 0
add hl, hl
add hl, hl
add hl, hl
add hl, hl
add hl, hl ; HL = row * 32
ld a, c
add a, l
ld l, a
ld bc, ATTR_BASE
add hl, bc ; HL = attribute address
pop de ; E = attribute
pop bc ; B = count
.sar_loop:
ld (hl), e
inc hl
djnz .sar_loop
ret
; ----------------------------------------------------------------------------
; Update Border
; ----------------------------------------------------------------------------
update_border:
ld a, (current_player)
cp 1
jr z, .ub_p1
ld a, P2_BORDER
jr .ub_set
.ub_p1:
ld a, P1_BORDER
.ub_set:
out (KEY_PORT), a
ret
; ----------------------------------------------------------------------------
; Initialise Game State
; ----------------------------------------------------------------------------
init_game:
ld hl, board_state
ld b, 64
xor a
.ig_loop:
ld (hl), a
inc hl
djnz .ig_loop
ld a, 1
ld (current_player), a
xor a
ld (cursor_row), a
ld (cursor_col), a
ld (p1_count), a
ld (p2_count), a
ret
; ----------------------------------------------------------------------------
; Draw Board Border
; ----------------------------------------------------------------------------
draw_board_border:
ld c, BOARD_ROW-1
ld d, BOARD_COL-1
ld b, BOARD_SIZE+2
call draw_border_row
ld c, BOARD_ROW+BOARD_SIZE
ld d, BOARD_COL-1
ld b, BOARD_SIZE+2
call draw_border_row
ld c, BOARD_ROW
ld d, BOARD_COL-1
ld b, BOARD_SIZE
call draw_border_col
ld c, BOARD_ROW
ld d, BOARD_COL+BOARD_SIZE
ld b, BOARD_SIZE
call draw_border_col
ret
draw_border_row:
push bc
.dbr_loop:
push bc
push de
ld a, c
ld l, a
ld h, 0
add hl, hl
add hl, hl
add hl, hl
add hl, hl
add hl, hl
ld a, d
add a, l
ld l, a
ld bc, ATTR_BASE
add hl, bc
ld (hl), BORDER_ATTR
pop de
pop bc
inc d
djnz .dbr_loop
pop bc
ret
draw_border_col:
push bc
.dbc_loop:
push bc
push de
ld a, c
ld l, a
ld h, 0
add hl, hl
add hl, hl
add hl, hl
add hl, hl
add hl, hl
ld a, d
add a, l
ld l, a
ld bc, ATTR_BASE
add hl, bc
ld (hl), BORDER_ATTR
pop de
pop bc
inc c
djnz .dbc_loop
pop bc
ret
; ----------------------------------------------------------------------------
; Draw Board
; ----------------------------------------------------------------------------
draw_board:
ld b, BOARD_SIZE
ld c, BOARD_ROW
.db_row:
push bc
ld b, BOARD_SIZE
ld d, BOARD_COL
.db_col:
push bc
ld a, c
ld l, a
ld h, 0
add hl, hl
add hl, hl
add hl, hl
add hl, hl
add hl, hl
ld a, d
add a, l
ld l, a
ld bc, ATTR_BASE
add hl, bc
ld (hl), EMPTY_ATTR
pop bc
inc d
djnz .db_col
pop bc
inc c
djnz .db_row
ret
; ----------------------------------------------------------------------------
; Draw Cursor
; ----------------------------------------------------------------------------
draw_cursor:
call get_cell_state
cp STATE_P1
jr z, .dc_p1
cp STATE_P2
jr z, .dc_p2
ld a, CURSOR_ATTR
jr .dc_set
.dc_p1:
ld a, P1_CURSOR
jr .dc_set
.dc_p2:
ld a, P2_CURSOR
.dc_set:
push af
ld a, (cursor_row)
add a, BOARD_ROW
ld l, a
ld h, 0
add hl, hl
add hl, hl
add hl, hl
add hl, hl
add hl, hl
ld a, (cursor_col)
add a, BOARD_COL
add a, l
ld l, a
ld bc, ATTR_BASE
add hl, bc
pop af
ld (hl), a
ret
; ----------------------------------------------------------------------------
; Clear Cursor
; ----------------------------------------------------------------------------
clear_cursor:
call get_cell_state
cp STATE_P1
jr z, .clc_p1
cp STATE_P2
jr z, .clc_p2
ld a, EMPTY_ATTR
jr .clc_set
.clc_p1:
ld a, P1_ATTR
jr .clc_set
.clc_p2:
ld a, P2_ATTR
.clc_set:
push af
ld a, (cursor_row)
add a, BOARD_ROW
ld l, a
ld h, 0
add hl, hl
add hl, hl
add hl, hl
add hl, hl
add hl, hl
ld a, (cursor_col)
add a, BOARD_COL
add a, l
ld l, a
ld bc, ATTR_BASE
add hl, bc
pop af
ld (hl), a
ret
; ----------------------------------------------------------------------------
; Get Cell State
; ----------------------------------------------------------------------------
get_cell_state:
ld a, (cursor_row)
add a, a
add a, a
add a, a
ld hl, board_state
ld b, 0
ld c, a
add hl, bc
ld a, (cursor_col)
ld c, a
add hl, bc
ld a, (hl)
ret
; ----------------------------------------------------------------------------
; Read Keyboard
; ----------------------------------------------------------------------------
read_keyboard:
xor a
ld (key_pressed), a
ld a, ROW_QAOP
in a, (KEY_PORT)
bit 0, a
jr nz, .rk_not_q
ld a, 1
ld (key_pressed), a
ret
.rk_not_q:
ld a, ROW_ASDF
in a, (KEY_PORT)
bit 0, a
jr nz, .rk_not_a
ld a, 2
ld (key_pressed), a
ret
.rk_not_a:
ld a, ROW_YUIOP
in a, (KEY_PORT)
bit 1, a
jr nz, .rk_not_o
ld a, 3
ld (key_pressed), a
ret
.rk_not_o:
ld a, ROW_YUIOP
in a, (KEY_PORT)
bit 0, a
jr nz, .rk_not_p
ld a, 4
ld (key_pressed), a
ret
.rk_not_p:
ld a, ROW_SPACE
in a, (KEY_PORT)
bit 0, a
jr nz, .rk_not_space
ld a, 5
ld (key_pressed), a
.rk_not_space:
ret
; ----------------------------------------------------------------------------
; Handle Input
; ----------------------------------------------------------------------------
handle_input:
ld a, (key_pressed)
or a
ret z
cp 5
jr z, try_claim
call clear_cursor
ld a, (key_pressed)
cp 1
jr nz, .hi_not_up
ld a, (cursor_row)
or a
jr z, .hi_done
dec a
ld (cursor_row), a
jr .hi_done
.hi_not_up:
cp 2
jr nz, .hi_not_down
ld a, (cursor_row)
cp BOARD_SIZE-1
jr z, .hi_done
inc a
ld (cursor_row), a
jr .hi_done
.hi_not_down:
cp 3
jr nz, .hi_not_left
ld a, (cursor_col)
or a
jr z, .hi_done
dec a
ld (cursor_col), a
jr .hi_done
.hi_not_left:
cp 4
jr nz, .hi_done
ld a, (cursor_col)
cp BOARD_SIZE-1
jr z, .hi_done
inc a
ld (cursor_col), a
.hi_done:
call draw_cursor
ret
; ----------------------------------------------------------------------------
; Try Claim Cell
; ----------------------------------------------------------------------------
try_claim:
call get_cell_state
or a
ret nz
call claim_cell
call sound_claim
ld a, (current_player)
xor 3
ld (current_player), a
call draw_ui ; Update scores and turn indicator
call update_border
call draw_cursor
ret
; ----------------------------------------------------------------------------
; Claim Cell
; ----------------------------------------------------------------------------
claim_cell:
ld a, (cursor_row)
add a, a
add a, a
add a, a
ld hl, board_state
ld b, 0
ld c, a
add hl, bc
ld a, (cursor_col)
ld c, a
add hl, bc
ld a, (current_player)
ld (hl), a
push af
ld a, (cursor_row)
add a, BOARD_ROW
ld l, a
ld h, 0
add hl, hl
add hl, hl
add hl, hl
add hl, hl
add hl, hl
ld a, (cursor_col)
add a, BOARD_COL
add a, l
ld l, a
ld bc, ATTR_BASE
add hl, bc
pop af
cp 1
jr z, .clm_is_p1
ld (hl), P2_ATTR
ret
.clm_is_p1:
ld (hl), P1_ATTR
ret
; ----------------------------------------------------------------------------
; Sound - Claim
; ----------------------------------------------------------------------------
sound_claim:
ld hl, 400
ld b, 20
.scl_loop:
push bc
push hl
ld b, h
ld c, l
.scl_tone:
ld a, $10
out (KEY_PORT), a
call .scl_delay
xor a
out (KEY_PORT), a
call .scl_delay
dec bc
ld a, b
or c
jr nz, .scl_tone
pop hl
pop bc
ld de, 20
or a
sbc hl, de
djnz .scl_loop
ret
.scl_delay:
push bc
ld b, 5
.scl_delay_loop:
djnz .scl_delay_loop
pop bc
ret
; ----------------------------------------------------------------------------
; Variables
; ----------------------------------------------------------------------------
cursor_row: defb 0
cursor_col: defb 0
key_pressed: defb 0
current_player: defb 1
p1_count: defb 0
p2_count: defb 0
board_state: defs 64, 0
; ----------------------------------------------------------------------------
; End
; ----------------------------------------------------------------------------
end start
Try This: Move the UI
Change the position constants:
; Scores at the bottom
SCORE_ROW equ 21
; Turn indicator on the left
TURN_ROW equ 12
TURN_COL equ 2
Try This: Different Colour Scheme
; Green for P1, Magenta for P2
P1_TEXT equ %01100111 ; Green paper, white ink
P2_TEXT equ %01011111 ; Magenta paper, white ink
What You’ve Learnt
- Custom print routine - Direct screen memory access gives full control
- ROM character set - Character data at $3C00, each character is 8 bytes
- Display file layout - Screen memory has complex interleaved addressing
- Number to ASCII - Add ‘0’ (48) to convert a digit to its character code
- Cell counting - Iterate with DJNZ, compare and branch to count categories
- Attribute ranges - Set consecutive attributes to create coloured text backgrounds
What’s Next
In Unit 5, we’ll add proper move validation with feedback - error sounds and visual cues when you try to claim an already-occupied cell.
What Changed
| 1 | 1 | ; ============================================================================ | |
| 2 | - | ; INK WAR - Unit 3: Making It Yours | |
| 2 | + | ; INK WAR - Unit 4: Score and Turn Display | |
| 3 | 3 | ; ============================================================================ | |
| 4 | - | ; Customised version demonstrating attribute control: | |
| 5 | - | ; - Cyan board cells (not white) | |
| 6 | - | ; - Yellow border cells around the board | |
| 7 | - | ; - Screen border changes colour with current player | |
| 8 | - | ; - Bright cursor (not flashing) | |
| 4 | + | ; Adds score display and turn indicator to the game. | |
| 5 | + | ; Shows "P1: nn P2: nn" and indicates whose turn it is. | |
| 9 | 6 | ; | |
| 10 | 7 | ; Controls: Q=Up, A=Down, O=Left, P=Right, SPACE=Claim | |
| 11 | 8 | ; ============================================================================ | |
| ... | |||
| 15 | 12 | ; ---------------------------------------------------------------------------- | |
| 16 | 13 | ; Constants | |
| 17 | 14 | ; ---------------------------------------------------------------------------- | |
| 18 | - | | |
| 19 | - | ATTR_BASE equ $5800 ; Start of attribute memory | |
| 20 | - | BOARD_ROW equ 8 ; Board starts at row 8 | |
| 21 | - | BOARD_COL equ 12 ; Board starts at column 12 | |
| 22 | - | BOARD_SIZE equ 8 ; 8x8 playing field | |
| 23 | - | | |
| 24 | - | ; ============================================================================ | |
| 25 | - | ; CUSTOMISATION SECTION - Change these values to personalise your game! | |
| 26 | - | ; ============================================================================ | |
| 27 | 15 | | |
| 28 | - | ; Attribute format: %FBPPPIII | |
| 29 | - | ; F = Flash (bit 7): 1 = flashing | |
| 30 | - | ; B = Bright (bit 6): 1 = brighter colours | |
| 31 | - | ; PPP = Paper colour (bits 5-3): background | |
| 32 | - | ; III = Ink colour (bits 2-0): foreground | |
| 33 | - | ; | |
| 34 | - | ; Colour values (0-7): | |
| 35 | - | ; 0=Black, 1=Blue, 2=Red, 3=Magenta, 4=Green, 5=Cyan, 6=Yellow, 7=White | |
| 16 | + | ATTR_BASE equ $5800 | |
| 17 | + | DISPLAY_FILE equ $4000 | |
| 18 | + | CHAR_SET equ $3C00 ; ROM character set base address | |
| 36 | 19 | | |
| 37 | - | ; Empty cells - CUSTOMISED: cyan instead of white | |
| 38 | - | ; %01101000 = BRIGHT + Paper 5 (cyan) + Ink 0 (black) | |
| 39 | - | EMPTY_ATTR equ %01101000 ; Cyan paper, black ink + BRIGHT | |
| 20 | + | BOARD_ROW equ 8 | |
| 21 | + | BOARD_COL equ 12 | |
| 22 | + | BOARD_SIZE equ 8 | |
| 40 | 23 | | |
| 41 | - | ; Board border - CUSTOMISED: yellow border around playing area | |
| 42 | - | ; %01110000 = BRIGHT + Paper 6 (yellow) + Ink 0 (black) | |
| 43 | - | BORDER_ATTR equ %01110000 ; Yellow paper, black ink + BRIGHT | |
| 24 | + | ; Display positions | |
| 25 | + | SCORE_ROW equ 2 ; Score display row | |
| 26 | + | P1_SCORE_COL equ 10 ; "P1: nn" column | |
| 27 | + | P2_SCORE_COL equ 18 ; "P2: nn" column | |
| 28 | + | TURN_ROW equ 4 ; Turn indicator row | |
| 29 | + | TURN_COL equ 14 ; Turn indicator column | |
| 44 | 30 | | |
| 45 | - | ; Cursor - CUSTOMISED: bright white instead of flashing | |
| 46 | - | ; %01111000 = BRIGHT + Paper 7 (white) + Ink 0 (black) | |
| 47 | - | CURSOR_ATTR equ %01111000 ; White paper + BRIGHT (no flash) | |
| 31 | + | ; Customised colours (from Unit 3) | |
| 32 | + | EMPTY_ATTR equ %01101000 ; Cyan paper + BRIGHT | |
| 33 | + | BORDER_ATTR equ %01110000 ; Yellow paper + BRIGHT | |
| 34 | + | CURSOR_ATTR equ %01111000 ; White paper + BRIGHT | |
| 48 | 35 | | |
| 49 | - | ; Player 1 - Red (unchanged) | |
| 50 | 36 | P1_ATTR equ %01010000 ; Red paper + BRIGHT | |
| 51 | - | P1_CURSOR equ %01111010 ; White paper + Red ink + BRIGHT | |
| 52 | - | | |
| 53 | - | ; Player 2 - Blue (unchanged) | |
| 54 | 37 | P2_ATTR equ %01001000 ; Blue paper + BRIGHT | |
| 38 | + | P1_CURSOR equ %01111010 ; White paper + Red ink + BRIGHT | |
| 55 | 39 | P2_CURSOR equ %01111001 ; White paper + Blue ink + BRIGHT | |
| 56 | 40 | | |
| 57 | - | ; Screen border colours for each player | |
| 58 | - | P1_BORDER equ 2 ; Red border for Player 1's turn | |
| 59 | - | P2_BORDER equ 1 ; Blue border for Player 2's turn | |
| 41 | + | ; Text display attributes | |
| 42 | + | TEXT_ATTR equ %00111000 ; White paper, black ink | |
| 43 | + | P1_TEXT equ %01010111 ; Red paper, white ink + BRIGHT | |
| 44 | + | P2_TEXT equ %01001111 ; Blue paper, white ink + BRIGHT | |
| 60 | 45 | | |
| 61 | - | ; ============================================================================ | |
| 62 | - | ; End of customisation section | |
| 63 | - | ; ============================================================================ | |
| 46 | + | P1_BORDER equ 2 | |
| 47 | + | P2_BORDER equ 1 | |
| 64 | 48 | | |
| 65 | - | ; Keyboard ports (active low) | |
| 49 | + | ; Keyboard ports | |
| 66 | 50 | KEY_PORT equ $fe | |
| 67 | 51 | ROW_QAOP equ $fb | |
| 68 | 52 | ROW_ASDF equ $fd | |
| ... | |||
| 81 | 65 | start: | |
| 82 | 66 | call init_screen | |
| 83 | 67 | call init_game | |
| 84 | - | call draw_board_border ; NEW: Draw visible border | |
| 68 | + | call draw_board_border | |
| 85 | 69 | call draw_board | |
| 70 | + | call draw_ui ; Draw score and turn display | |
| 86 | 71 | call draw_cursor | |
| 87 | - | call update_border ; Set initial border colour | |
| 72 | + | call update_border | |
| 88 | 73 | | |
| 89 | 74 | main_loop: | |
| 90 | 75 | halt | |
| ... | |||
| 101 | 86 | init_screen: | |
| 102 | 87 | xor a | |
| 103 | 88 | out (KEY_PORT), a | |
| 89 | + | | |
| 90 | + | ; Clear display file (pixels) | |
| 91 | + | ld hl, DISPLAY_FILE | |
| 92 | + | ld de, DISPLAY_FILE+1 | |
| 93 | + | ld bc, 6143 | |
| 94 | + | ld (hl), 0 | |
| 95 | + | ldir | |
| 104 | 96 | | |
| 97 | + | ; Clear all attributes to white paper, black ink | |
| 105 | 98 | ld hl, ATTR_BASE | |
| 106 | 99 | ld de, ATTR_BASE+1 | |
| 107 | 100 | ld bc, 767 | |
| 108 | - | ld (hl), 0 | |
| 101 | + | ld (hl), TEXT_ATTR ; White background for text areas | |
| 109 | 102 | ldir | |
| 110 | 103 | | |
| 111 | 104 | ret | |
| 112 | 105 | | |
| 113 | 106 | ; ---------------------------------------------------------------------------- | |
| 114 | - | ; Update Screen Border | |
| 107 | + | ; Draw UI | |
| 115 | 108 | ; ---------------------------------------------------------------------------- | |
| 116 | - | ; Sets border colour based on current player | |
| 109 | + | ; Draws score display and turn indicator | |
| 110 | + | | |
| 111 | + | draw_ui: | |
| 112 | + | call draw_scores | |
| 113 | + | call draw_turn_indicator | |
| 114 | + | ret | |
| 115 | + | | |
| 116 | + | ; ---------------------------------------------------------------------------- | |
| 117 | + | ; Draw Scores | |
| 118 | + | ; ---------------------------------------------------------------------------- | |
| 119 | + | ; Displays "P1: nn P2: nn" with player colours | |
| 120 | + | | |
| 121 | + | draw_scores: | |
| 122 | + | ; Count cells for each player | |
| 123 | + | call count_cells | |
| 124 | + | | |
| 125 | + | ; Draw P1 label "P1:" | |
| 126 | + | ld b, SCORE_ROW | |
| 127 | + | ld c, P1_SCORE_COL | |
| 128 | + | ld a, 'P' | |
| 129 | + | call print_char | |
| 130 | + | inc c | |
| 131 | + | ld a, '1' | |
| 132 | + | call print_char | |
| 133 | + | inc c | |
| 134 | + | ld a, ':' | |
| 135 | + | call print_char | |
| 136 | + | inc c | |
| 137 | + | | |
| 138 | + | ; Print P1 score | |
| 139 | + | ld a, (p1_count) | |
| 140 | + | call print_two_digits | |
| 141 | + | | |
| 142 | + | ; Set P1 colour attribute | |
| 143 | + | ld a, SCORE_ROW | |
| 144 | + | ld c, P1_SCORE_COL | |
| 145 | + | ld b, 5 ; "P1:nn" = 5 characters | |
| 146 | + | ld e, P1_TEXT | |
| 147 | + | call set_attr_range | |
| 148 | + | | |
| 149 | + | ; Draw P2 label "P2:" | |
| 150 | + | ld b, SCORE_ROW | |
| 151 | + | ld c, P2_SCORE_COL | |
| 152 | + | ld a, 'P' | |
| 153 | + | call print_char | |
| 154 | + | inc c | |
| 155 | + | ld a, '2' | |
| 156 | + | call print_char | |
| 157 | + | inc c | |
| 158 | + | ld a, ':' | |
| 159 | + | call print_char | |
| 160 | + | inc c | |
| 161 | + | | |
| 162 | + | ; Print P2 score | |
| 163 | + | ld a, (p2_count) | |
| 164 | + | call print_two_digits | |
| 165 | + | | |
| 166 | + | ; Set P2 colour attribute | |
| 167 | + | ld a, SCORE_ROW | |
| 168 | + | ld c, P2_SCORE_COL | |
| 169 | + | ld b, 5 | |
| 170 | + | ld e, P2_TEXT | |
| 171 | + | call set_attr_range | |
| 172 | + | | |
| 173 | + | ret | |
| 174 | + | | |
| 175 | + | ; ---------------------------------------------------------------------------- | |
| 176 | + | ; Draw Turn Indicator | |
| 177 | + | ; ---------------------------------------------------------------------------- | |
| 178 | + | ; Shows "TURN" with current player's colour | |
| 179 | + | | |
| 180 | + | draw_turn_indicator: | |
| 181 | + | ; Print "TURN" | |
| 182 | + | ld b, TURN_ROW | |
| 183 | + | ld c, TURN_COL | |
| 184 | + | ld a, 'T' | |
| 185 | + | call print_char | |
| 186 | + | inc c | |
| 187 | + | ld a, 'U' | |
| 188 | + | call print_char | |
| 189 | + | inc c | |
| 190 | + | ld a, 'R' | |
| 191 | + | call print_char | |
| 192 | + | inc c | |
| 193 | + | ld a, 'N' | |
| 194 | + | call print_char | |
| 195 | + | | |
| 196 | + | ; Set attribute based on current player | |
| 197 | + | ld a, (current_player) | |
| 198 | + | cp 1 | |
| 199 | + | jr z, .dti_p1 | |
| 200 | + | ld e, P2_TEXT | |
| 201 | + | jr .dti_set | |
| 202 | + | .dti_p1: | |
| 203 | + | ld e, P1_TEXT | |
| 204 | + | | |
| 205 | + | .dti_set: | |
| 206 | + | ld a, TURN_ROW | |
| 207 | + | ld c, TURN_COL | |
| 208 | + | ld b, 4 ; "TURN" = 4 chars | |
| 209 | + | call set_attr_range | |
| 210 | + | | |
| 211 | + | ret | |
| 212 | + | | |
| 213 | + | ; ---------------------------------------------------------------------------- | |
| 214 | + | ; Print Character | |
| 215 | + | ; ---------------------------------------------------------------------------- | |
| 216 | + | ; A = ASCII character (32-127), B = row (0-23), C = column (0-31) | |
| 217 | + | ; Writes character directly to display file using ROM character set | |
| 218 | + | | |
| 219 | + | print_char: | |
| 220 | + | push bc | |
| 221 | + | push de | |
| 222 | + | push hl | |
| 223 | + | push af | |
| 224 | + | | |
| 225 | + | ; Calculate character data address: CHAR_SET + char*8 | |
| 226 | + | ld l, a | |
| 227 | + | ld h, 0 | |
| 228 | + | add hl, hl | |
| 229 | + | add hl, hl | |
| 230 | + | add hl, hl ; HL = char * 8 | |
| 231 | + | ld de, CHAR_SET | |
| 232 | + | add hl, de ; HL = source address | |
| 233 | + | | |
| 234 | + | push hl ; Save character data address | |
| 235 | + | | |
| 236 | + | ; Calculate display file address | |
| 237 | + | ; Screen address: high byte varies with row, low byte = column | |
| 238 | + | ld a, b ; A = row (0-23) | |
| 239 | + | and %00011000 ; Get which third (0, 8, 16) | |
| 240 | + | add a, $40 ; Add display file base high byte | |
| 241 | + | ld d, a | |
| 242 | + | | |
| 243 | + | ld a, b ; A = row | |
| 244 | + | and %00000111 ; Get line within character row | |
| 245 | + | rrca | |
| 246 | + | rrca | |
| 247 | + | rrca ; Shift to bits 5-7 | |
| 248 | + | add a, c ; Add column | |
| 249 | + | ld e, a ; DE = screen address | |
| 250 | + | | |
| 251 | + | pop hl ; HL = character data | |
| 252 | + | | |
| 253 | + | ; Copy 8 bytes (8 pixel rows of character) | |
| 254 | + | ld b, 8 | |
| 255 | + | .pc_loop: | |
| 256 | + | ld a, (hl) | |
| 257 | + | ld (de), a | |
| 258 | + | inc hl | |
| 259 | + | inc d ; Next screen line (add 256) | |
| 260 | + | djnz .pc_loop | |
| 261 | + | | |
| 262 | + | pop af | |
| 263 | + | pop hl | |
| 264 | + | pop de | |
| 265 | + | pop bc | |
| 266 | + | ret | |
| 267 | + | | |
| 268 | + | ; ---------------------------------------------------------------------------- | |
| 269 | + | ; Print Two Digits | |
| 270 | + | ; ---------------------------------------------------------------------------- | |
| 271 | + | ; A = number (0-99), B = row, C = column (will advance by 2) | |
| 272 | + | ; Prints number as two digits | |
| 273 | + | | |
| 274 | + | print_two_digits: | |
| 275 | + | push bc | |
| 276 | + | | |
| 277 | + | ; Calculate tens digit | |
| 278 | + | ld d, 0 ; Tens counter | |
| 279 | + | .ptd_tens: | |
| 280 | + | cp 10 | |
| 281 | + | jr c, .ptd_print | |
| 282 | + | sub 10 | |
| 283 | + | inc d | |
| 284 | + | jr .ptd_tens | |
| 285 | + | | |
| 286 | + | .ptd_print: | |
| 287 | + | push af ; Save units digit | |
| 288 | + | | |
| 289 | + | ; Print tens digit | |
| 290 | + | ld a, d | |
| 291 | + | add a, '0' | |
| 292 | + | call print_char | |
| 293 | + | inc c | |
| 294 | + | | |
| 295 | + | ; Print units digit | |
| 296 | + | pop af | |
| 297 | + | add a, '0' | |
| 298 | + | call print_char | |
| 299 | + | inc c | |
| 300 | + | | |
| 301 | + | pop bc | |
| 302 | + | ret | |
| 303 | + | | |
| 304 | + | ; ---------------------------------------------------------------------------- | |
| 305 | + | ; Count Cells | |
| 306 | + | ; ---------------------------------------------------------------------------- | |
| 307 | + | ; Counts cells owned by each player | |
| 308 | + | | |
| 309 | + | count_cells: | |
| 310 | + | xor a | |
| 311 | + | ld (p1_count), a | |
| 312 | + | ld (p2_count), a | |
| 313 | + | | |
| 314 | + | ld hl, board_state | |
| 315 | + | ld b, 64 ; 64 cells | |
| 316 | + | | |
| 317 | + | .cc_loop: | |
| 318 | + | ld a, (hl) | |
| 319 | + | cp STATE_P1 | |
| 320 | + | jr nz, .cc_not_p1 | |
| 321 | + | ld a, (p1_count) | |
| 322 | + | inc a | |
| 323 | + | ld (p1_count), a | |
| 324 | + | jr .cc_next | |
| 325 | + | .cc_not_p1: | |
| 326 | + | cp STATE_P2 | |
| 327 | + | jr nz, .cc_next | |
| 328 | + | ld a, (p2_count) | |
| 329 | + | inc a | |
| 330 | + | ld (p2_count), a | |
| 331 | + | .cc_next: | |
| 332 | + | inc hl | |
| 333 | + | djnz .cc_loop | |
| 334 | + | | |
| 335 | + | ret | |
| 336 | + | | |
| 337 | + | ; ---------------------------------------------------------------------------- | |
| 338 | + | ; Set Attribute Range | |
| 339 | + | ; ---------------------------------------------------------------------------- | |
| 340 | + | ; A = row, C = start column, B = count, E = attribute | |
| 341 | + | | |
| 342 | + | set_attr_range: | |
| 343 | + | push bc | |
| 344 | + | push de | |
| 345 | + | | |
| 346 | + | ; Calculate start address: ATTR_BASE + row*32 + col | |
| 347 | + | ld l, a | |
| 348 | + | ld h, 0 | |
| 349 | + | add hl, hl | |
| 350 | + | add hl, hl | |
| 351 | + | add hl, hl | |
| 352 | + | add hl, hl | |
| 353 | + | add hl, hl ; HL = row * 32 | |
| 354 | + | ld a, c | |
| 355 | + | add a, l | |
| 356 | + | ld l, a | |
| 357 | + | ld bc, ATTR_BASE | |
| 358 | + | add hl, bc ; HL = attribute address | |
| 359 | + | | |
| 360 | + | pop de ; E = attribute | |
| 361 | + | pop bc ; B = count | |
| 362 | + | | |
| 363 | + | .sar_loop: | |
| 364 | + | ld (hl), e | |
| 365 | + | inc hl | |
| 366 | + | djnz .sar_loop | |
| 367 | + | | |
| 368 | + | ret | |
| 369 | + | | |
| 370 | + | ; ---------------------------------------------------------------------------- | |
| 371 | + | ; Update Border | |
| 372 | + | ; ---------------------------------------------------------------------------- | |
| 117 | 373 | | |
| 118 | 374 | update_border: | |
| 119 | 375 | ld a, (current_player) | |
| ... | |||
| 135 | 391 | ld hl, board_state | |
| 136 | 392 | ld b, 64 | |
| 137 | 393 | xor a | |
| 138 | - | .clear_loop: | |
| 394 | + | .ig_loop: | |
| 139 | 395 | ld (hl), a | |
| 140 | 396 | inc hl | |
| 141 | - | djnz .clear_loop | |
| 397 | + | djnz .ig_loop | |
| 142 | 398 | | |
| 143 | 399 | ld a, 1 | |
| 144 | 400 | ld (current_player), a | |
| ... | |||
| 146 | 402 | xor a | |
| 147 | 403 | ld (cursor_row), a | |
| 148 | 404 | ld (cursor_col), a | |
| 405 | + | ld (p1_count), a | |
| 406 | + | ld (p2_count), a | |
| 149 | 407 | | |
| 150 | 408 | ret | |
| 151 | 409 | | |
| 152 | 410 | ; ---------------------------------------------------------------------------- | |
| 153 | 411 | ; Draw Board Border | |
| 154 | 412 | ; ---------------------------------------------------------------------------- | |
| 155 | - | ; Draws a visible border around the 8x8 playing area | |
| 156 | 413 | | |
| 157 | 414 | draw_board_border: | |
| 158 | - | ; Top border (row 7, columns 11-20) | |
| 159 | - | ld c, BOARD_ROW-1 ; Row 7 | |
| 160 | - | ld d, BOARD_COL-1 ; Start at column 11 | |
| 161 | - | ld b, BOARD_SIZE+2 ; 10 cells wide | |
| 415 | + | ld c, BOARD_ROW-1 | |
| 416 | + | ld d, BOARD_COL-1 | |
| 417 | + | ld b, BOARD_SIZE+2 | |
| 162 | 418 | call draw_border_row | |
| 163 | 419 | | |
| 164 | - | ; Bottom border (row 16, columns 11-20) | |
| 165 | - | ld c, BOARD_ROW+BOARD_SIZE ; Row 16 | |
| 420 | + | ld c, BOARD_ROW+BOARD_SIZE | |
| 166 | 421 | ld d, BOARD_COL-1 | |
| 167 | 422 | ld b, BOARD_SIZE+2 | |
| 168 | 423 | call draw_border_row | |
| 169 | 424 | | |
| 170 | - | ; Left border (rows 8-15, column 11) | |
| 171 | - | ld c, BOARD_ROW ; Start at row 8 | |
| 172 | - | ld d, BOARD_COL-1 ; Column 11 | |
| 173 | - | ld b, BOARD_SIZE ; 8 cells tall | |
| 425 | + | ld c, BOARD_ROW | |
| 426 | + | ld d, BOARD_COL-1 | |
| 427 | + | ld b, BOARD_SIZE | |
| 174 | 428 | call draw_border_col | |
| 175 | 429 | | |
| 176 | - | ; Right border (rows 8-15, column 20) | |
| 177 | 430 | ld c, BOARD_ROW | |
| 178 | - | ld d, BOARD_COL+BOARD_SIZE ; Column 20 | |
| 431 | + | ld d, BOARD_COL+BOARD_SIZE | |
| 179 | 432 | ld b, BOARD_SIZE | |
| 180 | 433 | call draw_border_col | |
| 181 | 434 | | |
| 182 | 435 | ret | |
| 183 | 436 | | |
| 184 | - | ; Draw horizontal border row | |
| 185 | - | ; C = row, D = start column, B = width | |
| 186 | 437 | draw_border_row: | |
| 187 | 438 | push bc | |
| 188 | - | .row_loop: | |
| 439 | + | .dbr_loop: | |
| 189 | 440 | push bc | |
| 190 | 441 | push de | |
| 191 | 442 | | |
| 192 | - | ; Calculate attribute address | |
| 193 | 443 | ld a, c | |
| 194 | 444 | ld l, a | |
| 195 | 445 | ld h, 0 | |
| ... | |||
| 209 | 459 | pop de | |
| 210 | 460 | pop bc | |
| 211 | 461 | inc d | |
| 212 | - | djnz .row_loop | |
| 462 | + | djnz .dbr_loop | |
| 213 | 463 | pop bc | |
| 214 | 464 | ret | |
| 215 | 465 | | |
| 216 | - | ; Draw vertical border column | |
| 217 | - | ; C = start row, D = column, B = height | |
| 218 | 466 | draw_border_col: | |
| 219 | 467 | push bc | |
| 220 | - | .col_loop: | |
| 468 | + | .dbc_loop: | |
| 221 | 469 | push bc | |
| 222 | 470 | push de | |
| 223 | 471 | | |
| 224 | - | ; Calculate attribute address | |
| 225 | 472 | ld a, c | |
| 226 | 473 | ld l, a | |
| 227 | 474 | ld h, 0 | |
| ... | |||
| 241 | 488 | pop de | |
| 242 | 489 | pop bc | |
| 243 | 490 | inc c | |
| 244 | - | djnz .col_loop | |
| 491 | + | djnz .dbc_loop | |
| 245 | 492 | pop bc | |
| 246 | 493 | ret | |
| 247 | 494 | | |
| ... | |||
| 342 | 589 | call get_cell_state | |
| 343 | 590 | | |
| 344 | 591 | cp STATE_P1 | |
| 345 | - | jr z, .cc_p1 | |
| 592 | + | jr z, .clc_p1 | |
| 346 | 593 | cp STATE_P2 | |
| 347 | - | jr z, .cc_p2 | |
| 594 | + | jr z, .clc_p2 | |
| 348 | 595 | | |
| 349 | 596 | ld a, EMPTY_ATTR | |
| 350 | - | jr .cc_set | |
| 597 | + | jr .clc_set | |
| 351 | 598 | | |
| 352 | - | .cc_p1: | |
| 599 | + | .clc_p1: | |
| 353 | 600 | ld a, P1_ATTR | |
| 354 | - | jr .cc_set | |
| 601 | + | jr .clc_set | |
| 355 | 602 | | |
| 356 | - | .cc_p2: | |
| 603 | + | .clc_p2: | |
| 357 | 604 | ld a, P2_ATTR | |
| 358 | 605 | | |
| 359 | - | .cc_set: | |
| 606 | + | .clc_set: | |
| 360 | 607 | push af | |
| 361 | 608 | | |
| 362 | 609 | ld a, (cursor_row) | |
| ... | |||
| 410 | 657 | ld a, ROW_QAOP | |
| 411 | 658 | in a, (KEY_PORT) | |
| 412 | 659 | bit 0, a | |
| 413 | - | jr nz, .not_q | |
| 660 | + | jr nz, .rk_not_q | |
| 414 | 661 | ld a, 1 | |
| 415 | 662 | ld (key_pressed), a | |
| 416 | 663 | ret | |
| 417 | - | .not_q: | |
| 664 | + | .rk_not_q: | |
| 418 | 665 | ld a, ROW_ASDF | |
| 419 | 666 | in a, (KEY_PORT) | |
| 420 | 667 | bit 0, a | |
| 421 | - | jr nz, .not_a | |
| 668 | + | jr nz, .rk_not_a | |
| 422 | 669 | ld a, 2 | |
| 423 | 670 | ld (key_pressed), a | |
| 424 | 671 | ret | |
| 425 | - | .not_a: | |
| 672 | + | .rk_not_a: | |
| 426 | 673 | ld a, ROW_YUIOP | |
| 427 | 674 | in a, (KEY_PORT) | |
| 428 | 675 | bit 1, a | |
| 429 | - | jr nz, .not_o | |
| 676 | + | jr nz, .rk_not_o | |
| 430 | 677 | ld a, 3 | |
| 431 | 678 | ld (key_pressed), a | |
| 432 | 679 | ret | |
| 433 | - | .not_o: | |
| 680 | + | .rk_not_o: | |
| 434 | 681 | ld a, ROW_YUIOP | |
| 435 | 682 | in a, (KEY_PORT) | |
| 436 | 683 | bit 0, a | |
| 437 | - | jr nz, .not_p | |
| 684 | + | jr nz, .rk_not_p | |
| 438 | 685 | ld a, 4 | |
| 439 | 686 | ld (key_pressed), a | |
| 440 | 687 | ret | |
| 441 | - | .not_p: | |
| 688 | + | .rk_not_p: | |
| 442 | 689 | ld a, ROW_SPACE | |
| 443 | 690 | in a, (KEY_PORT) | |
| 444 | 691 | bit 0, a | |
| 445 | - | jr nz, .not_space | |
| 692 | + | jr nz, .rk_not_space | |
| 446 | 693 | ld a, 5 | |
| 447 | 694 | ld (key_pressed), a | |
| 448 | - | .not_space: | |
| 695 | + | .rk_not_space: | |
| 449 | 696 | ret | |
| 450 | 697 | | |
| 451 | 698 | ; ---------------------------------------------------------------------------- | |
| ... | |||
| 465 | 712 | ld a, (key_pressed) | |
| 466 | 713 | | |
| 467 | 714 | cp 1 | |
| 468 | - | jr nz, .not_up | |
| 715 | + | jr nz, .hi_not_up | |
| 469 | 716 | ld a, (cursor_row) | |
| 470 | 717 | or a | |
| 471 | - | jr z, .done | |
| 718 | + | jr z, .hi_done | |
| 472 | 719 | dec a | |
| 473 | 720 | ld (cursor_row), a | |
| 474 | - | jr .done | |
| 475 | - | .not_up: | |
| 721 | + | jr .hi_done | |
| 722 | + | .hi_not_up: | |
| 476 | 723 | cp 2 | |
| 477 | - | jr nz, .not_down | |
| 724 | + | jr nz, .hi_not_down | |
| 478 | 725 | ld a, (cursor_row) | |
| 479 | 726 | cp BOARD_SIZE-1 | |
| 480 | - | jr z, .done | |
| 727 | + | jr z, .hi_done | |
| 481 | 728 | inc a | |
| 482 | 729 | ld (cursor_row), a | |
| 483 | - | jr .done | |
| 484 | - | .not_down: | |
| 730 | + | jr .hi_done | |
| 731 | + | .hi_not_down: | |
| 485 | 732 | cp 3 | |
| 486 | - | jr nz, .not_left | |
| 733 | + | jr nz, .hi_not_left | |
| 487 | 734 | ld a, (cursor_col) | |
| 488 | 735 | or a | |
| 489 | - | jr z, .done | |
| 736 | + | jr z, .hi_done | |
| 490 | 737 | dec a | |
| 491 | 738 | ld (cursor_col), a | |
| 492 | - | jr .done | |
| 493 | - | .not_left: | |
| 739 | + | jr .hi_done | |
| 740 | + | .hi_not_left: | |
| 494 | 741 | cp 4 | |
| 495 | - | jr nz, .done | |
| 742 | + | jr nz, .hi_done | |
| 496 | 743 | ld a, (cursor_col) | |
| 497 | 744 | cp BOARD_SIZE-1 | |
| 498 | - | jr z, .done | |
| 745 | + | jr z, .hi_done | |
| 499 | 746 | inc a | |
| 500 | 747 | ld (cursor_col), a | |
| 501 | 748 | | |
| 502 | - | .done: | |
| 749 | + | .hi_done: | |
| 503 | 750 | call draw_cursor | |
| 504 | 751 | ret | |
| 505 | 752 | | |
| ... | |||
| 519 | 766 | xor 3 | |
| 520 | 767 | ld (current_player), a | |
| 521 | 768 | | |
| 522 | - | call update_border ; Update border for new player | |
| 769 | + | call draw_ui ; Update scores and turn indicator | |
| 770 | + | call update_border | |
| 523 | 771 | call draw_cursor | |
| 524 | 772 | | |
| 525 | 773 | ret | |
| ... | |||
| 564 | 812 | | |
| 565 | 813 | pop af | |
| 566 | 814 | cp 1 | |
| 567 | - | jr z, .cc_is_p1 | |
| 815 | + | jr z, .clm_is_p1 | |
| 568 | 816 | ld (hl), P2_ATTR | |
| 569 | 817 | ret | |
| 570 | - | .cc_is_p1: | |
| 818 | + | .clm_is_p1: | |
| 571 | 819 | ld (hl), P1_ATTR | |
| 572 | 820 | ret | |
| 573 | 821 | | |
| ... | |||
| 579 | 827 | ld hl, 400 | |
| 580 | 828 | ld b, 20 | |
| 581 | 829 | | |
| 582 | - | .loop: | |
| 830 | + | .scl_loop: | |
| 583 | 831 | push bc | |
| 584 | 832 | push hl | |
| 585 | 833 | | |
| 586 | 834 | ld b, h | |
| 587 | 835 | ld c, l | |
| 588 | - | .tone_loop: | |
| 836 | + | .scl_tone: | |
| 589 | 837 | ld a, $10 | |
| 590 | 838 | out (KEY_PORT), a | |
| 591 | - | call .delay | |
| 839 | + | call .scl_delay | |
| 592 | 840 | xor a | |
| 593 | 841 | out (KEY_PORT), a | |
| 594 | - | call .delay | |
| 842 | + | call .scl_delay | |
| 595 | 843 | dec bc | |
| 596 | 844 | ld a, b | |
| 597 | 845 | or c | |
| 598 | - | jr nz, .tone_loop | |
| 846 | + | jr nz, .scl_tone | |
| 599 | 847 | | |
| 600 | 848 | pop hl | |
| 601 | 849 | pop bc | |
| ... | |||
| 604 | 852 | or a | |
| 605 | 853 | sbc hl, de | |
| 606 | 854 | | |
| 607 | - | djnz .loop | |
| 855 | + | djnz .scl_loop | |
| 608 | 856 | ret | |
| 609 | 857 | | |
| 610 | - | .delay: | |
| 858 | + | .scl_delay: | |
| 611 | 859 | push bc | |
| 612 | 860 | ld b, 5 | |
| 613 | - | .delay_loop: | |
| 614 | - | djnz .delay_loop | |
| 861 | + | .scl_delay_loop: | |
| 862 | + | djnz .scl_delay_loop | |
| 615 | 863 | pop bc | |
| 616 | 864 | ret | |
| 617 | 865 | | |
| ... | |||
| 623 | 871 | cursor_col: defb 0 | |
| 624 | 872 | key_pressed: defb 0 | |
| 625 | 873 | current_player: defb 1 | |
| 874 | + | p1_count: defb 0 | |
| 875 | + | p2_count: defb 0 | |
| 626 | 876 | board_state: defs 64, 0 | |
| 627 | 877 | | |
| 628 | 878 | ; ---------------------------------------------------------------------------- |