Man...this game is hard!
I own Radiant Silvergun, Battle Garegga on my Sega Saturn and Ketsui and Esp.Rade on my PS3 and PS4. All of these are tricky games and Corsair Trainer has now joined them in the difficulty ranks
.
Congrats to the team for producing an excellent game. Wonderful coding by Axelay as usual. Rexbeng - wonderful job on the artwork and McKlain's solid sound engineering completes this package.
Well done!
Can't say I had those games in mind when I was thinking of the difficulty, but thanks for the comparison.
Do you think it would be possible to update your code to hide the redraw at the top of the screen? I want to try my hand at an arcade game, im ok with Z80 code,i would just like a routine that works. The mode 2 proposal with colour change where both colours are the same seems like a good fix but can it be interrupt driven or does it need specific timing( which sux
)
Here you go. Bear in mind this is that old prototype with the screen movement at the top hidden. No update of the comments, nor updating with whatever changes I might have subsequently made to the current code base for Corsair. It waits during the first interrupt for quite some time to show the highest possible line of the screen. If you don't want to find stable code to put there in the interrupt and not waste cpu time, you can remove the delay and move the second mode/colour change to the second interrupt, but you'll lose 2 characters from the top of the screen.
org &4000
nolist
run start
start:
;; standard screen is 39 chars tall and vsync at 30
;; with 25 chars displayed
;;
;; we want to change this to 26 chars displayed with vsync at 31
;;
;; Char Lines to end of screen: 39-31 = 8
;; Scan Lines to end of screen: 8*8 = 64
;; Interrupt occurs two lines after VSYNC, so lines until end of screen when interrupt occurs: 64-2 = 62
;;
;; If we then wait for one interrupt, we will be 10 (62-52 = 10) lines into the next screen.
;;
;; Then interrupts are:
;; 10, 62, 114, 166, 218
;;
;; And we will then be 10 lines into second screen.
di
ld bc,&7f10
out (c),c
ld bc,&7f54
out (c),c
; narrow the screen
ld bc,&bc01
out (c),c
ld bc,&bd00+32
out (c),c
; and centre it
ld bc,&bc02
out (c),c
ld bc,&bd00+42
out (c),c
;; set new vsync we want
ld bc,&bc07
out (c),c
ld bc,&bd00+31+4
out (c),c
;; wait for 2 vsyncs to allow it to stabalise and so that we can sync with that
ld e,2
wait_two_vsyncs:
ld b,&f5
wait_vsync_end:
in a,(c)
rra
jr c,wait_vsync_end
wait_vsync_start:
in a,(c)
rra
jr nc,wait_vsync_start
dec e
jp nz,wait_two_vsyncs
;; synchronised with start of vsync and we are synchronised with CRTC too, and we have the
;; same number of lines to next screen as we want.
;; set initial interrupt routine
ld hl,int_rout1
ld (int_rout_ptr+1),hl
;; set interrupt
ld a,&c3
ld hl,int_start
ld (&0038),a
ld (&0039),hl
;; enable
ei
main_loop:
ld b,&f5
vsync:
in a,(c)
rra
jr nc,vsync
halt
halt
call scroll_down
jp main_loop
;;---------
int_start:
push bc
push hl
push af
int_rout_ptr:
jp int_rout1
;;---------
;; first interrupt after vsync
int_rout1:
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f4b
;;out (c),c
;; set vsync position to turn it off
ld bc,&bc07
out (c),c
ld bc,&bdff
out (c),c
;; screen address for main part of screen
;; will not trigger until screen restarts
ld hl,(scroll_offset)
ld a,&30
or a,h
ld bc,&bc0c
out (c),c
inc b
out (c),a
ld bc,&bc0d
out (c),c
inc b
out (c),l
;; set height of main part of screen
;; since we are already past the end of the previous screen
;; this will take no effect.
ld bc,&bc06
out (c),c
ld bc,&bd00+25+4
out (c),c
ld bc,&bc05 ;; select vertical adjust register of CRTC
out (c),c
inc b
ld a,(scroll_fine_next)
out (c),a
ld (scroll_fine),a
; mask movement of screen top
;set mode 2
ld bc,&7F8e
out (c),c
; set colours to border
ld bc,&7f00
out (c),c
ld a,&54
out (c),a ; background to match border
inc c
out (c),c
out (c),a ; ink 1 to match border
; wait until at lowest point of screen top
ld b,246
.int1delaylp
defs 5 ; some nops
djnz int1delaylp
;set mode 1
ld bc,&7F8d
out (c),c
; set colours to standard mode 1
ld bc,&7f00
out (c),c
ld a,&44
out (c),a ; background to dark blue
inc c
out (c),c
ld a,&4a
out (c),a ; ink 1 to yellow
ld hl,int_rout2
jp int_end
;;---------
int_rout2:
;; 10 lines until end of screen
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f43
;;out (c),c
ld hl,int_rout3
jp int_end
;;---------
int_rout3:
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f42
;;out (c),c
;; now at line 42.
ld bc,&bc04
out (c),c
ld bc,&bd00+25-1+4-1 ; less 1 because of R5 offset
out (c),c
ld hl,int_rout4
jp int_end
;;---------
int_rout4:
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f40
;;out (c),c
ld hl,int_rout5
jp int_end
;;---------
int_rout5:
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f49
;;out (c),c
ld bc,&bc0c
out (c),c
ld bc,&bd00+&18
out (c),c
ld bc,&bc0d
out (c),c
ld bc,&bd00
out (c),c
ld bc,&bc05 ;; select vertical adjust register of CRTC
out (c),c
inc b
ld a,(scroll_fine)
xor a,7
inc a
out (c),a
ld hl,int_rout6
jp int_end
;;---------
int_rout6:
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f53
;;out (c),c
;; 2 lines before end of screen
;; 128 cycles
ld b,42-1 ; need one less after addition of push af
int_delay:
djnz int_delay
;; set display height of screen
ld bc,&bc06
out (c),c
ld bc,&bd00+1+3
out (c),c
;; set height of screen
ld bc,&bc04
out (c),c
ld bc,&bd00+14-1-4
out (c),c
;; set vsync position
ld bc,&bc07
out (c),c
ld bc,&bd00+6
out (c),c
ld hl,int_rout1
jp int_end
int_end:
ld (int_rout_ptr+1),hl
pop af
pop hl
pop bc
ei
ret
;;end start
.scroll_down
;; check fine value first
ld a,(scroll_fine_next)
inc a
and 7
ld (scroll_fine_next),a
or a
ret nz
;; get the current scroll offset
ld hl,(scroll_offset)
ld bc,32
or a
sbc hl,bc
;; ensure scroll offset is in range &000-&3ff
ld a,h
and &3
ld h,a
;; store new scroll offset. It is now ready to be written to the CRTC.
ld (scroll_offset),hl
ret
;; the scroll offset in CRTC character units
.scroll_offset
defw 0
;; offset for fine scroll
.scroll_fine
defb 0
.scroll_fine_next
defb 0