; ; source code of the 256 bytes demo Collideum ; (c) 1999 by Gekko/Tonik -- gk@scene.hu ; ; It was great fun for me to create it, I hope it will be the same ; for you to discover the tricks I use. If you liked this code or ; managed to learn something new from it, then please send me an email. ; ; ; This source complies with NASM. It is freeware, download it from: ; http://www.cryogen.com/Nasm ; ; ; This intro is just a few days of work. I stopped optimizing as soon ; as I reached the magic 256 bytes threshold, so there are still quite ; a few bytes which could be removed... I tried to make it as stable as ; possible, so no DOS 7.0 specific tricks are used, there is a check for ; ESC-press, it switches back to textmode on exit, and so on. ; ; You can step forward in the intro, just press any key (except for ESC). ; This 'feature' is because the synchronisation is done with HLT ; instructions, and these don't stop the code while any key is pressed. ; ; Some notes on the music player: ; There is a 16-note pattern stored; it is always played twice ; (2*16=32 notes), and the first 8 notes work as a base line, too ; (8*32=256 notes). After this, the song is repeating. ; I've tried to play the displayed text and some other freaky things, ; sometimes it even sounded good... ; Another hint is to try to change the MOV to ADD when the player ; separates octave and note (mov dh,al). Since dh is 12 then, it will ; raise the tune 3 octaves higher. The only problem is that it sometimes ; then overflows the available 0..7 octave range. Some strange rhythms ; are created, but they are rather good, too (oh well, considering the ; limitations of Adlib and the 256-ish byte limit). ; It is a good idea to have an Adlib SDK handy when messing around ; with the Adlib registers... ; ; macros ; %imacro note 2 %ifidni %1,C db (%2)*12 + 0 %elifidni %1,C# db (%2)*12 + 1 %elifidni %1,D db (%2)*12 + 2 %elifidni %1,D# db (%2)*12 + 3 %elifidni %1,E db (%2)*12 + 4 %elifidni %1,F db (%2)*12 + 5 %elifidni %1,F# db (%2)*12 + 6 %elifidni %1,G db (%2)*12 + 7 %elifidni %1,G# db (%2)*12 + 8 %elifidni %1,A db (%2)*12 + 9 %elifidni %1,A# db (%2)*12 + 10 %elifidni %1,H db (%2)*12 + 11 %else %error Invalid use of note macro. %endif %endmacro ; ; code ; bits 16 org 0x100 ; ch=0, ah=0 on entry main: ; bp will point to the adlibreg routine (during the whole demo) mov bp,adlibreg ; initialize 320x200 256 color video mode mov al,0x13 call initialize ; print text mov ah,9 mov dx,text mov cl,6 .print: int 0x21 loop .print ; change color of some lines of text from gray to something else ; this way these pixels won't be treaten as particles mov di,0xA000 ; 0xA000 = 320 * 128 mov ES,di .recolorize: mov al,[ES:di] shl al,1 stosb test di,di jnz .recolorize core: ; bl = frame counter ; bh = 0 (at least it seems so, but who cares, it's working well :) inc bl push bx ; --------------------------------------------------------------------------- ; adlib player routine ; --------------------------------------------------------------------------- player: mov ax,bx and al,0xEF shr bx,5 mov cl,[bx+pattern] and al,0x0F mov bx,ax add cl,[bx+pattern] and al,0x03 cmp al,0x03 jne .skip dec ax .skip: add al,0xA0 push ax xor ax,ax mov al,cl mov dh,12 div dh mov bl,ah shl ax,2 mov dh,al pop ax ; play one note ; al = channel (0..3) + 0xA0 ; bx = note (0..11) ; dh = 4 * octave (0..7) ; set frequency mov ah,[bx+freqtable] call bp ; note off add al,0x10 mov ah,dh call bp ; note on add ah,0x20 call bp ; --------------------------------------------------------------------------- ; end of adlib player routine ; --------------------------------------------------------------------------- hlt ; --------------------------------------------------------------------------- ; particle effect - 'snow' ; --------------------------------------------------------------------------- particles: std mov di,320*170 - 1 mov cx,di .loop: mov bx,321 - 1 ; Substract 1 to compensate in al,0x40 ; the bad pseudo random routine. and al,0x03 ; It would be better to keep the add bl,al ; value in range 0..2 instead of 0..3 mov ax,0x0007 cmp byte[ES:di+bx],al jae .cantmove mov byte[ES:di+1],ah mov byte[ES:di+bx],al ; This repne scasb should be in the .cantmove: ; beginning of the loop, but it takes repne scasb ; <---- ; less bytes this way. That's why inc cx ; there are a few messy pixels in loop .loop ; the bottom of the screen. ; generate new particles mov byte[ES:bx+0x7B],al ; --------------------------------------------------------------------------- ; end of particle effect ; --------------------------------------------------------------------------- hlt hlt pop bx ; repeat core loop unless ESC is pressed in al,0x60 cbw dec ax jne core ; deinitialization: set textmode, kill sound player and exit to the OS mov al,3 ; call initialize ; retn ; audio+video initialization ; al = videomode ; ah = 0 initialize: ; setting videomode int 0x10 ; clear all adlib registers mov al,244 .clear: call bp dec ax jne .clear ; upload instrument and channel data to adlib registers mov si,instrument mov cl,7 .loop: lodsw call bp inc ax call bp inc ax call bp loop .loop retn ; set value of one adlib register ; al = register ; ah = data adlibreg: pusha mov dx,0x388 out dx,al push word .here pusha .here: mov al,ah inc dx out dx,al dec dx .timer: mov cx,dx .loop: in al,dx loop .loop popa retn ; frequency table ; I've got the idea of this 1 byte/note table from ; Viznut/PWP's "Phygo" Assembly 1999 4kb intro source freqtable: db 0x157/4 ; C db 0x16B/4 ; C# db 0x181/4 ; D db 0x198/4 ; D# db 0x1B0/4 ; E db 0x1CA/4 ; F db 0x1E5/4 ; F# db 0x202/4 ; G db 0x220/4 ; G# db 0x241/4 ; A db 0x263/4 ; A# db 0x287/4 ; H ; (register, data) pairs ; if there were at least two instruments, it would be smaller to use ; (register, data1, data2) format, where data2 is written to register+3 instrument: db 0x20 db 00100000b db 0x23 db 10100000b db 0x60 db 11111000b db 0x63 db 11110011b db 0x80 db 01001010b db 0x83 db 00110010b db 0xC0 db 00000110b pattern: note C ,3 note C ,1 note C ,2 note D#,3 note G ,3 note G ,2 note D#,3 note D#,2 note F ,3 note F ,1 note F ,2 note F ,3 note A#,2 note A#,0 note A#,1 note A#,2 text db 10,10,10,9,9,"COLLiDEUM",13,'$' db 'G' ; to make it really 256 bytes :)