program MatrixEffect;
var  
   	i,j: byte; 
   	// The ypos array will contain the current pos for each column, ranging from 0-200. These values are divided by 8
   	// before being used as a y-coordinate
   	ypos : array[screen_width] of byte;
   	// Yadd contains the addition value for each column. Is reset for each cycle
   	yadd : array[screen_width] of byte;
   	// Screen and color address tables
	saddr: array[screen_width] of integer; // Screen address table
	caddr: array[screen_width] of integer; // Color adress table
   	sp:pointer;

/*
	Method that initializes the lookup tables used in this program
*/
procedure InitTables();
begin
	// Yadd has random values (0-255)/80 +1
	for i:=0 to screen_width do yadd[i]:=random()/80+1;
	// ypos has values 0-128
	for i:=0 to screen_width do ypos[i]:=random()/2;
	// Lookup address tables for 40 column mode, screen address and color address
	createaddresstable(saddr,screen_char_loc,screen_width,screen_height);
	createaddresstable(caddr,screen_col_loc,screen_width,screen_height);

end;

/*
	Small method that fills a color at a specific x/y value on screen.
	Only fills the value if the y is in a valid range 0..24
	If y is less than zero (>240), then we just cycle add with 25 
*/
procedure FillColor(xx,yy,cc:byte);
begin
	if (yy>240) then yy:=yy+screen_height;
	if (yy<screen_height) then 
	begin
		sp:=AddressTable(caddr,xx,yy);
		sp[0]:=cc;	
	end;
end;

/*
	Renders the actual matrix effect
*/
procedure RenderMatrix();
begin
	// Look through 80 columns
	for i:=0 to screen_width do 
	begin
		// Calculate actualy y screen position
		j:=ypos[i]/8;
		// Print random character
		if (j<screen_height) then begin
			sp:=AddressTable(saddr,i,j);
			sp[0]:=random()/4; // random character is located between 0 and 64
		end;
		// Fill the "tail" colors
		FillColor(i,j,light_green);
		FillColor(i,j-1,green);
		FillColor(i,j-2,grey);
		FillColor(i,j-3,dark_grey);
		FillColor(i,j-8,black);
		
		// increase ypos[i] with yadd[i]		
		ypos[i]:=ypos[i]+yadd[i];
		// Reset values when ypos is outside of the screen
		if (ypos[i]>=240) then
		begin 
			ypos[i]:=0;
			yadd[i]:=random()/80+1;
		end;
	end;	
end;	

/*
	Main block
*/
begin
	// Setup screen foreground / background colors
	screen_bg_col:=black;
	screen_fg_col:=black;
	// Clear screens	
	clearscreen(key_space,screen_char_loc);
	clearscreen(black,screen_col_loc);
	// Initialize tables	
	InitTables();
	
	// Loop effect
	while(true) do
	begin
		waitforraster(0);	
		RenderMatrix();

	end;
end.
