; Joypad emulation by keyboard
;
; Allows to emulate CD32 joypad buttons
; and to fake a joypad, since some games demand
; the joypad (e.g. Robocod CD32)
;
; By Jean-François Fabre 1999


*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»*

*## For the Startup.asm:

StartSkip	=	0		;0=WB/CLI, 1=CLI only (from AsmOne)
Processor	=	0		;0/680x0/0x0/x0
MathProc	=	0		;0/68881/68882/68040/68060

*## Default includes:

	INCDIR	Include:

	Include	"Startup.asm"
	include	"libs.i"
	include	"LVOs.i"

	INCLUDE	"workbench/workbench.i"
	INCLUDE	"workbench/startup.i"
	INCLUDE	"hardware/custom.i"
	INCLUDE	"libraries/lowlevel.i"

_custom = $DFF000

SET_BIT_BUTTON:MACRO
	bset	#JPB_BUTTON_\1,D0	; button pressed
	ENDM

*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»*
Init
	TaskName	JoypadEmu		;from AsmOne
	DefEnd

Start
	move.l	$4.w,_SysBase
	bsr	init

*·············································································*
Close	Return	0


	dc.b	0,"$VER: fAkePaD v0.1 by JF Fabre",0
	cnop	0,4
init:
	move.l	_SysBase,A6

	lea	lowname,A1
	moveq.l	#0,D0
	JSRLIB	OpenLibrary
	move.l	D0,lowbase
	beq	.err

	move.l	lowbase,A6
	add.l	#_LVOReadJoyPort+2,A6
	move.l	(A6),A1
	move.l	(2,A1),D0
	cmp.l	#'JOYP',D0
	beq	.err			; already there

	move.l	#MEMF_PUBLIC,D1
	move.l	#end_tsr-tsr,D0

	move.l	D0,tsrlen	; for future deletion

	move.l	_SysBase,A6
	JSRLIB	AllocMem
	move.l	D0,tsr_reloc
	beq	.err

	; interrupts disabled

	move.l	_SysBase,A6
	JSRLIB	Disable

	move.l	lowbase,A1
	move.l	#_LVOReadJoyPort,A0
	move.l	tsr_reloc(pc),D0
	JSRLIB	SetFunction

	move.l	D0,oldreadjoyport

	; relocates program

	lea	tsr(pc),A0
	move.l	tsr_reloc(pc),A1
	move.l	#end_tsr-tsr,D0
	subq.l	#1,D0
.copy
	move.b	(A0)+,(A1)+
	dbf	D0,.copy
	
	; interrupts enabled

	move.l	_SysBase,A6
	JSRLIB	Enable

	moveq.l	#0,D0
	rts

	; error
.err
	moveq.l	#5,D0
	rts

_SysBase:
	dc.l	0
tsr_reloc:
	dc.l	0

;;;;; relocatable section

tsr:
	bra.b	tsr_startup
	dc.b	'JOYP'	; must stay at offset $2 (patch ID)
tsrlen:
	dc.l	0	; must stay at offset $6
oldreadjoyport:
	dc.l	0	; must stay at offset $A
lowbase:
	dc.l	0
tsr_startup:

; reads joypads
; < D0
; > D0

READJOYPORT:
	cmp.w	#0,D0
	bne	.port1

	; mouse port bypassed

	move.l	oldreadjoyport(pc),-(A7)
	rts

.port1

	movem.l	D1-A6,-(A7)

;;	cmp.w	#0,D0
;;	beq	.joy0
	cmp.w	#1,D0
	beq	.joy1

	move.l	#JP_TYPE_NOTAVAIL,D0
	bra	.mainexit

; joystick port 0 (mouse)

.joy0
	move.l	#JP_TYPE_GAMECTLR,D0	; joypad connected

	btst	#6,$bfe001
	bne	.nob1_0

	bset	#JPB_BUTTON_RED,D0	; fire/lmb
	
.nob1_0:

	btst	#6,potinp+$DFF000
	bne	.nob2_0

	bset	#JPB_BUTTON_BLUE,D0	; fire 2/rmb
	move.w	#$CC01,potgo+$DFF000	; reset ports
.nob2_0	
	; joystick moves

	lea	(joy0dat+_custom),A6
	bsr	.joy_test

	bra	.mainexit

; joystick port 1

.joy1
	move.l	#JP_TYPE_GAMECTLR,D0	; joypad connected

	btst	#7,$bfe001
	bne	.nob1_1

	bset	#JPB_BUTTON_RED,D0	; fire/lmb
	
.nob1_1:

	btst	#6,potinp+$DFF000
	bne	.nob2_1

	bset	#JPB_BUTTON_BLUE,D0	; fire 2/rmb
	move.w	#$CC01,(potgo+_custom)	; reset ports
.nob2_1:

	; joystick moves

	lea	(joy1dat+_custom),A6
	bsr	.joy_test

	movem.l	D0,-(A7)

	move.l	old_buttonmask(pc),D0
	bsr	.button_test

	lea	old_buttonmask(pc),A0
	move.l	D0,(A0)			; relocatable memory write

	or.l	(A7),D0
	move.l	D0,(A7)
	movem.l	(A7)+,D0	

.mainexit
	movem.l	(A7)+,D1-A6
	rts

; other joypad buttons by keyboard emulation
; even a real joypad does not work properly on a real amiga!
; (I don't really know why!)

.qkstruct:
	dc.w	$50,$0,$51,0,$52,$0,$53,0,$54,0,$55,0

.button_test:
	movem.l	D1/A0-A1,-(A7)
	bsr	.btproc
	movem.l	(A7)+,D1/A0-A1
	rts

.btproc

	; reads keyboard current pressed key (maybe it won't work)

	lea	.qkstruct(pc),A0
	move.l	lowbase(pc),A6
	moveq.l	#6,D1
	JSRLIB	QueryKeys

	moveq.l	#0,D0

	lea	.qkstruct(pc),A0

	; F1: Blue
		
	tst.w	2(A0)
	beq	.noblue
	SET_BIT_BUTTON	BLUE
.noblue
	; F2: Green

	addq.l	#4,A0
	tst.w	2(A0)
	beq	.nogreen
	SET_BIT_BUTTON	GREEN
.nogreen:
	; F3: Yellow

	addq.l	#4,A0
	tst.w	2(A0)
	beq	.noyellow
	SET_BIT_BUTTON	YELLOW
.noyellow:
	; F4: Play/pause

	addq.l	#4,A0
	tst.w	2(A0)
	beq	.noplay
	SET_BIT_BUTTON	PLAY
.noplay:
	; F5: Reverse (left ear)

	addq.l	#4,A0
	tst.w	2(A0)
	beq	.nolear
	SET_BIT_BUTTON	REVERSE
.nolear:
	; F6: right ear
	addq.l	#4,A0
	tst.w	2(A0)
	beq	.norear
	SET_BIT_BUTTON	FORWARD

.norear:
	rts

; tests joystick moves
; < A6: custom reg. of the selected joystick
; > D0: joystick bits set

.joy_test:
	movem.l	D4-D6,-(A7)

	move.w	(A6),D4
	move.w	D4,D5
	btst	#1,D4
	beq.b	.left_off
	bset	#JPB_JOY_RIGHT,D0
	bra.b	.vert_test
.left_off:
	btst	#9,D4
	beq.b	.vert_test
	bset	#JPB_JOY_LEFT,D0
.vert_test
	lsr.w	#1,D4
	eor.w	D5,D4
	btst	#0,D4
	beq.b	.back_off
	bset	#JPB_JOY_DOWN,D0
	bra.b	.exit
.back_off
	btst	#8,D4
	beq.b	.exit
	bset	#JPB_JOY_UP,D0
.exit

	movem.l	(A7)+,D4-D6
	rts

old_buttonmask:
	dc.l	0
end_tsr:

lowname:
	dc.b	"lowlevel.library",0
