program tutorial_18_horizontal_starfield;



// number of stars
@define noStars 25
@define useKernal 0
// Which character to use?
@define charPos 64
// where to put char ROM data?
@define charsetPos $2000
// Use bank 1
@define screenLoc $04


/*
	This effect assumes 1 star per horizontal line, in total 25
	you could theoretically add more stars and goto x,y location, but this will slow down the process considerably. I would rather recommend having 2 stars per line if you need more

*/


var  
   	i,j,k,x,y,dx, time: byte = 0; 
	// a star can have 8 values in a single char
	charsetVals: array[8] of byte =(1,2,4,8,16,32,64,128);	
		// Star position in memory (0-40)
	posx: array[@noStars] of byte;
	// Star position in char pos (0-64) / 8 with range 0-7
	posdx: array[@noStars] of byte;
	// speed of star, subtracted to posdx, range 0-64 divided by 8
	posddx: array[@noStars] of byte;

	// Star color
	color: array[@noStars] of byte;
	// random table
	rands: array[256] of byte;
	zp,cp:pointer;
	starColors:array[8] of byte=(11,1, 2, 10, 6, 14, 7, ,1);//GREY, WHITE, RED, LIGHT_RED, BLUE, YELLOW, LIGHT_BLUE, WHITE);
	
	text: string = "EAT LOTS OF OATS";



// Creates 8 characters with 1 dot in each char from @charPos
procedure GenerateCharset();
begin
	zp:=@charsetPos;
	for i:=0 to @charPos do inczp(zp,8);
	for i:=0 to 8 do begin
		for j:=0 to 8 do begin
			zp[j]:=0;
		end;
		zp[4]:=charsetVals[i];
		inczp(zp,8);
	end;

end;

// initializes starfield
procedure InitializeStarfield();
begin
	j:=42;
	for i:=0 to @noStars do begin
		posx[i]:=rands[i]/2;  // 0-40
		posdx[i]:=rands[j]&63; // 0-64 (will be divided by 8)
		color[i]:=starColors[j&7];  // 0-7
		posddx[i]:=rands[i]&7+1;  // 1-8
		j:=j+11; // just some random shift
	end;
end;

procedure InitializeRand();
begin
	for i:=0 to 0 do begin
		rand(0,80,j);
		rands[i]:=j;
	end;

end;

// Renders field & colors
// this procedure can be seriously optimized, for example you don't need to write color memory (can be done while initializing), divide by 8 can be in a table, 
// the charpos should be inverted and lose the +7, write in assembler etc
procedure RenderStarfield();
begin
	moveto(0,0,@screenLoc);
	cp:=$D800;
	for i:=0 to @noStars do begin
		if i<>12 then begin // ignore stars at line 12
			x:=posx[i];
			dx:=posdx[i]/8;
			screenmemory[x]:=@charPos+7-dx;
			if x<>39 then
				screenmemory[x+1]:=$20
			else
				screenmemory[0]:=$20;

			cp[x]:=color[i];

		end;
		inczp(screenmemory,40);
		inczp(cp,40);
	end;
end;

// Moves the stars


procedure UpdateStarfield();
begin
	for i:=0 to @noStars do begin
		dx:=posdx[i]-posddx[i];
		if dx>127 then begin
			posx[i]:=posx[i]-1;
			if posx[i]>127 then begin	
				posx[i]:=39;
				posddx[i]:=rands[time]&7+1;
			end;
			posdx[i]:=63;


		end
		else 	
		posdx[i]:=dx;
	end;

end;


procedure InitializeText();
begin
	moveto(12,12,$04);
	printstring(text,0,20);

end;




interrupt Raster1();
begin
	StartIRQ(@useKernal);
	inc(time);
	RenderStarfield();	
	UpdateStarfield();
	closeIRQ();
end;




// Main routine
begin
	InitializeRand();
	InitializeStarfield();
	GenerateCharset();
	SCREEN_BG_COL:=BLACK;
	SCREEN_FG_COL:=BLACK;
	clearscreen($20,^$0400);	
	//VIC_DATA_LOC:=@charsetVicData;
	SetCharsetLocation(@charsetPos);
	copycharsetfromrom(^@charsetPos);
	InitializeText();
	

	SetMemoryConfig(1,@useKernal,0);
	StartRasterChain(Raster1(),$00,@useKernal);
	Loop(); 

end.
