.MOD_NewCode

	ld IX,MOD_type1
	ld HL,BALL1
	ld BC,3
	xor A

;module 1	
	or (HL)
	jr nz,MOD_Branch

	ld DE,MOD_TableSize
;next 2

	add IX,DE
	add HL,BC
	or (HL)
	jr nz,MOD_Branch
	
;next 3
	add IX,DE
	add HL,BC
	or (HL)
	jr z,MOD_End



;do branching
.MOD_Branch
;ret address
	ld DE,JEWELS
	push DE
;save current HL	
	push HL


	and 7	;only 8 actions
;get address
	ld L,A
	ld H,0
	add HL,HL
	ld DE,MOD_ActionTable
	add HL,DE
	ld E,(HL)
	inc HL
	ld D,(HL)
;restore HL
	pop HL
;jump address on stack
	push DE
	ret

.MOD_End
	jp JEWELS	;jump to other modules code
	
;action table
.MOD_ActionTable
	dw MOD_End 			;0
	dw MOD_LockedFront	: MOD_ActionLockedFront		EQU 1	; do not change theses actions ID
	dw MOD_LockedRear	: MOD_ActionLockedRear		EQU 2
	dw MOD_FloatRear	: MOD_ActionFloatRear 		EQU 3
	dw MOD_AttackFront	: MOD_ActionAttackFront		EQU 4
	dw MOD_AttackRear	: MOD_ActionAttackRear		EQU 5
	dw MOD_Return		: MOD_ActionReturn			EQU 6
	dw MOD_FloatFront	: MOD_ActionFloatFront		EQU 7

;module type tables
;0-1 XY adresses
;2	 rotation counter
;3	 first sprite of rotation
;4	 max counter (see 2)
;5-6 ball state	
;7	 X offset on rear attach

.MOD_type1
	dw BALL1X
	db 0,6,12
	dw BALL1
	db 1
MOD_TableSize	EQU $-MOD_type1
.MOD_type2
	dw BALL2X
	db 0,12,12
	dw BALL2
	db 0
.MOD_type3
	dw BALL3X
	db 0,18,8
	dw BALL3
	db 0

;************************	
;*** utility routines ***
;************************

;get module position
; pos in BC , pointer to pos in HL
.MOD_GetPos
	ld L,(IX+0)
	ld H,(IX+1)
	ld C,(HL)
	inc HL
	ld B,(HL)
	dec HL
	ret

	;check if we attach module
.MOD_CheckAttach
	ld A,(MOD_ONSHIP)
	or A
	ret Z	
;process attach of the module regarding position from player front/rear
.MOD_DoAttach
;get module pos
	call MOD_GetPos
	
;compare to ship pos	
	ld A,(SHIPX)
	ld B,MOD_ActionLockedFront
	cp C
	jr c,MOD_DoAttachReverse
	inc B
	
.MOD_DoAttachReverse	
	LD A,B
 	LD (ATTATCH),A
	
	call MOD_ChangeMode

	ld A,sfx_attach
	call SND_SfxPlay
	ret

;change mode	
.MOD_ChangeMode
	push DE
	ld E,(IX+5)
	ld D,(IX+6)
	ld (DE),A
	pop DE
	ret

;draw module	
.MOD_Draw
	ld A,(IX+2)
	inc A
	cp (IX+4)
	jr c,MOD_DrawDoNotCycleCounter
	xor A
.MOD_DrawDoNotCycleCounter	
;compute sprite
	ld (IX+2),A
	srl A
	add (IX+3)
;get coordinates	
	call MOD_GetPos
	
	ld E,A
	
	push DE
	ld E,(IX+5)
	ld D,(IX+6)
	ld A,(DE)
	pop DE
	
	cp MOD_ActionLockedRear
	
	jr z,MOD_DrawReverse
	
	
	ld A,E
	jp USPN
.MOD_DrawReverse
;add offset for reverse docking
	ld A,(IX+7)
	add C
	ld C,A

	ld A,E
	jp USPM
	
;find optimal distance to player
;C = x , B = y
.MOD_FindOptimalDistance

;move only 1 frame on 4 !
	ld A,(FRAME)
	and 7
	ret nz

;save xy in DE
	ld E,C
	ld D,B
;compute Y distance and save in A'
	ld A,(SHIPY)
	sub B
	jr c,MOD_FindOptimalDistanceCorrectYdistance
	neg		;remove sign
.MOD_FindOptimalDistanceCorrectYdistance
	ex AF,AF'
;compute for X
	ld A,(SHIPX)
	sub C
	jr c,MOD_FindOptimalDistanceXpositive
	jr nc,MOD_FindOptimalDistanceXnegative
.MOD_FindOptimalDistanceXdone
	ld A,C
	cp 29		;check if we are on screen border
	jr c,MOD_FindOptimalDistanceXvalidate
	ld C,E		;restore previous position
.MOD_FindOptimalDistanceXvalidate

	ret

;module is front of the player
.MOD_FindOptimalDistanceXpositive	
	neg
	cp 12	
	jr nc,MOD_FindOptimalDistanceDecreaseX
;check if aligned on Y
	ex AF,AF'
	or A	;if aligned on ship , check if we need to use autodocking
	jr z,MOD_FindOptimalCheckFrontAutodock
	cp 2
	jr c,MOD_FindOptimalDistanceGetY
	ex AF,AF'
	cp 9
	jr c,MOD_FindOptimalDistanceIncreaseX
;if we are on optimal X distance , move on Y
	jr MOD_FindOptimalDistanceGetY
.MOD_FindOptimalDistanceDecreaseX
	dec C
	jr MOD_FindOptimalDistanceXdone
.MOD_FindOptimalDistanceIncreaseX
	inc C
	jr MOD_FindOptimalDistanceXdone
;module is back of the player	
.MOD_FindOptimalDistanceXnegative
	cp 12
	jr nc,MOD_FindOptimalDistanceIncreaseX
	;check if aligned on Y
	ex AF,AF'
	or A	;if aligned on ship , check if we need to use autodocking
	jr z,MOD_FindOptimalCheckRearAutodock
	cp 2
	jr c,MOD_FindOptimalDistanceGetY
	ex AF,AF'
	cp 9
	jr c,MOD_FindOptimalDistanceDecreaseX
	;jr MOD_FindOptimalDistanceXdone	

;if we are on optimal X distance , move on Y axis
.MOD_FindOptimalDistanceGetY
	ld A,(SHIPY)
	cp B
	jr c,MOD_FindOptimalDistanceMoveUp
	jr nc,MOD_FindOptimalDistanceMoveDown
;aligned on Y , do not move
	jr MOD_FindOptimalDistanceXdone	
.MOD_FindOptimalDistanceMoveUp
	dec B
	jr MOD_FindOptimalDistanceXdone	
.MOD_FindOptimalDistanceMoveDown
	inc B
	jr MOD_FindOptimalDistanceXdone	
;autodock
.MOD_FindOptimalCheckFrontAutodock
	ex AF,AF'
	cp 6
	jr c,MOD_FindOptimalDistanceDecreaseX
	jr MOD_FindOptimalDistanceXdone
	
.MOD_FindOptimalCheckRearAutodock
	ex AF,AF'
	cp 6
	jr c,MOD_FindOptimalDistanceIncreaseX
	jr MOD_FindOptimalDistanceXdone
	
;******************************************
;*** CHECK IF CURRENT POSITION IS VALID ***
;******************************************
;in XY in BC , out XY in BC
.MOD_CorrectCurrentPos
;is current position valid
	call COLL_CheckPosition
	ret nc
	;cp 32
	;ret nc
	or A
	ret nz	;only on solid
	
	push HL
;check all 8 positions
	ld HL,MOD_CorrectCurrentPosRightSideTable
	ld A,(SHIPX)
	cp C
	jr nc,MOD_CorrectCurrentPosIsOnRightSide
	ld HL,MOD_CorrectCurrentPosLeftSideTable
.MOD_CorrectCurrentPosIsOnRightSide
	ld E,C
	ld D,B	;save original on DE

	ld B,8
	
.MOD_CorrectCurrentPosLoop
	push BC
;compute new pos with offset
	ld A,(HL)
	inc HL
	add E
	;are we on screen range for X ?
	cp 29
	jr nc,MOD_CorrectCurrentPosSkipPos
	
	ld C,A ;keep new X pos
	
	ld A,(HL)
	add D
	;are we on screen range for Y?
	cp 20
	jr nc,MOD_CorrectCurrentPosSkipPos
	
	ld B,A	;keep new Y pos

;is this position empty ?	
	call COLL_CheckPosition
	jr nc,MOD_CorrectCurrentPosEnd		;not solid
	cp 32
	jr nc,MOD_CorrectCurrentPosEnd		;not an enemy
	
.MOD_CorrectCurrentPosSkipPos
	inc HL
	pop BC
	djnz MOD_CorrectCurrentPosLoop

;did not find a correct position so stay on older one	
	ld C,E
	ld B,D
	
	pop HL
	ret
	
.MOD_CorrectCurrentPosEnd
	pop AF
	pop HL
	ret
	
	
;test table , 8 XY offsets
.MOD_CorrectCurrentPosRightSideTable
;current row,left row,right row
	db 0,-1,0,1
	db -1,0,-1,-1,-1,1
	db 1,0,1,-1,1,1
.MOD_CorrectCurrentPosLeftSideTable
	db 0,-1,0,1
	db 1,0,1,-1,1,1
	db -1,0,-1,-1,-1,1
	


;********************
;*** LOCKED FRONT ***
;********************
	
.MOD_LockedFront
	ld E,(IX+0)
	ld D,(IX+1)
	ld HL,(SHIPX)
	inc L
	inc L
	inc L
	ex DE,HL
	ld (HL),E
	inc HL
	ld (HL),D
	
	call MOD_Draw
	ret

;********************
;*** LOCKED REAR  ***
;********************	
	
.MOD_LockedRear	
	ld E,(IX+0)
	ld D,(IX+1)
	ld HL,(SHIPX)
	dec L
	dec L
	dec L
	ex DE,HL
	ld (HL),E
	inc HL
	ld (HL),D

	call MOD_Draw
	ret
	
;**********************
;*** RETURN TO SHIP ***
;**********************	
.MOD_Return		
;get pos
	call MOD_GetPos
;check if we are already on something
	call MOD_CorrectCurrentPos
	
	ld A,(SHIPX)
	inc A
	sub C
	jr c,MOD_ReturnXfront
	jr nc,MOD_ReturnXrear
	
.MOD_ReturnXdone

	ld A,(SHIPY)
	sub B
	jr c,MOD_ReturnYup
	jr nc,MOD_ReturnYdown
	
.MOD_ReturnYdone

	ld A,(FRAME)
	and 3
	jr nz,MOD_ReturnIgnoreMove
	
;can we move there ?
	call COLL_CheckPosition
	jr nc,MOD_ReturnValidPos
	cp 32
	jr c,MOD_ReturnIgnoreMove
	
.MOD_ReturnValidPos	
	ld (HL),C
	inc HL
	ld (HL),B
	
.MOD_ReturnIgnoreMove
	
	call MOD_Draw	
	jp MOD_CheckAttach
	
.MOD_ReturnYup
	neg
	cp 2
	jr c,MOD_ReturnYdone
	dec B
	jr MOD_ReturnYdone
	
.MOD_ReturnYdown
	cp 2
	jr c,MOD_ReturnYdone
	inc B
	jr MOD_ReturnYdone
	
.MOD_ReturnXfront
	neg
	cp 2
	jr c,MOD_ReturnXdone
	dec C
	jr MOD_ReturnXdone
	
.MOD_ReturnXrear
	cp 2
	jr c,MOD_ReturnXdone
	inc C
	jr MOD_ReturnXdone

;******************
;*** FLOAT REAR ***
;******************	
.MOD_FloatRear
;get pos
	call MOD_GetPos
;check if we are already on something
	call MOD_CorrectCurrentPos
;check distance to player
	ld A,(SHIPX)
	sub C
	jr c,MOD_FloatRearChange	;is front of the player now
	
	call MOD_FindOptimalDistance
;can we move there ?
	call COLL_CheckPosition
	jr nc,MOD_FloatRearValidPos
	cp 32
	jr c,MOD_FloatRearNotValidPos
	
.MOD_FloatRearValidPos

	ld (HL),C
	inc HL
	ld (HL),B
	
.MOD_FloatRearNotValidPos
	
	jr MOD_FloatRearDraw
	
;if module front of the player , change mode to float front
.MOD_FloatRearChange
	ld A,MOD_ActionFloatFront
	call MOD_ChangeMode

.MOD_FloatRearDraw
	call MOD_Draw	
	
	;check attach ?
	jp MOD_CheckAttach	
	

;*******************
;*** FRONT FLOAT ***
;*******************
.MOD_FloatFront	
;get pos
	call MOD_GetPos
;check if we are already on something
	call MOD_CorrectCurrentPos
;check distance to player
	ld A,(SHIPX)
	sub C
	jr nc,MOD_FloatFrontChange	;is behind the player

	call MOD_FindOptimalDistance
	
;can we move there ?
	call COLL_CheckPosition
	jr nc,MOD_FloatFrontValidPos
	cp 32
	jr c,MOD_FloatFrontNotValidPos
.MOD_FloatFrontValidPos	
	ld (HL),C
	inc HL
	ld (HL),B
.MOD_FloatFrontNotValidPos
	
	jr MOD_FloatFrontDraw	
		
;if module behind player , change mode to float rear
.MOD_FloatFrontChange
	ld A,MOD_ActionFloatRear
	call MOD_ChangeMode

.MOD_FloatFrontDraw
	call MOD_Draw	
	
	;check attach ?
	jp MOD_CheckAttach

;************************
;*** ATTACK REAR MODE ***
;************************	
.MOD_AttackRear		
	call MOD_GetPos
	
	ld A,C
	dec A
;reach left border ?
	cp 29
	jr c,MOD_AttackRearNotReachedBorder
	
;stick to border
	xor A
	ld (HL),A
	jr MOD_AttackRearChangeToFloat
	
.MOD_AttackRearNotReachedBorder

;collide something ?
	push AF
	ld C,A
	inc HL
	ld B,(HL)
	
	call COLL_CheckPosition
	
	jr nc,MOD_AttackRearNoCollision
	
	cp 32
	jr nc,MOD_AttackRearNoCollision
	
	pop AF

	
.MOD_AttackRearChangeToFloat
;change action to float	
	ld A,MOD_ActionFloatFront
	call MOD_ChangeMode
	jr MOD_AttackRearCollisionRet	

.MOD_AttackRearNoCollision

	pop AF
	dec HL
	ld (HL),A	
	
.MOD_AttackRearCollisionRet
	call MOD_Draw
	;check attach ?
	jp MOD_CheckAttach
	
;*************************	
;*** ATTACK FRONT MODE ***
;*************************
	
.MOD_AttackFront
	call MOD_GetPos
	
	;ld A,(HL)
	ld A,C
	inc A
	;inc A	speed ?
;reached border ?
	cp 29
	jr c,MOD_AttackFrontNotReachedBorder
	
;stick to border and change to float action
	ld A,29	
	ld (HL),A
	jr MOD_MOD_AttackFrontChangeToFloat
	
.MOD_AttackFrontNotReachedBorder
;collide something ?
	push AF
	ld C,A
	inc HL
	ld B,(HL)
	
	call COLL_CheckPosition
;if not , continues as it
	jr nc,MOD_MOD_AttackFrontNoCollision
	
	cp 32
	jr nc,MOD_MOD_AttackFrontNoCollision
	
	pop AF

.MOD_MOD_AttackFrontChangeToFloat
;change action to float	
	ld A,MOD_ActionFloatFront
	call MOD_ChangeMode
	jr MOD_MOD_AttackFrontCollisionRet
	
.MOD_MOD_AttackFrontNoCollision

	pop AF
	dec HL
	ld (HL),A

.MOD_MOD_AttackFrontCollisionRet

	call MOD_Draw
	
	;check attach ?
	jp MOD_CheckAttach
	

	

	
