program Tutorial_2_hello_sprites;

/*
	
	This example shows how to draw a simple background, turn on sprites,
    move the sprites around & finally play some music

*/

var  
   	i,k,j: byte; 
   	// Use the original zelda music score
	music: incnsf("music/zelda.nsf");
	// Standard palette. Use YYchr (https://www.romhacking.net/utilities/119/) to create and edit.

	
	// Location of the sprite
	sprite_x, sprite_y : byte;

	// Data location of the sprite (at $0200)
//	@define spriteLocHi $03
	@define spriteLoc $204
	
	palette: incbin("tiles/game_tiles.pal");
	
// Make sure game tiles are being automatically exported
@export "tiles/game_tiles.flf" "tiles/game_tiles.bin" 256


// Make sure that the sprites are automatically exported! 3 in total
@export "tiles/game_sprite_meta.flf" "tiles/spritedata.bin" 3
	spriteData : incbin("tiles/spritedata.bin");	
	// Format: Y, sprite, palette, X


	zp:pointer;


// Forward decleration
procedure SetSpritePosition();

// Empty
interrupt IRQ();
begin

end;


// Moves the player. ReadInput populates the "buttons" variable
procedure MovePlayer();
begin
	ReadInput();
	sprite_x:=sprite_x+getbit(buttons,1)-getbit(buttons,0); // x axis
	sprite_y:=sprite_y-getbit(buttons,2)+getbit(buttons,3); // y axis
	// Set sprite location after update
	SetSpritePosition();	


end;


// NMI will automatically be called on every vblank. Update PPU gfx here! For now,
// it is emtpy. 


interrupt NMI();
begin
	// Startirq pushes a,x,y onto the stack
	Startirq(0);
	// First, make sure that the PPU knows that sprites are located at @spriteLoc
	SetSpriteLocation(hi(^@spriteLoc));
	
	SetNametable(0);

	// Play the song!
	PlaySong();
	// MovePlayer should really be called outside the NMI, waste of raster time
	MovePlayer();
	// Make sure that sprite properties are set, re-enable NMI
	ToggleSpriteSize(0);
	ToggleSpriteTableAddress(0);
	ToggleBackgroundTableAddress(1);
	
	CloseIRQ();
end;




/*
	SetSpritePosition sets the sprite location (x,y) for the four sprites
	to (sprite_x, sprite_y)+(offset_x, offset_y), where the offsets are defined in colum 0,3 in 
 	the spritedata table. 
	
*/
procedure SetSpritePosition();
begin
	k:=16;
	j:=16;

	for i:=0 to 4 do begin
		poke(^@spriteLoc,k+0,spriteData[j+0]+sprite_y);
		poke(^@spriteLoc,k+3,spriteData[j+3]+sprite_x);
		k:=k+4;
		j:=j+4;
	end;

end;
/*
 	Simple sprite initialization: Copy sprite data, update sprite position
*/
procedure InitSprites();
begin
	fill(^$200,$FF,0);
	memcpy(#spriteData, 0,^@spriteLoc,6*16);
	SetSpritePosition();
end;

/*
 	Renders an initial screen:
 		- attribute table filled with random value %10101010
		- background namespace(0) = $2000 filled with two rows of value 96 (some random block)
*/
procedure InitScreen();
begin
	
	// Fill screen with some random values at $2000
	ppupointi($2000+32*20);
	for j:=0 to 10 do
		for i:=0 to 32 do ppuwrite(i&5+2 + ((j&1)*16));
		
	// Fill colour attributes at $23C0
	ppupointI($23C0);
	for i:=0 to 63 do 
		ppuwrite(i|01010100);
	


end;


/*
	Initializes variables
*/
procedure InitVariables();
begin
	sprite_x:=70;
	sprite_y:=40;
end;


// Starting point after resetting the NES
begin




	// Load palette
	LoadPalette(#palette);
	// Set up background & color values
	
	InitScreen();
	InitSprites();


	// Turn on background
	ToggleBackground(1);
	// Display background in border 0
	ToggleBorderBackground(1);


	// Load music
	LoadSong(2);
	InitVariables();
	// Turn on NMI and RUN!
	ToggleNMI(1);
	
	// Halt! (this is where non-drawing gamelogic should happen)
	Loop();
end.
