-
-
Save HonkeyKong/2d5c27b0eaac443e11b56794a661a8a9 to your computer and use it in GitHub Desktop.
Source code for Maniac Mansion mouse hack. Assembles with Ophis.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.data | |
.alias Port1 $4016 | |
.alias Port2 $4017 | |
.alias MOUSE_RIGHT %10000000 | |
.alias MOUSE_LEFT %01000000 | |
.alias M_SENSITIVITY %00110000 | |
.alias MOUSE_DIRECTION %10000000 | |
.alias MOUSE_MOTION %01111111 | |
.alias BUTTON_A %10000000 | |
.alias BUTTON_B %01000000 | |
.alias BUTTON_SELECT %00100000 | |
.alias BUTTON_START %00010000 | |
.alias GameInput $02 ; This is where the game reads buttons. | |
.alias InputBuffer $04 ; This is the previous button buffer. | |
.alias LowerButtons $2F ; This is the lower buttons. (B/Select/Start) | |
.alias CutscenePlaying $6B08 ; Non-zero when cutscene is playing. | |
.alias UpperButtons $710E ; This is the upper buttons. (A) | |
.alias CursorXPos $7116 ; Cursor X Position. | |
.alias CursorYPos $7118 ; Cursor Y Position. | |
.alias ReadCounter $7221 ; Counter used by controller read subroutine. | |
.org $7FF0 ; End of external work RAM | |
.space MouseButtons 1 ; Mouse buttons, sensitivity and low signature bit. | |
.space MouseXMotion 1 ; Mouse direction and X motion in mickeys. | |
.space MouseYMotion 1 ; Mouse direction and Y motion in mickeys. | |
.space MouseMotion 1 ; Mouse motion in mickeys, distilled from X or Y. | |
.space MouseBuffer 1 ; Buffer with previous frame's mouse buttons. | |
.space SigHi 1 ; High signature byte, should always be zero. | |
.space InjectLower 1 ; Bits to inject into lower input buffer. | |
.space InjectUpper 1 ; Bits to inject into upper input buffer. | |
.space MouseDetected 1 ; Whether or not a mouse has been detected. | |
.space MouseTweaked 1 ; Whether or not the mouse sensitivity is set. | |
.checkpc $7FFF ; Just a quick check to make sure we're not | |
; spilling over into the ROM/Mapper space. | |
.text | |
; This is the first free space in PRG 0 | |
; Put your JSR at $8320, AKA $330 in the ROM. | |
; Replace 68 FB with 10 98. Then, paste this | |
; assembled code at $1820 in the ROM file. | |
.org $9810 | |
ReadControls: | |
; Push the registers off to the stack | |
PHA | |
TYA | |
PHA | |
TXA | |
PHA | |
; Read first two bytes and detect mouse. | |
JSR DetectMouse | |
; If the mouse wasn't detected, skip all this. | |
BIT MouseDetected | |
BMI +++ | |
; Third byte is Y motion. Bit 7 determines direction. | |
LDX #$08 | |
* LDA Port2 | |
LSR | |
ROL MouseYMotion | |
DEX | |
CPX #$00 | |
BNE - | |
; Fourth byte is X motion. Bit 7 determines direction. | |
LDX #$08 | |
* LDA Port2 | |
LSR | |
ROL MouseXMotion | |
DEX | |
CPX #$00 | |
BNE - | |
; This is basically identical to the game's read routine. | |
* LDX #$01 | |
* LDA GameInput, X | |
STA InputBuffer, X | |
LDA #$08 | |
STA ReadCounter | |
LDA #$01 | |
STA Port1 | |
LDA #$00 | |
STA Port1 | |
* ASL GameInput, X | |
LDA Port1, X | |
AND #$01 | |
ORA GameInput, X | |
STA GameInput, X | |
DEC ReadCounter | |
BNE - | |
DEX | |
BPL -- | |
LDA InputBuffer | |
AND #BUTTON_B|BUTTON_SELECT|BUTTON_START | |
BNE + | |
LDA GameInput | |
AND #BUTTON_B|BUTTON_SELECT|BUTTON_START | |
BEQ + | |
STA LowerButtons | |
* LDA InputBuffer | |
AND #BUTTON_A | |
BNE + | |
LDA GameInput | |
AND #BUTTON_A | |
BEQ + | |
STA UpperButtons | |
LDA MouseDetected | |
BEQ ++ | |
; Welcome back! Now we're processing the mouse input. | |
; !! Uncomment this line when building for hardware. !! | |
* JSR TweakMouse ; Tweak mouse sensitivity now that we're not reading it. | |
JSR ProcessMouse ; Process mouse motion and buttons. | |
; First load the lower button bits, like A | |
LDA LowerButtons ; Load the game's A button buffer. | |
ORA InjectLower ; OR our bits from the mouse into it. | |
STA LowerButtons ; Store the new mask in LowerButtons. | |
; Now we do the same for the upper bits | |
LDA UpperButtons ; Load the B/Start/Select buffer. | |
ORA InjectUpper ; OR the mouse bits in like before. | |
STA UpperButtons ; Store the new mask in UpperButtons. | |
; Now restore all the registers from the stack and return. | |
* PLA | |
TAX | |
PLA | |
TAY | |
PLA | |
RTS | |
ProcessMouse: | |
; Process mouse input. | |
LDA MouseDetected ; Check if mouse is detected | |
BNE + ; If detected, start processing. | |
RTS ; If not detected, skip processing. | |
* LDA #$00 | |
STA InjectLower ; Clear our lower injection buffer. | |
STA InjectUpper ; Clear our upper injection buffer. | |
LDA MouseBuffer ; Read the mouse buffer. | |
AND #MOUSE_RIGHT ; Check the right button. | |
BNE + ; Skip if it's held. | |
LDA MouseButtons ; Read the mouse buttons. | |
AND #MOUSE_RIGHT ; Check the right button. | |
BEQ + ; Skip if it's not pressed. | |
LDA CutscenePlaying ; Check for a cutscene playing. | |
BEQ PressSelect ; Skip to Select if not. | |
PressB: | |
LDA InjectLower ; Load the lower injection buffer. | |
ORA #BUTTON_B ; OR the B button. | |
STA InjectLower ; Store the lower injection buffer. | |
JMP + ; Jump to the left button. | |
PressSelect: | |
LDA InjectLower ; Load the lower injection buffer. | |
ORA #BUTTON_SELECT ; OR the select button. | |
STA InjectLower ; Store the lower injection buffer. | |
* LDA MouseBuffer ; Same as above, but for the left button. | |
AND #MOUSE_LEFT | |
BNE + | |
LDA MouseButtons | |
AND #MOUSE_LEFT | |
BEQ + | |
LDA UpperButtons ; Load the upper injection buffer. | |
ORA #BUTTON_A ; OR the A button. | |
STA UpperButtons ; Store the upper injection buffer. | |
* LDA MouseButtons ; Load the mouse buttons. | |
STA MouseBuffer ; Copy into the buffer for the next frame. | |
LDA MouseYMotion ; Read the mouse Y motion. | |
AND #MOUSE_DIRECTION ; Check the direction. | |
BEQ ++ ; Branch ahead if it's moving down. | |
LDA MouseYMotion ; Load the motion again. | |
AND #MOUSE_MOTION ; Mask out the direction. | |
STA MouseMotion ; Store motion amount. | |
LDA CursorYPos ; Load Cursor Y position. | |
SEC ; Set the carry bit. | |
SBC MouseMotion ; Subtract the motion amount. | |
BCS + | |
LDA #$00 | |
* STA CursorYPos ; Store the new Y position. | |
JMP +++ ; We're done with Y, jump to X. | |
* LDA MouseYMotion ; Read the mouse Y motion. | |
AND #MOUSE_MOTION ; Mask out the direction. | |
STA MouseMotion ; Store motion amount. | |
LDA CursorYPos ; Load cursor Y position. | |
CLC ; Clear the carry bit. | |
ADC MouseMotion ; Add the motion amount. | |
BCC + | |
LDA #$FF | |
* STA CursorYPos ; Store the new Y position. | |
* LDA MouseXMotion ; This is the same stuff. | |
AND #MOUSE_DIRECTION ; It just processes the X axis. | |
BEQ ++ | |
LDA MouseXMotion | |
AND #MOUSE_MOTION | |
STA MouseMotion | |
LDA CursorXPos | |
SEC | |
SBC MouseMotion | |
BCS + | |
LDA #$00 | |
* STA CursorXPos | |
JMP +++ | |
* LDA MouseXMotion | |
AND #MOUSE_MOTION | |
STA MouseMotion | |
LDA CursorXPos | |
CLC | |
ADC MouseMotion | |
BCC + | |
LDA #$FF | |
* STA CursorXPos | |
* RTS | |
DetectMouse: | |
; Strobe port 1 to latch the controller ports | |
LDA #$01 | |
STA Port1 | |
LDA #$00 | |
STA Port1 | |
; Start reading bits from port 2 | |
LDX #$08 | |
* LDA Port2 ; Read port 2 | |
LSR ; Shift first bit right into carry | |
ROL SigHi ; Rotate bit left into SigHi | |
DEX ; Decrement X | |
CPX #$00 ; Is it zero? | |
BNE - ; If no, repeat. | |
BIT SigHi ; Check the signature high byte | |
BMI ++ ; Exit if it's zero. | |
LDX #$08 | |
* LDA Port2 ; Read the next 8 bits of port 2 | |
LSR ; Shift into carry | |
ROL MouseButtons ; Rotate left into button mask | |
DEX ; Decrement X | |
CPX #$00 ; Check for zero | |
BNE - ; Loop back | |
LDA MouseButtons ; Read mouse buttons | |
AND #$0F ; Mask lower 4 bits | |
CMP #$01 ; Is only bit 1 raised? | |
BNE + ; It's a SNES controller. Abort! | |
LDA #$01 ; Looks like we have a mouse | |
STA MouseDetected ; Set the detected flag | |
RTS ; Return from Subroutine. | |
* LDA #$00 ; If we got here, there's no mouse. | |
STA MouseDetected ; Clear the detected flag. | |
RTS ; Return | |
; This subroutine serves as our means of | |
; setting the sensitivity on the SNES mouse | |
; to an acceptable threshold. | |
TweakMouse: | |
LDA MouseTweaked | |
BPL + | |
LDY #$01 ; Prepare to latch the controllers. | |
STY Port1 ; Latch port 1 | |
LDA Port2 ; Strobe port 2 to change sensitivity. | |
DEY ; Decrement Y | |
STY Port1 ; Write port 1 to finish latch. | |
LDA #$01 ; Load 1 into accumulator | |
STA MouseTweaked ; Set the tweak flag. | |
* RTS ; Return | |
; End mouse processing | |
.byte 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment