-------[  RtC Mag, At the end of the universe  ]

--------------[  La Bombe du mag : Spanska's Art  ]
---------[ in RtC mag 5 ]
----[  by Androgyne <androgyne-rtc@fr.st>  ]


-------[  Introduction


    Spanska : ce nom ne dit peut tre rien  personne et pourtant... Ce fut l'un des plus grands auteurs de virus franais (aujourd'hui  la "retraite"). Il fut mme le premier  crer un ver qui s'est propag partout dans le monde, Happy99 (c'tait bien avant mlissa et les conneries en VB qui ont suivi). Spanska avait pour coutume de faire des bombes graphiques pour ses virus. Eh oui, vous avez bien entendu, des bombes graphiques, comme quoi une bombe n'est pas forcment destructrice.


-------[  La bombe


    Cette bombe appartient au virus Cosmos, fait en 1997 par Spanska. Les graphismes sont plutt primaires mais imaginez qu'ils tiennent en 301 octets (c'est environ la taille d'un raccourci sous Windows), moi, je trouve a totalement fantastique. Je tenais  vous la faire partager. Il est bien entendu interdit de riper cette bombe ou encore pire, d'y mettre son nom. Respectez l'auteur !
    Ici, Spanska nous a fait un champ toil qui dfile sur 8 couches diffrentes. Cette bombe est un hommage  Carl Sagan. Mais plutt que de vous en parler moi mme, je vais vous donner la bombe originale de Spanska, commente par ses soins... Une exclusivit pour le RtCm4g. Une version compil est donne avec le mag.


-------[  Le code original !


--- COSMOS.ASM ----------------------------------------------------------------

; Effet de champ d'etoile, par Spanska
;
; Cet effet graphique a ete developpe pour mon virus "Cosmos",
; appele Spanska.1120.B par les anti-virus. 
;
; Se compile avec TASM /m2 puis TLINK /t
; pour donner un fichier .com de 301 octets
;
; Ce virus etait dedie a la memoire de Carl Sagan, mort quelques
; semaines avant. Cet astrophysicien genial m'a appris grace a 
; ses livres (dont le fameux "Cosmos") que la science pouvait
; se melanger avec la poesie, l'histoire et la philosophie.
;
; Salut a Dake!
; Contactez-moi a el_gato@rocketmail.com

code    segment
	assume  ds:code, ss:code, cs:code, es:code
	org 100h
star:                                                   

;--------------------passer en VGA-------------------------------

	mov ax, 13h     ;passer en mode VGA
	int 10h         ;go!

;------------------ajuster la palette----------------------------

	mov dx, 3c8h    ;dx = port d'ecriture de la palette
	mov al, 1       ;on ne va modifier que la couleur 8
	out dx, al      ;on ecrit la premiere couleur dans le port
	inc dx          ;on passe a la definition des couleurs
mov cx, 8        
mov bx, 23
palette:
	mov ax, bx      ;on va mettre un gris
	out dx, al      ;composante 1
	out dx, al      ;composante 2
	out dx, al      ;composante 3
add bx, 5        
loop palette

;---------on met le curseur aux coordonnees 0, 3----------------------

mov dx, 0003h      ;coordonnees  
xor bh, bh         ;page 0
mov ah,02h         ;mettre le curseur a la position DH, DL
int 10h            ;BIOS Screen INT
						    
;-----------on affiche la premiere ligne du message---------------------

lea si,  message                 ;si pointe sur le message
mov cx, 34                       ;longueur du message
call affiche_message 

;---------on met le curseur aux coordonnees 24, 14----------------------

mov dx, 01803h     ;coordonnees  
xor bh, bh         ;page 0
mov ah,02h         ;mettre le curseur a la position DH, DL
int 10h            ;BIOS Screen INT
						    
;-----------on affiche la seconde ligne du message---------------------

;lea si, message2                 ;si pointe sur le message
mov cx, 33                       ;longueur du message
call affiche_message

;------remplir la zone memoire de coordonnees+vitesse des etoiles--------
      
lea di, zone        ;on va stocker dans cette zone coord+vitesse
mov cx, 512         ;nombre d'etoiles

boucle:
;---------------creation de nombres pseudo-aleatoires---------------------

	mov ax, aleat       ;routine piquee
	mov dx, 8405h       ;dans une demo
	mul dx              ;de flamme
	inc ax
	mov aleat, ax
stosw               
cmp cx, 500
mov al, 8
ja finitl
cmp cx, 490
dec ax
ja finitl
cmp cx, 470
dec ax          ;definition du nombre d'etoiles dans chaque plan (8)
ja finitl       ;et de leur vitesse
cmp cx, 430
dec ax
ja finitl
cmp cx, 380
dec ax
ja finitl
cmp cx, 300
dec ax
ja finitl
cmp cx, 150
dec ax
ja finitl
dec ax

finitl:

stosb               ;on met la vitesse dans la zone
loop boucle         ;on recommence
		   
;--------------------animation des etoiles-----------------------------

mov ax, 0A000h            ;memoire video 
mov es, ax                ;dans es

anim:                     ;debut du loop ecran

;***********************    
    mov     dx,3dah   ;*
;VRT:                  ;*
;    in      al,dx     ;*
;    test    al,8      ;*
;    jnz     VRT       ;*   synchronisation avec le retour de    
		      ;*   balayage vertical
NoVRT:                ;*
    in      al,dx     ;*
    test    al,8      ;*
    jz      NoVRT     ;*      
;***********************

lea si, zone              ;si pointe vers la zone
mov cx, 512               ;nombre d'etoiles

affiche:                  ;debut du loop etoile
lodsw                     ;on recupere les coordonnees de l'etoile
mov di, ax                ;on les mets dans di
mov dx, ax                ;et aussi dans dx
xor ah, ah                ;on annule ah
lodsb                     ;et on charge la vitesse dans al
add dx, ax                ;on ajoute la vitesse aux coordonnees
mov word ptr [si-3], dx   ;on stocke la nouvelle coordonnee dans la zone
      
shr di, 1
mov byte ptr ah, es:[di]	;part sup de l'ecran
mov byte ptr bl, es:[di+32512]	;part inf de l'ecran
and ah, 00001111b
and bl, 00001111b
xor byte ptr es:[di], ah       ;on efface l'etoile de son ancienne place
xor byte ptr es:[di+32512], bl ;on efface l'etoile sur la 2eme moitie

xchg dx, di
shr di, 1
or byte ptr es:[di], al        ;on affiche l'etoile a sa nouvelle position
or byte ptr es:[di+32512], al  ;on remplit la 2eme moitie de l'ecran
loop affiche                   ;on traite l'etoile suivante

	keystr:
	mov     ah,01     ;routine pour arreter le bordel
	int     16h       ;Has a key been pressed?
	jnz fin           ;oui => on arrete

jmp anim                  ;on recommence un nouveau cycle

;---------------------------fin du programme----------------------------

fin:
       mov ax, 3        ;revenir en    
       int 10h          ;mode texte

       mov ax,4c00h     ;redonner la main
       int 21h          ;au DOS

;------------routine d'affichage du texte----------------------------

affiche_message:
	lodsb           ;ds:si dans al
	mov bl, 32      ;la couleur ne doit utiliser que les 4 bits lourds
	mov ah, 0Eh     ;appel de
	int 10h         ;l'interruption "affichage d'1 caractere"
loop affiche_message
ret

;----------------------zones memoire utilisees-----------------------

message db  "To Carl Sagan, poet and scientist,"
message2 db "this little Cosmos.  (Spanska 97)"
aleat dw 0AFh                   
zone:

code    ends
	end     star

;------------------------(c) Spanska 1997------------------------------


--- COSMOS.ASM ----------------------------------------------------------------


-------[  Conclusion


    Comme quoi les virus ne sont pas tous destructeurs... Pour ceux qui le croient encore, c'est dommage. Seuls les lames transforment les sources pour qu'ils deviennent destructeurs. vx rulez !


-------[  Extended Play


    Bon, comme vous avez t sages, je vous en redonne... Voil deux autres codes de bombes de Spanska : No Pasaran et Mars Land... Toujours aussi gnial ! Evidemment, je vous donne les programmes compils avec le mag...

    Voila tout d'abord No Pasaran :


--- NOPASARAN.ASM -------------------------------------------------------------

; Effet de flamme, par Spanska
;
; Cet effet graphique a ete developpe pour mon premier 
; virus "No Pasaran!", dont les 2 versions sont
; appelees Spanska.1120 et Spanska.1000 par les anti-virus. 
;
; Se compile avec TASM /m2 puis TLINK /t
; pour donner un fichier .com de 367 octets
;
; Ce virus est dedie a tous ceux qui ont combattu le fascisme
; pendant la Guerre Civile espagnole (1936-1939), entre autre
; dans les violents combats pour defendre Madrid. Leur mot d'ordre
; etait "No Pasaran!" ("Ils ne passeront pas!")
;
; Salut a Dake!
; Contactez-moi a el_gato@rocketmail.com

code    segment
	assume  ds:code, ss:code, cs:code, es:code
	org 100h


;**********************************************************************
;*                 CODE DE LA BOMBE GRAPHIQUE                         *
;**********************************************************************
bomb:
;-----------------------VGA-----------------------------------

	mov ax, 13h     ;passer en mode VGA
	int 10h         ;go!

;----------initialisation de la palette "flamme"---------------

	mov dx, 3c8h    ;dx = port d'ecriture de la palette
	xor al, al      ;on commence par la couleur 0
	out dx, al      ;on ecrit la premiere couleur dans le port
	inc dx          ;on passe a la definition des couleurs
	
	xor cx, cx      ;
rouges:                 ;
	mov al, cl      ;
	out dx, al      ;boucle pour definir les 63 premieres couleurs
	xor al, al      ;avec la composante rouge qui augmente
	out dx, al      ;
	out dx, al      ;
	inc cx          ;
	cmp cx, 63      ;   
jne rouges              ;

	xor cx, cx      ;
jaunes:                 ;
	mov al, 63      ;
	out dx, al      ;
	mov al, cl      ;boucle pour definir les 63 couleurs suivantes
	out dx, al      ;avec la composante verte qui augmente
	xor al, al      ;
	out dx, al      ;
	inc cx          ;
	cmp cx, 63      ;    
jne jaunes              ;

	xor cx, cx      ;
blancs:                 ;
	mov al, 63      ;
	out dx, al      ;boucle pour definir les 63 couleurs suivantes
	out dx, al      ;avec la composante bleue qui augmente
	mov al, cl      ;
	out dx, al      ;
	inc cx          ;
	cmp cx, 63      ;
jne blancs              ;

	mov cx, 198     ;       
blancfin:               ;
	mov al, 255     ;definition des dernieres couleurs, en blanc
	out dx, al      ;
loop blancfin           ;

	xor al, al      ;la couleur 255 est noire, pour qu'on ne 
	mov cx, 3       ;voie pas les foyers blancs du bas
	rep out dx, al  ;

;----dessiner des foyers de cinq pixels en bas de l'ecran reel----------

	mov ax, 0a000h  ;memoire video dans ax
	mov es, ax      ;memoire video dans es
boucle:
	mov di, (320*199)+5     ;on commence a la derniere ligne
				;a 2 pixels du bord
	
foyers: 

	call random     ;la procedure ramene un dl aleatoire entre 0 et 255
	cmp dl, 180     ;au dessus de 180, pixel blanc. Au dessous, noir
	jb noir         ;si dl<180, on va rendre le pixel noir
	mov dl, 255     ;sinon, on met la couleur a fond
	jmp blanc       ;et on evite l'instruction qui met la couleur a zero

noir:
	xor dl, dl       ;on met la couleur a zero
blanc:
	mov al, dl      ;quelle que soit la couleur, on charge al avec
	mov cx,  5      ;on va repeter cinq fois le pixel
	
zobi:
	stosb           ;petite boucle pour 
			;faire une deuxieme
	add di, 319     ;ligne de foyers
	stosb           ;sous les premiers
	sub di, 320     ;
loop zobi

	cmp di, (320*199)+30   ;on continue pendant 300 pixels
jb foyers                       

;--------ecran reel--->modif--->ecran virtuel------------------

mov di, 320*120                         ;offset memoire video
lea si, ecran_virtuel                   ;offset ecran virtuel au debut de
mov dx, 80                              ;premiere boucle repetee 80 fois 
xor ax, ax                              ;sinon le premier pixel delire

ecran:                                  ;debut de la premiere boucle
	
mov cx, 30                              ;deuxieme boucle repetee 160 fois
		      
modif:                                  ;debut de la deuxieme boucle
	
	mov al, es:[di]         ;dans al, la valeur du pixel courant
	add al, es:[di+320]     ;ajout du pixel juste dessous
	adc ah, 0               ;et on ajoute le carry
	add al, es:[di+319]     ;ajout du pixel dessous a gauche
	adc ah, 0               ;et on ajoute le carry
	add al, es:[di+641]     ;ajout du pixel a 2 dessous, a droite
	adc ah, 0               ;et on ajoute le carry
	shr ax, 1               ;on divise ax par deux
	shr ax, 1               ;on divise encore ax par deux (moyenne)
	cmp al, 0               ;verifier si le pixel est noir
	je bitnoir              ;si oui, on ne va pas diminuer l'intensite
	dec al                  ;si non, on diminue l'intensite

bitnoir:
	mov ds:[si], al         ;stocke le pixel
	inc si                  ;suivant
	inc di                  ;suivant
			
loop modif         ;la ligne n'est pas encore calculee, on y revient

add di, (320-30)   ;sur le pixel suivant (descente d'une ligne)
dec dx             ;dx= compteur des lignes. Une en moins
cmp dx, 0          ;si dx n'est pas nul, on n'est pas au bas de l'ecran
jne ecran          ;et donc on continue la ligne suivante

;-------------ecran virtuel--->ecran reel---------------------

	mov di, (320*120)                   ;offset memoire video 
	lea si, ecran_virtuel               ;offset ecran virtuel au debut

xor dx, dx
deux_flammes:
	mov cx, 30        
	rep movsb               
	sub si, 30
	add di, 230
	mov cx, 30
	rep movsb
	add di, 30
	inc dx
	cmp dx, 79
jne deux_flammes

;---------on met le curseur aux coordonnees 5,1----------------------

mov dx, 0502h              
xor bh, bh         ;page 0
mov ah,02h         ;mettre le curseur a la position DH, DL
int 10h            ;BIOS Screen INT
						    
;------------------on affiche le message de la mort----------------

mov ah, clignote                 ;compteur dans ah
inc ah                           ;on incremente ah
mov clignote, ah                 ;et on remet le compteur a sa place
cmp ah, 128                      ;ce compteur par rapport a 128 est:
ja second_message                ;superieur?
lea si, message                  ;oui: on charge le premier message
jmp premier_message              ;et on evite de charger le deuxieme
second_message:                  ;
lea si, message2                 ;non: on charge le second message
premier_message:

mov cx, 34                       ;longueur du message
 
affiche_message:
	lodsb           ;ds:si dans al
	mov bl, 254     ;couleur ds bl
	mov ah, 0Eh     ;appel de
	int 10h         ;l'interruption "affichage d'1 caractere"
loop affiche_message

	mov     ah,01   ;
	int     16h     ;Has a key been pressed?
	jnz fin         ;si non, c'est reparti pour un autre cycle
	jmp boucle      ;on recommence

;---------------------fin du programme-----------------------------
fin:                    
       mov ax, 3       ;revenir en mode texte   
       int 10h         ;

    mov     ax,4c00h    ;redonner la main
    int     21h         ;au DOS

;--------------procedure de creation de nombres aleatoires-----------

random proc near
	mov ax, aleat                   ;routine piquee
	mov dx, 8405h                   ;dans une demo
	mul dx                          ;de flamme
	inc ax
	mov aleat, ax
	ret
random endp

;------------------les zones memoire utilisees---------------------------

message  db "Remember those who died for Madrid"
message2 db "No Pasaran! Virus (c) Spanska 1996"
clignote db 00                  ;pour le clignotement du message
aleat dw 0AAh                   ;definit un word qui sera utilise
				;dans l'algorithme de creation de
				;nombres aleatoires
ecran_virtuel:                  ;definit une zone memoire
				;qui sera l'ecran virtuel

code    ends
	end     bomb

;------------------------(c) Spanska 1996------------------------------

--- NOPASARAN.ASM -------------------------------------------------------------


    Puis Mars Land...


--- MARS.ASM ------------------------------------------------------------------

; Petit effet 3D Voxel, par Spanska
;
; Cet effet graphique a ete developpe pour mon virus "Mars Land",
; appele Spanska.1500 par les anti-virus. 
;
; Se compile avec TASM /m2 puis TLINK /t
; pour donner un fichier .com de 584 octets
;
; Le message affiche insiste sur le fait que coder un virus 
; n'est pas forcement destructeur. Les miens se contentent 
; de declencher une animation a l'ecran. Je n'aime pas
; detruire, j'aime creer.
;
; Salut a Dake!
; Contactez-moi a el_gato@rocketmail.com

code    segment
	assume  ds:code, ss:code, cs:code, es:code
	org 100h

largeur equ 128		;largeur de la grille

terrain:
;--------------------passer en VGA-------------------------------

mov ax, 13h     ;passer en mode VGA
int 10h         ;go!

;------------------palette noire----------------------------
;(parce que le calcul des montagnes se fait directement sur
;l'ecran, c'est plus beau quand on ne le voit pas)

mov dx, 3c8h    ;dx = port d'ecriture de la palette
xor al, al      ;on commence par la couleur 0
out dx, al      ;on ecrit la premiere couleur dans le port
inc dx          ;on passe a la definition des couleurs
mov cx, 768     ;256 couleurs x 3 composantes, toutes a 0 
tout_noir:                 
out dx, al      ;on ecrit la couleur noire dans le port
loop tout_noir	;et on recommence 768 fois

;------remplir l'ecran de gros blocs blancs aleatoires------
;(zone utilisee: 50 lignes x 128 colonnes en haut a gauche)
      
mov ax, 0A000h         ;memoire video 
mov es, ax             ;dans es
mov cx, 150            ;nombre de blocs
boucle:
	 random:
	 mov ax, aleat       ;routine semi-aleatoire
	 mov dx, 8405h       ;piquee dans une demo
	 mul dx              ;de flamme: donne un
	 inc ax              ;dx aleatoire
	 mov aleat, ax
push dx                ;dl = premier octet aleatoire pour les lignes
shr dl, 1              ;maintenant 0<dl<128
shr dl, 1              ;maintenant 0<dl<64  
cmp dl, 41             ;si dl plus grand que 41
ja pas_pixel           ;on le dessine pas
cmp dl, 5              ;si dl plus petit que 5
jb pas_pixel           ;on le dessine pas
mov ax, 320            ;calcul de l'offset video
xor dh, dh             ;c'est dl qui nous interesse
mul dx                 ;on le multiplie par 320
pop dx                 ;dh = second octet aleatoire pour les colonnes
cmp dh, 112            ;si dh plus grand que 112
ja pas_pixel           ;on le dessine pas
cmp dh, 8              ;si dh plus petit que 8
jb pas_pixel           ;on le dessine pas
xor dl, dl             ;c'est dh qui nous interesse
xchg dl, dh            ;on le met dans dl 
add ax, dx             ;on ajoute lignes*320 et colonne
xchg di, ax            ;on le met dans di 
mov al, 255            ;couleur des gros blocs (ce sera blanc)
push cx
mov bl, 4              ;les blocs font 4 pixels de haut
gros_pixel:
mov cx, 10             ;les blocs font 10 pixels de large
rep stosb              ;on les dessine sur l'ecran
add di, 310
dec bl
jne gros_pixel
pop cx
pas_pixel:
loop boucle

;--------calcul des degrades----------------
;(par un effet de feu, mais immobile: les blocs s'adoucissent)
;ici es=video

mov ax, cs		;besoin d'un segment de stockage libre, apres cs
add ah, 16		;on ajoute a cs 256*16 octets
mov ds, ax              ;ds pointe vers le segment de stockage
push ds                 ;sur la pile pour ne pas recalculer (cf [@@] + bas)

mov bl, 25              ;bl sera le compteur des cycles (25)
cycle:
xor si, si              ;ds:si=segment de stockage
xor di, di              ;es:di=video
mov cx, 50*320          ;on degrade les 50 premieres lignes 
degrade:
mov al, es:[di-1]       ;
add al, es:[di+1]       ;
adc ah,0                ;
add al, es:[di+320]     ;somme des pixels autour de l'offset di, dans ax
adc ah,0                ;
add al, es:[di-320]     ;
adc ah,0                ;
shr ax, 1
shr ax, 1               ;on divise par 4 donc on a la moyenne
je pas_dec              ;si ax=0, la couleur reste a 0
dec al                  ;sinon, on la decremente
pas_dec:
mov ds:[si], al         ;on met la valeur du nouveau pixel
inc si                  ;dans la zone de stockage
inc di
loop degrade            ;on recommence pour toute la zone
	
xor si, si              ;quand c'est fini
xor di, di              ;on recopie toute la zone dans le
mov cx, (50*320)/2      ;segment de stockage
rep movsw               ;sur l'ecran video
	
dec bl                  ;un cycle de plus
jne cycle               ;on en a fait 25? Non=on recommence

			;on a maintenant sur l'ecran, meme si on ne voit
			;rien, des blocs adoucis, c'est le paysage en 2D

;--------------creation de la table 3D (x,y,z)------------------------
;(a partir du paysage 2D qui est sur l'ecran. Cette table fait
;128x50x(1+1+2)=25 ko, voila pourquoi on a besoin de presque un segment)
;ici es=video  ds=stock

push es                 ;on veut ds=video et es=stock
push ds
pop es
pop ds

mov cx, largeur*50+2    ;il va y avoir 128*50 coordonnees
xor si, si              ;debut de l'ecran video
xor di, di              ;debut du segment de stockage
mov dl, 128             ;il faut un compteur qui marque chaque fin de ligne
table:

mov ah, dl              ;LES X (LARGEUR): entre 0 et 128
shl ah, 1               ;maintenant entre 0 et 256
mov al, 128
sub al, ah              ;maintenant entre -128 et +128
stosb                   ;on stocke dans le segment de stockage

movsb                   ;LES Y (HAUTEUR) sont directement la
dec dl                  ;couleur du pixel
jne pas_fin_de_ligne    ;si dl=0 on est en fin de ligne
mov dl, 128             ;dans ce cas, on remet le compteur a 128
add si, 320-largeur     ;et on ajuste le pointeur video sur la ligne suivante
pas_fin_de_ligne:

mov ax, cx              ;LES Z (PROFONDEUR): entre 0 et 50*128
shl ax, 1               ;maintenant entre 0 et 50*256
xor al, al              ;on s'interesse a la partie lourde (entre 0 et 50)
xchg ah, al             ;on la met dans al
shl al, 1               ;maintenant entre 0 et 100
shl al, 1               ;maintenant entre 0 et 200
add ax, 0080h           ;entre 128 et 328 (profondeur la plus proche=128)
stosw                   ;on stocke
loop table

;--------effacer la carte 2D------------------------
;ici ds=video  es=stock    

push ds
pop es
xor di, di              ;effacement des 50 premieres lignes de 
mov cx, (320*50)/2      ;la video, sinon ca va se voir quand
xor ax, ax              ;on va changer la palette
rep stosw

;---------on met le curseur aux bonnes coordonnees---------------------

mov dx, 030Ah      ;dh,dl = coordonnees (lignes/colonnes)
xor bh, bh         ;sur la page 0
mov ah,02h         ;mettre le curseur a la position DH, DL
int 10h            ;int du BIOS pour placer le curseur
						    
;-----------on affiche les deux messages---------------------
;ici ds=es=video     

push cs
pop ds
lea si, message           ;si pointe sur le message
mov cx, 21                ;longueur du message
affiche_message:
	lodsb		;recuperer la lettre
	mov bl, 125     ;couleur=jaune
	mov ah, 0Eh     ;appel de
	int 10h         ;l'interruption "affichage d'1 caractere"
loop affiche_message

add dx, 507		;ajuster les coordonnees pour le second message
mov ah, 02h		;mettre le curseur aux bonnes coordonnees
int 10h			;interruption du BIOS pour placer le curseur
lea si, messag2		;si pointe sur le second message
mov cx, 32		;longueur du second message
affiche_messag2:
	lodsb		;recuperer la lettre
	mov bl, 50	;couleur=rouge
	mov ah, 0Eh	;appel de
	int 10h		;l'interruption "affichage d'1 caractere"
loop affiche_messag2

;------------------ajuster la palette martienne-----------------------

	mov dx, 3c8h    ;dx = port d'ecriture de la palette
	xor al, al      ;on commence par la couleur 0
	out dx, al      ;on ecrit la premiere couleur dans le port
	inc dx          ;on passe a la definition des couleurs
	
	xor cx, cx      ;
rouges:                 ;
	mov al, cl      ;
	out dx, al      ;boucle pour definir les 63 premieres couleurs
	xor ax, ax      ;avec la composante rouge qui augmente
	out dx, al      ;
	out dx, al      ;
inc cl             
cmp cl, 63
jne rouges;

	xor cx, cx      ;
jaunes:                 ;
	mov al, 63      ;
	out dx, al      ;
	mov al, cl      ;boucle pour definir les 63 couleurs suivantes
	out dx, al      ;avec la composante verte qui augmente
	xor al, al      ;
	out dx, al      ;
	inc cx          ;
	cmp cx, 63      ;
jne jaunes              ;


;-------------------animation du sol-----------------------------
;ici ds=cs, es=video

pop ds                         ;ds pointe vers le segment de stockage [@@]
anime:                         ;revient ici apres chaque ecran dessine
mov cx, largeur*50             ;on va dessiner 128*50 voxels
xor si, si                     ;ds:si=stockage des coordonnees
xor di, di                     ;es:di=video
dessine:                       ;revient ici apres chaque voxel dessine
lodsb                          ;le X dans al
xchg dl, al                    ;on le stocke dans dl
lodsb                          ;le Y dans al
xchg bl, al                    ;on le stocke dans bl
mov byte ptr bh, ds:[si+3+4]   ;le Y_SUIVANT (pour l'ombre) dans bh
lodsw                          ;le Z dans ax
mov word ptr cs:[offset z], ax ;on le stocke dans sa zone memoire temporaire
cmp ax, 0080h                  ;le voxel est a la limite vers l'avant?
ja ca_sort_pas                 ;si non on va le rapprocher
add ax, 200                    ;si oui on le remet au loin
ca_sort_pas:                   ;
dec ax                         ;on le rapproche donc
mov word ptr ds:[si-2], ax

;------calcule xx et yy (ecran 2D) a partir de x, y et z (espace 3D)------
;(par un effet de perspective)
;NB:gain de place et vitesse en faisant passer x par dl
;y par bl et y_suivant par bh

push cx                          ;on va utiliser cx qui est le compteur  
xchg ah, dl                      ;on recupere X dans ah 
cmp ah, 128                      ;X est positif?
jb suite5                        ;oui
neg ah                           ;non: on le rend positif
mov byte ptr cs:[offset signe],1 ;et on se souvient qu'il est negatif
suite5:                          ;attention: calculs en virgule fixe
xor al, al                       ;X est dans ah: meme ordre que Z  
xor dx, dx                       ;pour que dx vienne pas foutre la merde     
div word ptr cs:[offset z]       ;on divise X par Z
push ax                          ;le resultat est la coordonnee 2D (XX)
 
mov al, bl                       ;on recupere Y dans al
mov cl, 4                        ;on va diviser al par 16 pour avoir une
shr al, cl                       ;hauteur de montagne entre 0 et 16
mov ah, 80                       ;attention: montagnes a l'envers, niveau
sub ah, al                       ;du sol = altitude 80, donc soustraire

xor al, al                       ;calcul en virgule fixe: Y est dans ax   
xor dx, dx                       ;pour que dx vienne pas foutre la merde     
div word ptr cs:[offset z]       ;on divise Y par Z
xchg cx, ax                      ;le resultat est la coordonnee 2D (YY) 

;-------calcule l'offset video du voxel-----------------
;NB: gain de place et vitesse en faisant passer YY par cx et XX par la pile

pop dx                               ;on recupere XX de la pile dans dx
cmp cx, 142                          ;pas afficher si trop bas  
ja pas_plot
cmp dx, 155                          ;pas afficher si trop sur les cotes
ja pas_plot

push dx                              ;on remet XX sur la pile
mov ax, 320                          ;calcul de l'offset video
mul cx                               ;on multiplie YY par 320
pop dx                               ;on recupere XX de la pile dans dx
cmp byte ptr cs:[offset signe], 1    ;X et donc XX sont negatifs?
jne pos
sub ax, dx                           ;oui: on soustrait XX a ax
mov byte ptr cs:[offset signe], 0    ;et on remet le signe a 0
jmp suite4
pos:
add ax, dx                           ;non: on ajoute XX a ax

suite4:
add ax, (320*60)+160                 ;pour que l'image soit en bas de l'ecran 

;--------calcule la couleur du voxel (avec 2 effets d'ombre)-------------

; premier effet d'ombre: depend de la pente des bords des montagnes

mov di, ax                           ;ax est donc l'offset video du voxel
xchg ax, bx                          ;rappel: bx contient Y et Y_SUIVANT
sub al, ah                           ;on soustrait Y_SUIVANT - Y
add al, 100                          ;on y ajoute la couleur moyenne

; si le voxel est trop loin, le colorer en noir

mov word ptr bx, cs:[offset z]       ;bx=profondeur
cmp bx, 285                          ;s'il est a une bonne distance
jb pas_eteindre                      ;on l'affiche
xor al, al                           ;sinon on l'eteint (ca permet d'effacer
pas_eteindre:                        ;les montagnes a l'horizon)

; second effet d'ombre: plus c'est loin, plus c'est sombre

shr bx, 1                            ;effet d'obscurcissement dans le fond
shr bx, 1                            ;profondeur /4
sub ax, bx                           ;et on la soustrait de la couleur

;--------calcule la taille du voxel (proche=gros)------------------   

mov bx, 328               ;profondeur maximum
sub bx, cs:[offset z]     ;maintenant bx=0 (lointains) ou bx=200 (proches)
mov cl, 6                 ;on va le diviser par 64
shr bx, cl                ;maintenant 0<bx<3
inc bx                    ;maintenant 1<bx<4 
inc bx                    ;maintenant 2<bx<5 (largeur du voxel)
mov dx, 2                 ;le voxel va toujours faire 2 lignes de pixels
voxel:
mov cx, bx                ;et le nb de pixels de large est bx puis cx
rep stosb                 ;on les ecrit (rappel:couleur dans al)
mov cx, 320               ;il va falloir reprendre a la ligne en dessous
sub cx, bx                ;ajustement selon la largeur du voxel
add di, cx                ;on reprend a la ligne en-dessous
dec dx                    ;on a fini la premiere ligne
jne voxel                 ;on recommence la seconde

pas_plot:                 ;on tombe la en cas de depassement de l'ecran

pop cx                    ;ne pas oublier de recuperer le compteur
dec cx                    ;un voxel de plus
je suite9                 ;si on a calcule tous les voxels, on recommence
jmp dessine               ;on recommence pour le voxel suivant
suite9:         
	
	keystr2:
       mov     ah,01     ;routine pour arreter le bordel
       int     16h       ;Has a key been pressed?
	jnz fin          ;oui => stop
   
jmp anime                ;on recommence tout

;---------------------------fin du programme----------------------------

fin:
       mov ax, 3        ;revenir en    
       int 10h          ;mode texte

       mov ax,4c00h     ;redonner la main
       int 21h          ;au DOS

;----------------------zones memoire utilisees-----------------------
message db "Mars Land, by Spanska"		;message 1
messag2 db "(coding a virus can be creative)"	;message 2
aleat dw 0FAh					;pour la routine random
z dw 3            				;pour stocker z 
signe db ?					;pour le signe de X
code    ends
	end     terrain

;------------------------(c) Spanska 1997------------------------------

--- MARS.ASM ------------------------------------------------------------------


-------[  EOF
