We just released a Feb. 5 '89 prototype of DuckTales for the NES!
If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!

Bubble Dizzy (DOS)

From The Cutting Room Floor
Jump to navigation Jump to search

Title Screen

Bubble Dizzy

Developer: The Oliver Twins
Publisher: Codemasters
Platform: DOS
Released in US: November 1990

SourceIcon.png This game has uncompiled source code.

Source Code

A big chunk of source code is present in sm.8:

; sm.8 Codemasters "ABSOLUTELY BRILLIANT" logo.

video_int       =       int 10h
general_int     =       int 21h
keyboard_port   =       0060h

right_speed     =       8               ; Speed. "ABSOLUTELY"
left_speed      =       -8              ; Speed. "BRILLIANT"
centre          =       32              ; Counter

frame_counter:  dw      0000h

file_length     =       54273
length2         =       13013
graphics_seg:   dw      0000h
gfx_seg2:       dw      0000h
pathname:       db      "gfx1.gfx",00h
fontname:       db      "antifont.bin",00h
; ----- Table of co-ords for the CodeMasters bit .....
;       0 - X position
;       2 - X shift
;       4 - Frame no.
;       6 - Y position
;       8 - Offset to image
;       a - Width (pixels)
;       c - Height (pixels)
off_tab:        dw      020h,0ah,00h,020h,4+0*1024,32,32
                dw      020h,07h,02h,020h,4+2*1024,32,32 
                dw      020h,03h,03h,020h,4+3*1024,32,32
                dw      020h,00h,04h,020h,4+4*1024,32,32            ; C
                dw      037h,06h,01h,020h,4+1*1024,32,32
                dw      037h,03h,05h,020h,4+5*1024,32,32
                dw      037h,01h,06h,020h,4+6*1024,32,32
                dw      037h,00h,07h,020h,4+7*1024,32,32            ; o

                dw      049h,0ah,00h,021h,4+0*1024,32,32
                dw      049h,03h,08h,021h,4+8*1024,32,32
                dw      049h,01h,09h,021h,4+9*1024,32,32
                dw      049h,00h,0ah,021h,4+10*1024,32,32           ; d

                dw      05dh,06h,01h,020h,4+1*1024,32,32
                dw      05dh,03h,0bh,020h,4+11*1024,32,32
                dw      05dh,01h,0ch,020h,4+12*1024,32,32
                dw      05dh,00h,0dh,020h,4+13*1024,32,32            ; e1

                dw      06fh,06h,01h,020h,4+1*1024,32,32
                dw      06fh,06h,0eh,020h,4+14*1024,32,32
                dw      06fh,07h,0fh,020h,4+15*1024,32,32
                dw      06fh,00h,10h,020h,4+16*1024,32,32            ; m

                dw      08bh,06h,01h,020h,4+1*1024,32,32
                dw      08bh,03h,11h,020h,4+17*1024,32,32
                dw      08bh,01h,12h,020h,4+18*1024,32,32
                dw      08bh,00h,13h,020h,4+19*1024,32,32            ; a

                dw      09eh,06h,01h,020h,4+1*1024,32,32
                dw      09eh,04h,14h,020h,4+20*1024,32,32
                dw      09eh,02h,15h,020h,4+21*1024,32,32
                dw      09eh,00h,16h,020h,4+22*1024,32,32            ; s1

                dw      0aeh,0ah,00h,020h,4+0*1024,32,32
                dw      0aeh,03h,17h,020h,4+23*1024,32,32
                dw      0aeh,01h,18h,020h,4+24*1024,32,32
                dw      0aeh,00h,19h,020h,4+25*1024,32,32            ; t
                dw      0bdh,0ah,01h,020h,4+1*1024,32,32
                dw      0bdh,03h,0bh,020h,4+11*1024,32,32
                dw      0bdh,01h,0ch,020h,4+12*1024,32,32
                dw      0bdh,00h,0dh,020h,4+13*1024,32,32            ; e2

                dw      0cfh,06h,01h,020h,4+1*1024,32,32
                dw      0cfh,04h,1ah,020h,4+26*1024,32,32
                dw      0cfh,01h,1bh,020h,4+27*1024,32,32
                dw      0cfh,00h,1ch,020h,4+28*1024,32,32            ; r
                dw      0e1h,06h,01h,020h,4+1*1024,32,32
                dw      0e1h,04h,14h,020h,4+20*1024,32,32
                dw      0e1h,02h,15h,020h,4+21*1024,32,32
                dw      0e1h,00h,16h,020h,4+22*1024,32,32            ; s

                dw      0f3h,03h,1dh,01ah,30720+0000,64,48
                dw      0f3h,03h,1eh,01ah,30720+3072,64,48
                dw      0f3h,03h,1fh,01ah,30720+6144,64,48
                dw      0f3h,03h,20h,01ah,30720+9216,64,48

code_offset     dw      0000h
AbsolX          dw      72
AB_Flag         dw      0000h
A_Flag:         db      0
B_Flag:         db      0
; ----- Sprite control block for letters for messages .....
LettersX:       dw      0020h   ; X co-ord in pixels
LettersY:       dw      00a4h   ; Y co-ord in pixels
LettersW:       dw      000bh   ; Width in pixels
LettersH:       dw      000dh   ; Height in pixels
LettersS:       dw      0000h   ; Segment address of sprite data
LettersO:       dw      143*3   ; Offset
                dw      0000h
                dw      0000h

sprite_0:       dw      0020h           ; X coord in pixels.
sprite_02:      dw      0020h           ; Y coord in pixels.
sprite_04:      dw      0020h           ; Width    ''  ''  .
sprite_06:      dw      0020h           ; Height   ''  ''  .
sprite_08:      dw      0000h           ; Segment of sprite data.
                dw      0000h           ; Offset  ''   ''    '' .
                dw      0000h
                dw      0000h
sprite_1:       dw      -208            ; X coord in pixels.    ; "ABSOLUTELY"
sprite_12:      dw      80             ; Y coord in pixels.
sprite_14:      dw      176             ; Width    ''  ''  .
sprite_16:      dw      37-1            ; Height   ''  ''  .
sprite_18:      dw      0000h           ; Segment of sprite data.
                dw      43008+4           ; Offset  ''   ''    '' .
                dw      0000h
                dw      0000h
sprite_2:       dw      368             ; X coord in pixels.    ; "BRILLIANT"
sprite_22:      dw      120             ; Y coord in pixels.
sprite_24:      dw      176             ; Width    ''  ''  .
sprite_26:      dw      27-1            ; Height   ''  ''  .
sprite_28:      dw      0000h           ; Segment of sprite data.
                dw      49520+4         ; Offset  ''   ''    '' .
                dw      0000h
                dw      0000h
sprite_3:       dw      100             ; X coord in pixels.    ; Squiggle.
sprite_32:      dw      0020h           ; Y coord in pixels.
sprite_34:      dw      0020h           ; Width    ''  ''  .
sprite_36:      dw      0020h           ; Height   ''  ''  .
sprite_38:      dw      0000h           ; Segment of sprite data.
                dw      0000h           ; Offset  ''   ''    '' .
                dw      0000h
                dw      0000h

gfx_lut:        dw      12*0            ; Long line.
                dw      1024*1          ; Short line.
                dw      1024*2          ; C
                dw      1024*3
                dw      1024*4
                dw      1024*5          ; o
                dw      1024*6
                dw      1024*7
                dw      1024*8          ; d
                dw      1024*9
                dw      1024*10
                dw      1024*11         ; e
                dw      1024*12
                dw      1024*13
                dw      1024*14         ; m
                dw      1024*15
                dw      1024*16
                dw      1024*17         ; a
                dw      1024*18
                dw      1024*19
                dw      1024*20         ; s
                dw      1024*21
                dw      1024*22
                dw      1024*23         ; t
                dw      1024*24
                dw      1024*25
                dw      1024*26         ; r
                dw      1024*27
                dw      1024*28
                dw      1024*29         ; TM
                dw      1024*30         ; CM 1
                dw      30720+3072      ; CM 2 
                dw      30720+6144      ; CM 3 
                dw      30720+9216      ; CM 4 
                dw      43008           ; ABSOLUTELY
                dw      49520           ; BRILLIANT

key_vector_seg: dw      0000h           ; Stores INT 09h seg and adr.
key_vector_adr: dw      0000h           ; for return to DOS.

scan_code:      db      00h             ; Scan code of last key

on              =       00h             ; General ON.
off             =       01h             ; General OFF.

screen_address: dw      0a000h          ; Start address of screen.
screen_width:   dw      320             ; Screen width in pixels.
screen_height:  dw      200             ; Screen height in pixels.

video_mode:     db      013h            ; Initial video mode.

palette:        db      000h,000h,000h  ; Background
                db      0ffh,0ffh,0ffh  ; Letters
                db      03fh,000h,020h  ; Squiggly
                db      018h,000h,020h  ;    ''
                db      028h,028h,028h
                db      018h,018h,018h
                db      008h,008h,008h
                db      000h,000h,000h
                db      038h,038h,038h  ; "ABSOLUTELY BRILLIANT" - filled
                db      008h,008h,008h  ; "ABSOLUTELY BRILLIANT" - outline
                db      028h,028h,028h
                db      000h,000h,000h
                db      000h,000h,000h
                db      000h,000h,000h
                db      30 DUP (0)
                db      0fch,0fch,0fch
                db      0ffh,0ffh,0ffh  ; Sheen bits
                db      03ch,03ch,03ch
                db      15 DUP (0)
                db      03ch,03ch,03ch
                db      020h,020h,020h
                db      010h,010h,010h
                db      663 DUP (0)
; ----- Message bits and pieces .....
SelfCheckV      db      "10",0
GameV           db      "10",0
MasterD_T       db      "0706931500",0
InfoLine        db      "T:v .   A:v .   D:  /  /     :  ",0
CopyRightMess   db      "(c) Codemasters 1993.",0
; ----- Variables for the clock waiting system .....
QuitFlag:       dw      0
Clock:          dw      0
NoCard:         dw      0
; ----- Co-ordinate variables for Version bits .....
VerX:           dw      0
VerY:           dw      0
AB_Done:        dw      0
PutFlag:        dw      0
; ----- Co-ordinates for the sheen effect .....
SheenX:         dw      0
SheenY:         dw      0
SheenFlag:      dw      0
SheenDone:      dw      0
; ----- Proportional font table (Times 13) .....
SC_LookUp:      db      " ",4,"!",3,"`",4,"ú",6,"$",5,"%",8,"&",9
                db      "'",3,"(",4,")",4,"*",5,"+",6,",",3,"-",7
                db      ".",3,"/",4,"0",5,"1",5,"2",5,"3",5,"4",6
                db      "5",5,"6",5,"7",5,"8",5,"9",5,":",3,";",3
                db      "<",5,"=",6,">",5,"?",4,"#",6,"A",8,"B",6
                db      "C",7,"D",7,"E",6,"F",6,"G",7,"H",8,"I",4
                db      "J",5,"K",7,"L",6,"M",10,"N",8,"O",7,"P",6
                db      "Q",7,"R",7,"S",5,"T",6,"U",8,"V",8,"W",12
                db      "X",8,"Y",8,"Z",6,"[",4,"\",3,"]",3,"^",5
                db      "_",6,"`",3,"a",4,"b",5,"c",4,"d",6,"e",4
                db      "f",5,"g",5,"h",6,"i",3,"j",3,"k",6,"l",4
                db      "m",9,"n",6,"o",5,"p",5,"q",6,"r",4,"s",4
                db      "t",5,"u",6,"v",6,"w",9,"x",6,"y",6,"z",5
                db      0ffh,0ffh
main:           push    ds,es           ; Program entry point
                mov     ds,cs
                mov     es,cs
                call    allocate_memory 
                call    Allocate2
                cmp     al,00h
                jnz     >o1
                call    load_and_initialise
                call    Load2

                call    initialise_skeleton_data
                cmp     w[NoCard],0
                je      CarryOn
                jmp     EndNow

CarryOn:        call    ResetVars
                call    SetCopyRight
                call    VersionFind
                mov     w[SheenX],72
                mov     w[SheenY],80

                call    action
EndNow:         call    deallocate_memory
                call    DeAllocate2
                call    restore_key_vector
o1:             pop     es,ds
                mov     ax,000eh
                int     10h
                mov     ah,04ch
                general_int             ; Return to DOS.
; ----- Resets all variables for re-entrant code .....
ResetVars:      mov     w[code_offset],0
                mov     w[AbsolX],0
                mov     w[AB_Flag],0
                mov     w[QuitFlag],0
                mov     w[Clock],0
                mov     w[VerX],0
                mov     w[VerY],0
                mov     w[AB_Done],0
                mov     w[SheenX],0
                mov     w[SheenY],0
                mov     w[SheenFlag],0
                mov     w[SheenDone],0
                mov     b[A_Flag],0
                mov     b[B_Flag],0
                mov     w[PutFlag],0
                mov     w[AbsolX],72
; ----- Sets up the copyright message in correct position on screen .....
;       Finds length of text to be put to screen
;       Puts text to screen
SetCopyRight:   lea     si,CopyRightMess        ; Message - SI
                xor     ax,ax
                xor     bx,bx
                xor     cx,cx
                xor     dx,dx
SC_Outer:       mov     di,SC_LookUp            ; Lookup table - DI
                mov     al,b[si]
SC_FindLength:  mov     bl,b[di]
                cmp     al,bl
                je      SC_FoundOne
                inc     di
                inc     di
                cmp     b[di+1],0ffh
                jne     SC_FindLength
                jmp     SC_Skip
SC_FoundOne:    mov     cl,[di+1]
                add     dx,cx                   ; DX - length of string
SC_Skip:        inc     si
                cmp     b[si],0
                jne     SC_Outer
                mov     cx,[screen_width]
                sub     cx,dx                   ; DX - screen width-string
                shr     cx,1                    ; For justification

                mov     w[LettersX],cx
                mov     w[LettersY],180

                lea     si,CopyRightMess        ; Message
SC_PrintIt:     xor     ax,ax
                xor     bx,bx
                xor     cx,cx
SCP_Outer:      xor     dx,dx                   ; Cleared for length
                mov     di,SC_LookUp            ; Lookup table
                mov     al,b[si]                ; First message character
SCP_FindLength: mov     bl,b[di]                ; First table character
                cmp     al,bl
                je      SCP_FoundIt
                inc     di
                inc     di                      ; Next table entry
                inc     dx                      ; Number of letter
                cmp     b[di+1],0ffh            ; End of table?
                jne     SCP_FindLength
                jmp     SCP_Skip
SCP_FoundIt:    mov     cl,b[di+1]                ; Letter length to CL
                push    cx,ax                   ; Preserve true letter width
                mov     w[LettersW],11             ; Put width into sprite block
                mov     ax,143                  ; Letter size - 143 bytes
                mul     dx                      ; Get offset
                mov     dx,ax                   ; in DX
                pop     ax,cx
                mov     LettersO,dx             ; Get offset
                push    ax,bx,cx,dx,si,di,bp
                mov     si,LettersX
                call    print_sprite
                pop     bp,di,si,dx,cx,bx,ax
                add     w[LettersX],cx          ; New X position
SCP_Skip:       inc     si
                mov     al,b[si]
                cmp     al,0
                jne     SC_PrintIt
SC_End:         ret
; ----- Places bits into version string, finds length for justification .....
VersionFind:    lea     si,InfoLine

                lea     di,SelfCheckV
                mov     ax,[di]
                mov     b[si+3],al
                mov     b[si+5],ah

                lea     di,GameV
                mov     ax,[di]
                mov     b[si+11],al
                mov     b[si+13],ah

                lea     di,MasterD_T
                mov     ax,[di]
                mov     b[si+18],al
                mov     b[si+19],ah
                inc     di
                inc     di
                mov     ax,[di]
                mov     b[si+21],al
                mov     b[si+22],ah
                inc     di
                inc     di
                mov     ax,[di]
                mov     b[si+24],al
                mov     b[si+25],ah
                inc     di
                inc     di
                mov     ax,[di]
                mov     b[si+27],al
                mov     b[si+28],ah
                inc     di
                inc     di
                mov     ax,[di]
                mov     b[si+30],al
                mov     b[si+31],ah             ; Stores all bits in message

VF_Length:      lea     si,InfoLine

                xor     ax,ax
                xor     bx,bx
                xor     cx,cx
                xor     dx,dx                   ; Work registers

VF_Outer:       mov     di,SC_LookUp
                mov     al,b[si]
VF_FindLength:  mov     bl,b[di]
                cmp     al,bl
                je      VF_FoundOne
                inc     di
                inc     di
                cmp     b[di+1],0ffh
                jne     VF_FindLength
                jmp     VF_Skip
VF_FoundOne:    mov     cl,[di+1]
                add     dx,cx                   ; DX - string length
VF_Skip:        inc     si
                cmp     b[si],0
                jne     VF_Outer

                mov     cx,[screen_width]
                sub     cx,dx                   ; Screen width-string width
                shr     cx,1                    ; Correct start position
                mov     w[VerX],cx
                mov     w[VerY],160
; General routines.
l1:             call    RealTime
                call    CodeMasters
                call    AbsolBrill
;                mov     cx,0ffffh
;Waiter:         loop    Waiter
                call    Info

                call    TestA
                cmp     w[AB_Done],0
                je      WaitVBL
                cmp     w[SheenDone],0
                jne     WaitVBL
                call    Sheen
                call    RemSheen

WaitVBL:        mov     dx,3dah
WVBL1:          in      al,dx
                test    al,8
                jne     WVBL1

;                call    AbsolBrill
;                mov     dx,3dah
;WVBL2:          in      al,dx
;                test    al,8
;                jne     WVBL2
                mov     ax,3
                int     33h
                cmp     bx,0                    ; Mouse pressed?
                je      A_Test
                jmp     A_End

A_Test:         cmp     w[QuitFlag],0
                jne     A_End

                jmp     l1
A_End:          ret
; ----- Test for A key being pressed .....
TestA:          mov     al,[scan_code]
                cmp     al,01eh+080h
                jne     TA_NotRelA
                mov     b[A_Flag],0
TA_NotRelA:     cmp     al,030h+080h
                jne     TA_NotRelB
                mov     b[B_Flag],0
TA_NotRelB:     cmp     al,01eh
                jne     TA_End
                mov     b[A_Flag],1
TA_End:         cmp     al,030h
                jne     TA_EndNow
                mov     b[B_Flag],1
TA_EndNow:      ret
; ----- Remove the previous sheen .....
RemSheen:       cmp     w[SheenFlag],6
                jb      RS_EndNow
                push    ax,bx,cx,dx,si,di,bp,ds
                mov     ax,w[SheenX]
                mov     bx,w[SheenY]
                sub     ax,32
                mov     cx,70
RS_Outer:       push    ax,bx,cx,ds
                push    ax
                mov     ax,320
                mul     bx
                mov     bx,ax
                pop     ax
                mov     cx,8
                mov     ds,[screen_address]
                mov     si,bx
                add     si,ax
RS_Loop:     ds mov     al,b[si]
                sub     al,16
             ds mov     b[si],al
                inc     si
                loop    RS_Loop
                pop     ds,cx,bx,ax
                inc     bx
                dec     ax
                loop    RS_Outer
RS_End:         pop     ds,bp,di,si,dx,cx,bx,ax
RS_EndNow:      ret
; ----- Do the sheen effect on the Absolutely Brilliant graphics .....
Sheen:          push    ax,bx,cx,dx,si,di,bp,ds
                mov     ax,w[SheenX]
                mov     bx,w[SheenY]
                mov     cx,70
S_Outer:        push    ax,bx,cx,ds             ; Save X,Y,Loop
                push    ax                      ; Save for MUL
                mov     ax,320
                mul     bx
                mov     bx,ax                   ; BX - line offset
                pop     ax                      ; Restore from MUL
                mov     cx,8                   ; Bytes to write/2
                mov     ds,[screen_address]
                mov     si,bx                   ; Offset to si
                add     si,ax                   ; Add X position
S_Loop:      ds mov     al,b[si]                ; Read from screen
                add     al,16                   ; New value
             ds mov     b[si],al                ; Write it
                inc     si
                loop    S_Loop                  ; Do correct amount
                pop     ds,cx,bx,ax             ; Restore X,Y,Loop
                inc     bx                      ; Add to Y
                dec     ax                      ; Take from X
                loop    S_Outer                 ; Do outer loop
S_End:          pop     ds,bp,di,si,dx,cx,bx,ax
                cmp     w[SheenFlag],8
                je      S_Continue
                inc     w[SheenFlag]
S_Continue:     add     w[SheenX],8
                cmp     w[SheenX],312
                jne     S_EndNow
                mov     w[SheenDone],0ffffh
S_EndNow:       ret
; ----- Set a clock up .....
RealTime:       inc     w[Clock]
                cmp     w[Clock],(70*10)
                jne     RT_End
                mov     w[QuitFlag],0ffffh
RT_End:         ret
; ----- Put the information to screen .....
Info:           mov     al,[A_Flag]
                mov     ah,[B_Flag]
                add     al,ah
                cmp     al,2
                jne     I_Clear
                jmp     I_Put
I_End:          ret

I_Clear:        push    ax,cx,ds,si
                mov     w[PutFlag],0
                mov     ds,[screen_address]
                xor     ax,ax
                mov     cx,(19*320)/2
                mov     si,159*320
IC_Loop:     ds mov     [si],ax
                inc     si,2
                loop    IC_Loop
                pop     si,ds,cx,ax
IC_End:         ret

I_Put:          push    ax,bx,cx,dx,si,di,bp
                mov     w[clock],0

                cmp     w[PutFlag],0
                jne     IP_End
                mov     ax,[VerX]
                mov     bx,[VerY]
                mov     w[LettersX],ax
                mov     w[LettersY],bx
                lea     si,InfoLine
IP_PrintIt:     xor     ax,ax
                xor     bx,bx
                xor     cx,cx
IP_Outer:       xor     dx,dx
                mov     di,SC_LookUp
                mov     al,b[si]
IP_FindLength:  mov     bl,b[di]
                cmp     al,bl
                je      IP_FoundIt
                inc     di
                inc     di
                inc     dx
                cmp     b[di+1],0ffh
                jne     IP_FindLength
                jmp     IP_Skip
IP_FoundIt:     mov     cl,b[di+1]
                push    cx,ax
                mov     w[LettersW],11
                mov     ax,143
                mul     dx
                mov     dx,ax
                pop     ax,cx
                mov     LettersO,dx
                push    ax,bx,cx,dx,si,di,bp
                mov     si,LettersX
                call    print_sprite
                pop     bp,di,si,dx,cx,bx,ax
                add     w[LettersX],cx
IP_Skip:        inc     si
                mov     al,b[si]
                cmp     al,0
                jne     IP_PrintIt
                mov     w[PutFlag],1
IP_End:         pop     bp,di,si,dx,cx,bx,ax
; ----- Put the Absolutely Brilliant bits to screen .....
AbsolBrill:     cmp     w[AB_Done],0
                jne     AB_End

                mov     si,sprite_1
                add     w[si+0],right_speed
                mov     si,sprite_2
                add     w[si+0],left_speed

                mov     si,sprite_1
                call    print_sprite
                mov     si,sprite_2
                call    print_sprite
                mov     si,sprite_1
                mov     ax,[AbsolX]
                cmp     ax,w[si+0]
                jne     AB_End
                mov     w[AB_Done],0ffh
AB_End:         ret
; ----- Process the CodeMasters data table and put sprites .....
CodeMasters:    mov     di,off_tab
                add     di,code_offset
                mov     si,sprite_0
                mov     ax,[di+0]               ; X 32 justified
                mov     bx,[di+2]               ; X pixel offset
                mov     cx,[di+6]
                mov     w[si+0],ax
                add     w[si+0],bx              ; Get correct X pos
                mov     w[si+2],cx              ; Correct Y

                mov     ax,[di+8]
                mov     w[si+10],ax             ; Correct offset

                mov     ax,[di+10]
                mov     bx,[di+12]
                mov     w[si+4],ax
                mov     w[si+6],bx              ; New width and height

                call    print_sprite
                cmp     [code_offset],47*14
                je      CM_Skip                 ;
                add     [code_offset],14
CM_Skip:        ret
; ----- Routine to load in any data needed .....
;       Entry:  N/A
;       Exit:   AL - 0 if OK
;               AL - 0ffh if error
                mov     bx,pathname
                mov     cx,file_length
                mov     ax,[graphics_seg]
                mov     dx,0000h
                call    general_load

                mov     ax,[graphics_seg]
                mov     [sprite_08],ax
                mov     [sprite_18],ax
                mov     [sprite_28],ax
                mov     [sprite_38],ax

Load2:          mov     bx,fontname
                mov     cx,Length2
                mov     ax,[gfx_seg2]
                mov     dx,0000h
                call    general_load

                mov     ax,[gfx_seg2]
                mov     [LettersS],ax           ; Store segment addr. in list
; ----- Routine to clip the sprites .....
clip_sprite:    cmp     cx,320          ; Return clip width+new X.
                jc      >s1
                test    cx,08000h
                jz      >o2
                jmp     >s2

s1:             mov     ax,320          ; Right clip.
                sub     ax,cx
                cmp     bx,ax
                jc      >o1
                mov     bx,ax
                jmp     >o1
s2:             add     bx,cx           ; Left clip
                test    bx,08000h
                jnz     >o2
                mov     ax,cx
                xor     cx,cx
                neg     ax      
o1:             xor     ax,ax
o2:             xor     bx,bx
; ----- Grab screen address (absolute) .....
;       Entry:  CX - X, DX - Y
;       Exit:   DI - Screen address
dfloc:          push    ax                    
             cs mov     ax,[screen_width]
                mul     dx
                add     ax,cx
                mov     di,ax
                pop     ax
fblock:         push    si
                add     ax,ax           ; Entry : AX=block number
                add     si,ax           ;         SI=LUT address.
             cs mov     ax,[si]         ; Exit  : AX=Table adr.
                pop     si
; ----- Initialise some data .....
initialise_skeleton_data:                       ; Set palette,reset vars,etc.
                call    save_key_vector         ; For return to DOS.
                call    set_key_vector          ; Re-vector keyboard INT 09h.
                call    set_video_mode          ; Set mode to [VIDEO_MODE].
                call    set_palette             ; Set palette to [PALETTE].
; KEYBOARD routines.
await_keys_press:                       ; Await any key press.
                xor     al,al
             cs mov     [scan_code],al
l1:          cs mov     al,[scan_code]
                cmp     al,00h
                jz      l1
                test    al,080h
                jnz     await_keys_press
save_key_vector:                        ; Saves INT 09h vector for 
                mov     al,09h          ; return to DOS.
                mov     ah,35h
                push    es
             cs mov     [key_vector_seg],es
             cs mov     [key_vector_adr],bx
                pop     es
set_key_vector:                                 ; Set INT 09h vector to new
                mov     al,09h                             
                mov     ah,25h
                push    ds
                mov     dx,keyboard_interrupt
                mov     ds,cs
                pop  ds
restore_key_vector:                             ; Set INT 09h vector to default
                mov     al,09h                  ; keyboard vector for DOS.
                mov     ah,25h
                push    ds
             cs mov     dx,[key_vector_adr]
             cs mov     ds,[key_vector_seg]
                pop     ds
keyboard_interrupt:                             ; GOTO here upon key press int.
                push    ax
                in      al,keyboard_port
             cs mov     [scan_code],al
ki_signal:      mov     al,020h                 ; Signal end of int.
                out     020h,al
                pop     ax
ki_end:         iret
; General VIDEO routines.
print_sprite:                                   ; Print raster block to screen.
                                                ; Entry : SI =  sprite control
                                                ;               block.
                push    ds,es
                mov     ds,cs

                mov     cx,[si+0]
                mov     dx,[si+2]
                mov     bx,[si+4]
                call    clip_sprite
                cmp      bx,0
                jz       >o1

                call    dfloc           ; di=screen adr.
                mov     dx,[si+4]
                mov     cx,[si+6]
                mov     es,[si+8]
                mov     si,[si+10]
                add     si,ax
                mov     ds,[screen_address]
l1:             push    cx,di,si
                mov     cx,bx
                shr     cx,1            ;JC
l2:          es mov     ax,[si]
             ds mov     [di],ax
                inc     di
                inc     di
                inc     si
                inc     si
                loop    l2

                pop     si,di,cx
                add     di,320
                add     si,dx
                loop    l1
o1:             pop     es,ds

cls:            push    ax,cx,ds,si 
                mov     ds,[screen_address]
                xor     ax,ax
                mov     cx,32768
                mov     si,0000h
l1:          ds mov     [si],ax
                inc     si,2
                loop    l1
                pop     si,ds,cx,ax
; -----Set the colour palette .....
set_palette:    push    es                                
                mov     es,cs
                mov     ah,10h
                mov     al,12h
                mov     bx,0000h
                mov     cx,256
                mov     dx,palette
                pop     es
set_video_mode:                                 ; Set mode to [VIDEO_MODE].
                mov     ax,1a00h
                int     10h
                cmp     al,1ah
                jne     SVM_Quit
                cmp     bl,07h
                jb      SVM_Quit

                mov     ah,00h
                mov     al,[video_mode]

SVM_Quit:       mov     w[NoCard],1
; General DISK routines.
general_load:                                   ; LOAD any file.
                                                ; Entry : CS:BX = Pathname
                                                ;       : CX    = File length
                                                ;       : AX:DX = Destination.
                push    ds
                push    ax
                push    cx
                push    dx                      ; Open file.

                mov     dx,bx                             
                mov     ah,03dh
                mov     al,02h

                pop     dx
                pop     cx
                pop     ds                      ; Read from file.
                mov     bx,ax
                push    bx
                mov     ah,03fh

                pop     bx
                mov     ah,03eh                 ; Close file.

                pop     ds
; Memory management routines.
allocate_memory:                                ; Allocate 64k seg. of memory.
                mov     ah,048h                 ; Exit : AX=Segment address.
                mov     bx,4000
                jc      >o1
             cs mov     [graphics_seg],ax
                xor     al,al
o1:             mov     al,0ffh
o2:             ret
deallocate_memory:                              ; Deallocate 64k seg. of memory.
                mov     ah,049h                             
                push    es
                mov     es,[graphics_seg]
                pop  es
; ----- Second allocation of memory .....
Allocate2:      mov     ah,048h
                mov     bx,4000
                jc      >o1
             cs mov     [gfx_seg2],ax
                xor     al,al
o1:             mov     al,0ffh
o2:             ret
DeAllocate2:    mov     ah,049h
                push    es
                mov     es,[gfx_seg2]
                pop     es
; ----- Stack and segment pieces .....
prog_stack      segment word stack
                dw      400 dup 0000h
code            ends