;Actual DIS server routines
;==========================
;note: lines with TEMP! are temporary to be replaced by smarter 
;techniques in the future...

LOCALS
.386
ALIGN 16

;北北北北北北北北北北 Variables 北北北北北北北北北
exitflag dw     0       ;1=exit key pressed
indemoflag dw   0       ;1=inside the great big ultra cool demo
passmuscode dw  0

ALIGN 4
msgarea0 db     64 dup(0)
msgarea1 db     64 dup(0)
msgarea2 db     64 dup(0)
msgarea3 db     64 dup(0)

;北北北北北北北 List of service routines 北北北北北北
service0 LABEL WORD
        dw      OFFSET version_0
        dw      OFFSET waitb_1
        dw      OFFSET exit_2
        dw      OFFSET indemo_3
        dw      OFFSET loader_4
        dw      OFFSET msgarea_5
        dw      OFFSET muscode_6
        dw      OFFSET setcopper_7
        dw      OFFSET fastvmode_8
        dw      OFFSET musframe_9
        dw      OFFSET sync_10
service9 LABEL WORD

;北北北北北北北北北北 General stuff 北北北北北北北北北

dis_oldint dd   ?

dis_setint PROC NEAR
        push    ds
        xor     ax,ax
        mov     ds,ax
        mov     ax,word ptr ds:[0fch*4+0]
        mov     bx,word ptr ds:[0fch*4+2]
        mov     word ptr cs:dis_oldint[0],ax
        mov     word ptr cs:dis_oldint[2],bx
        mov     word ptr ds:[0fch*4+0],OFFSET dis_int
        mov     word ptr ds:[0fch*4+2],cs
        pop     ds
        ret
dis_setint ENDP

dis_resetint PROC NEAR
        xor     ax,ax
        mov     ds,ax
        mov     ax,word ptr cs:dis_oldint[0]
        mov     bx,word ptr cs:dis_oldint[2]
        mov     word ptr ds:[0fch*4+0],ax
        mov     word ptr ds:[0fch*4+2],bx
        ret
dis_resetint ENDP

        dw      0fc0h ;signature for dis
        dw      0fc0h ;installation check
dis_int PROC FAR ;interrupt 0fch server, BX=function number
        sti
        shl     bx,1
        cmp     bx,(service9-service0)
        jae     @@1
        call    cs:service0[bx]
@@1:    iret
dis_int ENDP

;北北北北北北北北北北 Service Routines 北北北北北北北北北

;entry: -
; exit: AX=version
;descr: -
version_0 PROC NEAR
        ;indemo?
        IFDEF INDEMO
        mov     ax,1
        ELSE
        mov     ax,0
        ENDIF
        mov     cs:indemoflag,ax
        ;initialize
        mov     cs:passmuscode,0
        mov     cs:exitflag,0
        ;return version
        mov     ax,0100h
        ret
version_0 ENDP

ff      PROC FAR
        IFDEF INDEMO
        push    es
        mov     es,cs:stmikseg
        mov     bx,es:_np_ord
        inc     bx
        xor     ax,ax
        push    ax
        push    bx
        call    _zgotosong
        add     sp,4
        pop     es
        ENDIF
        ret
ff      ENDP

checkkeys PROC NEAR
        IFDEF INDEMO
        cmp     cs:forcebreak,0
        jne     @@3
        ENDIF
        call    ctrldown
        jc      @@6
        mov     ah,1                                    ;TEMP!
        int     16h
        jz      @@3
        mov     ah,0
        int     16h
        cmp     al,'0'
        jne     @@9
        pusha
        push    ds
        push    es
        mov     ax,0fcfch
        mov     bx,1
        int     33h
        pop     es
        pop     ds
        popa
        ret
@@9:    cmp     al,'9'
        jne     @@8
        pusha
        push    ds
        push    es
        mov     ax,0fcfch
        mov     bx,2
        int     33h
        pop     es
        pop     ds
        popa
        ret
@@8:    cmp     al,'1'
        jne     @@5
        call    ff
@@5:    cmp     al,27
        jne     @@4
@@6:    mov     cs:exitflag,1
@@4:    mov     cs:passmuscode,1
@@3:    ret
checkkeys ENDP

;entry: -
; exit: -
;descr: Waits for border start
waitb_1 PROC NEAR
        call    checkkeys
        IFDEF INDEMO
        sti
        mov     ax,cs:copperframecount
@@v:    cmp     cs:copperframecount,ax
        je      @@v
@@q:    mov     ax,cs:copperframecount
        mov     cs:copperframecount,0
        ELSE
        mov     dx,3dah
@@1:    in      al,dx
        test    al,8
        jnz     @@1
@@2:    in      al,dx
        test    al,8
        jz      @@2
        mov     ax,1 ;number of frames taken            ;TEMP!
        ENDIF
        ret
waitb_1 ENDP

;entry: -
; exit: AX=return
;descr: returns 1 if part should exit.
exit_2 PROC NEAR
        call    checkkeys
        mov     ax,cs:exitflag
        ret
exit_2 ENDP

;entry: -
; exit: AX=return
;descr: returns 1 if inside demo (and not testing from dos)
indemo_3 PROC NEAR
        mov     ax,cs:indemoflag
        ret
indemo_3 ENDP

;entry: AX=area desired (0..3)
; exit: DX:AX=pointer to msgarea
;descr: returns a pointer to interpart communications area.
;       There is ONLY 64 bytes of space in the area, DON'T OVERFLOW IT :-)
msgarea_5 PROC NEAR
        cmp     ax,1
        je      @@1
        cmp     ax,2
        je      @@2
        cmp     ax,3
        je      @@3
@@0:    mov     dx,cs
        mov     ax,OFFSET msgarea0
        ret
@@1:    mov     dx,cs
        mov     ax,OFFSET msgarea1
        ret
@@2:    mov     dx,cs
        mov     ax,OFFSET msgarea2
        ret
@@3:    mov     dx,cs
        mov     ax,OFFSET msgarea3
        ret
msgarea_5 ENDP

;Loader functions (not for parts)
;entry: AX=0/1
; exit: -
;descr: AX=0: restores dos process id
;       AX=1: sets dos process id to the loader
;       AX=100h: call _zloadinstrument(dx)
;       AX=101h: call _zinitmodule(dx:0)
;       This is used to load the music in name of the loader!
loader_4 PROC NEAR
        IFDEF INDEMO
        call    loaderservices
        ENDIF
        ret
loader_4 ENDP

;entry: AX=code you want (are waiting for)
; exit: AX=current code,BX=row
muscode_6 PROC NEAR
        push    ax
        call    checkkeys
        pop     ax
        IFDEF INDEMO
        push    es
        mov     es,cs:stmikseg
        mov     ax,es:_np_zinfo
        mov     bx,es:_np_row
        mov     cx,es:_np_ord
        mov     dx,-32
        cmp     es:_np_zplus,0
        je      @@1a
        cmp     es:_np_zplus,1
        je      @@1b
        cmp     es:_np_zplus,2
        je      @@1e
@@1eb:  cmp     bx,32
        ja      @@1b
@@1e:   mov     dx,bx
        cmp     dx,32
        jb      @@1a
        mov     dx,-32
        jmp     @@1a
@@1b:   ;plus coming
        mov     dx,bx
        sub     dx,64
        cmp     dx,-32
        jge     @@1a
        mov     dx,-32
@@1a:   mov     bx,es:_np_row
	pop     es
        ELSE
        cmp     cs:passmuscode,0
        jne     @@1
        xor     ax,ax
        ENDIF
        ret
@@1:    mov     cs:passmuscode,0
        ret
muscode_6 ENDP

;entry: AX=number of copper interrupt to capture:
;               0=after display start (about scan line 25)
;               1=just before retrace (AVOID USING THIS IF POSSIBLE)
;               2=in the retrace
;       DX:CX=far pointer to routine (0:0=remove routine)
;       The routine pointed to must end in a RETF. It must save any
;       386 registers it uses (including FS/GS)
; exit: -
;descr: sets the specified copper interrupt to call the specified routine.
;       IMPORTANT: The part must reset the copper int before it exits!
setcopper_7 PROC NEAR
        IFDEF INDEMO
        or      dx,dx
        jnz     @@1
        or      cx,cx
        jnz     @@1
        mov     dx,cs
        mov     cx,OFFSET copper_intretf
@@1:    cmp     ax,0
        jne     @@2
        mov     word ptr cs:copper_int0[0],cx
        mov     word ptr cs:copper_int0[2],dx
@@2:    cmp     ax,1
        jne     @@3
        mov     word ptr cs:copper_int1[0],cx
        mov     word ptr cs:copper_int1[2],dx
@@3:    cmp     ax,2
        jne     @@4
        mov     word ptr cs:copper_int2[0],cx
        mov     word ptr cs:copper_int2[2],dx
@@4:    ENDIF
        ret
setcopper_7 ENDP

;entry: AX=area (0..3) containing the saved VGA state.
; exit: -
;descr: Quicksets the desired vga mode (takes one frame)
fastvmode_8 PROC NEAR ;DOESN'T WORK!-(
        IFDEF INDEMO
        push    si
        push    ds
        call    msgarea_5 ;dx:ax=ds:ax
        mov     si,ax
        mov     ax,cs
        mov     ds,ax
        ;data now at ds:si
        push    si
        call    waitb_1
        pop     si
        mov     dx,3dah
        in      al,dx
        ;Syncronous reset
        mov     dx,3c4h
        mov     ax,0200h
        out     dx,ax
        ;Clear CRTC protection flag
        mov     dx,3d4h
        mov     al,011h
        out     dx,al
        inc     dx
        in      al,dx
        and     al,not 128
        out     dx,al
        ;Set misc register
        mov     al,ds:[si]
        inc     si
        mov     dx,3c2h
        out     dx,al
        ;Set Sequencer (3C4)
        mov     dx,3c4h
        xor     al,al
        REPT    04h+1
        mov     ah,ds:[si]
        inc     si
        out     dx,ax
        inc     al
        ENDM
        ;Set CRTC (3D4)
        mov     dx,3d4h
        xor     al,al
        REPT    018h+1
        mov     ah,ds:[si]
        inc     si
        out     dx,ax
        inc     al
        ENDM
        ;Set GFX controller (3CE)
        mov     dx,3ceh
        xor     al,al
        REPT    08h+1
        mov     ah,ds:[si]
        inc     si
        out     dx,ax
        inc     al
        ENDM
        ;Set Attribute controller (3C0)
        mov     dx,3dah
        in      al,dx
        mov     dx,3c0h
        zzz=0
        REPT    014h+1
        mov     al,zzz
        out     dx,al
        mov     al,ds:[si]
        out     dx,al
        inc     si
        zzz=zzz+1
        ENDM
        ;Enable display, enable PEL mask
        mov     dx,3c0h
        mov     al,20h
        out     dx,al
        mov     dx,3c6h
        mov     al,0ffh
        out     dx,al
        pop     ds
        pop     si
        ELSE
        mov     ax,13h
        int     10h
        ENDIF
        ret
fastvmode_8 ENDP

;entry: AX=1 : set frame to DX
;       AX=0 : read frame to AX
; exit: AX=frame)
;descr: controls/returns music frame numbers
musframe_9 PROC NEAR
        IFDEF INDEMO
        push    es
        mov     es,cs:stmikseg
        cmp     ax,0
        je      @@1
        mov     es:_np_zframe,dx
@@1:    mov     ax,es:_np_zframe
        pop     es
        ELSE
        xor     ax,ax
        ENDIF
        ret
musframe_9 ENDP

IFDEF INDEMO
ordersync1 LABEL BYTE ;startpart
dw      0000h,0
dw      0200h,1
dw      0300h,2
dw      032fh,3
dw      042fh,4
dw      052fh,5
dw      062fh,6
dw      072fh,7
dw      082fh,8
dw      0900h,9
dw      0d00h,10
;dw      0800h,8
;dw      0c00h,9
;dw      0f00h,10
dw      3d00h,1
dw      3f00h,2
dw      4100h,3
dw      4200h,4
ENDIF     

sync_10 PROC NEAR
        IFDEF INDEMO
        mov     es,cs:stmikseg
        mov     dh,byte ptr es:_np_ord
        mov     dl,byte ptr es:_np_row
        mov     bx,OFFSET ordersync1
        mov     cx,16
@@2:    cmp     dx,cs:[bx]
        jbe     @@1
        add     bx,4
        loop    @@2
@@1:    mov     ax,cs:[bx-2]
        ENDIF
        ret
sync_10 ENDP
