start: mov      ds,cs                   ;data segment = code segment
	jmp     s0                      ;jmp around
savbp: dw       0f000h                  ;train speed delay
s0:     call    scan400                 ;set 400 scan lines
	mov     ax,3
	int     10h                     ;clear the screen
	call    cursof                  ;turn off the cursor
	mov     es,0b800h               ;text mode video segment
	mov     ah,7                    ;medium white on black
	mov     di,line                 ;begin line, line address
	mov     si,0                    ;first video line location
	mov     cx,25                   ;do 25 lines

diz:    mov     al,[di]                 ;get character from line
	inc     di                      ;next character
	cmp     al,0                    ;ASCII terminated zero?
	jz      diz1                    ;if so, go to diz1
	mov     es:[si],ax              ;display ASCII + attribute
	add     si,2                    ;next video location
	jmp     diz                     ;get next one
diz1:   add    si,152                   ;next video line location
	loop    diz                     ;152 + 8 = 160 chars./line
	mov     di,msg1                 ;message to display
	mov     si,16                   ;top line - in 8 bytes
	call    diz12                   ;display it
	mov     di,msg1a                ;message to display
	mov     si,176                  ;2nd line - in 8 bytes
	call    diz12                   ;display it
	mov     di,msg2                 ;message to display
	mov     si,3856                 ;bottom line - in 8 bytes
	call    diz12                   ;display it

	call    wait1                   ;await key press

	mov     ah,1                    ;start medium blue on black
	mov     di,>s0                  ;list 7 medium colors
	mov     si,844                  ;video start address
	mov     cx,7
	call    diz2                    ;display

	mov     ah,9                    ;start bright blue on black
	mov     di,>s1                  ;list 7 bright colors
	mov     si,1964                 ;video location to start diz2
	mov     cx,7                    ;display 7 lines
	call    diz2                    ;display
	call    wate                    ;await key press

diz2:   mov    al,[di]                  ;get character to display
	inc     di                      ;next one
	cmp     al,0                    ;test for zero end of string
	jz      diz3                    ;if so, go to diz3
	mov     es:[si],ax              ;display ASCII char.+ attribute
	add     si,2                    ;next video mem address
	jmp     diz2                    ;continue
diz3: inc    ah                         ;next color
	add     si,98                   ;next video mem to display
	loop    diz2                    ;display 7 lines bright colors
	ret                             ;return to next after call

wate:   call      wait1                 ;await key press

	mov     al,218                  ;┌ character
	mov     ah,15                   ;bright white attribute
	mov     es:[682],ax             ;display at 682 video
	mov     si,684                  ;next video address
	mov     al,196                  ;─ character
	mov     cx,31                   ;31 chars. +31 attribs. display
diz4: mov       es:[si],ax              ;display
	add     si,2                    ;next
	loop    diz4                    ;do 31 times
	mov     al,191                  ;┐ character
	mov     es:[si],ax              ;display
	mov     al,179                  ;│ character
	mov     cx,14                   ;14 vertical │
	add     si,160                  ;next line below
diz5: mov       es:[si],ax              ;display
	add     si,160                  ;next below
	loop    diz5                    ;do 14 times
	mov     al,217                  ;┘ character
	mov     es:[si],ax              ;display
	sub     si,2                    ;1 character left
	mov     al,196                  ;─ character
	mov     cx,31                   ;31 chars +31 attribs. display
diz6: mov       es:[si],ax              ;display
	sub     si,2                    ;move left
	loop    diz6                    ;do 31 times
	mov     al,192                  ;└ character
	mov     es:[si],ax              ;display
	sub     si,160                  ;next line above
	mov     al,179                  ;│ character
	mov     cx,14                   ;14 vertical │
diz7: mov       es:[si],ax              ;display
	sub     si,160                  ;next line above
	loop    diz7                    ;do 14 times

	call    wait1                   ;await key press

	mov     al,201                  ;╔ character
	mov     ah,15                   ;bright white attribute
	mov     es:[682],ax             ;display at 682 video
	mov     si,684                  ;next video address
	mov     al,205                  ;═ character
	mov     cx,31                   ;31 chars. +31 attribs. display
diz8: mov       es:[si],ax              ;display
	add     si,2                    ;next
	loop    diz8                    ;do 31 times
	mov     al,187                  ;╗ character
	mov     es:[si],ax              ;display
	mov     al,186                  ;║ character
	mov     cx,14                   ;14 vertical ║
	add     si,160                  ;next line below
diz9: mov       es:[si],ax              ;display
	add     si,160                  ;next below
	loop    diz9                    ;do 14 times
	mov     al,188                  ;╝ character
	mov     es:[si],ax              ;display
	sub     si,2                    ;1 character left
	mov     al,205                  ;═ character
	mov     cx,31                   ;31 chars +31 attribs. display
diz10: mov      es:[si],ax              ;display
	sub     si,2                    ;move left
	loop    diz10                   ;do 31 times
	mov     al,200                  ;╚ character
	mov     es:[si],ax              ;display
	sub     si,160                  ;next line above
	mov     al,186                  ;║ character
	mov     cx,14                   ;14 vertical ║
diz11: mov      es:[si],ax              ;display
	sub     si,160                  ;next line above
	loop    diz11                   ;do 14 times

	call    wait1                   ;await key press

	mov     ax,3
	int     10h                     ;clear the screen
	call    cursof                  ;must do after cls above
	mov     di,aa1                  ;characters to display
	mov     si,1120                 ;start here on video display
	call    diz12                   ;display them

	call    wait1                   ;await key press

	mov     ax,3
	int     10h                     ;clear the screen
	call    cursof                  ;must do after cls above
	mov     di,aa2                  ;characters to display
	mov     si,320                  ;start here on video display
	call    diz12                   ;display them

	call    wait1                   ;await key press

	mov     ax,3
	int     10h                     ;clear the screen
	call    cursof                  ;must do after cls above
	mov     di,aa3                  ;characters to display
	mov     si,0                    ;start here on video display
	call    diz12                   ;display them

	call    wait1                   ;await key press

	call    scan350                 ;350 scan lines text mode
	mov     ax,3
	int     10h                     ;cls
	call    cursof
	call    setalfa                 ;set custom character table
	push    es
	mov     ax,1002h                ;set 17 palette registers
	mov     es,cs
	mov     dx,palette              ;0-7 and 8-15 identical colors
	int     10h
	pop     es
	call    delay1                  ;wait 1 1/2 seconds
	mov     di,train1               ;train text
	mov     si,0
	call    diz12                   ;display at top of page
	call    track                   ;lay down train track
	mov     cx,[savbp]              ;train speed delay countdown
	call    dizspd                  ;display it

tt0:    mov     ah,7                    ;medium white
	mov     di,rt1                  ;first train`s 15 bytes
	mov     si,1250

t1:     mov     dl,8
t2:     call    >u0
	dec     dl
	jnz     t2
	cmp     si,1442
	ja      >t3
	mov     ah,20h
	mov     es:[si-162],ah
t3:     mov     ah,61                   ;simulated smoke
	cmp     si,1412
	ja      >t4
	cmp     si,1254
	jb      >t4
	mov     es:[si-134],ah          ;show smoke
t4: call        chekey
	mov     ah,7                    ;attribute
	cmp     si,1440                 ;end of bottom line +
if ae jmp       p0a
	mov     di,rt1                  ;1st train`s 15 bytes
	add     si,2
	mov     es:[si-2] b,20h         ;clear last cabose byte
	jmp     t1

u0:     push    si                      ;save start for 8 trains
	mov     cx,15                   ;display train's 15 bytes
u1:     mov     al,[di]
	inc     di
	cmp     si,1438
	ja      u2
	cmp     si,1280
	jb      u2
	mov     es:[si],ax
u2:     add     si,2
	loop    u1
	pop     si
	mov     bp,cs:[savbp]           ;countdown train delay
u3:     dec     bp
	jnz     u3
	ret

p0a: call       movdn1
	call    setalfa
	mov     ah,7
	mov     di,rt1                  ;first train`s 15 bytes
	mov     si,1440+480

p1:     mov     dl,8
	push    ax
	mov     ah,0
;       int     16h
	pop     ax
p2:     call    vv0
	dec     dl
	jnz     p2
	cmp     si,1246+480
	jb      p2a
	mov     es:[si-130] b,20h
p2a:    mov     ah,61                   ;simulated smoke
	cmp     si,1278+480
	jb      p2b
	cmp     si,1436+480
	ja      p2b
	mov     es:[si-158],ah          ;show smoke
p2b: call       chekey                  ;check keyboard
pp3:    mov     ah,7
	cmp     si,1250+480             ;begin of bottom line
	jbe     >p4
	mov     di,rt1                  ;1st train`s 15 bytes
	sub     si,2
	jmp     p1
p4:     call    movdn2
	call    setalfa
	jmp     tt1

vv0:    push    si                      ;save start for 8 trains
	mov     cx,15                   ;display train's 15 bytes
v1:     mov     al,[di]
	inc     di
	cmp     si,1280+480
	jb      v2a
	cmp     si,1438+480
	ja      v2a
	mov     es:[si],ax
v2a: add        si,2
	loop    v1
	cmp     si,1438+480
	ja      >v2
	mov     al,32                   ;space
	cmp     si,1440+480
if z    mov     al,205
	mov     es:[si],al
v2:     pop     si
v2b:    mov     bp,cs:[savbp]           ;countdown train delay
v3:     dec     bp
	jnz     v3
	ret

tt1:    mov     ah,7                    ;medium white
	mov     di,rt1                  ;first train`s 15 bytes
	mov     si,1250+960

t1:     mov     dl,8
t2:     call    >u0
	dec     dl
	jnz     t2
	cmp     si,2242
	jb      >t3
	mov     ah,20h
	mov     es:[si-162],ah
t3:     mov     ah,61                   ;simulated smoke
	cmp     si,1412+960
	ja      >t4
	cmp     si,1254+960
	jb      >t4
	mov     es:[si-134],ah          ;show smoke
t4: call        chekey
	mov     ah,7                    ;attribute
	cmp     si,1440+960             ;end of line
if ae jmp       p0b
	mov     di,rt1                  ;1st train`s 15 bytes
	add     si,2
	mov     es:[si-2] b,20h         ;clear last cabose byte
	jmp     t1

u0:     push    si                      ;save start for 8 trains
	mov     cx,15                   ;display train's 15 bytes
u1:     mov     al,[di]
	inc     di
	cmp     si,1280+960
	jb      >u2
	cmp     si,1438+960
	ja      >u2
	mov     es:[si],ax
u2: add si,2
	loop    u1
u3:     pop     si
	mov     bp,cs:[savbp]           ;countdown train delay
u4:     dec     bp
	jnz     u4
	ret

p0b: call       movdn1
	call    setalfa
	mov     ah,7
	mov     di,rt1                  ;first train`s 15 bytes
	mov     si,1440+1440

p1:     mov     dl,8
	push    ax
	mov     ah,0
;       int     16h
	pop     ax
p2:     call    >v0
	dec     dl
	jnz     p2
	cmp     si,1246+1440
	jb      >p3
	mov     es:[si-130] b,20h
p3:     mov     ah,61                   ;simulated smoke
	cmp     si,1278+1440
	jb      >p4
	cmp     si,1436+1440
	ja      >p4
	mov     es:[si-158],ah          ;show smoke
p4:     call    chekey
p5:     mov     ah,7
	cmp     si,1250+1440            ;begin of bottom line
	jbe     >p6
	mov     di,rt1                  ;1st train`s 15 bytes
	sub     si,2
	jmp     p1
p6:     call    movdn2
	call    setalfa
	jmp     tt2

v0:     push    si                      ;save start for 8 trains
	mov     cx,15                   ;display train's 15 bytes
v1:     mov     al,[di]
	inc     di
	cmp     si,1280+1440
	jb      >v2
	cmp     si,1438+1440
	ja      >v2
	mov     es:[si],ax
v2: add si,2
	loop    v1
	cmp     si,1438+1440
	ja      >v3
	mov     al,32                   ;space
	cmp     si,1440+1440
if z    mov     al,205
	mov     es:[si],al
v3:     pop     si
	mov     bp,cs:[savbp]           ;countdown train delay
v4:     dec     bp
	jnz     v4
	ret

tt2:    mov     ah,7                    ;medium white
	mov     di,rt1                  ;first train`s 15 bytes
	mov     si,1250+1920

t1:     mov     dl,8
t2:     call    >u0
	dec     dl
	jnz     t2
	cmp     si,2242+960
	jb      >t3
	mov     ah,20h
	mov     es:[si-162],ah
t3:     mov     ah,61                   ;simulated smoke
	cmp     si,1412+1920
	ja      >t4
	cmp     si,1254+1920
	jb      >t4
	mov     es:[si-134],ah          ;show smoke
t4: call        chekey                  ;check keyboard ?
	mov     ah,7                    ;reset attribute
	cmp     si,1440+1920            ;end of line
if ae jmp       tt0
	mov     di,rt1                  ;1st train`s 15 bytes
	add     si,2
	mov     es:[si-2] b,20h         ;clear last car byte
	jmp     t1

u0:     push    si                      ;save start for 8 trains
	mov     cx,15                   ;display train's 15 bytes
u1:     mov     al,[di]
	inc     di
	cmp     si,1280+1920
	jb      >u2
	cmp     si,1438+1920
	ja      >u2
	mov     es:[si],ax
u2: add si,2
	loop    u1
u3:     pop     si
	mov     bp,cs:[savbp]           ;countdown train delay
u4:     dec     bp
	jnz     u4
	ret

chekey: mov     ah,1                    ;check keyboard
	int     16h
if z    ret                             ;no key pressed so return
	pop     dx                      ;return address in dx
	mov     ah,0
	int     16h                     ;unload keyboard buffer
	push    ax
	call    clrkey                  ;wait for key release
	pop     ax
	cmp     ah,1                    ;Esc key
if z    jmp     >w2                     ;exit to DOS> prompt
	cmp     ah,1ch                  ;enter key pressed ?
if z    jmp     tt7                     ;exit to next text page
	cmp     ah,48h                  ;up arrow
if z    jmp     speedup                 ;speed up train
	cmp     ah,50h                  ;down arrow
if z    jmp     slowdn                  ;slow down train
	jmp     dx                      ;return call+next instruction

diz12: mov      ah,7                    ;medium white
z1:     mov     al,[di]                 ;character to display
	inc     di                      ;next one
	cmp     al,0                    ;end ?
if z    ret                             ;if so, return - all done
	mov     es:[si],ax              ;diz character + attribute
	add     si,2                    ;next
	jmp     diz12

wait1: mov      ah,0
	int     16h                     ;await key press
	cmp     ah,1                    ;Esc key ?
	jz      >w1                     ;if so, go to >w1
	call    clrkey                  ;wait key release+clr kybd buf
	ret                             ;return to call +1 instruct.
w1:     pop     ax                      ;adjust for call
w2:     call    scan400                 ;VGA text mode 400 scanlines
	mov     ax,3
	int     10h                     ;clear the screen (cls)
	call    curson                  ;turn cursor back on
	call    resetalf                ;standard alphabet +
	mov     ax,4c00h
	int     21h                     ;exit to DOS> prompt

wait2: mov      ah,0
	int     16h                     ;await key press
	cmp     ah,1                    ;Esc key ?
	jz      w1                      ;backward jmp no >
	pop     ax                      ;adjust stack for cal
	jmp     start                   ;ok, start over - no Esc key

line:                                ;these are zero term. strings
db '0   ',0,'160 ',0,'320 ',0,'480 ',0,'640 ',0,'800 ',0
db '960 ',0,'1120',0,'1280',0,'1440',0,'1600',0,'1760',0,'1920',0,
db '2080',0,'2240',0,'2400',0,'2560',0,'2720',0,'2880',0,'3040',0,
db '3200',0,'3360',0,'3520',0,'3680',0,'3840',0

s0:
db  'This is medium blue    on black',0
db  'This is medium green   on black',0
db  'This is medium cyan    on black',0
db  'This is medium red     on black',0
db  'This is medium magenta on black',0
db  'This is medium orange  on black',0
db  'This is medium white   on black',0
s1:
db  'This is bright blue    on black',0
db  'This is bright green   on black',0
db  'This is bright cyan    on black',0
db  'This is bright red     on black',0
db  'This is bright magenta on black',0
db  'This is bright yellow  on black',0
db  'This is bright white   on black',0

msg1:
db 'These are the video display`s 25 line starting addresses in text mode.',0
msg1a:
db 'Each 80 byte line alternates an ASCII byte then attribute = 160 bytes.',0


msg2:
db 'Press enter to continue or repeat.  Use Esc to exit to DOS> prompt.',0

curson: mov  ah,1                    ;set cursor type
	mov     cx,0607h                ;cursor type
	int     10h                     ;do it
	mov     dx,0                    ;cursor position
	jmp     >c1                     ;> = forward jump
cursof: mov  dx,1900h                ;cursor out of view on text
c1:  mov     ah,2                    ;set cursor position
	mov     bh,0                    ;page zero in text mode
	int     10h                     ;do it
	ret                             ;return to call+next instruct.

aa1:
db '     The following diagrams illustrate how the attribute byte works:            '
db '                                                                                '
db '                        7   6 5 4   3   2 1 0   <-- attribute bits              '
db '                      ┌───┬───────┬───┬───────┐                                 '
db '                      │ BL│ R G B │ I │ R G B │                                 '
db '                      └─┬─┴───┬───┴─┬─┴───┬───┘                                 '
db '                        │ background│ foreground                                '
db ' Blinking bit───────────┘           └──────────────Intensity bit                '
db '   0 = not blinking                                  0 = normal intensity       '
db '   1 = blinking                                      1 = high intensity         '
db 0

aa2:
db '             ┌─────────────────────────────────────────────┐                    '
db '             │      Foreground/Background Color codes      │                    '
db '             ├────────────────────┬────────────────────────┤                    '
db '             │ R G B     Color    │                        │                    '
db '             ├────────┬───────────┤                        │                    '
db '             │ 0 0 0  │  Black    │                        │                    '
db '             │ 0 0 1  │  Blue     │ Setting the "I" - bit  │                    '
db '             │ 0 1 0  │  Green    │ will result in 8       │                    '
db '             │ 0 1 1  │  Cyan     │ additional shades of   │                    '
db '             │ 1 0 0  │  Red      │ these 8 colors for     │                    '
db '             │ 1 0 1  │  Magenta  │ the foreground color.  │                    '
db '             │ 1 1 0  │  Yellow   │->(or medium orange)    │                    '
db '             │ 1 1 1  │  White    │                        │                    '
db '             └────────┴───────────┴────────────────────────┘                    '
db '                                                                                '
db '             ┌────────────┬────────────┬───────────────────┐                    '
db '             │ Foreground │ Background │ Color Graphics    │                    '
db '             ├────────────┼────────────┼───────────────────┤                    '
db '             │    1 1 1   │    0 0 0   │  normal display   │                    '
db '             │    0 0 0   │    1 1 1   │  reverse video    │                    '
db '             └────────────┴────────────┴───────────────────┘                    '
db 0
aa3:
db 'To draw extended ASCII characters on the IBM PC and compatibles in text         '
db 'mode, press the Alt key and the 3 numbers illustrated below using the right     '
db 'hand keypad keys.  This works with EDLIN.COM, EDIT.COM and a number of          '
db 'word processing programs.                                                       '
db '                                                                                '
db '         218 ┌        194 ┬            ─ 196               ┐ 191                '
db '                                                                                '
db '         195 ├        197 ┼            │ 179               ┤ 180                '
db '                                                                                '
db '         192 └        193 ┴            ─ 196               ┘ 217                '
db '                                                                                '
db '             ╔════════════╦════════════╦═══════════════════╗                    '
db '             ║ Foreground ║ Background ║ Color Graphics    ║                    '
db '             ╠════════════╬════════════╬═══════════════════╣                    '
db '             ║    1 1 1   ║    0 0 0   ║  normal display   ║                    '
db '             ║    0 0 0   ║    1 1 1   ║  reverse video    ║                    '
db '             ╚════════════╩════════════╩═══════════════════╝                    '
db '                                                                                '
db 'For double lines as illustrated above, use Alt plus keypad values below.        '
db '                                                                                '
db '         201 ╔        203 ╦            ═ 205               ╗ 187                '
db '                                                                                '
db '         204 ╠        206 ╬            ║ 186               ╣ 185                '
db '                                                                                '
db '         200 ╚        202 ╩            ═ 205               ╝ 188                '
db 0

ALF1: db 'C:\ALFA\TBLK.OBJ',0,0

LDALFA: push ds                 ;load custom alphabet +
	MOV     AX,3D00H
	MOV     DX,ALF1                 ;file name
	INT     21H                     ;open
	MOV     BX,AX
	MOV     AH,3FH
	MOV     DX,0                    ;start ds zero
	MOV     DS,5000H                ;use 5000h data segment
	MOV     CX,4096                 ;4096 bytes long
	INT     21H                     ;read
	NOP
	MOV     AH,3EH
	INT     21H                     ;close
	POP     DS

resetalf: mov ah,11h                    ;reset standard VGA alphabet
	mov     al,4                    ;8 x 16 VGA characters
	mov     bl,0                    ;table zero
	int     10H
	ret

setalfa: push es                        ;enable custom character set 1
	mov     al,0                    ;user created table
	mov     ah,11h                  ;character generator interface
	mov     bh,16                   ;16 bytes per character
	mov     bl,0                    ;table zero
	mov     cx,256                  ;number characters in table
	mov     dx,0                    ;ASCII code first character
	mov     es,cs                   ;segment where loaded
	mov     bp,alfaobj              ;where loaded in segment
	int     10h                     ;do it
	pop     es
	ret

scan350: mov    ax,1201h
	mov     bl,30h
	int     10h                     ;set EGA's 350 scan lines
	ret                             ;in text mode

scan400: mov ax,1202h
	mov     bl,30h
	int     10h                     ;set VGA's 400 scan lines
	ret                             ;in text mode

delay1: pusha
	mov     ah,0                    ;read
	int     1ah                     ;time of day
	add     dx,27                   ;wait about 1 1/2 seconds
	mov     bx,dx                   ;store 1/100ths seconds in bx
e1:     int     1ah                     ;read
	cmp     dx,bx
	jne     e1
	popa
	ret

speedup: mov    ax,cs:[savbp]
	cmp     ax,1000h
	jbe     >o1
	sub     ax,1000h
	mov     cs:[savbp],ax
o1:     mov     cx,ax
	call    dizspd                  ;display speed count down
	call    clrln5
	call    movdn2
	call    setalfa
	jmp     tt0

slowdn: mov     ax,cs:[savbp]
	cmp     ax,0f000h
	jae     o1
	add     ax,1000h
	mov     cs:[savbp],ax
	jmp     o1                      ;jump back to o1 above

spd: db 'speed delay',0

dizspd: mov     di,spd
	mov     si,3966
	call    diz12
	call    unsign                  ;convert cx hex to ascii
	mov     di,dezmal
	mov     al,[di]
	cmp     al,'8'
	jnz     >d2
	mov     al,[di+1]
	cmp     al,'1'
	jnz     >d2
	mov     [di+4] b,' '            ;fix error
d2:     mov     al,[di+2]
	cmp     al,'9'
	jnz     >d3
	mov     al,[di+3]
	cmp     al,'6'
	jnz     >d3
	mov     al,[di+4]
	cmp     al,'8'
	jnz     >d3
	mov     [di+4] b,' '            ;fix error
d3:     mov     si,3990
	call    diz12                   ;and display it at 3990
	mov     di,dezmal
	mov     al,0
	mov     cx,8
d4:     mov     [di],al
	inc     di
	loop    d4
	ret

clrln5: mov     ax,720h                 ;clear train & smoke
	mov     si,1120
	mov     cx,160                  ;clear 2 lines
c1:     mov     es:[si],ax
	add     si,2
	loop    c1
	mov     si,1600
	mov     cx,160
c2:     mov     es:[si],ax
	add     si,2
	loop    c2
	mov     si,2080
	mov     cx,160                  ;clear 2 lines
c3:     mov     es:[si],ax
	add     si,2
	loop    c3
	mov     si,2560
	mov     cx,160
c4:     mov     es:[si],ax
	add     si,2
	loop    c4
	mov     si,3040
	mov     cx,160
c5:     mov     es:[si],ax              ;5th and last 2 lines
	add     si,2
	loop    c5
	ret             ;above simplified for teaching newcomers

train1:
db 'This page illustrates text mode animation^  Was written for my grandson a few   '
db 'years ago^ It is a circus train pulling a giraffe car and passenger car^        '
db 'Speed delay is from 61440 very slow to 4096 fast^  Much faster blurs the screen^'
db 'Use the keypad`s up arrow to speed up the train or down arrow to slow it down^  '
db '                                                                                '
db 'To continue please press Enter or the Esc key to exit to the DOS> prompt^       ',0

;rt1 thru rt8 that follow are the train's 15 each 8 bit bytes shifted  1 bit by using my ALFA.COM draw text characters program in ALPHA.ZIP.
rt1: db 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
rt2: db 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
rt3: db 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47
rt4: db 123,124,125,126,127,128,129,130,131,132,133,134,135,136,137
rt5: db 138,139,140,141,142,143,144,145,146,147,148,149,150,151,152
rt6: db 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167
rt7: db 226,227,228,229,230,231,232,233,234,235,236,237,238,239,240
rt8: db 241,242,243,244,245,246,247,248,249,250,251,252,253,254,255

track: mov      dl,5                    ;5 tracks
	mov     si,1440                 ;line below train
t0:     mov     cx,80
	push    si
t1:     mov     es:[si],07cdh           ;lay down track
	add     si,2
	loop    t1
	pop     si
	add     si,480
	dec     dl
	jnz     t0
	ret

palette: db 0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0

movdn1: mov     di,alfaobj
	add     di,4096
m0:     mov     si,alfaobj
	mov     cx,2048
m1:     mov     ax,[di]
	add     di,2
	mov     [si],ax
	add     si,2
	loop    m1
	ret

movdn2: mov     di,alfaobj
	add     di,8192
	jmp     m0

beep: pusha
	mov     ah,2
	mov     dl,7
	int     21h
	popa
	ret

DEZMAL: DB 9 DUP(0)

UNSIGN: PUSHA                   ;CONV CX TO ASCII DECIMAL
	MOV     DS,CS
	MOV     DI,DEZMAL
	MOV     SI,MULT1
Z1:     XOR     AL,AL
	MOV     DH,[SI+1]
	MOV     DL,[SI]
Z2:     OR      AL,AL
	SUB     CX,DX
	JC      >Z3
	INC     AL
	JMP     Z2
Z3:     ADD     CX,DX
	ADD     AL,48
	CMP     AL,48
	JZ      SUPRES
	PUSH    AX
	MOV     AL,1
	MOV     [NOSUPR],AL
Z4:     POP     AX
	MOV     [DI],AL
	INC     DI
Z5:     ADD     SI,2
	MOV     AL,1
	CMP     AL,DL
	JZ      >Z6
	JMP     Z1
Z6:     MOV     AL,[NOSUPR]
	CMP     AL,0
IF Z    CALL    ZEROIT
	XOR     AL,AL
	MOV     [DI],AL
	MOV     [NOSUPR],AL
	POPA
	RET
SUPRES: PUSH    AX
	MOV     AL,[NOSUPR]
	CMP     AL,0
	JZ      >Z7
	JMP     Z4
Z7:     POP     AX
	JMP     Z5
ZEROIT: MOV     DI,DEZMAL
	MOV     [DI] B,48
	INC     DI
	RET
NOSUPR: DB      0
MULT1: DW       10000
	DW      1000
	DW      100
	DW      10
	DW      1

animate:
db '         DOING ANIMATION IN TEXT MODE IS DIFFERENT THAN GRAPHICS MODE           '
db '                                                                                '
db 'The reason this is a fact is that VGA graphics mode (640 bits wide by 480 bits  '
db 'in height), allows the programmer to easily program each bit in each of the 480 '
db 'lines.  This is done using any paint program such as the Windows `Paintbrush.`  '
db '                                                                                '
db 'In VGA or EGA text mode, we usually have each of the 256 characters available   '
db 'occupying 8 bits in width by 14 (EGA) or 16 (VGA) bytes in height.              '
db '                                                                                '
db 'As such, one cannot rotate a text character right or left without totally       '
db 'destroying the character`s coherence.  Therefore, text mode animation is truly  '
db 'a different animal!                                                             '
db '                                                                                '
db 'By using the ALFA.COM program I wrote years ago, one may create 8 different 15  '
db 'byte long custom characters representing the little train we viewed on the last '
db 'page.  By drawing right (RCR =) 1 bit of each of the 16 bytes that make up each '
db 'character in the 15 character train, we can achieve the text mode animation     '
db 'displayed on the last page.                                                     '
db '                                                                                '
db 'It is not truly an enervating experience drawing 8 x 16 pixels = 128 pixels per '
db 'character for 8x15 characters which = 15,360 pixels redrawn, but it can be fun. '
db 'Using the ALFA.COM text character creation/drawing program can make it easier   '
db 'than it sounds since a Microsoft mouse takes all the real drugery out of it.    '
db '                                                                                '
db '            Press enter to continue or Esc to exit to DOS> prompt.              ',0

animate2:
db '                      HOW 2 DIFFERENT TRAINS WERE DISPLAYED                     '
db '                                                                                '
db 'Understandably, two different trains (going different directions), cannot be    '
db 'displayed using the same 256 byte character table if one needs to include the   '
db 'standard upper and lower case alphabet characters too.  One approach is to use  '
db 'use the BIOS` capability of using 2 character tables with the displayed         '
db 'character chosen from table 2 by setting bit 3 of its attribute (color, etc.).  '
db '                                                                                '
db 'But what if you wish to use 3 or more character tables?  The BIOS select table  '
db 'routine is incredibly slowsville...on the order of seconds even when using a    '
db '100 MHz clocked Pentium.  The solution is simply to concatenate those additional'
db 'character sets you wish to use with your program onto the program itself.  To do'
db 'so, let us assume the last line of your program end ends with the label ALFAOBJ:'
db 'Assemble the program using Eric Issacson`s brilliant A386 assembler.  Then write'
db 'a little batch file named copyall.bat as follows:                               '
db '                                                                                '
db '            1: copy tutor5.com/b+tblk.obj+tblj.obj+tblk.obj                     '
db '                                                                                '
db 'Note the /b above. It tells copy to treat the files as binary and may have 0`s. '
db 'Assuming that you are using VGA character sets which use 4096 bytes of memory   '
db 'all one needs do to access any of the character sets is just to move the        '
db 'character set down to the 4096 byte buffer provided by the 1st tblk.obj above   '
db 'and use interrupt 10h`s subfunction AH = 11H and ES:BP pointing to your buffer. '
db 'Please study TUTOR5.ASM, this program`s source code to see how it is done.      '
db '            Press enter to continue or Esc to exit to DOS> prompt.              ',0
animate3:
db '                    EMBEDDING GRAPHICS FILES IN YOUR PROGRAM                    '
db 'Why bother?  It saves the user the trouble of setting up a subdirectory that you'
db 'specify so your program can find the graphics files it wishes to load, plus     '
db 'saving the user the trouble of moving the graphics file to that subdirectory.   '
db 'Here is how TUTOR.COM`s VGA graphics files are embedded using the copyall.bat   '
db 'file again.                                                                     '
db '                                                                                '
db '     1: copy tutor5.com/b+tblk.obj+tblj.obj+tblk.obj+texta.pcx+textb.pcx        '
db '                                                                                '
db 'So how does the VGA graphics unpacking routine, (only 100+ lines of code), know '
db 'how to find them?  It is easy.  We know the size of each of the three 4096 byte '
db 'custom alphabet tables so texta.pcx MUST start at alfaobj: plus 12,288 bytes.   '
db 'TEXTA.PCX is 17,410 bytes long so textb.pcx must start at alfaobj: plus 12,288 +'
db '17,410 = 28,490.                                                                '
db '                                                                                '
db 'The next 2 pages are VGA 16 color graphics pages depicting the output of our    '
db 'customizing text table program called ALFA.COM.  The first one shows the custom '
db '8 by 15 each train characters moving right.  The second one shows the custom 8  '
db 'by 15 each train characters moving left.                                        '
db '                                                                                '
db 'If you wish to backup from the second graphics page to the first one, please    '
db 'press the minus key.  Tutor5.com has a neat little 10 line routine in it called '
db 'clrkey that waits for the user to release a key and then clears the keyboard    '
db 'buffer.  See the tutor.asm source code.                                         '
db '            Press enter to continue or Esc to exit to DOS> prompt.              ',0





tt7: call       scan400                 ;set 400 VGA text scan lines
	mov     ax,3
	int     10h                     ;cls
	call    cursof                  ;cursor off
	call    resetalf                ;reset standard alphabet
	mov     di,animate              ;text page 
	mov     si,0
	call    diz12                   ;display whole page
	call    wait1
	mov     di,animate2             ;text page 
	mov     si,0
	call    diz12                   ;display whole page
	call    wait1
	mov     di,animate3
	mov     si,0
	call    diz12                   ;display whole page
	call    wait1
tt8:    pusha
	mov     di,alfaobj+12288
	mov     ds,6000h
	mov     si,0
	mov     cx,17410
x1:     mov     al,cs:[di]
	inc     di
	mov     [si],al
	inc     si
	loop    x1
	mov     ds,cs
	call    unpakw4
	popa
	mov     ds,cs
	call    wait1
	pusha
	mov     di,alfaobj+29698
	mov     ds,6000h
	mov     si,0
	mov     cx,19644
x2:     mov     al,cs:[di]
	inc     di
	mov     [si],al
	inc     si
	loop    x2
	mov     ds,cs
	call    unpakw4
	popa
	mov     ds,cs
	mov     ah,0
	int     16h
	push    ax
	call    clrkey
	pop     ax
	cmp     ah,0ch                  ;minus key pressed ?
if z    jmp     tt8                     ;if so, back to last graphics
	jmp     start

clrkey: pusha                   ;wait for key release
k0:     in      al,60h                  ;keyboard port
	test    al,80h                  ;key down ?
	jz      k0                      ;if so, wait for release
	cli                             ;clear interrupts
	mov     ds,0
	mov     ds:al,[41ah]            ;clear keyboard's circular
	mov     ds:[41ch],al            ;buffer.
	mov     ds,cs
	sti                             ;set interrupts
	popa
	ret

UNPAKW4:;CALL WMEM4 not needed. TUTOR5.COM has .pcx's embedded.
VSEG3: MOV      ES,0A000H               ;EGA/VGA VIDEO SEGMENT
	CLD
	MOV     AX,6000H
	MOV     DS,AX
	CALL    PCXPAL                  ;DECODE PCX 16 COLORS
VS3:    MOV     CS:BP,480               ;NO. SCAN LINES TO WRITE
	MOV     DX,3C4H                 ;SEQUENCER REGISTER PORT
	MOV     CS:BX,80                ;BYTES/LINE
	XCHG    BL,BH
	MOV     SI,80H                  ;BEGIN PACKED DATA
	MOV     CX,0                    ;CL= NO. CARRY CH=VIDEO VALUE
UU0:    MOV     DI,0                    ;START IN A000H
U1:     MOV     AX,102H                 ;ENABLE WRITE PLANE 0
	OUT     DX,AX                   ;SEQUENCER REGISTER PORT
	CALL    UPCX                    ;UNPACK AND WRITE TO PLANE
	MOV     AX,202H                 ;ENABLE WRITE PLANE 1
	OUT     DX,AX
	CALL    UPCX
	MOV     AX,402H                 ;ENABLE WRITE PLANE 2
	OUT     DX,AX
	CALL    UPCX
	MOV     AX,802H                 ;ENABLE WRITE PLANE 3
	OUT     DX,AX
	CALL    UPCX
	ADD     DI,80                   ;NEXT SCAN LINE 8x80=640 PELS
	DEC     BP                      ;LINE COUNTER=350 or 480 LINES
	JNZ     U1                      ;             EGA    VGA
	MOV     DS,CS
	RET
UPCX: PUSH      DI                      ;VIDEO MEM ADDRESS OF PLANE
	MOV     BL,BH                   ;BH=BYTES/LINE
	CMP     CL,0                    ;CL=NUMBER CARRY CH=PIXEL
	JNZ     >X4                     ;DO BALANCE OF LAST RLL
X1:     MOV     AL,[SI]
	CMP     AL,191
	JA      >X2
	INC     SI
IF Z    CALL    >X7
	MOV     ES:[DI],AL
	INC     DI
	DEC     BL
	JNZ     X1                      ;DO NEXT BYTE
	POP     DI
	RET                             ;DO NEXT PLANE
X2:     INC     SI
IF Z    CALL    >X7
	MOV     AH,AL
	AND     AH,63                   ;NUMBER RLL BYTES TO DISPLAY
	MOV     AL,[SI]                 ;PIXELS' BYTE VALUE TO SHOW
	INC     SI
IF Z    CALL    >X7
X3:     STOSB
	DEC     BL                      ;BYTES/PLANE
	JZ      >X6                     ;DONE THIS PLANE
	DEC     AH                      ;RLL
	JNZ     X3
	JMP     SHORT X1
X4:     MOV     AL,CH                   ;BALANCE RLL LAST LINE
X5:     STOSB                           ;DO REMAINDER RLL BYTES
	DEC     BL                      ;FROM LAST PLANE
	DEC     CL                      ;REMAINDER
	JNZ     X5
	JMP     SHORT X1                ;REMAINDER DONE - TEST NEXT
X6:     DEC     AH                      ;DONE WITH THIS PLANE
	XCHG    AL,AH
	MOV     CX,AX                   ;UNPACK CARRY BYTES REMAIN
	POP     DI
	RET                             ;DO NEXT PLANE
X7:     MOV     CS:[SAVDI6],DI
	MOV     DI,DS
	ADD     DI,1000H
	MOV     DS,DI
	MOV     CS:DI,[SAVDI6]
	MOV     SI,0
	RET

WMEM4:; MOV     DX,W4 not needed as graphic.pcx's embedded.
KK0:    MOV     DS,CS
	MOV     AX,6000H
	MOV     CS:[SAVDS6],AX
	PUSHA
	MOV     AX,3D02H        ;OPEN FILE
	INT     21H
IF C    JMP     >F2
	MOV     BX,AX
	NOP
	MOV     AX,4202H        ;LSEEK EOF
	MOV     CX,0
	MOV     DX,0
	INT     21H
	MOV     DI,DX           ;MSP
	MOV     SI,AX           ;LSP
	MOV     CS:[SAVDX6],DX
	MOV     CS:[SAVAX6],AX
A1:     MOV     AX,4200H        ;LSEEK BEGIN FILE
	MOV     CX,0
	MOV     DX,0
	INT     21H
	MOV     CS:AX,[SAVDS6]
	MOV     DS,AX           ;1ST SEG
	CMP     CS:[SAVDX6] W,0 ;MSP
	JZ      >F1             ;< 1 SEG
	CALL    LHNG1           ;READ 65536 BYTES
	DEC     CS:[SAVDX6] W   ;MSP
	JZ      >F1
	CALL    LHNG1
	DEC     CS:[SAVDX6] W   ;MSP
	JZ      >F1
	CALL    LHNG1
	DEC     CS:[SAVDX6] W   ;MSP
	JZ      >F1
	CALL    LHNG1
	DEC     CS:[SAVDX6] W   ;MSP
	JZ      >F1
	CALL    LHNG1
F1:     MOV     CS:CX,[SAVAX6]
	MOV     CS:AX,[SAVDS6]
	MOV     DS,AX
	MOV     DX,0
	MOV     AX,3F00H
	INT     21H
	NOP
	MOV     AX,3E00H        ;CLOSE
	INT     21H
	POPA
	MOV     DS,CS
	RET
LHNG1: MOV      AX,3F00H        ;READ ENTIRE SEGMENT
	MOV     CX,0FFFFH
	MOV     CS:DX,[SAVDS6]
	MOV     DS,DX
	MOV     DX,0
	INT     21H
	NOP
	MOV     AX,3F00H
	MOV     CX,1
	MOV     CS:DX,[SAVDS6]
	MOV     DS,DX
	MOV     DX,0FFFFH
	INT     21H
	ADD     CS:[SAVDS6] W,1000H     ;NEXT SEGMENT
	RET
F2:     POPA
	MOV     DS,CS
	CALL    BEEP
	RET

PALETE: DB 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
SETOVER: DB     0
SCANLIN: DW     0
LINBYT:  DW     0
PCXPAL: PUSH    ES                      ;DECODE SCREWY PCX TRIPLES
	MOV     ES,CS                   ;SETPAL SEGMENT
	MOV     AX,12H
	INT     10H
	JMP     CONVDAC                 ;CONVERT DACS+SET PALETTES
CONVDAC: MOV    AX,1013H
	MOV     BL,0
	MOV     BH,1
	INT     10H             ;SET ATTRIBUTE CONTROLLER SELECT STATE
	MOV     ES,DS                   ;HEADER ADDRESS NOW ES = DS
	MOV     DI,16                   ;BEGIN TRIPLES IN HEADER
	MOV     CX,48                   ;NUMBER TO UPDATE
X1:     SHR     [DI] B,2                ;SHR 2 BITS - BIT 6/7 IGNORED
	INC     DI
	LOOP    X1
	MOV     AX,1012H                ;UPDATE BLOCK
	MOV     BX,0
	MOV     CX,16                   ;16 EA 3 BYTE DACs
	MOV     ES:DX,16
	INT     10H                     ;UPDATE 16 DAC COLOR REGISTERS
	MOV     AX,1000H                ;FIX INDEX #6
	MOV     BX,606H                 ;BAD BIOS DAC UPDATE
	INT     10H                     ;BIOS ERROR
	POP     ES                      ;BACK TO A000H
	RET                             ;GO UNPACK

SAVDI6: DW      0
SAVDS6: DW      0
SAVDX6: DW      0
SAVAX6: DW      0

alfaobj:
uggs cyber monday uggs cyber monday michael kors black friday michael kors black friday michael kors black friday uggs cyber monday uggs cyber monday michael kors black friday michael kors black friday michael kors black friday north face black friday north face cyber monday uggs black friday north face black friday uggs cyber monday north face cyber monday north face black friday uggs black friday uggs black friday uggs black friday michael kors black Friday uggs black friday uggs black friday uggs cyber monday michael kors black Friday michael kors black Friday uggs cyber monday uggs black friday michael kors black friday uggs cyber monday north face black friday michael kors cyber Monday michael kors cyber Monday beats by dre black Friday north face black friday north face black friday michael kors cyber Monday beats by dre cyber Monday michael kors cyber Monday north face black friday uggs black friday gucci black friday michael kors black Friday lululemon black friday michael kors cyber monday jordan black friday uggs black friday Longchamp black friday michael kors black Friday canada goose cyber monday tod's black friday uggs black friday lululemon black friday burberry cyber Monday uggs black friday uggs cyber monday michael kors cyber Monday coach black friday canada goose black friday kate spade cyber monday uggs black friday uggs black friday Oakley black Friday canada goose black friday north face cyber monday uggs cyber monday beats by dre black Friday prada cyber monday north face black friday michael kors black Friday coach cyber monday uggs black friday lululemon cyber monday canada goose cyber monday north face cyber Monday michael kors black Friday nike cyber monday lululemon black friday coach black friday canada goose black friday michael kors cyber monday canada goose black friday uggs cyber monday north face cyber Monday beats by dre cyber Monday uggs black Friday uggs cyber monday uggs cyber Monday kate spade cyber monday canada goose black friday lululemon black friday north face cyber Monday uggs black friday beats by dre cyber Monday beats by dre black friday north face cyber Monday moncler cyber monday north face cyber Monday north face cyber Monday michael kors black friday moncler black friday hollister black friday canada goose black friday canada goose black friday juicy couture cyber monday Dior cyber monday bose black friday Mulberry cyber monday Ray Ban cyber monday bose cyber monday michael kors Black Friday michael kors Black Friday michael kors Black Friday michael kors black friday michael kors Black Friday beats by dre cyber monday jordan 11 legend blue black infrared 13s legend blue 11s legend blue 11s jordan 13 black infrared jordan 11 legend blue jordan 13 black infrared legend blue 11s jordan 11 legend blue jordan 13 black infrared black infrared 13s legend blue 11s jordan 11 legend blue black infrared 13s jordan 11 legend blue jordan 11 legend blue legend blue 11s legend blue 11s jordan 13 black infrared 23 jordan 11 legend blue jordan 11 legend blue jordan 11 legend blue jordan 13 black infrared jordan 13 black infrared 23 jordan 11 legend blue legend blue 11s jordan 13 black infrared 23 jordan 11 legend blue black infrared 13s jordan 11 legend blue legend blue 11s jordan 11 legend blue jordan 11 legend blue jordan 11 legend blue black infrared 13s jordan 11 legend blue jordan 11 legend blue black infrared 13s black infrared 13s legend blue 11s