the cutting room mirror

Bubble Dizzy (DOS)

This page contains no introduction.
What makes this game notable or what is it about? Are you a bad enough dude to save this article?

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
                even
fontname:       db      "antifont.bin",00h
                even
;
; ----- 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
                even

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.
                even

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)
                even
;
; ----- Message bits and pieces .....
SelfCheckV      db      "10",0
                even
GameV           db      "10",0
                even
MasterD_T       db      "0706931500",0
                even
InfoLine        db      "T:v .   A:v .   D:  /  /     :  ",0
                even
CopyRightMess   db      "(c) Codemasters 1993.",0
                even
;
; ----- 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
                even
;
;------------------------------------------------------------------------------
; PROGRAM
;==============================================================================
;
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
                ret
;
; ----- 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
                ret
;------------------------------------------------------------------------------
; General routines.
;==============================================================================
;
; ----- THIS IS THE MAIN PROGRAM LOOP .....
action:         
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
                ret
;
; ----- 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
load_and_initialise:
                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
                ret

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
                ret
;
; ----- 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      
                ret
o1:             xor     ax,ax
                ret
o2:             xor     bx,bx
                ret
;
; ----- 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
                ret
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
                ret
;
; ----- 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].
                ret
;------------------------------------------------------------------------------
; 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
                ret
save_key_vector:                        ; Saves INT 09h vector for 
                mov     al,09h          ; return to DOS.
                mov     ah,35h
                push    es
                general_int
             cs mov     [key_vector_seg],es
             cs mov     [key_vector_adr],bx
                pop     es
                ret
set_key_vector:                                 ; Set INT 09h vector to new
                mov     al,09h                             
                mov     ah,25h
                push    ds
                mov     dx,keyboard_interrupt
                mov     ds,cs
                general_int
                pop  ds
                ret
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]
                general_int
                pop     ds
                ret
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
                ret

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
                ret
;
; -----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
                video_int
                pop     es
                ret
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]
                video_int
                ret

SVM_Quit:       mov     w[NoCard],1
                ret
;------------------------------------------------------------------------------
; 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
                general_int

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

                pop     bx
                mov     ah,03eh                 ; Close file.
                general_int

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