From 7995aefa4f0abef2b70cceb9aa780714f2757682 Mon Sep 17 00:00:00 2001 From: Jeremy Rand Date: Fri, 19 Aug 2016 00:08:38 -0400 Subject: [PATCH] Add mouse support. --- a2bejwld.xcodeproj/project.pbxproj | 12 +- a2bejwld/a2e.stdmou.s | 427 +++++++++++++++++++++++ a2bejwld/anim.c | 35 +- a2bejwld/anim.h | 3 - a2bejwld/macros.s | 120 ------- a2bejwld/mouse.s | 535 ----------------------------- a2bejwld/mouseWrapper.c | 109 ++++++ a2bejwld/mouseWrapper.h | 33 ++ a2bejwld/switches.s | 32 -- a2bejwld/ui.c | 127 ++++++- a2bejwld/ui.h | 5 + 11 files changed, 700 insertions(+), 738 deletions(-) create mode 100644 a2bejwld/a2e.stdmou.s delete mode 100755 a2bejwld/macros.s delete mode 100755 a2bejwld/mouse.s create mode 100644 a2bejwld/mouseWrapper.c create mode 100644 a2bejwld/mouseWrapper.h delete mode 100755 a2bejwld/switches.s diff --git a/a2bejwld.xcodeproj/project.pbxproj b/a2bejwld.xcodeproj/project.pbxproj index da00ce7..960ca9a 100644 --- a/a2bejwld.xcodeproj/project.pbxproj +++ b/a2bejwld.xcodeproj/project.pbxproj @@ -9,9 +9,9 @@ /* Begin PBXFileReference section */ 9D3A9FB81D455CCF004C5897 /* joystick.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = joystick.h; sourceTree = ""; }; 9D3A9FB91D455CD8004C5897 /* joystick.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = joystick.c; sourceTree = ""; }; - 9D3A9FBB1D457900004C5897 /* macros.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = macros.s; sourceTree = ""; }; - 9D3A9FBC1D457900004C5897 /* mouse.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = mouse.s; sourceTree = ""; }; - 9D3A9FBD1D457900004C5897 /* switches.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = switches.s; sourceTree = ""; }; + 9D509F911D654F9900161DDC /* mouseWrapper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mouseWrapper.c; sourceTree = ""; }; + 9D509F921D654F9900161DDC /* mouseWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mouseWrapper.h; sourceTree = ""; }; + 9D509F941D66AE2800161DDC /* a2e.stdmou.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = a2e.stdmou.s; sourceTree = ""; }; 9D6B472E1D3FB16F00F6D704 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 9D6B472F1D3FB16F00F6D704 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 9D6B47311D3FB16F00F6D704 /* AppleCommander.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; name = AppleCommander.jar; path = make/AppleCommander.jar; sourceTree = ""; }; @@ -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 = ""; diff --git a/a2bejwld/a2e.stdmou.s b/a2bejwld/a2e.stdmou.s new file mode 100644 index 0000000..4dfb3b3 --- /dev/null +++ b/a2bejwld/a2e.stdmou.s @@ -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 diff --git a/a2bejwld/anim.c b/a2bejwld/anim.c index 9c2e7f1..1d1f164 100644 --- a/a2bejwld/anim.c +++ b/a2bejwld/anim.c @@ -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)) { diff --git a/a2bejwld/anim.h b/a2bejwld/anim.h index a27c2e6..0d33e4c 100644 --- a/a2bejwld/anim.h +++ b/a2bejwld/anim.h @@ -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__) */ diff --git a/a2bejwld/macros.s b/a2bejwld/macros.s deleted file mode 100755 index 2c6f932..0000000 --- a/a2bejwld/macros.s +++ /dev/null @@ -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 PARAM1 -.endmacro - - -.macro CALL16 func,addr - PARAM16 addr - jsr func -.endmacro - - diff --git a/a2bejwld/mouse.s b/a2bejwld/mouse.s deleted file mode 100755 index 551e65b..0000000 --- a/a2bejwld/mouse.s +++ /dev/null @@ -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_CLAMPH - lda #0 - CALLMOUSE CLAMPMOUSE - - 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_CLAMPH - lda #0 - CALLMOUSE CLAMPMOUSE - - 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 - - diff --git a/a2bejwld/mouseWrapper.c b/a2bejwld/mouseWrapper.c new file mode 100644 index 0000000..3df4ea3 --- /dev/null +++ b/a2bejwld/mouseWrapper.c @@ -0,0 +1,109 @@ +// +// mouseWrapper.c +// a2bejwld +// +// Created by Jeremy Rand on 2016-08-17. +// Copyright © 2016 Jeremy Rand. All rights reserved. +// + + +#include +#include +#include + +#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; +} \ No newline at end of file diff --git a/a2bejwld/mouseWrapper.h b/a2bejwld/mouseWrapper.h new file mode 100644 index 0000000..27d3380 --- /dev/null +++ b/a2bejwld/mouseWrapper.h @@ -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 + +#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__) */ diff --git a/a2bejwld/switches.s b/a2bejwld/switches.s deleted file mode 100755 index 81181c8..0000000 --- a/a2bejwld/switches.s +++ /dev/null @@ -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) diff --git a/a2bejwld/ui.c b/a2bejwld/ui.c index 5d0e737..c77a5e8 100644 --- a/a2bejwld/ui.c +++ b/a2bejwld/ui.c @@ -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; } } diff --git a/a2bejwld/ui.h b/a2bejwld/ui.h index 98c0376..05361ca 100644 --- a/a2bejwld/ui.h +++ b/a2bejwld/ui.h @@ -10,6 +10,9 @@ #define __a2bejwld__ui__ +#include + + // 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__) */