program Tutorial3_Levels;
@use levels
@use screens

// Export the level data
@export "images/level.flf" "images/level.bin" 256

// Export the metatile data (2x2 chunks of tiles)
@export "images/metatiles.flf" "images/metatiles.bin" 256

// Export the tile data
@export "images/tiles.flf" "images/tiles.bin" 256


// Delete the packed data
@deletefile "images/sprites_packed.flf"
// Delete the packed index lookup file
@deletefile "images/sprites_index.bin"

// Pack sprite 1 : girl at 0,0 - 2,3 in "sprites.flf"
@spritepacker "images/sprites.flf" "images/sprites_packed.flf" "images/sprites_index.bin" "gameboy" 0 0 2 3 0
// Pack sprite 2 : girl at 2,0 - 4,3 in "sprites.flf"
@spritepacker "images/sprites.flf" "images/sprites_packed.flf" "images/sprites_index.bin" "gameboy" 2 0 2 3 0
// Pack sprite 3 : girl at 4,0 - 6,3 in "sprites.flf"
@spritepacker "images/sprites.flf" "images/sprites_packed.flf" "images/sprites_index.bin" "gameboy" 4 0 2 3 0

// Export the packed file to a binary file
@export "images/sprites_packed.flf" "images/sprites_packed.bin" 64


var  
	// Bank to place sprites
	const levelBank : byte = 3;
	// Bank to place sprites
	const spriteBank : byte = 2;
	const stop_pos : byte = 100;
	const stop_pos2 : byte = (128+16)-stop_pos;
	
	level_data : incbin("images/level.bin") bank(levelBank);
	tiles : incbin("images/tiles.bin") bank(levelBank);
	metatiles : incbin("images/metatiles.bin") bank(levelBank);


	i,j,k,colldirx, colldiry, curx, cury, x,y,time,spritex,spritey,curLevel,sx,sy,pos,pad1,pad2,px,py  : byte;
	blockr, blockl, blockup, blockdown : byte;
	// A temporary address to store the screen
	
	sprites_index : incbin("images/sprites_index.bin") bank(spriteBank);
	
	sprites_data : incbin("images/sprites_packed.bin") bank(spriteBank);

	// 1 sprite takes up 4 bytes, the grl sprite is 3x2x4 bytes starting at $C000 (Sprite ram)
	sprGirl : array[3*2*4] of byte sprram;

	p1:pointer;


procedure RenderLevel(x,y : global byte);
begin
	current_bank := levelBank;
	Levels::lp := #level_data;
	Levels::RenderLevel2x2MetaTiles(x,y);
	// Remember to turn off LCD before copying to VRAM!
	Screens::StopLCD();
	memcpy(^$D000,screen0,$400);
	Screens::Set9800();
end;

procedure UpdateCollision();
begin
	x:=px/8;
	y:=py/8;
	y:=y+colldiry;
	x:=x+colldirx;
		
	p1:=Levels::temp+y*32;
	i:=p1[x];
	blockr:=0;
	blockl:=0;
	blockdown:=0;
	blockup:=0;
	
	if (i<>$24) then
	begin
		if (colldirx=1) then blockr:=1;
		if (colldirx=255) then blockl:=1;
		if (colldiry=1) then blockup:=1;
		if (colldiry=255) then blockdown:=1;
	end;	
end;


procedure UpdateSprite();
begin

	// Initialize sprite: address of internal table at $C000 (sprGirl), indices, position in sprite data, width, flipping
	current_bank:=spriteBank;

	Screens::InitSpriteFromData(#sprGirl,#sprites_index, pos, 6 ,2, 0);

	// Set sprite position			
	spritex:=px;
	spritey:=py;


	// Set correct sprite + scroll data from py 
	if (py>stop_pos) then
	begin
		spritey:=stop_pos;
		sy:=py-stop_pos;
		if (py>255-stop_pos2) then
		begin
			sy:=(128-16);
			spritey:=py-(128-16);
		end;
	end;	

	// Set correct sprite + scroll data from px 
	if (px>stop_pos) then
	begin
		spritex:=stop_pos;
		sx:=px-stop_pos;
		if (px>255-stop_pos2-16) then
		begin
			sx:=(128-32);
			spritex:=px-(128-32);
		end;
	end;	
	Screens::SetSprite(#sprGirl,spritex,spritey, 2,30);
	// Advance to next sprite		
	colldirx := 0;	
	colldiry := 0;	
	
	if (pad1&PAD_RIGHT=PAD_RIGHT) then begin colldirx:=1; end;
	if (pad1&PAD_LEFT=PAD_LEFT) then begin colldirx:=255; end;
	if (pad1&PAD_DOWN=PAD_DOWN) then begin colldiry:=255; end;
	if (pad1&PAD_UP=PAD_UP) then begin colldiry:=1; end;
	
	UpdateCollision();	
	
	if (colldirx=1) then begin if (blockr=0) then px:=px+1; end;
	if (colldirx=255) then begin if (blockl=0) then px:=px-1; end;
	if (colldiry=255) then begin if (blockdown=0) then py:=py-1;  end;
	if (colldiry=1) then begin if (blockup=0) then py:=py+1; end;


	
	if (colldirx <>0  or colldiry<>0) then
	if (time&7=0) then
	begin
		pos:=pos+6; // Point to next sprite
		if (pos=18) then pos:=0; // Reset sprite
	end;	

end;


procedure UpdateLevels();
begin
	if (px>=248) then
	begin
		px:=16;
		sx:=0;
		curx:=curx+1;
		RenderLevel(curx,cury);
	end;
	if (px<15) then
	begin
		px:=247;
		sx:=(128-16);
		curx:=curx-1;
		RenderLevel(curx,cury);
	end;
	if (py>=248) then
	begin
		py:=16;
		sy:=0;
		cury:=cury+1;
		RenderLevel(curx,cury);
	end;
	if (py<15) then
	begin
		py:=247;
		sy:=(128-16);
		cury:=cury-1;
		RenderLevel(curx,cury);
	end;
end;




procedure VBlank();
begin
	time:=time+1;
	Joypad(pad1,pad2);
	UpdateSprite();
	UpdateLevels();
	scrollx:=sx;
	scrolly:=sy;
	
end;



procedure InitLevelData();
begin
	current_bank := levelBank;
	// Set up tile data
	Screens::CopyFullCharset(#tiles);

	// Set TRU data to point to level & metatiles
	Levels::mt := #metatiles;
	
	Levels::ReadHeader(#level_data);
	// Set a nice palette
	background_palette:=%11010010;
	object0_palette:=%11010010;

end;


procedure InitSprites();
begin
	current_bank:=spriteBank;

	// Tile palette - set background to dark grey 	
	background_palette:=%11010010;
	// Sprite palette
	object0_palette:=%11010010;
	Screens::CopyBankHB(#sprites_data, vram, 8); // Copy 8x$100 bytes of data

end;

procedure InitVariables();
begin
	curx:=0;
	cury:=0;
	sx:=0;
	sy:=0;
	px:=50;
	py:=100;
	time:=0;
	curLevel:=0;
end;


begin
	Screens::InitDefaultScreen();
	InitVariables();
	InitSprites();	

	current_bank:=levelBank;

	InitLevelData();
	RenderLevel(curx,cury);
	

	
	// must have Vertical blank in order to be able to display sprites
	InitVBlank(VBlank());
	EnableVBLank();
	Loop();	
end.
