122-byte Quality fireAssembler/80486

A new version arrived to me from Mark Andreas reducing the size to 122 bytes. If speed is not the issue and a very instable keycheck is used it can be reduced to 120 bytes (both these to version are included in the archive along with the previous two ones). All optimizations are described in the text below. Also note that it may run on a 386 based computer if source modified (still same size), read in the source.

This is the original gem text:

The sources, object decks and linked programs of all versions displayed on this page is available for download 9684 bytes). This includes the 128, 126, 122 and 120 byte versions.
Visit: http://www.ar.com.au/~gaffer
;
;
;                              -  f l a m e  -
;                           quality 122 byte fire
;                      copyright 1997 Gaffer/prometheus
;                             gaffer@zip.com.au
;
;                         optimization contribution:        
;                  goblin,icepick,mf,patrik sundberg,pgeist
;                                 mark andreas


.MODEL TINY
.486                            ;# see note next to XADD instruction

UDATASEG
Buffer  DB      320*203 dup(?)
;# You may wish to insert code to keep Buffer aligned on an
;# even address, regardless of the size of the program.

CODESEG
ORG 100h
LOCALS




; INITIALIZATION: setup video mode & palette
; ------------------------------------------
    .STARTUP


; SETUP VGA SEG
        push    0A000h
        pop     es


; INIT VGA MODE 13h
        mov     al,13h          ;# doesn't look nice if using mode 93h
        int     10h


; GENERATE PALETTE
        dec     di
PaletteGen:                     ; alternate palette generation
        xor     ax,ax           ; (Patrick Sundberg)
        mov     cl,63
@@L1:
        stosb
        inc     ax
        cmpsw                   ; small way to advance si,di!
                                ;# why are we advancing SI too
                                ;# scasw works just as well (same size)
        loop    @@L1
        push    di
        mov     cl,192
@@L2:
        stosw
        inc     di
        loop    @@L2
        pop     di
        inc     di
        jns     PaletteGen      ; cheesy! :)


; SET PALETTE
        mov     ax,1012h
        cwd                     ; equivalent to 'xor dx,dx'
        mov     cl,255
        int     10h




; MAIN LOOP: Cycle through flame animation until keypress
; -------------------------------------------------------
MainLoop:

        push    es
        push    ds
        pop     es              ; set es=ds to use stosw


; FLAME ANIMATION
        inc     cx
        mov     di,OFFSET Buffer
        mov     bl,99
@@L3:
        mov     ax,[di+639]                   
        add     al,ah                         
        setc    ah
        mov     dl,[di+641]
        add     ax,dx
        mov     dl,[di+1280]
        add     ax,dx
        shr     ax,2
        jz      @@ZERO          ; cool a bit...
        dec     ax
@@ZERO:
        stosb
        add     ax,dx           ; double the height
        shr     ax,1                          
        mov     [di+319],al                   
        loop    @@L3                         
        mov     cx,320
        add     di,cx
        dec     bx
        jnz     @@L3


; FLAME GENERATOR BAR
; assumes cx=320
; assumes di=generator bar offset (bottom of flame buffer)
@@L4:

;#        in      ax,40h          ; read from timer
;# don't need to thump the clock 320 times per frame.  That just
;# kills the display on slower video cards, even on Pentiums
;# In fact, the display looks just as nice without this instruction.
;# If you decide it's needed, try moving it to be just before the
;# loop, so you're only reading the port once per frame.


;#      xadd    [ds:100h],ax      ; "seed" is first two bytes of code
;# Instead, use the BP register as a seed.
        xadd    bp,ax           ;#

;# another option for allowing the program to run on a 386 is to
;# replace XADD, since that's the only 486 instruction used.
;# an alternate of the same size is:
;#        add     ax,[di]
;#        inc     ax

;#        mov     ah,al                         
;# removing this instruction doesn't seem to affect the display.

        stosw
        stosw
        loop    @@L4

        pop     es                    ; restore es=A000h


; OUTPUT FLAME TO SCREEN
        xor     di,di
        mov     si,OFFSET Buffer + 320
        mov     ch,60                 ; assumes cl=0
        rep     movsd                 ; change to "mov ch,120" "rep movsw"
                                      ; saves one byte but is slower
                                      ; (patrik sundberg)
                                      
; CHECK FOR KEYPRESS
        mov     ah,1
        int     16h
        jz      MainLoop              ; alternative keypress check
                                      ; "in al,60h" "das" "jc MainLoop"
                                      ; saves one byte but is not as reliable
                                      ; (icepick)


; DOS EXIT CODE: Switch to textmode, return to DOS
; ------------------------------------------------

        mov     ax,03h
        int     10h
        ret                               

        END
Gem writers: Gaffer/prometheus
Mark Andreas
last updated: 1998-03-16