; NOTE: This is just a compilation  of the source code files. You can not
; compile this file.

;               (C)93 xToto

		TITLE   'Mythic-Writer V1.10'

		PAGE    66, 132

		P286
		MODEL   SMALL

INCLUDE         INCLUDE\BIOS.INC
INCLUDE         INCLUDE\DOS.INC
INCLUDE         INCLUDE\KEYCODES.INC

STRWARN         EQU     KBLF, KBCR, '$'

PRSEQUENCER     =       03C4H
PRGRAPHICS      =       03CEH
PRCRT           =       03D4H

NO              =       0
OFF             =       0
YES             =       1
ON              =       1

ENOFF           =       0
ENJUSTOFF       =       1
ENON            =       2
ENJUSTON        =       3

CCOLOR          =       256
CBASECOLOR      =       3
CPATTERN        =       4
MSECSPERTICK    =       54945
CCHAR           =       256
BOTTOMLINE      =       24
LEFTCOLUMN      =       0
RIGHTCOLUMN     =       39
TOPLINE         =       0

CCURSET         =       2
CCURSOR         =       16
CCURCOLUMN      =       8
CCURLINE        =       8

CITEM           =       2
COBJECT         =       8
COBJCOLUMN      =       16
COBJLINE        =       16

CSTAR           =       200
CSTARCOLOR      =       5
CBITMAP         =       4
CFRAME          =       2
CFX             =       3
CSCRCOLUMN      =       320
CSCRLINE        =       200
CSTONELINE      =       8
CSTONECOLUMN    =       8
CEXTKEY         =       128
CBCHAR          =       2
CBDELAY         =       2
CCURPHASE       =       16
SEGGFX          =       0A000H

CBATTRIBUTE     =       11
CBCURBUFFER     =       CCURCOLUMN * CCURLINE
CBCURSOR        =       CCURLINE * CCURCOLUMN
CBOBJECT        =       COBJLINE * COBJCOLUMN
CBOBJBUFFER     =       CBOBJECT * COBJECT
CBOBJECTPOS     =       COBJECT * 2
CBPARAGRAPH     =       16
CBSCRBUFFER     =       CSCRCOLUMN * CSCRLINE
CBSTACK         =       512
CBCHARSET       =       CCHAR * CCURLINE
CBCOLUMN        =       CCURLINE * (BOTTOMLINE - TOPLINE + 1)
CBLINE          =       CCURCOLUMN * (RIGHTCOLUMN - LEFTCOLUMN + 1)
CBMAP           =       CBCOLUMN * CSCRCOLUMN
CBOBJMASK       =       CITEM * COBJECT * COBJLINE * COBJCOLUMN / CBITMAP

Stack           CBSTACK

Data            SEGMENT PUBLIC
		ASSUME  CS:Code,        DS:Data

STREXT          DB      '.WRT', 0
STR286ERROR     DB      '286-Processor required.', STRWARN
STRVGAERROR     DB      'VGA-Card required.', STRWARN
		IFDEF   _WRITE
STRACCESSERROR  DB      'Can''t write to file.', STRWARN
STRERROR        DB      'Can''t create file.', STRWARN
STRUSAGE        DB      'Usage: WRITE <FileName>', STRWARN
		ENDIF
IFDEF   _READ
STRACCESSERROR  DB      'Can''t read from file.', STRWARN
STRERROR        DB      'Can''t open file.', STRWARN
STRUSAGE        DB      'Usage: READ <FileName>', STRWARN
		ENDIF
STRHEXNUMBERS   DB      '0123456789ABCDEF', 0
STRQUADNUMBERS  DB      '0123', 0
STRDUALNUMBERS  DB      '01', 0

INCLUDE         INCLUDE\PALETTE.INC
INCLUDE         CURSOR\CURSOR.INC
INCLUDE         INCLUDE\STONE.INC

OFFSAAABFONTS   =       OFFSET  $
INCLUDE         CHAR\BIG.INC
INCLUDE         CHAR\SMALL.INC
INCLUDE         CHAR\TINY.INC
VGACHARS        =       $
		DB      CCHAR * CCURLINE DUP (0)
INCLUDE         INCLUDE\REQUEST.INC

AAABOBJ         =       AABSTAR
INCLUDE         OBJECT\STAR.INC
INCLUDE         OBJECT\HEART.INC

OFFSAAABOBJ     =       0A0H
OFFSAAABCUR     =       0C8H
OFFSAABCURBUF   =       0ECH
OFFSAABMBOXBUF  =       0F0H
OFFSAAABOBJBUF  =       CSCRCOLUMN * CITEM * COBJLINE + OFFSAAABOBJ
OFFSAAABSTONE   =       OFFSAAABCUR + CSCRCOLUMN * CCURSET * CCURLINE

AOBJECTSEQ      DB      0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0
abObjTimer      DB      000H, 010H, 020H, 030H, 040H, 050H, 060H, 070H

offsCursor      DW      OFFSAAABCUR
offsFont        DW      OFFSAAABFONTS
offsPalette     DW      AABCOLOR
offsPattern     DW      AAPATTERN
		IFDEF   _PLAY
offsText        DW      OFFSET  abText
		ENDIF
ynInsert        DB      YES
ynLock          DB      NO
		IFNDEF  _WRITE
ynShowEnd       DB      YES
		ENDIF

aenFXDefault    DB      ENON
		DB      ENON
		DB      ENON

aenFX           =       $
enStars         DB      ENON
enCursor        DB      ENON
enObjects       DB      ENON

AENHANCEPROC    DW      OFFSET  EnhanceStars
		DW      OFFSET  EnhanceCursor
		DW      OFFSET  EnhanceObjects

AINITPROC       DW      OFFSET  InitStars
		DW      OFFSET  InitCursor
		DW      OFFSET  InitObjects

ATURNOFFPROC    DW      OFFSET  TurnOffStars
		DW      OFFSET  TurnOffCursor
		DW      OFFSET  TurnOffObjects

ATURNONPROC     DW      OFFSET  TurnOnStars
		DW      OFFSET  TurnOnCursor
		DW      OFFSET  TurnOnObjects

AJUMPPROC       DW      0
		DW      0               ; !
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      OFFSET  KeyBackSpace
		DW      0
		DW      0               ; 10
		DW      0
		DW      0
		DW      OFFSET  KeyReturn
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		IFDEF   _WRITE
		DW      OFFSET  ResetFile
		ELSE
		DW      0
		ENDIF
		DW      OFFSET  AskText ; 20
		DW      0
		DW      0
		DW      OFFSET  AskInfo
		DW      OFFSET  AskObject
		DW      OFFSET  AskPattern
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0               ; 30
		DW      0
		DW      0
		DW      OFFSET  AskFont
		DW      0
		DW      OFFSET  AskHelp
		DW      0
		DW      0
		DW      OFFSET  KeyInsLine
		DW      0
		DW      0               ; 40
		DW      0
		DW      0
		DW      0
		DW      OFFSET  KeyDelLine
		DW      0
		DW      OFFSET  AskCursor
		DW      0
		DW      OFFSET  AskBack
		DW      0
		DW      0               ; 50
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      OFFSET  AskHelp
		DW      OFFSET  SwitchStars ; 60
		DW      OFFSET  SwitchCursor
		DW      OFFSET  SwitchSprites
		DW      OFFSET  KeyClear
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0               ; 70
		DW      OFFSET  KeyToLeft
		DW      OFFSET  KeyUp
		DW      OFFSET  KeyToUp
		DW      0
		DW      OFFSET  KeyLeft
		DW      0
		DW      OFFSET  KeyRight
		DW      0
		DW      OFFSET  KeyToRight
		DW      OFFSET  KeyDown ; 80
		DW      OFFSET  KeyToDown
		DW      OFFSET  KeyInsert
		DW      OFFSET  KeyDelete
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0               ; 90
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0               ; 100
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0               ; 110
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0               ; 120
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0
		DW      0

;               Uninitialisierte Variablen werden auf 0 gesetzt
;

offsFirstVoid   =       OFFSET  $

BackColor       DB      ?
BitPlane        DB      ?
cRepeat         DB      ?
CursorNewX      DW      ?
CursorNewY      DW      ?
CursorX         DW      ?
CursorY         DW      ?
		DW      2 * (CFRAME - 1) DUP (?)
Delay           DW      ?
iCursor         DW      ?
iFrame          DW      ?
iItem           DW      ?
iObject         DW      ?
iPhase          DW      ?
		IFNDEF  _WRITE
NextChar        DW      ?
		ENDIF
offs            DW      ?
offsChar        DW      ?
offsFileName    DW      ?
offsFrame       DW      ?
OldRWMode       DB      ?
segFileName     DW      ?
		IFDEF   _PLAY
segText         DW      ?
		ENDIF
Random          DW      ?
		IFNDEF  _PLAY
skey            DW      ?
		ENDIF
Timer           DW      ?
TimerLast       DW      ?
XPos            DW      ?
YPos            DW      ?
		DW      2 * CFRAME DUP (?)
ynError         DB      ?
ynFXOn          DB      ?
ynQuit          DB      ?
ynSingle        DB      ?
ynSkip          DB      ?
Char            DW      ?

;               Koordinaten der MessageBox in Zeichen
;
MBox_Coords     =       MBox_Left
MBox_Left       DW      ?
MBox_Top        DW      ?
MBox_Right      DW      ?
MBox_Bottom     DW      ?
MBox_Text       DW      ?

aoffsItem       DW      COBJECT                 DUP     (?)
aoffsMask       DW      COBJECT                 DUP     (?)
aoffsObj        DW      COBJECT * CFRAME        DUP     (?)
aoffsObjNew     DW      COBJECT                 DUP     (?)
abAttribBuffer  DB      CBATTRIBUTE             DUP     (?)
aaabObjMask     DB      CBOBJMASK               DUP     (?)
awStarX         DW      CSTAR * CFRAME          DUP     (?)

offsLastVoid    =       OFFSET  $
cbVoid          =       offsLastVoid - offsFirstVoid

		IFDEF   _PLAY
dummy           DB      0
		IFDEF   _TEST
abText          DW      'H', 50
		DW      'a', 50
		DW      'l', 50
		DW      'l', 50
		DW      'o', 50
		DW      KBESC, 50
		ELSE
abText          =       $
		ENDIF
		ENDIF
Data            ENDS

Code            SEGMENT PUBLIC
		ASSUME  CS:Code,        DS:Data


; *****************************************************************************
; Holt das nchste Zeichen aus dem Speicher: C
; *****************************************************************************
		IFDEF   _PLAY
AccessFile      PROC
		push    si
		push    es
		push    ax
		mov     si, offsText
		mov     es, segText
		mov     ax, es:[si]
		mov     NextChar, ax
		mov     ax, es:[si+CBCHAR]
		mov     Delay, ax
		add     offsText, CBCHAR + CBDELAY
		cmp     offsText, CBPARAGRAPH
		jna     AccessFile_Ok
		sub     offsText, CBPARAGRAPH
		inc     segText
AccessFile_Ok:  mov     cRepeat, CFRAME
		dec     Delay
		clc
		pop     ax
		pop     es
		pop     si
		ret
AccessFile      ENDP
		ENDIF

; *****************************************************************************
; Liest die Informationen zum nchsten Zeichen aus der Datei: C
; *****************************************************************************
		IFDEF   _READ
AccessFile      PROC
		pusha
		mov     ah, DOS_Read_FROM_HANDLE
		mov     bx, skey
		mov     cx, cbChar
		mov     dx, OFFSET NextChar
		int     DOS_FUNCTION
		jc      Access_Error
		cmp     ax, cbChar
		jne     Access_Error

;               Liest die Verzgerung
;
		mov     ah, DOS_Read_FROM_HANDLE
		mov     bx, skey
		mov     cx, cbDelay
		mov     dx, OFFSET Delay
		int     DOS_FUNCTION
		jc      Access_Error
		cmp     ax, cbDelay
		jne     Access_Error
		clc
		mov     cRepeat, CFRAME
		dec     Delay
		jmp     Access_End

Access_Error:   mov     ynError, YES
		stc
Access_End:     popa
		ret
AccessFile      ENDP
		ENDIF

; *****************************************************************************
; Schreibt die Informationen zum nchsten Zeichein in die Datei: C
; *****************************************************************************
		IFDEF   _WRITE
AccessFile      PROC
		pusha
		call    GetDelay
		mov     ah, DOS_WRITE_TO_HANDLE
		mov     bx, skey
		mov     cx, cbChar
		mov     dx, OFFSET Char
		int     DOS_FUNCTION
		jc      Access_Error
		cmp     ax, cbChar
		jne     Access_Error

;               Schreibt die Verzgerung
;
		mov     ah, DOS_WRITE_TO_HANDLE
		mov     bx, skey
		mov     cx, cbDelay
		mov     dx, OFFSET Delay
		int     DOS_FUNCTION
		jc      Access_Error
		cmp     ax, cbDelay
		jne     Access_Error
		jmp     Access_End
Access_Error:   mov     ynError, YES
		stc
Access_End:     popa
		ret
AccessFile      ENDP
		ENDIF

ActualizeCursor PROC
		push    ax
		push    si
		mov     si, iFrame
		shl     si, 2
		add     si, OFFSET CursorX
		mov     ax, CursorNewX
		mov     ds:[si], ax
		mov     ax, CursorNewY
		mov     ds:[si+2], ax
		pop     si
		pop     ax
		ret
ActualizeCursor ENDP

; *****************************************************************************
; Dialogboxen auf dem Bildschirm darstellen
; *****************************************************************************
AskBack         PROC
		pusha
		mov     si, OFFSET BACKREQUESTER
		call    MessageBox
		jc      AskBack_End
		call    UpCase
		mov     ax, Char
		mov     di, OFFSET STRHEXNUMBERS
		call    Pos
		jc      AskBack_End
		mov     si, OFFSET ABACKCOLOR
		add     si, cx
		mov     al, ds:[si]
		mov     BackColor, al
AskBack_End:    popa
		ret
AskBack         ENDP

AskCursor       PROC
		pusha
		mov     si, OFFSET CURSORREQUESTER
		call    MessageBox
		jc      AskCursor_End
		mov     ax, Char
		mov     di, OFFSET STRDUALNUMBERS
		call    Pos
		jc      AskCursor_End
		mov     iCursor, cx
		mov     ax, cx
		mov     dx, CCURLINE * CSCRCOLUMN
		mul     dx
		add     ax, OFFSAAABCUR
		mov     offsCursor, ax
AskCursor_End:  popa
		ret
AskCursor       ENDP

		IFNDEF  _WRITE
AskEnd          PROC
		push    ax
		push    si
		mov     ynLock, YES
AskEnd_Wait:    call    ExpectRetrace
		call    ExpectPicture
		call    SwitchFrame
		call    TurnOffFX
		mov     ax, 1
		call    EnhanceTimer
		cmp     ynShowEnd, YES
		jne     AskEnd_NoShow
		cmp     iFrame, 0
		jne     AskEnd_NoShow
		mov     si, OFFSET ENDREQUESTER
		call    MessageBox
		mov     ynShowEnd, NO
AskEnd_NoShow:  call    TurnOnFX
		call    GetKey
		jc      AskEnd_Wait
		pop     si
		pop     ax
		ret
AskEnd          ENDP
		ENDIF

AskFont         PROC
		pusha
		mov     si, OFFSET FONTREQUESTER
		call    MessageBox
		jc      AskFont_End
		mov     ax, Char
		mov     di, OFFSET STRQUADNUMBERS
		call    Pos
		jc      AskFont_End
		shl     cx, 11
		add     cx, OFFSAAABFONTS
		mov     offsFont, cx
AskFont_End:    popa
		ret
AskFont         ENDP

AskText         PROC
		pusha
		mov     si, OFFSET FRONTREQUESTER
		call    MessageBox
		jc      AskText_End
		mov     ax, Char
		mov     di, OFFSET STRHEXNUMBERS
		call    Pos
		jc      AskText_End
		shl     cx, 4
		add     cx, OFFSET AABCOLOR
		mov     offsPalette, cx
AskText_End:    popa
		ret
AskText         ENDP

AskHelp         PROC
		push    si
		mov     si, OFFSET HELP1REQUESTER
		call    MessageBox
		mov     si, OFFSET HELP2REQUESTER
		call    MessageBox
		pop     si
		ret
AskHelp         ENDP

AskInfo         PROC
		push    si
		mov     si, OFFSET INFOREQUESTER
		call    MessageBox
		pop     si
		ret
AskInfo         ENDP

AskObject       PROC
		pusha
		mov     si, OFFSET OBJECTREQUESTER
		call    MessageBox
		jc      AskObject_End
		mov     ax, Char
		mov     di, OFFSET STRDUALNUMBERS
		call    Pos
		jc      AskObject_End
		mov     iItem, cx
AskObject_End:  popa
		ret
AskObject       ENDP

AskPattern      PROC
		pusha
		mov     si, OFFSET PATTERNREQUESTER
		call    MessageBox
		mov     ax, Char
		mov     di, OFFSET STRQUADNUMBERS
		call    Pos
		jc      AskPattern_End
		shl     cx, 6
		add     cx, OFFSET AAPATTERN
		mov     offsPattern, cx
AskPattern_End: popa
		ret
AskPattern      ENDP

ClearLatches    PROC
		push    ds
		push    si
		mov     ax, SEGGFX
		mov     ds, ax
		mov     si, CSCRLINE * CSCRCOLUMN
		lodsb
		pop     si
		pop     ds
		ret
ClearLatches    ENDP

; *****************************************************************************
; Schliet die Textdatei
; *****************************************************************************
		IFNDEF  _PLAY
CloseFile       PROC
		push    ax
		push    bx
		mov     ah, DOS_CLOSE_FILE
		mov     bx, skey

		int     DOS_FUNCTION
		pop     bx
		pop     ax
		ret
CloseFile       ENDP
		ENDIF

; *****************************************************************************
; Konvertiert die Objekte in das Video-Format
; *****************************************************************************
Convert         PROC
		pusha
		mov     bp, sp
		add     bp, 012H
		mov     dx, PRSEQUENCER
		mov     al, 002H
		out     dx, al
		inc     dx
		mov     al, 001H
		mov     bx, ss:[bp]
		mov     si, ss:[bp+2]
		mov     di, ss:[bp+4]
		mov     cx, ss:[bp+6]
Convert_NextLn: push    cx
		mov     cx, ss:[bp+8]
Convert_NextCl: out     dx, al
		mov     ah, ds:[si]
		mov     es:[di], ah
		or      ah, ah
		je      Convert_Blank
		mov     ah, 0FFH
		mov     ds:[si], ah
Convert_Blank:  inc     si
		add     al, al
		cmp     al, 010H
		jne     Convert_Next
		inc     di
		mov     al, 001H
Convert_Next:   loop    Convert_NextCl
		pop     cx
		sub     di, bx
		add     di, CSCRCOLUMN
		loop    Convert_NextLn
		popa
		ret     10
Convert         ENDP

ConvertChars    PROC
		pusha
		mov     bp, OFFSET ABCPHASE
		mov     ax, CCURCOLUMN
		mov     dx, CCURLINE
		mov     di, OFFSAAABCUR
		mov     si, OFFSET AAAABCURSOR
		mov     bx, CCURCOLUMN / CBITMAP
		mov     cx, CCURSET + 1
ConvChr_NextIt: push    cx
		xor     ch, ch
		mov     cl, ds:[bp]
ConvChr_Next:   push    ax
		push    dx
		push    di
		push    si
		push    bx
		call    Convert
		add     si, CBCURSOR
		add     di, CCURCOLUMN / CBITMAP
		loop    ConvChr_Next
		mov     cl, ds:[bp]
		shl     cl, 1
		sub     di, cx
		add     di, CSCRCOLUMN * CCURLINE
		inc     bp
		pop     cx
		loop    ConvChr_NextIt
		popa
		ret
ConvertChars    ENDP

ConvertObjects  PROC
		pusha
		mov     ax, COBJCOLUMN
		mov     dx, COBJLINE
		mov     di, OFFSAAABOBJ
		mov     si, OFFSET AAABOBJ
		mov     bx, COBJCOLUMN / CBITMAP
		mov     cx, CITEM
ConvObj_NextIt: push    cx
		mov     cx, COBJECT
ConvObj_Next:   push    ax
		push    dx
		push    di
		push    si
		push    bx
		call    Convert
		add     si, CBOBJECT
		add     di, COBJCOLUMN / CBITMAP
		loop    ConvObj_Next
		pop     cx
		add     di, CSCRCOLUMN * COBJLINE - COBJCOLUMN * 2
		loop    ConvObj_NextIt

;               Bitmasken anlegen
;
		mov     si, OFFSET AAABOBJ
		mov     di, OFFSET aaabObjMask
		push    es
		push    ds
		pop     es
		mov     cx, CBOBJMASK
ConvObj_NextMsk:push    cx
		xor     ah, ah
		mov     cx, CBITMAP
ConvObj_NextBit:shr     ah, 1
		lodsb
		or      al, al
		je      ConvObj_Void
		or      ah, 008H
ConvObj_Void:   loop    ConvObj_NextBit
		mov     al, ah
		stosb
		pop     cx
		loop    ConvObj_NextMsk
		pop     es
		popa
		ret
ConvertObjects  ENDP

; *****************************************************************************
; Schaltet die Rahmenfarbe auf Schwarz
; *****************************************************************************
		IFDEF   _TEST
DarkBorder      PROC
		push    ax
		push    dx
		mov     dx, 003C0H
		mov     al, 031H
		out     dx, al
		mov     al, 000H
		out     dx, al
		pop     dx
		pop     ax
		ret
DarkBorder      ENDP
		ENDIF

; *****************************************************************************
; Fhrt Aktionen auf dem Bildschirm aus
; *****************************************************************************
DoABC           PROC
		pusha
		cmp     ynSingle, YES
		je      DoABC_Single
		mov     ax, Char

;               Kontrolle auf Ende
;
		cmp     ax, KBESC
		jne     DoABC_NotEnd
		mov     ynQuit, YES
		jmp     DoABC_End

;               Kontrolle auf Rckschritt
;
DoABC_NotEnd:   cmp     ax, KBBS
		jne     DoABC_NoBS
		call    KeyBackSpace
		jmp     DoABC_End

;               Kontrolle auf Zeilenvorschub
;
DoABC_NoBS:     cmp     ax, KBLF
		je      DoABC_End
		cmp     ax, KBCR
		jne     DoABC_NoCR
		call    KeyReturn
		jmp     DoABC_End

;               Kontrolle aus ASCII-Textzeichen
;
DoABC_NoCR:     or      ah, ah
		jne     DoABC_Ext
		call    KeyABC
		jmp     DoABC_End

;               Ansprung einer Funktion fr Steuerzeichen
;
DoABC_Ext:      shr     ax, 7
		mov     si, ax
		add     si, OFFSET AJUMPPROC
		mov     bx, ds:[si]
		or      bx, bx
		je      DoABC_End
		call    bx
		jmp     DoABC_End
DoABC_Single:   mov     ynSingle, NO
		mov     ynSkip, YES
DoABC_End:      dec     cRepeat
		call    ResetCursor
		call    ActualizeCursor
		popa
		ret
DoABC           ENDP

DoClear         PROC
		pusha
		call    ClearLatches
		xor     di, di
		mov     cx, CSCRLINE
DoClear_NextLn: push    cx
		mov     cx, CSCRCOLUMN / CBITMAP
		rep     stosb
		add     di, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		pop     cx
		loop    DoClear_NextLn

;               Uhr vorstellen
;
		mov     ax, 2
		call    EnhanceTimer
		popa
		ret
DoClear         ENDP

DoDown          PROC

;               Bildinhalt verschieben und neue Zeile leeren
;
		pusha
		std
		mov     si, (CSCRLINE - CCURLINE - 1) * CSCRCOLUMN + CSCRCOLUMN / CBITMAP - 1
		mov     di, (CSCRLINE - 1) * CSCRCOLUMN + CSCRCOLUMN / CBITMAP - 1
		push    ds
		push    es
		pop     ds
		mov     cx, CSCRLINE - CCURLINE
DoDown_NextCpy: push    cx
		mov     cx, CSCRCOLUMN / CBITMAP
		rep     movsb
		sub     di, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		sub     si, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		pop     cx
		loop    DoDown_NextCpy
		pop     ds
		cld

		call    ClearLatches
		xor     di, di
		mov     cx, CCURLINE
DoDown_NextClr: push    cx
		mov     cx, CSCRCOLUMN / CBITMAP
		rep     stosb
		add     di, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		pop     cx
		loop    DoDown_NextClr

;               Uhr vorstellen
;
		mov     ax, 2
		call    EnhanceTimer
		popa
		ret
DoDown          ENDP

DoInsert        PROC
		pusha
		call    GetCurOffset
		std
		mov     dx, RIGHTCOLUMN
		sub     dx, xPos
		add     dx, dx
		mov     si, offs
		add     si, (CCURLINE - 1) * CSCRCOLUMN - 1
		add     si, dx
		mov     di, si
		add     di, CCURCOLUMN / CBITMAP
		push    ds
		push    es
		pop     ds
		mov     cx, CCURLINE
DoIns_NextLn:   push    cx
		mov     cx, dx
		rep     movsb
		call    ClearLatches
		mov     cx, CCURCOLUMN / CBITMAP
		rep     stosb
		add     si, dx
		sub     si, CSCRCOLUMN
		add     di, dx
		sub     di, CSCRCOLUMN - (CCURCOLUMN / CBITMAP)
		pop     cx
		loop    DoIns_NextLn
		cld
		pop     ds
		popa
		ret
DoInsert        ENDP

DoInsLine       PROC

;               Bildinhalt verschieben und neue Zeile leeren
;
		pusha
		std
		mov     si, (CSCRLINE - CCURLINE - 1) * CSCRCOLUMN + CSCRCOLUMN / CBITMAP - 1
		mov     di, (CSCRLINE - 1) * CSCRCOLUMN + CSCRCOLUMN / CBITMAP - 1
		mov     cx, BOTTOMLINE
		sub     cx, yPos
		push    ds
		push    es
		pop     ds
		je      DoInsL_Bottom
		shl     cx, 3
DoInsL_NextCpy: push    cx
		mov     cx, CSCRCOLUMN / CBITMAP
		rep     movsb
		sub     di, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		sub     si, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		pop     cx
		loop    DoInsL_NextCpy
DoInsL_Bottom:  pop     ds
		cld

		call    ClearLatches
		mov     di, si
		add     di, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP + 1
		mov     cx, CCURLINE
DoInsL_NextClr: push    cx
		mov     cx, CSCRCOLUMN / CBITMAP
		rep     stosb
		add     di, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		pop     cx
		loop    DoInsL_NextClr

;               Uhr vorstellen
;
		mov     ax, 2
		call    EnhanceTimer
		popa
		ret
DoInsLine       ENDP

DoUp            PROC

;               Bildinhalt verschieben und neue Zeile leeren
;
		pusha
		mov     si, CCURLINE * CSCRCOLUMN
		xor     di, di
		push    ds
		push    es
		pop     ds
		mov     cx, CSCRLINE - CCURLINE
DoUp_NextCpy:   push    cx
		mov     cx, CSCRCOLUMN / CBITMAP
		rep     movsb
		add     di, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		add     si, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		pop     cx
		loop    DoUp_NextCpy
		pop     ds

		call    ClearLatches
		mov     cx, CCURLINE
DoUp_NextClr:   push    cx
		mov     cx, CSCRCOLUMN / CBITMAP
		rep     stosb
		add     di, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		pop     cx
		loop    DoUp_NextClr

;               Uhr vorstellen
;
		mov     ax, 2
		call    EnhanceTimer
		popa
		ret
DoUp            ENDP

DoZipChar       PROC
		pusha
		call    GetCurOffset
		mov     dx, RIGHTCOLUMN
		sub     dx, xPos
		add     dx, dx
		mov     si, offs
		add     si, CCURCOLUMN / CBITMAP
		mov     di, offs
		push    ds
		push    es
		pop     ds
		mov     cx, CCURLINE
DoZipChar_Next: push    cx
		mov     cx, dx
		rep     movsb
		call    ClearLatches
		mov     cx, CCURCOLUMN / CBITMAP
		rep     stosb
		sub     si, dx
		add     si, CSCRCOLUMN
		sub     di, dx
		add     di, CSCRCOLUMN - (CCURCOLUMN / CBITMAP)
		pop     cx
		loop    DoZipChar_Next
		pop     ds
		popa
		ret
DoZipChar       ENDP

DoZipLine       PROC

;               Bildinhalt verschieben und neue Zeile leeren
;
		pusha
		mov     ax, yPos
		mov     dx, CSCRCOLUMN * CCURLINE
		mul     dx
		mov     di, ax
		mov     si, ax
		add     si, CSCRCOLUMN * CCURLINE
		mov     cx, BOTTOMLINE
		sub     cx, yPos
		push    ds
		push    es
		pop     ds
		je      DoZipL_Bottom
		shl     cx, 3
DoZipL_NextCpy: push    cx
		mov     cx, CSCRCOLUMN / CBITMAP
		rep     movsb
		add     di, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		add     si, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		pop     cx
		loop    DoZipL_NextCpy
DoZipL_Bottom:  pop     ds

		call    ClearLatches
		mov     cx, CCURLINE
DoZipL_NextClr: push    cx
		mov     cx, CSCRCOLUMN / CBITMAP
		rep     stosb
		add     di, (CSCRCOLUMN * (CBITMAP - 1)) / CBITMAP
		pop     cx
		loop    DoZipL_NextClr

;               Uhr vorstellen
;
		mov     ax, 2
		call    EnhanceTimer
		popa
		ret
DoZipLine       ENDP

; *****************************************************************************
; Stellt den alten Video-Modus wieder her
; *****************************************************************************
Done            PROC
		pusha
		mov     ah, VIDEO_SET_MODE
		mov     al, VIDEO_80x25x16
		int     VIDEO_FUNCTION

		IFNDEF  _PLAY
		cmp     ynError, YES
		jne     Done_OK
		IFDEF   _READ
		cmp     NextChar, KBESC
		je      Done_OK
		ENDIF
		mov     dx, OFFSET STRACCESSERROR
		mov     ah, DOS_WRITE_STRING
		int     DOS_FUNCTION
		stc
		jmp     Done_End
		ENDIF

Done_OK:        clc
Done_End:       popa
		ret
Done            ENDP

DoneBlit        PROC
		push    dx
		push    ax
		mov     al, OldRWMode
		mov     ah, 005H
		xchg    al, ah
		mov     dx, PRGRAPHICS
		out     dx, ax
		pop     ax
		pop     dx
		ret
DoneBlit        ENDP

; *****************************************************************************
; Zeichnet den Block ax ab der Adresse es:di
; *****************************************************************************
DrawBlock       PROC

;               Anfangsadresse des Steins bestimmen
;
		pusha
		mov     si, OFFSAAABSTONE
		add     si, ax
		add     si, ax
		push    ds
		mov     ax, SEGGFX
		mov     ds, ax

		mov     cx, CSTONELINE
DBlock_NextLn:  push    cx
		mov     cx, CSTONECOLUMN / CBITMAP
		rep     movsb
		add     di, CSCRCOLUMN - CSTONECOLUMN / CBITMAP
		add     si, CSCRCOLUMN - CSTONECOLUMN / CBITMAP
		pop     cx
		loop    DBlock_NextLn
		pop     ds
		popa
		ret
DrawBlock       ENDP

EnhanceTimer    PROC
		pusha
		add     Timer, ax

;               Effekte weiterstellen
;
		mov     si, OFFSET AENHANCEPROC
		mov     di, OFFSET aenFX
		mov     cx, CFX
EnhanceTimer_FX:mov     dl, ds:[di]
		inc     dl
		and     dl, 3
		cmp     dl, ENON
		jl      EnhanceTimer_No
		mov     bx, ds:[si]
		call    bx
EnhanceTimer_No:inc     di
		add     si, 2
		loop    EnhanceTimer_FX
		popa
		ret
EnhanceTimer    ENDP

EnhanceCursor   PROC
		pusha
		add     iPhase, ax
		mov     si, iCursor
		add     si, OFFSET ABCPHASE
		xor     dh, dh
		mov     dl, ds:[si]
		shl     dx, 2
		cmp     iPhase, dx
		jnae    EnhCur_End
		sub     iPhase, dx
EnhCur_End:     popa
		ret
EnhanceCursor   ENDP

EnhanceObjects  PROC
		pusha
		cmp     enObjects, ENON
		jl      EnhObj_End
		mov     si, OFFSET abObjTimer
		mov     cx, COBJECT
EnhanceTm_Obj:  add     ds:[si], al
		inc     si
		loop    EnhanceTm_Obj
EnhObj_End:     popa
		ret
EnhanceObjects  ENDP

EnhanceStars    PROC
		pusha
		mov     si, OFFSET awStarX
		cmp     iFrame, 0
		je      EnhStars_Frm0
		add     si, CSTAR * 2
EnhStars_Frm0:  mov     cx, CSTAR
EnhStars_Next:  mov     ax, ds:[si]
		mov     dx, cx
		and     dx, 3
		inc     dx
		sub     ax, dx
		jns     EnhStars_Ok
		add     ax, CSCRCOLUMN
EnhStars_Ok:    mov     ds:[si], ax
		add     si, 2
		loop    EnhStars_Next
		popa
		ret
EnhanceStars    ENDP

; *****************************************************************************
; Auf Rasterstrahlpositionen warten
; *****************************************************************************
ExpectPicture   PROC
		push    dx
		push    ax
		mov     dx, 003DAH
Ray_OutFrame:   in      ax, dx
		and     ax, 00008H
		cmp     ax, 00000H
		jne     Ray_OutFrame
		pop     ax
		pop     dx
		ret
ExpectPicture   ENDP

ExpectRetrace   PROC
		pusha

;               Bildanfangsadresse bestimmen
;
		mov     dx, PRCRT
		mov     al, 00DH
		out     dx, al
		inc     dx
		mov     ax, offsFrame
		out     dx, al

;               Auf Rcklauf warten
;
		IFDEF   _TEST
		call    DarkBorder
		ENDIF
		mov     dx, 003DAH
Ray_InFrame:    in      ax, dx
		and     ax, 00008H
		cmp     ax, 00008H
		jne     Ray_InFrame
		IFDEF   _TEST
		call    WhiteBorder
		ENDIF
		popa
		ret
ExpectRetrace   ENDP

; *****************************************************************************
; Bestimmt die Bildschiradresse der oberen linken Cursor-Ecke: Offs
; *****************************************************************************
GetCurOffset    PROC
		pusha
		mov     si, iFrame
		shl     si, 2
		add     si, OFFSET CursorX
		mov     ax, ds:[si+2]
		mov     dx, CCURLINE * CSCRCOLUMN
		mul     dx
		mov     dx, ds:[si]
		add     ax, dx
		add     ax, dx
		mov     offs, ax
		popa
		ret
GetCurOffset    ENDP

; ****************************************************************************
; Bestimmt die Zeit zwischen zwei Tastendrcken: Delay
; ****************************************************************************
GetDelay        PROC
		push    ax
		mov     ax, Timer
		sub     ax, TimerLast
		mov     Delay, ax
		mov     ax, Timer
		mov     TimerLast, ax
		pop     ax
		ret
GetDelay        ENDP

		IFNDEF  _PLAY
GetFile         PROC
		pusha

;               Kontrolle, ob Dateiname angegeben ist
;
		mov     segFileName, es
		mov     di, 080H
		mov     al, es:[di]
		or      al, al
		je      GetFile_Error
;               0zeichen einfgen
;
GetFile_Ok1:    xor     ah, ah
		inc     di
		mov     si, di
		add     di, ax
		mov     es:[di], ah

;               Fhrende Leerzeichen berspringen
;
		mov     di, si
		mov     cx, ax
		mov     bx, ax
		mov     al, ' '
		inc     cx
		repe    scasb
		or      cx, cx
		je      GetFile_Error
GetFile_Ok2:    dec     di
		mov     offsFileName, di

;               Aus Option untersuchen
;
		mov     al, es:[di]
		cmp     al, '0'
		jl      GetFile_Error

;               Endung suchen
;
		mov     di, si
		mov     cx, bx
		mov     al, '.'
		repne   scasb
		or      cx, cx
		jne     GetFile_Ok

;               Endung .WRT anfgen
;
		mov     si, OFFSET STREXT
		mov     cx, 5
		rep     movsb
GetFile_Ok:     clc
GetFile_End:    popa
		ret

;               Zeigt die Syntax ax
;
GetFile_Error:  mov     dx, OFFSET STRUSAGE
		mov     ah, DOS_WRITE_STRING
		int     021H
		stc
		jmp     GetFile_End

GetFile         ENDP
		ENDIF

		IFDEF   _WRITE
; ****************************************************************************
; Liest ein Zeichen von der Tastatur: Char, C
; ****************************************************************************
GetKey          PROC

;               Kontrolle, ob ein Zeichen vorliegt
;
		push    ax
		mov     ah, KEYBOARD_GET_STATUS
		int     KEYBOARD_FUNCTION
		jz      GKey_None

;               Vorhandenes Zeichen einlesen
;
		mov     ah, KEYBOARD_READ_CHAR
		int     KEYBOARD_FUNCTION
		cmp     al, 0
		je      GKey_Normal
		xor     ah, ah
Gkey_Normal:    mov     Char, ax

;               Zeichen abspeichern
;
		cmp     ynLock, YES
		je      GKey_Locked
		call    AccessFile

GKey_Locked:    clc
		jmp     GKey_End

GKey_None:      stc
GKey_End:       pop     ax
		ret
GetKey          ENDP
		ENDIF

; *****************************************************************************
; Liest ein Zeichen aus einer Datei oder von der Tastatur
; *****************************************************************************
		IFNDEF  _WRITE
GetKey          PROC
		push    ax
		cmp     ynLock, YES
		je      GKey_Locked

;               Verzgerung abwarten
;
		call    MakeDelay
		jg      GKey_None
		mov     ax, NextChar
		call    AccessFile
		mov     Char, ax
		jmp     GKey_Hit

GKey_Locked:    mov     ah, KEYBOARD_GET_STATUS
		int     KEYBOARD_FUNCTION
		jz      GKey_None

;               Vorhandenes Zeichen einlesen
;
		mov     ah, KEYBOARD_READ_CHAR
		int     KEYBOARD_FUNCTION
GKey_Hit:       clc
		jmp     GKey_End

GKey_None:      stc

GKey_End:       pop     ax
		ret
GetKey          ENDP
		ENDIF


; *****************************************************************************
; Erzeugt eine Zufallszahl: Random
; *****************************************************************************
GetRandom       PROC
		push    ax
		mov     ax, Random
		ror     ax, 1
		xor     ax, Timer
		not     ax
		add     ax, 04294
		xchg    ah, al
		mov     Random, ax
		pop     ax
		ret
GetRandom       ENDP

; *****************************************************************************
; Nimmt alle ntigen Voreinstellungen vor: C
; *****************************************************************************
Init            PROC

;               Initialisierung der Segmentregister
;
		pusha
		mov     ax, SEG Data
		mov     ds, ax

;               Uninitialisierte Variablen auf 0 setzen
;
		push    es
		push    ds
		pop     es
		mov     di, offsFirstVoid
		xor     al, al
		mov     cx, cbVoid
		rep     stosb
		pop     es

		IFNDEF  _PLAY
		call    GetFile
		jnc     Init_OpenFile
		jmp     Init_End
		ENDIF

;               Datei ffnen
;
Init_OpenFile:  call    OpenFile

		IFNDEF  _PLAY
		jnc     Init_Opened
		mov     dx, OFFSET STRERROR
		mov     ah, DOS_WRITE_STRING
		int     021H
		stc
		jmp     Init_End
		ENDIF

Init_Opened:    cld
		mov     ax, SEGGFX
		mov     es, ax

;               Bestimmung des Prozessortypes
;
		xor     ax, ax
		push    ax
		popf
		pushf
		pop     ax
		and     ax, 0F0H
		cmp     ax, 0F0H
		jne     Init_286OK
		mov     dx, OFFSET STR286ERROR
		mov     ah, DOS_WRITE_STRING
		int     DOS_FUNCTION
		stc
		jmp     Init_End

;               Bestimmung der Grafikkarte
;
Init_286OK:     mov     ah, VIDEO_GET_VGA
		int     VIDEO_FUNCTION
		cmp     al, VIDEO_GET_VGA
		je      Init_VGAOK
		mov     dx, OFFSET STRVGAERROR
		mov     ah, DOS_WRITE_STRING
		int     DOS_FUNCTION
		stc
		jmp     Init_End

;               VGA-Zeichensatz laden
;
Init_VGAOK:     push    ds
		push    es
		mov     ax, 01130H
		mov     bh, 003H
		int     VIDEO_FUNCTION
		mov     ax, ds
		push    es
		pop     ds
		mov     es, ax
		mov     si, bp
		mov     di, OFFSET VGAChars
		mov     cx, CCHAR * CCURLINE
		rep     movsb
		pop     es
		pop     ds

;               Sicherung des alten Bildschirmmodus und Einschaltung des neuen
;
		mov     ah, VIDEO_SET_MODE
		mov     al, VIDEO_320x200x256
		int     VIDEO_FUNCTION

;               Lineare Adressierung des Graphics-Controllers
;
		mov     dx, 003CEH
		mov     al, 005H
		out     dx, al
		inc     dx
		in      al, dx
		and     al, 0EFH
		out     dx, al
		dec     dx

;               Lineare Adressierung des Graphics-Controllers (s.o.)
;
		mov     al, 006H
		out     dx, al
		inc     dx
		in      al, dx
		and     al, 0FDH
		out     dx, al

;               Lineare Adressierung des Sequencer-Controllers
;
		mov     dx, PRSEQUENCER
		mov     al, 004H
		out     dx, al
		inc     dx
		in      al, dx
		and     al, 0F7H
		or      al, 4
		out     dx, al

;               Byteweise-Adressierung des CRT-Controllers
;
		mov     dx, PRCRT
		mov     al, 014H
		out     dx, al
		inc     dx
		in      al, dx
		and     al, 0BFH
		out     dx, al
		dec     dx

;               Byteweise-Adressierung des CRT-Controllers (s.o.)
;
		mov     al, 017H
		out     dx, al
		inc     dx
		in      al, dx
		or      al, 040H
		out     dx, al

;               Bildschirm lschen
;
		xor     di, di
		xor     al, al
		mov     cx, CBMAP
		rep     stosb

;               Initialisierung der 256 Farben
;
		push    es
		push    ds
		pop     es
		mov     dx, OFFSET AAPALETTE
		mov     ah, VIDEO_DACS
		mov     al, VIDEO_SET_DACS
		xor     bx, bx
		mov     cx, CCOLOR
		int     VIDEO_FUNCTION
		pop     es

;               Alle Bitplanes fr Zugriff einschalten
;
		mov     dx, PRSEQUENCER
		mov     al, 002H
		out     dx, al
		inc     dx
		mov     al, 00FH
		out     dx, al

;               Zeilen-Abstand bestimmen
;
		mov     dx, PRCRT
		mov     al, 013H
		out     dx, al
		inc     dx
		mov     al, CSCRCOLUMN / 2
		out     dx, al

;               Effekte initialisieren
;
		mov     si, OFFSET AINITPROC
		mov     cx, CFX
Init_NextFX:    mov     bx, ds:[si]
		call    bx
		add     si, 2
		loop    Init_NextFX

		call    InitBlit
		call    TurnOnFX
		call    SwitchFrame
		call    TurnOnFX
		call    SwitchFrame
		clc
Init_End:       popa
		ret
Init            ENDP

InitBlit        PROC
		push    dx
		push    ax
		mov     dx, PRSEQUENCER
		mov     al, 002H
		out     dx, al
		inc     dx
		mov     al, 00FH
		out     dx, al
		mov     dx, PRGRAPHICS
		mov     al, 005H
		out     dx, al
		inc     dx
		in      al, dx
		mov     OldRWMode, al
		and     al, not 3
		or      al, 1
		out     dx, al
		pop     ax
		pop     dx
		ret
InitBlit        ENDP

; *****************************************************************************
; Cursor initialisieren
; *****************************************************************************
InitCursor      PROC
		call    ConvertChars
		ret
InitCursor      ENDP

; *****************************************************************************
; Sprites initialisieren
; *****************************************************************************
InitObjects     PROC
		push    cx
		call    ConvertObjects
		xor     cx, cx
InitObjects_Nx: mov     iObject, cx
		call    MoveObject
		inc     cx
		cmp     cx, COBJECT
		jl      InitObjects_Nx
		pop     cx
		ret
InitObjects     ENDP

; *****************************************************************************
; Sterne initialisieren
; *****************************************************************************
InitStars       PROC
		pusha
		mov     si, OFFSET awStarX
		mov     di, si
		add     di, CSTAR * 2
		mov     cx, CSTAR
InitStars_Next: call    GetRandom
		mov     dx, Random
		mov     ax, CSCRCOLUMN
		mul     dx
		mov     ds:[si], dx
		mov     ax, cx
		and     ax, 3
		inc     ax
		shr     ax, 1
		add     dx, ax
		mov     ds:[di], dx
		add     si, 2
		add     di, 2
		loop    InitStars_Next
		popa
		ret
InitStars       ENDP

; *****************************************************************************
; Funktionen zur Ausgabe von Tasten
; *****************************************************************************
KeyABC          PROC
		call    GetCurOffset
		cmp     ynInsert, YES
		jne     KeyABC_NoIns
		call    DoInsert
KeyABC_NoIns:   call    MoveRight
		pushf
		call    DoneBlit
		call    Print
		call    InitBlit
		popf
		jnc     KeyABC_End
		call    DoUp
KeyABC_End:     ret
KeyABC          ENDP

KeyBackSpace    PROC
		call    MoveLeft
		jnc     KeyLeft_Del
		call    DoDown
KeyLeft_Del:    call    ResetCursor
		call    ActualizeCursor
		call    DoZipChar
		ret
KeyBackSpace    ENDP

KeyDelete       PROC
		call    DoZipChar
		ret
KeyDelete       ENDP

KeyDelLine      PROC
		call    DoZipLine
		ret
KeyDelLine      ENDP

KeyDown         PROC
		call    MoveDown
		jnc     KeyDown_End
		call    DoUp
KeyDown_End:    ret
KeyDown         ENDP

KeyInsert       PROC
		cmp     iFrame, 0
		jne     KeyInsert_End
		xor     ynInsert, YES
KeyInsert_End:  ret
KeyInsert       ENDP

KeyInsLine      PROC
		call    DoInsLine
		ret
KeyInsLine      ENDP

KeyClear        PROC
		call    DoClear
		ret
KeyClear        ENDP

KeyLeft         PROC
		call    MoveLeft
		jnc     KeyLeft_End
		call    DoDown
KeyLeft_End:    ret
KeyLeft         ENDP

KeyReturn       PROC
		call    MoveToNextLine
		jnc     KeyReturn_End
		call    DoUp
KeyReturn_End:  ret
KeyReturn       ENDP

KeyRight        PROC
		call    MoveRight
		jnc     KeyRight_End
		call    DoUp
KeyRight_End:   ret
KeyRight        ENDP

KeyToDown       PROC
		call    MoveToBottom
		ret
KeyToDown       ENDP

KeyToLeft       PROC
		call    MoveToLeft
		ret
KeyToLeft       ENDP

KeyToRight      PROC
		call    MoveToRight
		ret
KeyToRight      ENDP

KeyToUp         PROC
		call    MoveToTop
		ret
KeyToUp         ENDP

KeyUp           PROC
		call    MoveUp
		jnc     KeyDown_End
		call    DoDown
KeyUp_End:      ret
KeyUp           ENDP

; ****************************************************************************
; Stellt die Bildattribute wieder her
; ****************************************************************************
LoadAttributes  PROC
		push    es
		push    si
		push    di
		mov     si, OFFSET abAttribBuffer
		mov     di, OFFSET CursorX
		push    ds
		pop     es
		movsw
		movsw
		mov     di, OFFSET BackColor
		movsb
		mov     di, OFFSET offsPalette
		movsw
		mov     di, OFFSET offsPattern
		movsw
		mov     di, OFFSET offsFont
		movsw
		pop     di
		pop     si
		pop     es
		ret
LoadAttributes  ENDP

; *****************************************************************************
; Hauptprogramm
; *****************************************************************************
Main            PROC
		call    Init
		jc      Main_Error1
		call    Run

		IFNDEF  _PLAY
		call    CloseFile
		ENDIF

		call    Done
Main_Error1:    mov     al, 0
		adc     al, al
		mov     ah, DOS_TERMINATE_EXE
		int     DOS_FUNCTION
Main            ENDP

; ****************************************************************************
; Bestimmt, ob wieder ein Tastendruck kommt
; ****************************************************************************
MakeDelay       PROC
		push    ax

;               Kontrolle, ob eine Taste gedrckt wird
;
		mov     ah, KEYBOARD_GET_STATUS
		int     KEYBOARD_FUNCTION
		je      MakeDelay_OK
		mov     ah, KEYBOARD_READ_CHAR
		int     KEYBOARD_FUNCTION
		cmp     al, KBESC
		jne     MakeDelay_GoOn
		mov     ynQuit, YES
MakeDelay_GoOn: mov     ax, 00001H
		mov     Delay, ax
MakeDelay_OK:   dec     Delay
		cmp     Delay, 0
		pop     ax
		ret
MakeDelay       ENDP

; *****************************************************************************
; Zeichnet einen Kasten auf den Bildschirm < ds:si
; *****************************************************************************
MessageBox      PROC
		pusha
		call    TurnOnFX

;               Koordinaten der Box und Text bestimmen
;
MBox_Draw:      mov     di, OFFSET MBox_Coords
		push    es
		push    ds
		pop     es
		mov     cx, 4
		rep     movsw
		pop     es
		mov     MBox_Text, si

;               Startadresse des Hintergrundes bestimmen: ds:si
;
		mov     ax, MBox_Top
		shl     ax, 3
		mov     dx, CSCRCOLUMN
		mul     dx
		mov     dx, MBox_Left
		shl     dx, 1
		add     ax, dx
		mov     si, ax

;               Startadresses der Puffers bestimmen
		mov     di, OFFSAABMBOXBUF

;               Zahl der Bildschirmzeilen bestimmen
;
		mov     cx, MBox_Bottom
		sub     cx, MBox_Top
		inc     cx
		shl     cx, 3

;               Zahl der Bildschirmspalten bestimmen
;
		mov     bx, MBox_Right
		sub     bx, MBox_Left
		inc     bx
		shl     bx, 1

;               Daten zum Zurcklesen sichern
;
		push    bx
		push    cx
		push    si

;               Hintergrund kopieren
;
		push    es
		push    ds
		push    es
		pop     ds
		mov     ax, SEGGFX
		mov     es, ax
MBox_SNextLn:   push    cx
		mov     cx, bx
		rep     movsb
		add     si, CSCRCOLUMN
		sub     si, bx
		add     di, CSCRCOLUMN
		sub     di, bx
		pop     cx
		loop    MBox_SNextLn
		pop     ds
		pop     es

;               Obere Kante zeichnen
;
		pop     di
		push    di
		push    di
		mov     ax, ISTONETOPLEFT
		call    DrawBlock
		add     di, CCURCOLUMN / CBITMAP
		mov     cx, MBox_Right
		sub     cx, MBox_Left
		dec     cx
		push    cx
		mov     ax, ISTONEHORIZONTAL
MBox_TopLn:     call    DrawBlock
		add     di, CCURCOLUMN / CBITMAP
		loop    MBox_TopLn
		mov     ax, ISTONETOPRIGHT
		call    DrawBlock

;               Mittleren Bereich zeichnen
;
		pop     cx
		inc     cx
		shl     cx, 1
		push    cx
		mov     cx, MBox_Bottom
		sub     cx, MBox_Top
		dec     cx
MBox_NextLn:    mov     bx, cx
		pop     cx
		pop     di
		add     di, CSCRCOLUMN * CSTONELINE
		push    di
		push    cx
		mov     ax, ISTONEVERTICAL
		call    DrawBlock
		add     di, cx
		call    DrawBlock
		mov     cx, bx
		loop    MBox_NextLn

;               Untere Kante zeichnen
;
		pop     cx
		shr     cx, 1
		dec     cx
		pop     di
		add     di, CSCRCOLUMN * CSTONELINE
		mov     ax, ISTONEBOTTOMLEFT
		call    DrawBlock
		mov     ax, ISTONEHORIZONTAL
MBox_BottomLn:  add     di, CCURCOLUMN / CBITMAP
		call    DrawBlock
		loop    MBox_BottomLn
		add     di, CCURCOLUMN / CBITMAP
		mov     ax, ISTONEBOTTOMRIGHT
		call    DrawBlock

;               Hintergrund wiederherstellen
;
		call    Write
		call    WaitKey
		mov     ynSingle, YES
		mov     ynSkip, YES
		mov     si, OFFSAABMBOXBUF
		pop     di
		pop     cx
		pop     bx
		push    ds
		mov     ax, SEGGFX
		mov     ds, ax
MBox_LNextLn:   push    cx
		mov     cx, bx
		rep     movsb
		add     di, CSCRCOLUMN
		sub     di, bx
		add     si, CSCRCOLUMN
		sub     si, bx
		pop     cx
		loop    MBox_LNextLn
		pop     ds
		clc
MBox_End:       popa
		ret
MessageBox      ENDP

; ****************************************************************************
; Funktionen zur Bewegung des Cursors: C
; ****************************************************************************
MoveDown        PROC
		push    ax
		mov     ax, yPos
		cmp     ax, BOTTOMLINE
		je      MoveDown_Scroll
		inc     yPos
		clc
		jmp     MoveDown_End
MoveDown_Scroll:stc
MoveDown_End:   pop     ax
		ret
MoveDown        ENDP

MoveLeft        PROC
		push    ax
		mov     ax, xPos
		cmp     ax, LEFTCOLUMN
		je      MoveLeft_Jump
		dec     xPos
		clc
		jmp     MoveLeft_End
MoveLeft_Jump:  mov     ax, RIGHTCOLUMN
		mov     xPos, ax
		call    MoveUp
MoveLeft_End:   pop     ax
		ret
MoveLeft        ENDP

MoveRight       PROC
		push    ax
		mov     ax, xPos
		cmp     ax, RIGHTCOLUMN
		je      MoveRight_Jump
		inc     xPos
		clc
		jmp     MoveRight_End
MoveRight_Jump: mov     ax, LEFTCOLUMN
		mov     xPos, ax
		call    MoveDown
MoveRight_End:  pop     ax
		ret
MoveRight       ENDP

MoveToBottom    PROC
		push    ax
		mov     ax, BOTTOMLINE
		mov     yPos, ax
		pop     ax
		ret
MoveToBottom    ENDP

MoveToLeft      PROC
		push    ax
		mov     ax, LEFTCOLUMN
		mov     xPos, ax
		pop     ax
		ret
MoveToLeft      ENDP

MoveToNextLine  PROC
		push    ax
		mov     ax, LEFTCOLUMN
		mov     xPos, ax
		call    MoveDown
		pop     ax
		ret
MoveToNextLine  ENDP

MoveToRight     PROC
		push    ax
		mov     ax, RIGHTCOLUMN
		mov     xPos, ax
		pop     ax
		ret
MoveToRight     ENDP

MoveToTop       PROC
		push    ax
		mov     ax, TOPLINE
		mov     yPos, ax
		pop     ax
		ret
MoveToTop       ENDP

MoveUp          PROC
		push    ax
		mov     ax, yPos
		cmp     ax, TOPLINE
		je      MoveUp_Scroll
		dec     yPos
		clc
		jmp     MoveUp_End
MoveUp_Scroll:  stc
MoveUp_End:     pop     ax
		ret
MoveUp          ENDP

; *****************************************************************************
; Versetzt das mit iObject angegebene Objekt zufllig
; *****************************************************************************
MoveObject      PROC
		pusha

;               Adresse des Objekttypes bestimmen
;
		mov     ax, iItem
		mov     dx, CSCRCOLUMN * COBJLINE
		mul     dx
		add     ax, 0A0H
		mov     si, OFFSET aoffsItem
		add     si, iObject
		add     si, iObject
		mov     ds:[si], ax

;               Adresse der Maske bestimmen
;
		add     si, OFFSET aoffsMask - OFFSET aoffsItem
		mov     ax, iItem
		mov     dx, CBOBJMASK / CITEM
		mul     dx
		add     ax, OFFSET aaabObjMask
		mov     ds:[si], ax

;               Startadresse in Grafik bestimmen
;
		add     si, OFFSET aoffsObjNew - OFFSET aoffsMask

		call    GetRandom
		mov     dx, Random
		mov     ax, (CSCRCOLUMN - COBJCOLUMN) / CBITMAP
		mul     dx
		mov     bx, dx

		call    GetRandom
		mov     dx, CSCRLINE - COBJLINE
		mov     ax, Random
		mul     dx
		mov     ax, CSCRCOLUMN
		mul     dx
		add     ax, bx
		mov     ds:[si], ax
		popa
		ret
MoveObject      ENDP

; *****************************************************************************
; ffnen der Datei zum Abspielen
; *****************************************************************************
		IFDEF   _PLAY
OpenFile        PROC
		push    ax
		push    dx
		mov     ax, offsText
		shr     ax, 4
		mov     dx, ds
		add     ax, dx
		mov     segText, ax
		and     offsText, 0000FH
		pop     dx
		pop     ax
		clc
		ret
OpenFile        ENDP
		ENDIF

; *****************************************************************************
; ffnen der Textdatei zum lesen: C
; *****************************************************************************
		IFDEF   _READ
OpenFile        PROC
		push    ax
		push    dx
		mov     ah, DOS_OPEN_FILE
		xor     al, al
		mov     dx, offsFileName
		push    ds
		mov     ds, segFileName
		int     DOS_FUNCTION
		pop     ds
		mov     skey, ax
		pop     dx
		pop     ax
		ret
OpenFile        ENDP
		ENDIF

; *****************************************************************************
; ffnen der Textdatei zum schreiben: C
; *****************************************************************************
		IFDEF   _WRITE
OpenFile        PROC
		pusha
		mov     ah, DOS_CREATE_FILE
		xor     cx, cx
		mov     dx, offsFileName
		push    ds
		mov     ds, segFileName
		int     DOS_FUNCTION
		pop     ds
		mov     skey, ax
		popa
		ret
OpenFile        ENDP
		ENDIF

; ****************************************************************************
; Bestimmt die Position eines Zeichens (> cx) in einem String (< di)
; ****************************************************************************
Pos             PROC
		push    dx
		push    es
		push    ds
		pop     es
		xor     cx, cx
		dec     cx
		push    ax
		push    di
		xor     al, al
		repne   scasb
		not     cx
		mov     dx, cx
		pop     di
		pop     ax
		repne   scasb
		or      cx, cx
		je      Pos_Failure
		sub     dx, cx
		mov     cx, dx
		dec     cx
		clc
		jmp     Pos_End
Pos_Failure:    stc
Pos_End:        pop     es
		pop     dx
		ret
Pos             ENDP

; *****************************************************************************
; Gibt ein Zeichen auf dem Bildschirm aus
; *****************************************************************************
Print           PROC
		pusha

;               Sequencer-Controller einstellen
;
		mov     dx, PRSEQUENCER
		mov     al, 002H
		out     dx, al
		inc     dx
		mov     al, 080H
		mov     BitPlane, al

;               Bildschirmadresse bestimmen: es:[di]
;
		mov     di, Offs

;               Adresse der Zeichenmusters bestimmen: ds:[si]
;
		mov     si, Char
		shl     si, 3
		add     si, offsFont

;               Anfangsadresse der Fllmusters bestimmen: ds:[bx]
;
		mov     bx, offsPattern

;               Anfangsadresse der Fllfarben bestimmem: ds:[bp]
;
		mov     bp, offsPalette

		mov     cx, CCURLINE
Print_NextLn:   push    cx
		lodsb
		mov     ah, al
		mov     cx, CCURCOLUMN
Print_NextCol:  mov     al, BitPlane
		rol     al, 1
		cmp     al, 010H
		jne     Print_NoReMap
		mov     al, 001H
		inc     di
Print_NoReMap:  out     dx, al
		mov     BitPlane, al
		push    dx
		shl     ah, 1
		jnc     Print_Back

;               Pixel in der Vordergrundfarbe setzen
;
Print_Front:    xor     dh, dh
		mov     dl, ds:[bx]
		add     bp, dx
		mov     al, ds:[bp]
		sub     bp, dx
		jmp     Print_Pixel

;               Pixel in der Hintergrundfarbe setzen
;
Print_Back:     mov     al, BackColor
Print_Pixel:    mov     es:[di], al
		inc     bx
		pop     dx
		loop    Print_NextCol
		add     di, CSCRCOLUMN - (CCURCOLUMN / CBITMAP)
		pop     cx
		loop    Print_NextLn
		popa
		ret
Print           ENDP

; *****************************************************************************
; Setzt die Schreibposition auf die Cursorposition
; *****************************************************************************
ResetCursor     PROC
		push    ax
		mov     ax, xPos
		mov     CursorNewX, ax
		mov     ax, yPos
		mov     CursorNewY, ax
		pop     ax
		ret
ResetCursor     ENDP

; *****************************************************************************
; Springt zum Anfang der Datei
; *****************************************************************************
		IFDEF   _WRITE
ResetFile       PROC
		pusha

;               Dateizeiger an Anfang zurcksetzen
;
		mov     ah, DOS_MOVE_FILE_POINTER
		xor     al, al
		mov     bx, sKey
		xor     cx, cx
		xor     dx, dx
		int     DOS_FUNCTION

;               Bildschirm lschen und Cursor in obere linke Ecke bewegen
;
		call    DoClear
		call    MoveToLeft
		call    MoveToTop

;               Effekte auf Anfangswerte setzen
;
		mov     si, OFFSET aenFXDefault
		mov     di, OFFSET aenFX
		mov     cx, CFX
ResetFile_FX:   mov     al, ds:[si]
		cmp     al, ds:[di]
		je      ResetFile_FXNo
		dec     BYTE PTR ds:[di]
		and     BYTE PTR ds:[di], 3
ResetFile_FXNo: inc     si
		inc     di
		loop    ResetFile_FX

;               Einstellungen zurcksetzen
;
ResetFile_SpOn: mov     iItem, 0
		mov     ynInsert, YES
		mov     BackColor, PABLACK
		mov     iCursor, 0
		mov     iPhase, 0
		mov     offsCursor, OFFSAAABCUR
		mov     offsFont, OFFSAAABFONTS
		mov     offsPalette, OFFSET AABCOLOR
		mov     offsPattern, OFFSET AAPATTERN
		popa
		ret
ResetFile       ENDP
		ENDIF

ResetInput      PROC
		mov     Char, 0
		mov     Timer, 0
		mov     TimerLast, 0
		mov     Delay, 0
		mov     iFrame, 0
		mov     ynLock, OFF
		mov     ynSingle, NO
		mov     ynSkip, NO
		mov     cRepeat, 0
		ret
ResetInput      ENDP

; *****************************************************************************
; Arbeitet den Ablauf synchron zum Kathodenstrahl ab
; *****************************************************************************
Run             PROC
		push    ax

		IFNDEF  _WRITE
		call    AccessFile
		mov     cRepeat, 0
		jc      Run_End
		ENDIF

;               Auf neuen Bildschirm warten
;
Run_Next:       call    ExpectPicture
		call    ExpectRetrace

;               Bildschirme vertauschen
;
		call    SwitchFrame

;               Zeichen auf zweitem Bildschirm wiederholen
;
		cmp     cRepeat, 0
		jne     Run_Key

;               Zeichen nur vom ersten Bildschirm annehmen
;
		cmp     iFrame, 0
		jne     Run_NoKey

;               Zeichen lesen und zwei Wiederholungen setzen
;
		call    GetKey
		jc      Run_NoKey
		mov     cRepeat, CFRAME

;               Effekte whrend Zeichenausgabe abschalten
;
Run_Key:        call    TurnOffFX
		call    DoABC
		cmp     ynSkip, YES
		je      Run_Skip

;               Uhr weiterstellen
;
		mov     ax, 1
		call    EnhanceTimer
Run_Skip:       mov     ynSkip, NO
		call    TurnOnFX

;               Weitermachen, solange nicht am Ende
;
		cmp     ynQuit, YES
		jne     Run_Next
		cmp     cRepeat, 0
		jne     Run_Next
		jmp     Run_Exit

;               Aktualisiert nur den Cusor und die Objekte
;
Run_NoKey:      call    TurnOffFX

;               Uhr weiterstellen
;
		mov     ax, 1
		call    EnhanceTimer

		call    TurnOnFX
		jmp     Run_Next

Run_Exit:       IFNDEF  _WRITE
		call    AskEnd
		clc
		ENDIF

Run_End:        pop     ax
		ret
Run             ENDP

; *****************************************************************************
; Sichert die Bildattribute
; *****************************************************************************
SaveAttributes  PROC
		push    es
		push    si
		push    di
		mov     di, OFFSET abAttribBuffer
		mov     si, OFFSET CursorX
		push    ds
		pop     es
		movsw
		movsw
		mov     si, OFFSET BackColor
		movsb
		mov     si, OFFSET offsPalette
		movsw
		mov     si, OFFSET offsPattern
		movsw
		mov     si, OFFSET offsFont
		movsw
		pop     di
		pop     si
		pop     es
		ret
SaveAttributes  ENDP

SwitchFrame     PROC
		push    ax
		push    si

;               Cursor-Position sichern
;
		mov     si, iFrame
		inc     si
		shl     si, 2
		add     si, OFFSET xPos
		mov     ax, xPos
		mov     ds:[si], ax
		mov     ax, yPos
		mov     ds:[si+2], ax

		mov     ax, iFrame
		xor     ax, 1
		mov     iFrame, ax
		mov     ax, offsFrame
		xor     ax, CSCRCOLUMN / CBITMAP
		mov     offsFrame, ax
		shr     ax, 4
		or      ax, SEGGFX
		mov     es, ax

;               Cursor-Position restaurieren
;
		mov     si, iFrame
		inc     si
		shl     si, 2
		add     si, OFFSET xPos
		mov     ax, ds:[si]
		mov     xPos, ax
		mov     ax, ds:[si+2]
		mov     yPos, ax
		pop     si
		pop     ax
		ret
SwitchFrame     ENDP

SwitchCursor    PROC
		dec     enCursor
		and     enCursor, 3
		ret
SwitchCursor    ENDP

SwitchSprites   PROC
		dec     enObjects
		and     enObjects, 3
		ret
SwitchSprites   ENDP

SwitchStars     PROC
		dec     enStars
		and     enStars, 3
		ret
SwitchStars     ENDP

; ****************************************************************************
; Stellt den Hintergrund des Cursors wieder her
; ****************************************************************************
TurnOffCursor   PROC
		pusha
		call    GetCurOffset
		mov     di, offs
		mov     si, OFFSET OFFSAABCURBUF
		mov     ax, iFrame
		add     ax, ax
		add     si, ax
		push    ds
		mov     ax, SEGGFX
		mov     ds, ax
		mov     cx, CCURLINE
TOfCur_NextLn:  push    cx
		mov     cx, CCURCOLUMN / CBITMAP
		rep     movsb
		add     si, CSCRCOLUMN - (CCURCOLUMN / CBITMAP)
		add     di, CSCRCOLUMN - (CCURCOLUMN / CBITMAP)
		pop     cx
		loop    TOfCur_NextLn
		pop     ds
		popa
		ret
TurnOffCursor   ENDP

; ****************************************************************************
; Schaltet den Cursor ein
; ****************************************************************************
TurnOnCursor    PROC
		pusha

		call    GetCurOffset

;               Sicherung des Hintergrundes
;
		mov     si, offs
		mov     di, OFFSET OFFSAABCURBUF
		mov     ax, iFrame
		add     ax, ax
		add     di, ax
		push    ds
		push    es
		push    es
		pop     ds
		mov     ax, SEGGFX
		mov     es, ax
		mov     cx, CCURLINE
TOnCur_SNextLn: push    cx
		mov     cx, CCURCOLUMN / CBITMAP
		rep     movsb
		add     si, CSCRCOLUMN - (CCURCOLUMN / CBITMAP)
		add     di, CSCRCOLUMN - (CCURCOLUMN / CBITMAP)
		pop     cx
		loop    TOnCur_SNextLn
		pop     es
		pop     ds

;               Zeichnet den Cursor neu
;
		mov     si, iPhase
		shr     si, 1
		and     si, 0FFFEH
		add     si, offsCursor
		mov     di, offs
		push    ds
		mov     ax, SEGGFX
		mov     ds, ax
		mov     cx, CCURLINE
TOnCur_CNextLn: push    cx
		mov     cx, CCURCOLUMN / CBITMAP
		rep     movsb
		add     di, CSCRCOLUMN - CCURCOLUMN / CBITMAP
		add     si, CSCRCOLUMN - CCURCOLUMN / CBITMAP
		pop     cx
		loop    TOnCur_CNextLn
		pop     ds
		popa
		ret
TurnOnCursor    ENDP

TurnOffFX       PROC
		pusha

;               Kontrolle, ob Effekte schon aus sind
;
		cmp     ynFXOn, OFF
		je      TurnOffFX_End
		mov     ynFXOn, OFF

;               Alle gewhlten Objekte einschalten
;
		mov     si, OFFSET aenFX + (CFX - 1)
		mov     di, OFFSET ATURNOFFPROC + (CFX - 1) * 2
		mov     cx, CFX
TurnOffFX_Next: mov     al, ds:[si]
		inc     al
		and     al, 3
		cmp     al, ENON
		jl      TurnOffFX_Not
		mov     bx, ds:[di]
		call    bx
TurnOffFX_Not:  dec     si
		sub     di, 2
		loop    TurnOffFX_Next
TurnOffFX_End:  popa
		ret
TurnOffFX       ENDP

TurnOnFX        PROC
		pusha

;               Kontrolle, ob Effekte schon an sind
;
		cmp     ynFXOn, ON
		je      TurnOnFX_End
		mov     ynFXOn, ON

;               Alle gewhlten Objekte einschalten
;
		mov     si, OFFSET aenFX
		mov     di, OFFSET ATURNONPROC
		mov     cx, CFX
TurnOnFX_Next:  cmp     BYTE PTR ds:[si], ENON
		jl      TurnOnFX_Not
		mov     bx, ds:[di]
		call    bx
TurnOnFX_Not:   inc     si
		add     di, 2
		loop    TurnOnFX_Next
TurnOnFX_End:   popa
		ret
TurnOnFX        ENDP

; *****************************************************************************
; Lschen aller Objekte
; *****************************************************************************
TurnOffObjects  PROC
		pusha
		xor     cx, cx

;               Anfangsadresse der Hintergrund-Puffers bestimmen: es:si
;
TOfObj_Next:    mov     si, cx
		shl     si, 2
		add     si, OFFSAAABOBJBUF
		mov     ax, iFrame
		or      ax, ax
		je      TOfObj_F1
		add     si, CSCRCOLUMN * COBJLINE

;               Anfangsadresse des Hintergrundes bestimmen: es:di
;
TOfObj_F1:      mov     di, iFrame
		shl     di, 4
		add     di, OFFSET aoffsObj
		add     di, cx
		add     di, cx
		mov     di, ds:[di]

;               Hintergrund wiederherstellen
;
		push    cx
		push    ds
		mov     ax, SEGGFX
		mov     ds, ax
		mov     cx, COBJLINE
TOfObj_SNextLn: push    cx
		mov     cx, COBJCOLUMN / CBITMAP
		rep     movsb
		add     si, CSCRCOLUMN - COBJCOLUMN / CBITMAP
		add     di, CSCRCOLUMN - COBJCOLUMN / CBITMAP
		pop     cx
		loop    TOfObj_SNextLn
		pop     ds
		pop     cx
		inc     cx
		cmp     cx, COBJECT
		jne     TOfObj_Next
		popa
		ret
TurnOffObjects  ENDP

; *****************************************************************************
; Neuzeichnen der Objekte
; *****************************************************************************
TurnOnObjects   PROC
		pusha
		mov     cx, COBJECT - 1

;               Kontrolle, ob das Objekt bewegt werden mu
;
TOnObj_Next:    xor     dh, dh
		mov     si, OFFSET abObjTimer
		add     si, cx
		mov     dl, ds:[si]
		or      dl, dl
		jns     TOnObj_NoMove
		xor     dl, dl
		mov     iObject, cx
		call    MoveObject

;               Anfangsadresse des Hintergrundes bestimmen: es:si
;
TOnObj_NoMove:  mov     ds:[si], dl
		shr     dl, 3
		mov     si, OFFSET aoffsObjNew
		add     si, cx
		add     si, cx
		mov     ax, ds:[si]
		mov     di, iFrame
		shl     di, 4
		add     di, OFFSET aoffsObj
		add     di, cx
		add     di, cx
		mov     ds:[di], ax
		mov     si, ax

;               Anfangsadresse der Hintergrund-Puffers bestimmen: es:di
;
		mov     di, cx
		shl     di, 2
		add     di, OFFSAAABOBJBUF
		mov     ax, iFrame
		or      ax, ax
		je      TOnObj_F1
		add     di, CSCRCOLUMN * COBJLINE

;               Hintergrund sichern
;
TOnObj_F1:      push    cx
		push    es
		push    ds
		push    es
		pop     ds
		mov     ax, SEGGFX
		mov     es, ax
		push    si
		mov     cx, COBJLINE
TOnObj_SNextLn: push    cx
		mov     cx, COBJCOLUMN / CBITMAP
		rep     movsb
		add     si, CSCRCOLUMN - COBJCOLUMN / CBITMAP
		add     di, CSCRCOLUMN - COBJCOLUMN / CBITMAP
		pop     cx
		loop    TOnObj_SNextLn

;               Hintergrundadresse bestimmen: es:[di]
;
		pop     di
		pop     ds
		pop     es

;               Anfangsadresse des Objekts bestimmen: es:[si]
;
		pop     cx
		push    cx
		mov     si, OFFSET AOBJECTSEQ
		add     si, dx
		mov     al, ds:[si]
		xor     ah, ah
		mov     dx, ax
		shl     ax, 2
		mov     si, OFFSET aoffsItem
		add     si, cx
		add     si, cx
		mov     si, ds:[si]
		add     si, ax

;               Adresse der Maske bestimmen: ds:bx
;
		mov     bx, OFFSET aoffsMask
		add     bx, cx
		add     bx, cx
		mov     bx, ds:[bx]
		mov     ax, COBJLINE * COBJCOLUMN / CBITMAP
		mul     dx
		add     bx, ax

;               Sequencer-Controller einstellen
;
		mov     dx, PRSEQUENCER
		mov     al, 002H
		out     dx, al
		inc     dx

;               Objekt auf Hintergrund kopieren
;
		mov     bp, ds
		mov     ax, SEGGFX
		mov     ds, ax
		mov     cx, COBJLINE
TOnObj_CNextLn: push    cx
		mov     cx, COBJCOLUMN / CBITMAP
TOnObj_CNextCl: push    ds
		mov     ds, bp
		mov     al, ds:[bx]
		pop     ds
		out     dx, al
		mov     al, ds:[si]
		mov     es:[di], al
		inc     bx
		inc     si
		inc     di
		loop    TOnObj_CNextCl
		add     si, CSCRCOLUMN - COBJCOLUMN / CBITMAP
		add     di, CSCRCOLUMN - COBJCOLUMN / CBITMAP
		pop     cx
		loop    TOnObj_CNextLn

		mov     ds, bp
		mov     al, 00FH
		out     dx, al

;               Nchstes Objekt
;
		pop     cx
		dec     cx
		js      TOnObj_End
		jmp     TOnObj_Next
TOnObj_End:     popa
		ret
TurnOnObjects   ENDP

TurnOffStars    PROC
		pusha
;               Sequencer-Controller einstellen
;
		call    DoneBlit
		mov     dx, PRSEQUENCER
		mov     al, 002H
		out     dx, al
		mov     dx, PRGRAPHICS
		mov     al, 004H
		out     dx, al
		mov     cx, CSTAR
		xor     di, di
		cmp     iFrame, 0
		jne     TOffStr_Page2
		mov     si, OFFSET awStarX
		jmp     TOffStr_Next
TOffStr_Page2:  mov     si, OFFSET awStarX + 2 * CSTAR
TOffStr_Next:   push    cx
		push    di
		mov     bx, ds:[si]
		mov     cl, bl
		and     cl, 3
		mov     al, 1
		shl     al, cl
		mov     dx, PRSEQUENCER + 1
		out     dx, al
		mov     al, cl
		mov     dx, PRGRAPHICS + 1
		out     dx, al
		shr     bx, 2
		add     di, bx
		mov     al, es:[di]
		cmp     al, CSTARCOLOR
		ja      TOffStr_No
		mov     BYTE PTR es:[di], 0
TOffStr_No:     add     si, 2
		pop     di
		add     di, CSCRCOLUMN
		pop     cx
		loop    TOffStr_Next
		call    InitBlit
		popa
		ret
TurnOffStars    ENDP

TurnOnStars     PROC
		pusha

;               Sequencer-Controller einstellen
;
		call    DoneBlit
		mov     dx, PRSEQUENCER
		mov     al, 002H
		out     dx, al
		mov     dx, PRGRAPHICS
		mov     al, 004H
		out     dx, al
		mov     cx, CSTAR
		xor     di, di
		cmp     iFrame, 0
		jne     TOnStr_Page2
		mov     si, OFFSET awStarX
		jmp     TOnStr_Next
TOnStr_Page2:   mov     si, OFFSET awStarX + 2 * CSTAR
TOnStr_Next:    push    cx
		push    di
		mov     ah, cl
		and     ah, 3
		inc     ah
		mov     bx, ds:[si]
		mov     cl, bl
		and     cl, 3
		mov     al, 1
		shl     al, cl
		mov     dx, PRSEQUENCER + 1
		out     dx, al
		mov     al, cl
		mov     dx, PRGRAPHICS + 1
		out     dx, al
		shr     bx, 2
		add     di, bx
		mov     al, es:[di]
		cmp     al, CSTARCOLOR
		ja      TOnStr_Above
		mov     es:[di], ah
TOnStr_Above:   add     si, 2
		pop     di
		add     di, CSCRCOLUMN
		pop     cx
		loop    TOnStr_Next
		call    InitBlit
		popa
		ret
TurnOnStars     ENDP

; *****************************************************************************
; Wandelt einen Buchstaben in einen Grobuchstaben um
; *****************************************************************************
UpCase          PROC
		cmp     Char, 'a'
		jnae    UpCase_End
		cmp     Char, 'z'
		ja      UpCase_End
		add     Char, 'A' - 'a'
UpCase_End:     ret
UpCase          ENDP

VoidProc        PROC
		ret
VoidProc        ENDP

; *****************************************************************************
; Wartet auf einen Tastendruck
; *****************************************************************************
WaitKey         PROC

;               Auf neuen Bildschirm warten
;
WaitKey_More:   call    ExpectPicture
		call    ExpectRetrace

;               Uhr weiterstellen
;
		cmp     ynLock, YES
		je      WaitKey_Locked
		inc     Timer

WaitKey_Locked: call    GetKey
		jc      WaitKey_More
		ret
WaitKey         ENDP

; ****************************************************************************
; Schaltet die Rahmenfarbe auf Wei
; ****************************************************************************
		IFDEF   _TEST
WhiteBorder     PROC
		push    ax
		push    dx
		mov     dx, 003C0H
		mov     al, 031H
		out     dx, al
		mov     al, 03FH
		out     dx, al
		pop     dx
		pop     ax
		ret
WhiteBorder     ENDP
		ENDIF

; ****************************************************************************
; Gibt eine Zeichenkette aus
; ****************************************************************************
Write           PROC
		pusha
		call    SaveAttributes
		mov     si, MBox_Text
		mov     dx, MBox_Left
		inc     dx
		mov     CursorX, dx
		mov     dx, MBox_Top
		inc     dx
		mov     CursorY, dx
Write_Next:     xor     ah, ah
		lodsb
		cmp     al, CHBACK
		je      Write_Back
		cmp     al, CHTEXT
		je      Write_Front
		cmp     al, CHPATTERN
		je      Write_Pattern
		cmp     al, CHFONT
		je      Write_Font

		mov     Char, ax
		call    GetCurOffset
		call    DoneBlit
		call    Print
		call    InitBlit

		inc     CursorX
		mov     ax, CursorX
		cmp     ax, MBox_Right
		jne     Write_Next

		inc     CursorY
		mov     ax, CursorY
		cmp     ax, MBox_Bottom
		je      Write_End

		mov     ax, MBox_Left
		inc     ax
		mov     CursorX, ax
		jmp     Write_Next

Write_Back:     lodsb
		mov     BackColor, al
		jmp     Write_Next

Write_Font:     lodsb
		shl     ax, 11
		add     ax, OFFSAAABFONTS
		mov     offsFont, ax
		jmp     Write_Next

Write_Front:    lodsb
		shl     ax, 4
		add     ax, OFFSET AABCOLOR
		mov     offsPalette, ax
		jmp     Write_Next

Write_Pattern:  lodsb
		shl     ax, 6
		add     ax, OFFSET AAPATTERN
		mov     offsPattern, ax
		jmp     Write_Next

Write_End:      call    LoadAttributes
		popa
		ret
Write           ENDP

Code            ENDS

		END     Main
		TITLE   'Connect'

		PAGE    66, 132

		P286
		MODEL   COMPACT

INCLUDE         INCLUDE\DOS.INC
INCLUDE         INCLUDE\KEYCODES.INC

STRWARN         EQU     KBLF, KBCR, '$'
CBBUFFER        EQU     01000H

Data            SEGMENT PUBLIC
		ASSUME  cs:Code, ds: Data

STREXTWRT       DB      '.WRT', 0
STREXTEXE       DB      '.EXE', 0
STRCOPYERROR    DB      'Can''t create EXE-File entirely.', STRWARN
STRCREATEERROR  DB      'Can''t create EXE-File.', STRWARN
STRFINDERROR    DB      'Can''t find WRT-File.', STRWARN
STROPENERROR    DB      'Can''t open WRT-File.', STRWARN
STRREADERROR    DB      'Can''t read from WRT-File.', STRWARN
STRWRITEERROR   DB      'Can''t write to EXE-File.', STRWARN
STRUSAGE        DB      'Usage: CONNECT <FileName>', STRWARN

cbLoEXE         =       $ + 2
cbHiEXE         =       $ + 4

ABFILE          LABEL
INCLUDE         PLAY.INC

CBFILE          =       OFFSET $ - OFFSET ABFILE

cbLoWrite       DW      ?
cbHiWrite       DW      ?
hWrite          DW      ?
hEXE            DW      ?
segFileName     DW      ?
offsFileName    DW      ?
offsExt         DW      ?

abBuffer        DB      CBBUFFER DUP (?)
Data            ENDS

Stack           0100H

Code            SEGMENT PUBLIC
		ASSUME  cs:Code, ds: Data

CloseEXE        PROC
		pusha
		mov     ah, DOS_CLOSE_FILE
		mov     bx, hEXE
		int     DOS_FUNCTION
		popa
		ret
CloseEXE        ENDP

CloseWrite      PROC
		pusha
		mov     ah, DOS_CLOSE_FILE
		mov     bx, hWrite
		int     DOS_FUNCTION
		popa
		ret
CloseWrite      ENDP

; *****************************************************************************
; Erstellung der ausfhrbaren Datei
; *****************************************************************************
CreateEXE       PROC
		pusha

;               Endung des Dateinamens ndern
;
		mov     di, offsExt
		mov     si, OFFSET STREXTEXE
		mov     cx, 5
		rep     movsb

;               Datei zur Ausgabe ffnen
;
		mov     ah, DOS_CREATE_FILE
		xor     cx, cx
		mov     dx, offsFileName
		push    ds
		push    es
		pop     ds
		int     DOS_FUNCTION
		pop     ds
		jc      CreateEXE_Error
		mov     WORD PTR hEXE, ax

;               Lnge in EXE-Kopf ndern
;
		mov     ax, WORD PTR cbLoWrite
		mov     dx, ax
		and     ax, 001FFH
		shr     dx, 9
		add     dx, WORD PTR cbHiWrite
		add     WORD PTR cbLoEXE, ax
		cmp     WORD PTR cbLoEXE, 00200H
		jnae    CreateEXE_NoOv
		sub     WORD PTR cbLoEXE, 00200H
		inc     WORD PTR cbHiEXE

CreateEXE_NoOv: add     WORD PTR cbHiEXE, dx
		clc
		jmp     CreateEXE_End

CreateEXE_Error:mov     dx, OFFSET STRCREATEERROR
		mov     ah, DOS_WRITE_STRING
		int     DOS_FUNCTION
		stc

CreateEXE_End:  popa
		ret
CreateEXE       ENDP

; *****************************************************************************
; Bestimmung des Dateinamens
; *****************************************************************************
GetWrite        PROC
		pusha

;               Kontrolle, ob Dateiname angegeben ist
;
		mov     WORD PTR segFileName, es
		mov     di, 080H
		mov     al, es:[di]
		or      al, al
		je      GetWrite_Help

;               Nullzeichen einfgen
;
		xor     ah, ah
		inc     di
		mov     si, di
		add     di, ax
		mov     es:[di], ah

;               Fhrende Leerzeichen berspringen
;
		mov     di, si
		mov     cx, ax
		mov     bx, ax
		mov     al, ' '
		repe    scasb
		or      cx, cx
		jne     GetWrite_Ok2
		mov     dx, WORD
		stc
		jmp     GetWrite_Error
GetWrite_Ok2:   dec     di
		mov     WORD PTR offsFileName, di

;               Endung suchen
;
		mov     di, si
		mov     cx, bx
		mov     al, '.'
		repne   scasb
		or      cx, cx
		jne     GetWrite_GetExt

;               Endung .WRT anfgen
;
		mov     WORD PTR offsExt, di
		mov     si, OFFSET STREXTWRT
		mov     cx, 5
		rep     movsb
		jmp     GetWrite_Ok

GetWrite_Error: mov     dx, OFFSET STRFINDERROR
		mov     ah, DOS_WRITE_STRING
		int     DOS_FUNCTION
		stc
		jmp     GetWrite_End

GetWrite_GetExt:dec     di
		mov     WORD PTR offsExt, di

GetWrite_Help:  mov     dx, OFFSET STRUSAGE
		mov     ah, DOS_WRITE_STRING
		int     DOS_FUNCTION
		stc
		jmp     GetWrite_End

GetWrite_Ok:    clc

GetWrite_End:   popa
		ret
GetWrite        ENDP

; *****************************************************************************
; Initialisierung der Register
; *****************************************************************************
Init            PROC
		push    ax
		mov     ax, SEG Data
		mov     ds, ax
		pop     ax
		ret
Init            ENDP

; *****************************************************************************
; Hauptteil
; *****************************************************************************
Main            PROC
		call    Init
		call    GetWrite
		jc      Main_End
		call    OpenWrite
		jc      Main_End
		call    CreateEXE
		jc      Main_CloseWrite
		call    WriteEXE
		call    CloseEXE
Main_CloseWrite:call    CloseWrite
Main_End:       mov     al, 0
		adc     al, al
		mov     ah, DOS_TERMINATE_EXE
		int     DOS_FUNCTION
Main            ENDP

OpenWrite       PROC
		pusha
		mov     ah, DOS_OPEN_FILE
		xor     al, al
		mov     dx, WORD PTR offsFileName
		push    ds
		push    es
		pop     ds
		int     DOS_FUNCTION
		pop     ds
		jc      OpenWrite_Error
		mov     WORD PTR hWrite, ax

;               Dateilnge bestimmen
;
		mov     ah, DOS_MOVE_FILE_POINTER
		mov     al, 2
		mov     bx, WORD PTR hWrite
		xor     cx, cx
		xor     dx, dx
		int     DOS_FUNCTION
		jc      OpenWrite_Error
		mov     WORD PTR cbHiWrite, dx
		mov     WORD PTR cbLoWrite, ax

;               Dateizeiger an Anfang setzen
;
		mov     ah, DOS_MOVE_FILE_POINTER
		mov     al, 0
		xor     dx, dx
		int     DOS_FUNCTION
		clc
		jmp     OpenWrite_End

;               Fehlermeldung ausgeben
;
OpenWrite_Error:mov     dx, OFFSET STROPENERROR
		mov     ah, DOS_WRITE_STRING
		int     DOS_FUNCTION
		stc

OpenWrite_End:  popa
		ret
OpenWrite       ENDP

WriteEXE        PROC
		pusha

;               Abspieler in EXE-Datei schreiben
;
		mov     ah, DOS_WRITE_TO_HANDLE
		mov     bx, hEXE
		mov     cx, CBFILE
		mov     dx, OFFSET ABFILE
		int     DOS_FUNCTION
		jc      WriteEXE_WErr
		cmp     ax, cx
		jne     WriteEXE_WErr

;               Datenblock aus Write-Datei lesen
;
WriteEXE_RNext: mov     ah, DOS_READ_FROM_HANDLE
		mov     bx, hWrite
		mov     cx, CBBUFFER
		mov     dx, OFFSET abBuffer
		int     DOS_FUNCTION
		jc      WriteEXE_RErr
		or      ax, ax
		je      WriteEXE_Done

;               Restlnge vermindern
;
		sub     WORD PTR cbLoWrite, ax
		jnc     WriteEXE_WNext
		dec     WORD PTR cbHiWrite

;               Datenblock in EXE-Datei schreiben
;
WriteEXE_WNext: mov     bx, hEXE
		mov     cx, ax
		mov     ah, DOS_WRITE_TO_HANDLE
		mov     dx, OFFSET abBuffer
		int     DOS_FUNCTION
		jc      WriteEXE_WErr
		cmp     ax, cx
		jne     WriteEXE_WErr
		jmp     WriteEXE_RNext

;               Kontrolle, ob die ganze Datei kopiert wurde
;
WriteEXE_Done:  cmp     cbLoWrite, 0
		jne     WriteEXE_CErr
		cmp     cbHiWrite, 0
		jne     WriteEXE_Cerr
		jmp     WriteEXE_End

WriteEXE_CErr:  mov     ah, DOS_WRITE_STRING
		mov     dx, OFFSET STRCOPYERROR
		int     DOS_FUNCTION
		stc
		jmp     WriteEXE_End

WriteEXE_RErr:  mov     ah, DOS_WRITE_STRING
		mov     dx, OFFSET STRREADERROR
		int     DOS_FUNCTION
		stc
		jmp     WriteEXE_End

WriteEXE_WErr:  mov     ah, DOS_WRITE_STRING
		mov     dx, OFFSET STRWRITEERROR
		int     DOS_FUNCTION
		stc

WriteEXE_End:   popa
		ret
WriteEXE        ENDP

Code            ENDS

		END     Main
