Add mouse support.

This commit is contained in:
Jeremy Rand 2016-08-19 00:08:38 -04:00
parent cb1ae69c00
commit 7995aefa4f
11 changed files with 700 additions and 738 deletions

View File

@ -9,9 +9,9 @@
/* Begin PBXFileReference section */
9D3A9FB81D455CCF004C5897 /* joystick.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = joystick.h; sourceTree = "<group>"; };
9D3A9FB91D455CD8004C5897 /* joystick.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = joystick.c; sourceTree = "<group>"; };
9D3A9FBB1D457900004C5897 /* macros.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = macros.s; sourceTree = "<group>"; };
9D3A9FBC1D457900004C5897 /* mouse.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = mouse.s; sourceTree = "<group>"; };
9D3A9FBD1D457900004C5897 /* switches.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = switches.s; sourceTree = "<group>"; };
9D509F911D654F9900161DDC /* mouseWrapper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mouseWrapper.c; sourceTree = "<group>"; };
9D509F921D654F9900161DDC /* mouseWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mouseWrapper.h; sourceTree = "<group>"; };
9D509F941D66AE2800161DDC /* a2e.stdmou.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = a2e.stdmou.s; sourceTree = "<group>"; };
9D6B472E1D3FB16F00F6D704 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
9D6B472F1D3FB16F00F6D704 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
9D6B47311D3FB16F00F6D704 /* AppleCommander.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; name = AppleCommander.jar; path = make/AppleCommander.jar; sourceTree = "<group>"; };
@ -41,9 +41,9 @@
9D3A9FBA1D4578B4004C5897 /* mouse */ = {
isa = PBXGroup;
children = (
9D3A9FBB1D457900004C5897 /* macros.s */,
9D3A9FBC1D457900004C5897 /* mouse.s */,
9D3A9FBD1D457900004C5897 /* switches.s */,
9D509F941D66AE2800161DDC /* a2e.stdmou.s */,
9D509F911D654F9900161DDC /* mouseWrapper.c */,
9D509F921D654F9900161DDC /* mouseWrapper.h */,
);
name = mouse;
sourceTree = "<group>";

427
a2bejwld/a2e.stdmou.s Normal file
View File

@ -0,0 +1,427 @@
;
; File generated by co65 v 2.13.3 using model `cc65-module'
;
.fopt compiler,"co65 v 2.13.3"
.case on
.debuginfo off
.export _a2e_stdmou_mou
;
; CODE SEGMENT
;
.segment "CODE"
_a2e_stdmou_mou:
.byte $6D
.byte $6F
.byte $75
.byte $02
.word _a2e_stdmou_mou+41
.word _a2e_stdmou_mou+170
.word _a2e_stdmou_mou+286
.word _a2e_stdmou_mou+295
.word _a2e_stdmou_mou+180
.word _a2e_stdmou_mou+238
.word _a2e_stdmou_mou+253
.word _a2e_stdmou_mou+299
.word _a2e_stdmou_mou+305
.word _a2e_stdmou_mou+309
.word _a2e_stdmou_mou+322
.word _a2e_stdmou_mou+327
.byte $40
.byte $4C
.byte $00
.byte $00
.byte $4C
.byte $00
.byte $00
.byte $4C
.byte $00
.byte $00
.byte $4C
.byte $00
.byte $00
.byte $A9
.byte $00
.byte $85
.byte <(ZEROPAGE+8)
.byte $A9
.byte $C0
.byte $85
.byte <(ZEROPAGE+9)
.byte $E6
.byte <(ZEROPAGE+9)
.byte $A5
.byte <(ZEROPAGE+9)
.byte $C9
.byte $C8
.byte $90
.byte $05
.byte $A9
.byte $04
.byte $A2
.byte $00
.byte $60
.byte $A2
.byte $03
.byte $BC
.word _a2e_stdmou_mou+421
.byte $BD
.word _a2e_stdmou_mou+425
.byte $D1
.byte <(ZEROPAGE+8)
.byte $D0
.byte $E7
.byte $CA
.byte $10
.byte $F3
.byte $A5
.byte <(ZEROPAGE+9)
.byte $8D
.word DATA+2
.byte $8D
.word DATA+7
.byte $8D
.word DATA+12
.byte $78
.byte $29
.byte $0F
.byte $8D
.word BSS+13
.byte $0A
.byte $0A
.byte $0A
.byte $0A
.byte $8D
.word DATA+9
.byte $2C
.byte $82
.byte $C0
.byte $A2
.byte $19
.byte $20
.word DATA+0
.byte $2C
.byte $80
.byte $C0
.byte $A9
.byte $01
.byte $A2
.byte $12
.byte $20
.word DATA+0
.byte $A9
.byte <(_a2e_stdmou_mou+173)
.byte $A2
.byte >(_a2e_stdmou_mou+429)
.byte $20
.word _a2e_stdmou_mou+180
.byte $AE
.word BSS+13
.byte $A9
.byte $8B
.byte $9D
.byte $78
.byte $04
.byte $A9
.byte $00
.byte $9D
.byte $78
.byte $05
.byte $A9
.byte $5F
.byte $9D
.byte $F8
.byte $04
.byte $A9
.byte $00
.byte $9D
.byte $F8
.byte $05
.byte $A2
.byte $16
.byte $20
.word DATA+0
.byte $20
.word _a2e_stdmou_mou+372
.byte $A9
.byte $09
.byte $A2
.byte $12
.byte $20
.word DATA+0
.byte $58
.byte $A9
.byte $00
.byte $A2
.byte $00
.byte $60
.byte $78
.byte $20
.word _a2e_stdmou_mou+29
.byte $A9
.byte $00
.byte $A2
.byte $12
.byte $D0
.byte $ED
.byte $85
.byte <(ZEROPAGE+8)
.byte $86
.byte <(ZEROPAGE+9)
.byte $A2
.byte $00
.byte $A0
.byte $00
.byte $20
.word _a2e_stdmou_mou+195
.byte $A2
.byte $01
.byte $A0
.byte $02
.byte $78
.byte $B1
.byte <(ZEROPAGE+8)
.byte $99
.word BSS+0
.byte $8D
.byte $78
.byte $04
.byte $C8
.byte $B1
.byte <(ZEROPAGE+8)
.byte $99
.word BSS+0
.byte $8D
.byte $78
.byte $05
.byte $C8
.byte $C8
.byte $C8
.byte $B1
.byte <(ZEROPAGE+8)
.byte $99
.word BSS+0
.byte $8D
.byte $F8
.byte $04
.byte $C8
.byte $B1
.byte <(ZEROPAGE+8)
.byte $99
.word BSS+0
.byte $8D
.byte $F8
.byte $05
.byte $8A
.byte $A2
.byte $17
.byte $D0
.byte $B3
.byte $85
.byte <(ZEROPAGE+8)
.byte $86
.byte <(ZEROPAGE+9)
.byte $A0
.byte $07
.byte $B9
.word BSS+0
.byte $91
.byte <(ZEROPAGE+8)
.byte $88
.byte $10
.byte $F8
.byte $60
.byte $AC
.word BSS+13
.byte $78
.byte $99
.byte $F8
.byte $04
.byte $8A
.byte $99
.byte $F8
.byte $05
.byte $98
.byte $AA
.byte $A0
.byte $00
.byte $B1
.byte <(ZEROPAGE+0)
.byte $C8
.byte $9D
.byte $78
.byte $04
.byte $B1
.byte <(ZEROPAGE+0)
.byte $9D
.byte $78
.byte $05
.byte $20
.word _a2e_stdmou_mou+372
.byte $A2
.byte $16
.byte $D0
.byte $83
.byte $CE
.word BSS+14
.byte $78
.byte $20
.word _a2e_stdmou_mou+29
.byte $58
.byte $60
.byte $EE
.word BSS+14
.byte $60
.byte $AD
.word BSS+12
.byte $A2
.byte $00
.byte $60
.byte $A0
.byte $03
.byte $D0
.byte $02
.byte $A0
.byte $04
.byte $78
.byte $B9
.word BSS+8
.byte $91
.byte <(ZEROPAGE+8)
.byte $88
.byte $10
.byte $F8
.byte $58
.byte $60
.byte $A9
.byte $05
.byte $A2
.byte $00
.byte $60
.byte $AD
.word BSS+13
.byte $F0
.byte $08
.byte $A2
.byte $13
.byte $20
.word DATA+0
.byte $90
.byte $02
.byte $18
.byte $60
.byte $A2
.byte $14
.byte $20
.word DATA+0
.byte $AC
.word BSS+13
.byte $B9
.byte $78
.byte $07
.byte $AA
.byte $0A
.byte $29
.byte $20
.byte $F0
.byte $02
.byte $A9
.byte $01
.byte $90
.byte $02
.byte $09
.byte $10
.byte $8D
.word BSS+12
.byte $8A
.byte $29
.byte $20
.byte $F0
.byte $27
.byte $20
.word _a2e_stdmou_mou+29
.byte $AC
.word BSS+13
.byte $B9
.byte $78
.byte $04
.byte $BE
.byte $78
.byte $05
.byte $8D
.word BSS+8
.byte $8E
.word BSS+9
.byte $20
.word _a2e_stdmou_mou+35
.byte $AC
.word BSS+13
.byte $B9
.byte $F8
.byte $04
.byte $BE
.byte $F8
.byte $05
.byte $8D
.word BSS+10
.byte $8E
.word BSS+11
.byte $20
.word _a2e_stdmou_mou+38
.byte $AD
.word BSS+14
.byte $F0
.byte $03
.byte $20
.word _a2e_stdmou_mou+32
.byte $38
.byte $60
.byte $05
.byte $07
.byte $0B
.byte $0C
.byte $38
.byte $18
.byte $01
.byte $20
.byte $00
.byte $00
.byte $00
.byte $00
.byte $17
.byte $01
.byte $BF
.byte $00
;
; DATA SEGMENT
;
.segment "DATA"
DATA:
.byte $BC
.byte $00
.byte $FF
.byte $8C
.word DATA+11
.byte $A2
.byte $FF
.byte $A0
.byte $FF
.byte $4C
.byte $FF
.byte $FF
;
; BSS SEGMENT
;
.segment "BSS"
BSS:
.res 15
;
; ZEROPAGE SEGMENT
;
.import __ZP_START__ ; Linker generated symbol
ZEROPAGE = __ZP_START__
.end

View File

@ -18,6 +18,7 @@
#include "dbllores.h"
#include "game.h"
#include "vbl.h"
#include "ui.h"
// Defines
@ -31,7 +32,7 @@
#define CLEAR_GEM_SOUND_STAR 1
#define CLEAR_GEM_SOUND_SPECIAL 2
#define CLEAR_GEM_SOUND_EXPLODE 3
#define NUM_CLEAR_GEM_SOUNDS
#define NUM_CLEAR_GEM_SOUNDS 4
// Typedefs
@ -75,7 +76,6 @@ typedef void (*tVblWaitFunction)(void);
// Globals
static tVblWaitFunction gVblWait = vblWait;
static bool gPlaySounds = true;
static tStarAnimState gStarAnimState;
static tClearGemAnimState gClearGemAnimState;
@ -126,37 +126,6 @@ void animInit(void)
}
void toggleSound(void)
{
gPlaySounds = !gPlaySounds;
}
void badThingHappened(void)
{
if (gPlaySounds)
printf("\007");
}
void playSound(int8_t startFreq, int8_t duration)
{
int8_t freq;
if (!gPlaySounds)
return;
while (duration > 0) {
asm ("STA %w", 0xc030);
freq = startFreq;
while (freq > 0) {
freq--;
}
duration--;
}
}
void drawGemAtSquare(tSquare square)
{
switch (gemTypeAtSquare(square)) {

View File

@ -40,8 +40,5 @@ extern void dropSquareFromTo(tSquare srcSquare, tSquare tgtSquare, tGemType gemT
extern void dropSquareFromOffscreen(tSquare tgtSquare, tGemType gemType, bool starred);
extern void endDropAnim(void);
extern void toggleSound(void);
extern void badThingHappened(void);
#endif /* defined(__a2bejwld__anim__) */

View File

@ -1,120 +0,0 @@
;
; macros.s
; Generally useful macros for 6502 code
;
; Created by Quinn Dunki on 8/15/14.
; Copyright (c) 2014 One Girl, One Laptop Productions. All rights reserved.
;
; Macros
.macro SETSWITCH name ; Sets the named softswitch (assumes write method)
sta name
.endmacro
.macro SAVE_AXY ; Saves all registers
pha
phx
phy
.endmacro
.macro RESTORE_AXY ; Restores all registers
ply
plx
pla
.endmacro
.macro SAVE_AY ; Saves accumulator and Y index
pha
phy
.endmacro
.macro RESTORE_AY ; Restores accumulator and Y index
ply
pla
.endmacro
.macro SAVE_AX ; Saves accumulator and X index
pha
phx
.endmacro
.macro RESTORE_AX ; Restores accumulator and X index
plx
pla
.endmacro
.macro SAVE_XY ; Saves X and Y index
phx
phy
.endmacro
.macro RESTORE_XY ; Restores X and Y index
ply
plx
.endmacro
.macro SAVE_ZPP ; Saves Zero Page locations we use for parameters
lda PARAM0
pha
lda PARAM1
pha
lda PARAM2
pha
lda PARAM3
pha
.endmacro
.macro RESTORE_ZPP ; Restores Zero Page locations we use for parameters
pla
sta PARAM3
pla
sta PARAM2
pla
sta PARAM1
pla
sta PARAM0
.endmacro
.macro SAVE_ZPS ; Saves Zero Page locations we use for scratch
lda SCRATCH0
pha
lda SCRATCH1
pha
.endmacro
.macro RESTORE_ZPS ; Restores Zero Page locations we use for scratch
pla
sta SCRATCH1
pla
sta SCRATCH0
.endmacro
.macro PARAM16 addr
lda #<addr
sta PARAM0
lda #>addr
sta PARAM1
.endmacro
.macro CALL16 func,addr
PARAM16 addr
jsr func
.endmacro

View File

@ -1,535 +0,0 @@
;
; mouse.s
; Mouse driver for Apple //e Enhanced with mouse card (any slot), or Apple //c(+)
;
; Created by Quinn Dunki on 7/14/15.
; Copyright (c) 2014 One Girl, One Laptop Productions. All rights reserved.
;
.include "macros.s"
.include "switches.s"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Mouse clamping values. These are set to a convenient one-byte
; range, but you can change to suit your application. If you
; change them, also change the scaling math below (search for SCALING)
; Hardware produces values 0-1023 in both dimensions if not clamped
SCALE_X_IIE = $027f ; 640-1
SCALE_Y_IIE = $02e0 ; 736
; //c tracks much slower, so smaller clamps and no scaling works better
SCALE_X_IIC = $004f ; 8-1
SCALE_Y_IIC = $0017 ; 24-1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ProDOS ROM entry points and constants
;
PRODOS_MLI = $bf00
ALLOC_INTERRUPT = $40
DEALLOC_INTERRUPT = $41
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Mouse firmware ROM entry points and constants
;
; These mouse firmware entry points are offsets from the firmware
; entry point of the slot, and also indirect.
SETMOUSE = $12
SERVEMOUSE = $13
READMOUSE = $14
CLEARMOUSE = $15
POSMOUSE = $16
CLAMPMOUSE = $17
HOMEMOUSE = $18
INITMOUSE = $19
MOUSTAT = $0778 ; + Slot Num
MOUSE_XL = $0478 ; + Slot Num
MOUSE_XH = $0578 ; + Slot Num
MOUSE_YL = $04f8 ; + Slot Num
MOUSE_YH = $05f8 ; + Slot Num
MOUSE_CLAMPL = $04f8 ; Upper mouse clamp (LSB). Slot independent.
MOUSE_CLAMPH = $05f8 ; Upper mouse clamp (MSB). Slot independent.
MOUSE_ZEROL = $0478 ; Zero value of mouse (LSB). Slot independent.
MOUSE_ZEROH = $0578 ; Zero value of mouse (MSB). Slot independent.
MOUSTAT_MASK_BUTTONINT = %00000100
MOUSTAT_MASK_VBLINT = %00001000
MOUSTAT_MASK_MOVEINT = %00000010
MOUSTAT_MASK_DOWN = %10000000
MOUSTAT_MASK_WASDOWN = %01000000
MOUSTAT_MASK_MOVED = %00100000
MOUSEMODE_OFF = $00 ; Mouse off
MOUSEMODE_PASSIVE = $01 ; Passive mode (polling only)
MOUSEMODE_MOVEINT = $03 ; Interrupts on movement
MOUSEMODE_BUTINT = $05 ; Interrupts on button
MOUSEMODE_COMBINT = $0f ; Interrupts on VBL, movement and button
; Mouse firmware is all indirectly called, because
; it moved around a lot in different Apple II ROM
; versions. This macro helps abstracts this for us.
.macro CALLMOUSE name
ldx #name
jsr WGCallMouse
.endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGEnableMouse
; Prepares the mouse for use
;
WGEnableMouse:
pha
SETSWITCH PAGE2OFF
; Find slot number and calculate the various indirections needed
jsr WGFindMouse
bcs WGEnableMouse_Error
; Note if we're a //e or //c, because mouse tracking and interrupts are different
lda $fbb3
cmp #$06
bne WGEnableMouse_Error ; II or II+? Sorry...
lda $fbc0
bne WGEnableMouse_IIe
lda #1
sta WG_APPLEIIC
WGEnableMouse_IIe:
; Install our interrupt handler via ProDOS (play nice!)
jsr PRODOS_MLI
.byte ALLOC_INTERRUPT
.addr WG_PRODOS_ALLOC
bne WGEnableMouse_Error ; ProDOS will return here with Z clear on error
; Initialize the mouse
stz WG_MOUSEPOS_X
stz WG_MOUSEPOS_Y
stz WG_MOUSEBG
CALLMOUSE INITMOUSE
bcs WGEnableMouse_Error ; Firmware sets carry if mouse is not available
CALLMOUSE CLEARMOUSE
lda #MOUSEMODE_COMBINT ; Enable combination interrupt mode
CALLMOUSE SETMOUSE
; Set the mouse's zero postion to (1,1), since we're in text screen space
stz MOUSE_ZEROH
lda #0
sta MOUSE_ZEROL
lda #1
CALLMOUSE CLAMPMOUSE
lda #0
CALLMOUSE CLAMPMOUSE
; Scale the mouse's range into something easy to do math with,
; while retaining as much range of motion and precision as possible
lda WG_APPLEIIC
bne WGEnableMouse_ConfigIIc ; Sorry //c, no scaling for you
lda #<SCALE_X_IIE
sta MOUSE_CLAMPL
lda #>SCALE_X_IIE
sta MOUSE_CLAMPH
lda #0
CALLMOUSE CLAMPMOUSE
lda #<SCALE_Y_IIE
sta MOUSE_CLAMPL
lda #>SCALE_Y_IIE
sta MOUSE_CLAMPH
lda #1
CALLMOUSE CLAMPMOUSE
bra WGEnableMouse_Activate
WGEnableMouse_Error:
stz WG_MOUSEACTIVE
WGEnableMouse_done: ; Exit point here for branch range
pla
rts
WGEnableMouse_ConfigIIc: ; //c's tracking is weird. Need to clamp to a much smaller range
lda #<SCALE_X_IIC
sta MOUSE_CLAMPL
lda #>SCALE_X_IIC
sta MOUSE_CLAMPH
lda #0
CALLMOUSE CLAMPMOUSE
lda #<SCALE_Y_IIC
sta MOUSE_CLAMPL
lda #>SCALE_Y_IIC
sta MOUSE_CLAMPH
lda #1
CALLMOUSE CLAMPMOUSE
WGEnableMouse_Activate:
lda #1
sta WG_MOUSEACTIVE
cli ; Once all setup is done, it's safe to enable interrupts
bra WGEnableMouse_done
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGDisableMouse
; Shuts off the mouse when we're done with it
;
WGDisableMouse:
pha
SETSWITCH PAGE2OFF
lda WG_MOUSEACTIVE ; Never activated the mouse
beq WGDisableMouse_done
lda MOUSEMODE_OFF
CALLMOUSE SETMOUSE
stz WG_MOUSEACTIVE
lda #MOUSEMODE_OFF ; Disable VBL manually
CALLMOUSE SETMOUSE
; Remove our interrupt handler via ProDOS (done playing nice!)
lda WG_PRODOS_ALLOC+1 ; Copy interrupt ID that ProDOS gave us
sta WG_PRODOS_DEALLOC+1
jsr PRODOS_MLI
.byte DEALLOC_INTERRUPT
.addr WG_PRODOS_DEALLOC
jsr WGUndrawPointer ; Be nice if we're disabled during a program
WGDisableMouse_done:
pla
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGCallMouse
; Calls a mouse firmware routine. Here's where we handle all
; the layers of indirection needed to call mouse firmware. The
; firmware moved in ROM several times over the life of the
; Apple II, so it's kind of a hassle to call it.
; X: Name of routine (firmware offset constant)
; Side effects: Clobbers all registers
WGCallMouse:
stx WGCallMouse+4 ; Use self-modifying code to smooth out some indirection
; This load address is overwritten by the above code, AND by the mouse set
; up code, to make sure we have the right slot entry point and firmware
; offset
ldx $c400 ; Self-modifying code!
stx WG_MOUSE_JUMPL ; Get low byte of final jump from firmware
php ; Note that mouse firmware is not re-entrant,
sei ; so we must disable interrupts inside them
jsr WGCallMouse_redirect
plp ; Restore interrupts to previous state
rts
WGCallMouse_redirect:
ldx WG_MOUSE_JUMPH
ldy WG_MOUSE_SLOTSHIFTED
jmp (WG_MOUSE_JUMPL)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGFindMouse
; Figures out which slot (//e) or port (//c) the mouse is in.
; It moved around a lot over the years. Sets it to 0 if no mouse
; could be found
; OUT C: Set if no mouse could be found
WGFindMouse:
SAVE_AX
ldx #7
WGFindMouse_loop:
txa ; Compute slot firmware locations for this loop
ora #$c0
sta WGFindMouse_loopModify+2 ; Self-modifying code!
sta WGFindMouse_loopModify+9
sta WGFindMouse_loopModify+16
sta WGFindMouse_loopModify+23
sta WGFindMouse_loopModify+30
WGFindMouse_loopModify:
; Check for the magic 5-byte pattern that gives away the mouse card
lda $c005 ; These addresses are modified in place on
cmp #$38 ; each loop iteration
bne WGFindMouse_nextSlot
lda $c007
cmp #$18
bne WGFindMouse_nextSlot
lda $c00b
cmp #$01
bne WGFindMouse_nextSlot
lda $c00c
cmp #$20
bne WGFindMouse_nextSlot
lda $c0fb
cmp #$d6
bne WGFindMouse_nextSlot
bra WGFindMouse_found
WGFindMouse_nextSlot:
dex
bmi WGFindMouse_none
bra WGFindMouse_loop
WGFindMouse_found:
; Found it! Now configure all our indirection lookups
stx WG_MOUSE_SLOT
lda #$c0
ora WG_MOUSE_SLOT
sta WG_MOUSE_JUMPH
sta WGCallMouse+5 ; Self-modifying code!
txa
asl
asl
asl
asl
sta WG_MOUSE_SLOTSHIFTED
clc
bra WGFindMouse_done
WGFindMouse_none:
stz WG_MOUSE_SLOT
sec
WGFindMouse_done:
RESTORE_AX
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGMouseInterruptHandler
; Handles interrupts that may be related to the mouse
; This is a ProDOS-compliant interrupt handling routine, and
; should be installed and removed via ProDOS as needed.
;
; IMPORTANT: This routine is NOT MLI-reentrant, which means MLI
; calls can NOT be made within this handler. See page 108 of the
; ProDOS 8 Technical Reference Manual if this feature needs to be
; added.
;
WGMouseInterruptHandler:
cld ; ProDOS interrupt handlers must open with this
SAVE_AXY
CALLMOUSE SERVEMOUSE
bcc WGMouseInterruptHandler_regard
jmp WGMouseInterruptHandler_disregard
WGMouseInterruptHandler_regard:
php
sei
lda PAGE2 ; Need to preserve text bank, because we may interrupt rendering
pha
SETSWITCH PAGE2OFF
ldx WG_MOUSE_SLOT
lda MOUSTAT,x ; Check interrupt status bits first, because READMOUSE clears them
and #MOUSTAT_MASK_BUTTONINT
bne WGMouseInterruptHandler_button
lda MOUSTAT,x
and #MOUSTAT_MASK_MOVEINT
bne WGMouseInterruptHandler_mouse
jmp WGMouseInterruptHandler_VBL
WGMouseInterruptHandler_mouse:
jsr WGUndrawPointer ; Erase the old mouse pointer
; Read the mouse state. Note that interrupts need to remain
; off until after the data is copied.
CALLMOUSE READMOUSE
ldx WG_MOUSE_SLOT
lda MOUSTAT,x ; Movement/button status bits are now valid
sta WG_MOUSE_STAT
lda WG_APPLEIIC
bne WGMouseInterruptHandler_IIc
; Read mouse position and transform it into screen space
; SCALING: If you change the clamps, change this division from
; 1024 to match your new values.
lsr MOUSE_XH,x
ror MOUSE_XL,x
lsr MOUSE_XH,x
ror MOUSE_XL,x
lsr MOUSE_XH,x
ror MOUSE_XL,x
lda MOUSE_XL,x
sta WG_MOUSEPOS_X
lsr MOUSE_YH,x
ror MOUSE_YL,x
lsr MOUSE_YH,x
ror MOUSE_YL,x
lsr MOUSE_YH,x
ror MOUSE_YL,x
lsr MOUSE_YH,x
ror MOUSE_YL,x
lsr MOUSE_YH,x
ror MOUSE_YL,x
lda MOUSE_YL,x
sta WG_MOUSEPOS_Y
bra WGMouseInterruptHandler_draw
WGMouseInterruptHandler_IIc: ; IIc tracks much slower, so don't scale
lda MOUSE_XL,x
sta WG_MOUSEPOS_X
lda MOUSE_YL,x
sta WG_MOUSEPOS_Y
WGMouseInterruptHandler_draw:
jsr WGDrawPointer ; Redraw the pointer
bra WGMouseInterruptHandler_intDone
WGMouseInterruptHandler_disregard:
; Carry will still be set here, to notify ProDOS that
; this interrupt was not ours
RESTORE_AXY
rts
WGMouseInterruptHandler_button:
CALLMOUSE READMOUSE
ldx WG_MOUSE_SLOT
lda MOUSTAT,x ; Movement/button status bits are now valid
sta WG_MOUSE_STAT
bit WG_MOUSE_STAT ; Check for rising edge of button state
bpl WGMouseInterruptHandler_intDone
lda WG_MOUSE_BUTTON_DOWN
bne WGMouseInterruptHandler_intDone
WGMouseInterruptHandler_buttonDown:
; Button went down, so make a note of location for later
lda #1
sta WG_MOUSE_BUTTON_DOWN
lda WG_MOUSEPOS_X
sta WG_MOUSECLICK_X
lda WG_MOUSEPOS_Y
sta WG_MOUSECLICK_Y
WGMouseInterruptHandler_intDone:
pla ; Restore text bank
bpl WGMouseInterruptHandler_intDoneBankOff
SETSWITCH PAGE2ON
bra WGMouseInterruptHandler_done
WGMouseInterruptHandler_VBL:
CALLMOUSE READMOUSE
ldx WG_MOUSE_SLOT
lda MOUSTAT,x ; Movement/button status bits are now valid
sta WG_MOUSE_STAT
bmi WGMouseInterruptHandler_intDone
stz WG_MOUSE_BUTTON_DOWN
bra WGMouseInterruptHandler_intDone
WGMouseInterruptHandler_intDoneBankOff:
SETSWITCH PAGE2OFF
WGMouseInterruptHandler_done:
RESTORE_AXY
plp
clc ; Notify ProDOS this was our interrupt
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGUndrawPointer
; Unplots the mouse pointer at current location
; Stub for your use
;
WGUndrawPointer:
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGDrawPointer
; Plots the mouse pointer at current location
; Stub for your use
;
WGDrawPointer:
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Mouse API state
;
; Useful things you can poll in your code:
WG_MOUSEACTIVE:
.byte 0
WG_MOUSEPOS_X:
.byte 39
WG_MOUSEPOS_Y:
.byte 11
WG_MOUSECLICK_X:
.byte $ff
WG_MOUSECLICK_Y:
.byte 0
; Internal state for the driver (no touchy!)
WG_MOUSE_STAT:
.byte 0
WG_MOUSEBG:
.byte 0
WG_APPLEIIC:
.byte 0
WG_MOUSE_JUMPL:
.byte 0
WG_MOUSE_JUMPH:
.byte 0
WG_MOUSE_SLOT:
.byte 0
WG_MOUSE_SLOTSHIFTED:
.byte 0
WG_MOUSE_BUTTON_DOWN:
.byte 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ProDOS system call parameter blocks
;
WG_PRODOS_ALLOC:
.byte 2
.byte 0 ; ProDOS returns an ID number for the interrupt here
.addr WGMouseInterruptHandler
WG_PRODOS_DEALLOC:
.byte 1
.byte 0 ; To be filled with ProDOS ID number

109
a2bejwld/mouseWrapper.c Normal file
View File

@ -0,0 +1,109 @@
//
// mouseWrapper.c
// a2bejwld
//
// Created by Jeremy Rand on 2016-08-17.
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#include <conio.h>
#include <stdio.h>
#include <mouse.h>
#include "mouseWrapper.h"
#include "game.h"
// Extern to mouse driver
extern char a2e_stdmou_mou;
// Globals
static tMouseCallbacks *gMouseCallbacks = NULL;
static bool gMouseInstalled = false;
void initMouse(tMouseCallbacks *callbacks)
{
if (mouse_install(&mouse_def_callbacks, &a2e_stdmou_mou) == 0) {
gMouseInstalled = true;
}
gMouseCallbacks = callbacks;
}
void shutdownMouse(void)
{
if (gMouseInstalled) {
mouse_uninstall();
gMouseInstalled = false;
}
}
bool pollMouse(void)
{
static uint8_t oldX = 0;
static uint8_t oldY = 0;
static bool oldMouseDown = false;
static bool handledMouseDown = false;
struct mouse_info mouseInfo;
uint8_t newX;
uint8_t newY;
bool newMouseDown;
bool result = false;
if (!gMouseInstalled) {
return result;
}
mouse_info(&mouseInfo);
newMouseDown = (mouseInfo.buttons != 0);
newX = mouseInfo.pos.x / 35;
newY = mouseInfo.pos.y / 8;
if (newX >= BOARD_SIZE)
newX = BOARD_SIZE - 1;
if (newY >= BOARD_SIZE)
newY = BOARD_SIZE - 1;
if (!newMouseDown) {
handledMouseDown = false;
if ((oldX != newX) ||
(oldY != newY)) {
result = gMouseCallbacks->mouseSelectSquare(XY_TO_SQUARE(newX, newY));
}
} else if (!handledMouseDown) {
if (newX < oldX) {
if (newY == oldY) {
result = gMouseCallbacks->mouseSwapSquare(XY_TO_SQUARE(oldX, oldY), DIR_LEFT);
}
handledMouseDown = true;
} else if (newX > oldX) {
if (newY == oldY) {
result = gMouseCallbacks->mouseSwapSquare(XY_TO_SQUARE(oldX, oldY), DIR_RIGHT);
}
handledMouseDown = true;
} else if (newY < oldY) {
result = gMouseCallbacks->mouseSwapSquare(XY_TO_SQUARE(oldX, oldY), DIR_UP);
handledMouseDown = true;
} else if (newY > oldY) {
result = gMouseCallbacks->mouseSwapSquare(XY_TO_SQUARE(oldX, oldY), DIR_DOWN);
handledMouseDown = true;
}
}
oldX = newX;
oldY = newY;
oldMouseDown = newMouseDown;
return result;
}

33
a2bejwld/mouseWrapper.h Normal file
View File

@ -0,0 +1,33 @@
//
// mouseWrapper.h
// a2bejwld
//
// Created by Jeremy Rand on 2016-08-17.
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#ifndef __a2bejwld__mouseWrapper__
#define __a2bejwld__mouseWrapper__
#include <stdbool.h>
#include "types.h"
// Types
typedef struct tMouseCallbacks {
bool (*mouseSelectSquare)(tSquare square);
bool (*mouseSwapSquare)(tSquare square, tDirection dir);
} tMouseCallbacks;
// API
extern void initMouse(tMouseCallbacks *callbacks);
extern void shutdownMouse(void);
extern bool pollMouse(void);
#endif /* defined(__a2bejwld__mouseWrapper__) */

View File

@ -1,32 +0,0 @@
;
; switches.s
; Softswitches for Apple ][
;
; Created by Quinn Dunki on 8/15/14.
; Copyright (c) 2014 One Girl, One Laptop Productions. All rights reserved.
;
PAGE2 = $c01c ; Read bit 7
PAGE2OFF = $c054 ; Read/Write
PAGE2ON = $c055 ; Read/Write
COL80 = $c01f ; Read bit 7
COL80OFF = $c00c ; Write
COL80ON = $c00d ; Write
STORE80 = $c018 ; Read bit 7
STORE80OFF = $c000 ; Write
STORE80ON = $c001 ; Write
TEXT = $c01a ; Read bit 7
TEXTOFF = $c050 ; Read/Write
TEXTON = $C051 ; Read/Write
KBD = $c000 ; Read
KBDSTRB = $c010 ; Read/Write
RDVBLBAR = $C019 ; Read bit 7 (active low)
OURCH = $057b ; 80 col cursor position (H)
OURCV = $05fb ; 80 col cursor position (V)

View File

@ -16,6 +16,16 @@
#include "dbllores.h"
#include "game.h"
#include "joystick.h"
#include "mouseWrapper.h"
// Typedefs
typedef struct tGameOptions {
bool enableJoystick;
bool enableMouse;
bool enableSound;
} tGameOptions;
// Forward delcarations
@ -27,6 +37,9 @@ static void refreshLevel(tLevel level);
static bool joystickChangedCallback(tJoyState *oldState, tJoyState *newState);
static bool joystickNoChangeCallback(tJoyState *oldState);
static bool mouseSelectSquare(tSquare square);
static bool mouseSwapSquare(tSquare square, tDirection dir);
// Globals
@ -63,11 +76,48 @@ static tJoyCallbacks gJoyCallbacks = {
10 // Subsequent no change poll time
};
static tMouseCallbacks gMouseCallbacks = {
mouseSelectSquare,
mouseSwapSquare,
};
static bool gShouldSave = false;
static tGameOptions gGameOptions = {
false,
true,
true,
};
// Implementation
void badThingHappened(void)
{
if (gGameOptions.enableSound)
printf("\007");
}
void playSound(int8_t startFreq, int8_t duration)
{
int8_t freq;
if (!gGameOptions.enableSound)
return;
while (duration > 0) {
asm ("STA %w", 0xc030);
freq = startFreq;
while (freq > 0) {
freq--;
}
duration--;
}
}
static void showAndClearDblLoRes(void)
{
showDblLoRes();
@ -77,7 +127,6 @@ static void showAndClearDblLoRes(void)
void printInstructions(void)
{
int seed = 0;
unshowDblLoRes();
@ -89,9 +138,9 @@ void printInstructions(void)
" Apple Jeweled\n"
" by Jeremy Rand\n"
"\n"
" Use I-J-K-M, the arrow keys or the joystick to move your selection.\n"
" Hold either apple key or joystick button and move your selection to\n"
" swap two jewels and match 3 or more jewels. When you match three\n"
" Use I-J-K-M, the arrow keys, joystick or mouse to move your selection.\n"
" Hold either apple key, joystick or mouse button and move your selection\n"
" to swap two jewels and match 3 or more jewels. When you match three\n"
" jewels, they disappear and new jewels will drop from the top.\n"
"\n"
" If you match four jewels or three jewels in two directions, then the\n"
@ -105,7 +154,7 @@ void printInstructions(void)
"\n"
" Press Q or escape to quit at any time.\n"
" Press R to start a new game.\n"
" Press S to toggle sound.\n"
" Press O to select options.\n"
" Press H to get a hint.\n"
" Press ? to see this info again.\n"
"\n"
@ -122,6 +171,20 @@ void printInstructions(void)
}
void selectOptions(void)
{
unshowDblLoRes();
videomode(VIDEOMODE_80x24);
clrscr();
printf("Options go here...");
cgetc();
clrscr();
}
static void refreshSquare(tSquare square)
{
drawBgSquare(square);
@ -150,6 +213,7 @@ static void quitGame(void)
unshowDblLoRes();
videomode(VIDEOMODE_40x24);
clrscr();
shutdownMouse();
exit(0);
}
@ -490,6 +554,43 @@ void initUI(void)
initGameEngine(&gCallbacks);
animInit();
initJoystick(&gJoyCallbacks);
initMouse(&gMouseCallbacks);
}
static bool mouseSelectSquare(tSquare square)
{
refreshSquare(gSelectedSquare);
gSelectedSquare = square;
selectSquare(gSelectedSquare);
return false;
}
static bool mouseSwapSquare(tSquare square, tDirection dir)
{
if (gSelectedSquare != square) {
refreshSquare(gSelectedSquare);
gSelectedSquare = square;
selectSquare(gSelectedSquare);
}
switch (dir) {
case DIR_UP:
return swapUp();
case DIR_DOWN:
return swapDown();
case DIR_LEFT:
return swapLeft();
case DIR_RIGHT:
return swapRight();
}
return false;
}
@ -659,9 +760,11 @@ static bool pollKeyboard(void)
gShouldSave = false;
return true;
case 's':
case 'S':
toggleSound();
case 'o':
case 'O':
selectOptions();
showAndClearDblLoRes();
drawBoard();
break;
case 'h':
@ -738,7 +841,13 @@ void playGame(void)
break;
}
if (pollJoystick()) {
if ((gGameOptions.enableJoystick) &&
(pollJoystick())) {
break;
}
if ((gGameOptions.enableMouse) &&
(pollMouse())) {
break;
}
}

View File

@ -10,6 +10,9 @@
#define __a2bejwld__ui__
#include <stdint.h>
// API
extern void initUI(void);
@ -18,5 +21,7 @@ extern void printInstructions(void);
extern void playGame(void);
extern void playSound(int8_t startFreq, int8_t duration);
#endif /* defined(__a2bejwld__ui__) */