#include "neslib.h"

#define PROFILE_BEGIN()			*((unsigned char*)0x401e)=0;
#define PROFILE_END()			*((unsigned char*)0x401f)=0;

enum {
	NMI_EMPTY=0,
	NMI_NORMAL,
	NMI_TITLE,
	NMI_VID_DMC
};

enum {
	IRQ_EMPTY=0,
	IRQ_ROW_ADR,
	IRQ_NESCART,
	IRQ_ROLL_FADE,
	IRQ_ROW_FULLX,
	IRQ_INSPIRED,
	IRQ_DUNGEON,
	IRQ_PACMAN
};

#define M_VERTICAL			0
#define M_HORIZONTAL		1

#define PRG_BGM1			0x00	//three bansk for music data
#define PRG_BGM2			0x01
#define PRG_BGM3			0x02

#define PRG_SAMPLE			0x03	//one bank for software DPCM samples
#define PRG_NESCART_ROTATE	0x04	//three banks just for rotate table

#define PRG_OVL7			0x07
#define PRG_OVL8			0x08
#define PRG_OVL9			0x09
#define PRG_OVLA			0x0a
#define PRG_OVLB			0x0b
#define PRG_OVLC			0x0c
#define PRG_OVLD			0x0d

#define PRG_MAIN			0x0e

#define CHR_INTRO			(0x00*8+0)
#define CHR_BARS			(0x00*8+4)
#define CHR_FONT			(0x01*8+0)
#define CHR_NOISE			(0x01*8+4)
#define CHR_VID				(0x02*8+0)
#define CHR_TITLE			(0x02*8+4)
#define CHR_KIRBY_GOOD		(0x03*8+0)
#define CHR_KIRBY_EVIL		(0x04*8+0)
#define CHR_NESCART			(0x05*8+0)
#define CHR_NESCART_TEXT	(0x05*8+4)
#define CHR_INSPIRED		(0x06*8+0)	//8 banks of animation
#define CHR_GREETS_FONT		(0x0e*8+0)
#define CHR_VADERS			(0x0e*8+4)
#define CHR_PACMAN			(0x0f*8+0)
#define CHR_TOWER_TEXTURE_1	(0x10*8+0)
#define CHR_TOWER_TEXTURE_2	(0x10*8+0)
#define CHR_TOWER_TEXTURE_3	(0x12*8+0)
#define CHR_DUNGEON_FWD		(0x14*8+0)
#define CHR_DUNGEON_ROT		(0x14*8+4)
#define CHR_DUNGEON_SPRITE	(0x15*8+0)



//update and split list put into separate segments to keep them aligned to page
//they're also reused sometimes for other purposes

#pragma bssseg (push,"UPDLST")
#pragma dataseg(push,"UPDLST")

unsigned char update_list[256];

#pragma dataseg(pop);
#pragma bssseg (pop);

#pragma bssseg (push,"SPLIST")
#pragma dataseg(push,"SPLIST")

unsigned char split_list[256];

#pragma dataseg(pop);
#pragma bssseg (pop);

#pragma bssseg (push,"ZEROPAGE")
#pragma dataseg(push,"ZEROPAGE")

unsigned char oam_off;
unsigned char oam_step;

unsigned char upd_off;

unsigned char _i;
unsigned char _j;
unsigned char _id;
unsigned char _sx;
unsigned char _sy;
unsigned char _pal;
unsigned char _col;
unsigned char _row;
unsigned char _spr;
unsigned char _tile;
unsigned char _attr;
unsigned char _mask;
unsigned char _ptr;

#pragma dataseg(pop);
#pragma bssseg (pop);



//assembly functions

void __fastcall__ ovl_call(unsigned char prg,void (*func)(void));

void __fastcall__ set_nmi_handler(unsigned char id);
void __fastcall__ set_irq_handler(unsigned char id);

void __fastcall__ mmc3_irq_enable(unsigned char enable);
void __fastcall__ mmc3_chr_bank(unsigned char bank,unsigned char page);
void __fastcall__ mmc3_set_mirroring(unsigned char mode);

void __fastcall__ oam_clear_fast(void);

void __fastcall__ oam_meta_clip_y(int sx,int sy,unsigned char pal,const unsigned char *meta);
void __fastcall__ oam_meta_clip_x(int sx,int sy,unsigned char pal,const unsigned char *meta);

unsigned char playdump_sync;

void __fastcall__ playdump_start(unsigned char prg,const unsigned char* src);
void __fastcall__ playdump_stop(void);
void __fastcall__ playdump_soft_dmc(unsigned char prg,const unsigned char* src,unsigned int len);

extern const unsigned char m_bgm1_dendy_rus[];
extern const unsigned char m_bgm1_signal[];
extern const unsigned char m_bgm1_title[];
extern const unsigned char m_bgm1_vaders[];
extern const unsigned char m_bgm2_kirby[];
extern const unsigned char m_bgm2_greets[];
extern const unsigned char m_bgm3_credits[];
extern const unsigned char m_bgm3_demo[];
extern const unsigned char m_bgm3_pacman[];
extern const unsigned char m_bgm3_dungeon[];

#pragma rodataseg (push,"PRG3")
#pragma codeseg   (push,"PRG3")

#include "data/fatality_1.h"
#include "data/fatality_2.h"

#pragma codeseg   (pop)
#pragma rodataseg (pop)



#pragma rodataseg (push,"PRG_OVLD")
#pragma codeseg   (push,"PRG_OVLD")

#include "e_ntsc_only.h"
#include "e_intro.h"
#include "e_bars.h"
#include "e_noise.h"
#include "e_roll.h"

#pragma codeseg   (pop)
#pragma rodataseg (pop)



#pragma rodataseg (push,"PRG_OVLC")
#pragma codeseg   (push,"PRG_OVLC")

#include "e_nescart.h"
#include "e_based.h"
#include "e_kirby.h"
#include "e_vid.h"
#include "e_ok.h"
#include "e_pacman.h"
#include "e_vaders.h"

#pragma codeseg   (pop)
#pragma rodataseg (pop)



#pragma rodataseg (push,"PRG_OVLB")
#pragma codeseg   (push,"PRG_OVLB")

#include "e_title.h"
#include "e_dungeon.h"

#pragma codeseg   (pop)
#pragma rodataseg (pop)



#pragma rodataseg (push,"PRG_OVLA")
#pragma codeseg   (push,"PRG_OVLA")

#include "e_inspired.h"

#pragma codeseg   (pop)
#pragma rodataseg (pop)

#pragma rodataseg (push,"PRG_OVL9")
#pragma codeseg   (push,"PRG_OVL9")

#include "e_greets.h"

#pragma codeseg   (pop)
#pragma rodataseg (pop)



void main(void)
{
	bank_bg(0);			//mmc3 interrupts won't work if sprites and BG set to the same PPU table, they must be in the different tables
	bank_spr(1);

	set_nmi_handler(NMI_NORMAL);
	
	if(!ppu_system())
	{
		delay(30);
		ovl_call(PRG_OVLD,e_ntsc_only);
	}

	delay(1*60);
	ovl_call(PRG_OVLC,e_based);
	
	delay(3*60);
	playdump_start(PRG_BGM1,m_bgm1_dendy_rus);
	ovl_call(PRG_OVLD,e_intro);
	playdump_stop();
	playdump_start(PRG_BGM1,m_bgm1_signal);
	ovl_call(PRG_OVLD,e_noise);
	ovl_call(PRG_OVLD,e_bars);

	playdump_start(PRG_BGM1,m_bgm1_title);
	delay(4*60);
	delay(40);
	ovl_call(PRG_OVLB,e_title);

	playdump_start(PRG_BGM1,m_bgm1_vaders);
	delay(104);
	ovl_call(PRG_OVLC,e_vaders);
	
	delay(24);
	playdump_start(PRG_BGM3,m_bgm3_demo);
	delay(24);
	ovl_call(PRG_OVLA,e_inspired);
	ovl_call(PRG_OVLC,e_nescart);

	playdump_start(PRG_BGM3,m_bgm3_pacman);
	ovl_call(PRG_OVLC,e_pacman);
	delay(30);
	
	playdump_start(PRG_BGM2,m_bgm2_kirby);
	ovl_call(PRG_OVLC,e_kirby);
	
	delay(60);
	playdump_start(PRG_BGM2,m_bgm2_greets);
	ovl_call(PRG_OVL9,e_greets);
	
	delay(60);
	
	playdump_start(PRG_BGM3,m_bgm3_dungeon);
	ovl_call(PRG_OVLB,e_dungeon);
	
	delay(60);
	
	playdump_start(PRG_BGM3,m_bgm3_credits);
	delay(60*2);
	ovl_call(PRG_OVLD,e_roll);
	
	playdump_stop();
	
	ovl_call(PRG_OVLC,e_vid);
	delay(60);
	ovl_call(PRG_OVLC,e_ok);
	
	while(1);
}
