Penetrator-apple2/src/apple2/input.inc

415 lines
14 KiB
PHP

;-----------------------------------------------------------------------------
; input.inc
; Part of penetrator, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2019
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc inputReadJoystick
joyMask = tempBlock + 21
ldx #$0 ; start the x counter at 0
ldy #$0 ; start the y counter at 0
lda PTRIG ; trigger the fact that the joystick will be read
readBoth:
lda PADDL0 ; get the value for X axis
bpl :+ ; if MSB is zero, done with X
upX:
inx ; increment the counter
bne :+ ; while x <> 0 go check y
dex ; if x reaches 0 it's overflow, set to 255
:
lda PADDL0 + 1 ; read the value for the Y axis
bpl readX ; if MSB is zero Y is done
iny ; increment the Y counter
bne readBoth ; branch to the start to check both axis
dey ; if Y reaches 0 it's overflow, set to 255 and drop through to check x only
readX:
lda PADDL0 ; get the value for X axis
bmi upX ; Y is done but X is not so go increment x
lda #$ff ; Done analog. Start the digital mask with all On
cpx #$20 ; compare to the low end dead zone
bcs :+ ; if greater than, then not left
eor #KEY_LEFT ; the joystick is left (bit is off)
bne chkY ; JuMP as acc is now non-zero
:
cpx #$60 ; check the upper bound of the dead-zone
bcc chkY ; if less than, then not right
eor #KEY_RIGHT ; gt high end of dead zone so joystick is right
chkY:
cpy #$20 ; do the same for the Y axis as for the X axis
bcs :+
eor #KEY_UP
bne buttons
:
cpy #$60
bcc buttons
eor #KEY_DOWN
buttons:
ldx BUTN0 ; read the button 0 state
cpx #$80 ; if ge 128 the button is fully depressed
bcc :+
eor #KEY_FIRE ; mark the button as down
:
ldx BUTN1 ; do the same for button 1 as for button 0
cpx #$80
bcc :+
eor #KEY_BOMB
:
sta joyMask ; save the mask
rts
.endproc
;-----------------------------------------------------------------------------
; Reads the joystick and moves the player.
.proc inputGame
zaRawInput = tempBlock + 1
zaRawEor = tempBlock + 2
lda fireCoolDown
beq :+
dec fireCoolDown
:
jsr inputReadJoystick
sta zaRawInput ; save the input
eor #$ff ; invert the bits
sta zaRawEor ; save this state too
lda zaRawInput ; no vertical move so process vertical joystick
up:
bit Bit4Mask ; set when moving up
bne down
lda playerShipY ; and move the ship up 2 rows
sec
sbc #3
cmp #(SHIP_HEIGHT+WORLD_START) ; limit at the top
bcc preLeft ; if too high, just ignore saving the move
sta playerShipY ; save the new position
bcs preLeft ; up, so skip down and check horizontal
down:
bit Bit3Mask ; ser for joystick down
bne left
lda playerShipY ; move the ship 2 rows down
clc
adc #3
cmp #(WORLD_END+1) ; limit at the bottom
bcs preBomb ; skip saving the new position if too low
sta playerShipY ; new position okay so save it
preLeft:
lda zaRawInput ; no horizontal movement so process horiz joystick
left:
bit Bit2Mask ; left sets this bit
bne right ; not set see if right is set
ldx playerShipX ; the ship should move left
dex ; move left one column
bmi preBomb ; if off-screen to the left, ignore
stx playerShipX ; save the movement
lda audioFrame
ora #AUDIO_MOTOR_REW
sta audioFrame
bne preBomb
right:
bit Bit1Mask ; bit set when right joystick active
bne bomb ; if nothing, go process player movement
ldx playerShipX ; get the ship position
inx ; move one column to the right
cpx #(((XSIZE/3)*2) - SHIP_WIDTH - 1) ; limit to two-thirds toward the right
bcs preBomb ; if over limit, ignore
stx playerShipX ; save movement
lda audioFrame
ora #AUDIO_MOTOR_FWD
sta audioFrame
preBomb:
lda zaRawInput
bomb:
bit Bit8Mask ; Button_A = bomb
bne fire
lda lastInput ; debounce the key for single shot
and zaRawEor
and Bit8Mask
beq nobomb ; bomb key not down
lda playerShipY ; bomb requested but can't
cmp #(WORLD_END-BOMB_HEIGHT) ; drop it when there's no room
bcs nobomb ; before the world end (else it draws out of bounds)
ldx #NUM_BOMBS-1 ; iterate over all bombs
:
lda bombY, x
beq drop ; find one that's available
dex
bpl :-
bmi nobomb ; none available
drop:
lda playerShipX ; bomb is relative to player
clc
adc #2
sta bombX, x
lda playerShipY
adc #6
sta bombY, x
lda #BOMB_FRWRD_FRMS ; set it to fly forward
sta bombDir, x
lda audioFrame
ora #AUDIO_BOMB_DROP
sta audioFrame
nobomb:
lda zaRawInput
fire:
bit Bit7Mask ; Button_B = fire
bne joyDone
lda fireCoolDown
bne joyDone
lda lastInput ; debounce the key for single shot
and zaRawEor
and Bit7Mask
beq joyDone
lda playerShipX ; Put even/odd into carry
lsr
lda playerShipX ; bullets start relative to ship
adc #4 ; 4 for even, 5 for odd
adc bulletIndex
tax
lda playerShipY
sec
sbc #4
sta bulletsBuffer, x ; put height into 3 columns
lda #3
sta fireCoolDown
lda audioFrame
ora #AUDIO_FIRE
sta audioFrame
joyDone:
lda zaRawInput ; remember the key-state for next time
sta lastInput ; so that fire and bombs can be debounced
lda KBD ; leave with a key in the accumulator
bit KBDSTRB ; reset the key
clc ; keep carry clear between routines
rts
.endproc
;-----------------------------------------------------------------------------
.proc inputEdit
rawInput = tempBlock + 17
rawEor = tempBlock + 18
brushType = tempBlock + 16
lda KBD
bit Bit8Mask
beq :+
bit KBDSTRB
and #$7f
bne :++
:
lda #0
:
pha
jsr inputReadJoystick
sta rawInput ; save the input state
pla
pha
cmp #' '
bne :+
lda rawInput
eor #KEY_SELECT
sta rawInput
pla
pha
:
cmp #'B'
bne :+
lda rawInput
eor #KEY_START
sta rawInput
:
lda rawInput
eor #$ff ; invert the bits so 1 means button down
sta rawEor ; save the inverted bits
bit Bit6Mask ; see if select button is held
bne Button_B ; if it is down, key processing done
and lastInput ; otherwise debounce the keys
sta rawEor ; and save this state as the key state
Button_B:
bit Bit7Mask ; Button_B
beq Button_A
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
lda brushType
bne radar
ora #KEY_RIGHT ; when pressed, move right as well
sta rawEor
jsr editSetTerrainBottom
jmp :+
radar:
jsr editSetRadar
:
lda rawEor ; no horizontal movement so process horiz joystick
Button_A:
bit Bit8Mask ; Button_A
beq up
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
lda brushType
bne missile
ora #KEY_RIGHT
sta rawEor
jsr editSetTerrainTop
jmp :+
missile:
jsr editSetMissile
:
lda rawEor ; no horizontal movement so process horiz joystick
up:
bit Bit4Mask ; set when moving up
beq down
ldx playerShipY
cpx #9
bcc :+
dex
stx playerShipY
:
lda rawEor ; no horizontal movement so process horiz joystick
down:
bit Bit3Mask ; ser for joystick down
beq left
ldx playerShipY
cpx #WORLD_END
bcs :+
inx
stx playerShipY
:
lda rawEor ; no horizontal movement so process horiz joystick
left:
bit Bit2Mask ; left sets this bit
beq right ; not set see if right is set
jsr editGameWorldLeft
lda rawEor ; no horizontal movement so process horiz joystick
right:
bit Bit1Mask ; bit set when right joystick active
beq Button_Start
jsr editGameWorldRight
Button_Start:
lda rawInput ; This is a toggle so never auto-repeat
eor #$ff ; start from source
and lastInput ; and debounce
bit Bit5Mask ; test if Start button down
beq joyDone
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
lda brushType ; if down, toggle the brush type between terrain and enemies
eor #1
sta brushType
jsr uiShowEditLabels ; update the HUD
joyDone:
lda rawInput ; preserve this input for next frame as last input
sta lastInput ; so that fire and bombs can be debounced
pla ; get the keyboard in accumulator
clc ; keep carry clear between routines
rts
.endproc
;-----------------------------------------------------------------------------
; Checks for a user input on keyboard or joystick
; upon exit - acc 0 means nothing, <> 0 means user input detected
.proc inputCheckForInput
rawInput = tempBlock + 20 ; internal
lda KBD
bit Bit8Mask
bne done ; if there's a key then done here
jsr inputReadJoystick ; check the joystick
sta rawInput ; keep the raw bits
eor #$ff ; invert
and lastInput ; debounce
pha ; save this
lda rawInput ; back up the raw to the last
sta lastInput
pla ; and get back the debounced bits
beq done
bit Bit7Mask ; FIRE should eq 1 player
beq :+
lda #KEY_RIGHT
bne check ; JuMP
:
bit Bit8Mask ; BOMB should eq 2 player
beq check
lda #KEY_LEFT
check:
ldx #1
:
lsr
bcs :+
inx
bne :-
:
txa
done:
and #$7f
beq :+
pha ; Save the "key"
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
pla ; restore the "key"
:
rts ; upon return 0 means no interaction, anything else is a user input
.endproc