← BCAD Wait until no key is pressed Map BE03 → Draw the KRAKOUT title logo
BCB9: Front end: title screen, input-device menu, and attract cycle
Runs the game's front end, and returns only when the player starts a game. It leaves the chosen input device set.
kstate_save BCB9 DEFB $00,$00,$00,$00,$00,$00,$00,$00 Saved copy of the ROM keyboard state
frames_save BCC1 DEFB $00,$00,$00 Saved copy of the ROM FRAMES counter: its low word first, then its high byte
menu_attr_ptr BCC4 DEFB $0A,$59 The attribute-cell address of the input-device line the menu highlights, low byte first
Setup: black border, cleared bitmap, bright white attributes, logo and menu drawn, credits scroller primed, title tune cued. Falls into the menu loop.
title_screen BCC6 XOR A Black border
BCC7 OUT ($FE),A
BCC9 CALL clear_screen
BCCC LD A,$47 Paint every attribute cell bright white on black.
BCCE CALL fill_attrs
BCD1 CALL draw_title_logo
BCD4 CALL draw_title_menu
BCD7 CALL credits_scroll_init
BCDA LD HL,title_tune Point the tune pointer at the start of the title tune.
BCDD LD (tune_ptr),HL
One pass per loop. Poll the 1–4 device keys and pulse the selected menu line. Check the O key, play one tune note, then run one attract/frame step. An option key does nothing when its device is already current, so a second press of the active option neither beeps nor redraws. There is no option 5 on the menu, so its key is ignored.
title_menu_loop BCE0 LD A,(input_device) Stash the current input device in A' for the re-select check below.
BCE3 EX AF,AF'
BCE4 LD BC,KBD_ROW_1_5 Read the 1/2/3/4/5 keyboard half-row and keep the five key bits.
BCE7 IN A,(C)
BCE9 AND $1F
BCEB BIT 0,A Key 1 down? If not, fall through to the key-2 test.
BCED JR NZ,title_check_key2
BCEF EX AF,AF' Already keyboard? Then just keep the pulse – no reselect.
BCF0 OR A
BCF1 JR Z,title_pulse_menu
BCF3 LD HL,ATTR_BASE+$10A Otherwise arm the keyboard and select the KEYBOARD line's attributes.
BCF6 XOR A
BCF7 JR title_set_device
title_check_key2 BCF9 BIT 1,A Key 2 down? If not, fall through to the key-3 test.
BCFB JR NZ,title_check_key3
BCFD EX AF,AF' Already Kempston? Then just keep the pulse.
BCFE CP $01
BD00 JR Z,title_pulse_menu
BD02 LD HL,ATTR_BASE+$14A Otherwise arm Kempston and select the KEMPSTON line's attributes.
BD05 LD A,$01
BD07 JR title_set_device
title_check_key3 BD09 BIT 2,A Key 3 down? If not, fall through to the key-4 test.
BD0B JR NZ,title_check_key4
BD0D EX AF,AF' Already the cursor keys? Then just keep the pulse.
BD0E CP $02
BD10 JR Z,title_pulse_menu
BD12 LD HL,ATTR_BASE+$18A Otherwise arm the cursor keys and select the CURSOR line's attributes.
BD15 LD A,$02
BD17 JR title_set_device
title_check_key4 BD19 BIT 3,A Key 4 down? If not, nothing is selected – go pulse the current line.
BD1B JR NZ,title_pulse_menu
BD1D EX AF,AF' Already the Sinclair joystick? Then just keep the pulse.
BD1E CP $03
BD20 JR Z,title_pulse_menu
BD22 LD HL,ATTR_BASE+$1CA Otherwise arm the Sinclair/Interface II joystick and select that line's attributes; falls into the setter.
BD25 LD A,$03
Commit the newly chosen option. Remember the line's attribute address for the pulse and store the device. Redraw the menu to clear the old highlight, and beep.
title_set_device BD27 LD (menu_attr_ptr),HL Save the selected line's attribute address (in the buffer just below this routine) for the pulse animation.
BD2A LD (input_device),A Store the chosen device.
BD2D CALL draw_title_menu
BD30 CALL sfx_key_blip
Pulse the selected option. Both character rows of the line step through the bright inks magenta, green, cyan, yellow and white once per frame. From white they wrap back to magenta. The line comes from the choice made by the option keys, the KEYBOARD line by default.
title_pulse_menu BD33 LD HL,(menu_attr_ptr) Load the selected line's attribute address; keep a copy for the second row.
BD36 PUSH HL
BD37 LD B,$14 Pulse every cell of the line's first character row.
title_pulse_loop1 BD39 LD A,(HL) Step this cell's attribute, and wrap at the end of the run.
BD3A INC A
BD3B CP $48
BD3D JR NC,title_pulse_wrap1
title_pulse_set1 BD3F LD (HL),A Store the stepped attribute, advance to the next cell, and repeat for all 20.
BD40 INC L
BD41 DJNZ title_pulse_loop1
BD43 JR title_pulse_line2
title_pulse_wrap1 BD45 LD A,$43 Past bright white – restart the cell at bright magenta.
BD47 JR title_pulse_set1
title_pulse_line2 BD49 POP HL Drop to the menu line's second character row and pulse it the same way.
BD4A CALL advance_buffer_row
BD4D LD B,$14
title_pulse_loop2 BD4F LD A,(HL) Step each cell of the second row the same way.
BD50 INC A
BD51 CP $48
BD53 JR NC,title_pulse_wrap2
title_pulse_set2 BD55 LD (HL),A Write the stepped ink back to this cell.
BD56 INC L
BD57 DJNZ title_pulse_loop2
BD59 JR title_check_options
title_pulse_wrap2 BD5B LD A,$43 Past bright white – restart the cell at bright magenta.
BD5D JR title_pulse_set2
Check the O key (options), then advance the title tune by one note. At the terminator the tune loops.
title_check_options BD5F LD BC,KBD_ROW_Y_P Read the Y/U/I/O/P half-row and keep the five key bits.
BD62 IN A,(C)
BD64 AND $1F
BD66 BIT 1,A O pressed? Enter the options screen.
BD68 JP Z,options_menu
BD6B CALL play_tune_note Play the next title-tune note. Has the tune reached its terminator?
BD6E CP $0D
BD70 JR NZ,title_attract_loop Not the end – skip the rewind.
BD72 LD HL,title_tune Tune finished – rewind the tune pointer to loop it.
BD75 LD (tune_ptr),HL
Per-frame step of the menu loop. It busy-waits to set the pace, then waits for one frame, the front end's only interrupt sync. The ROM keyboard state and frame counter are saved and restored around it, because they lie inside the sprite bank. Then scroll the credits two pixels, read the player's controls, and test the start inputs.
title_attract_loop BD78 LD BC,$05DC Pace the loop with a busy-wait.
BD7B CALL delay
BD7E LD IY,$0000 Park IY at zero before the frame sync, because the interrupt's ROM handler writes through it. The keyboard scan sets a flag bit in the byte after IY on each new key. The frame tick increments a byte at a fixed offset from IY each time FRAMES wraps. Parked at zero, both writes land in ROM and do nothing. After a game IY still points at a game record, where they would land in game memory.
BD82 LD HL,slot_visor_1 Save the ROM keyboard state (KSTATE) into the buffer below this routine. Those bytes are also the head of the sprite bank, and the interrupt that ends the HALT below rewrites them. The same interrupt also writes the byte after them, which nothing restores – see Defects.
BD85 LD DE,kstate_save
BD88 LD BC,$0008
BD8B LDIR
BD8D LD HL,(frames_low) Save the ROM frame counter (FRAMES).
BD90 LD (frames_save),HL
BD93 LD A,(frames_high)
BD96 LD (frames_save+$2),A
BD99 EI Wait for the next frame interrupt.
BD9A HALT
BD9B DI
BD9C LD HL,kstate_save Restore KSTATE so the interrupt's keyboard scan does not perturb it.
BD9F LD DE,slot_visor_1
BDA2 LD BC,$0008
BDA5 LDIR
BDA7 LD HL,(frames_save) Restore the ROM frame counter.
BDAA LD (frames_low),HL
BDAD LD A,(frames_save+$2)
BDB0 LD (frames_high),A
BDB3 CALL credits_scroll_step Scroll the credits two pixels this frame (two steps).
BDB6 CALL credits_scroll_step
BDB9 CP $FF Credits exhausted? Switch to the high-score display.
BDBB JP Z,title_attract_check
BDBE CALL read_ctrl
BDC1 LD HL,controls Fire held? Return to start the game.
BDC4 BIT 4,(HL)
BDC6 RET NZ
BDC7 LD BC,KBD_ROW_6_0 Read the 0/9/8/7/6 half-row and keep the five key bits.
BDCA IN A,(C)
BDCC AND $1F
BDCE BIT 0,A Key 0 up? Loop the menu. Key 0 (START) pressed falls through to RET and starts the game.
BDD0 JP NZ,title_menu_loop
BDD3 RET
Credits finished: show the high-score table and play the title tune once. Any key, the end of the tune, or fire restarts the front end. The game cannot be started from this screen – fire here only loops back to the menu.
title_attract_check BDD4 CALL draw_highscore_table
BDD7 LD HL,title_tune Rewind the tune pointer for the high-score wait.
BDDA LD (tune_ptr),HL
title_attract_cont BDDD LD BC,$0BB8 Pace the high-score wait.
BDE0 CALL delay
BDE3 CALL play_tune_note Play the next tune note. Has the tune reached its terminator?
BDE6 CP $0D
BDE8 JP Z,title_screen Restart the whole front end.
BDEB LD BC,$00FE Read all key half-rows at once and keep the five key bits.
BDEE IN A,(C)
BDF0 AND $1F
BDF2 XOR $1F
BDF4 JR NZ,title_attract_end Any key down? End the wait and restart the front end.
BDF6 CALL read_ctrl
BDF9 LD HL,controls Loop until fire is pressed, then restart.
BDFC BIT 4,(HL)
BDFE JR Z,title_attract_cont
title_attract_end BE00 JP title_screen Fire or any key: back to the top of the front end.
← BCAD Wait until no key is pressed Map BE03 → Draw the KRAKOUT title logo
Fork me on GitHub