
#ifndef __H_EFFECTS
#define __H_EFFECTS


//#define PLACEHOLDERS


void	Init_All_Effects();
void	Update_All_Effects();
void	Draw_All_Effects();
void	Kill_All_Effects();
void pickupClearSpells();


// lots of drawlines
void RadiusCheckCheck(SVECTOR *pos, int r);


/****************************************************************************/

extern SPRITEX*	overlayssprpointer;


//dont forget a bit field shpuld be set up of all the Garibs collected.
//Becuase this information needs to be saved onto memory card 
#define GARIBFLAG_COLLECTED 1
#define GARIBFLAG_DISPLAY   2

typedef struct tagGARIBPOS{
//	USHORT num;  //set top bit of num if collected 
	SHORT shadowheight;
	SHORT x,y,z;

	SHORT targy;
	int yvel;
	int accy;


	BYTE type; // 0=normal, 2=extra life
	BYTE flags;
	BYTE group;
//	BYTE scoretimer;
//	BYTE scorevalue;
}GARIBPOS;

// this is from "collect.h" in the n64
enum
{
	NORMAL_GARIB,
	SUPER_GARIB,
	EXTRA_LIFE,
	GENERATED_GARIB,
	GENERATED_LIFE,
//	NUM_GARIB_TYPES
};


extern	GARIBPOS *garibpositions;
extern ULONG numberofgaribs; //set to garibs on THIS level, including extra lives;
extern ULONG numGaribs;	// number of garibs on level, including non-existant ones inside enemies
// temp mod by Fred till I get a better counting mech going
//(atbonus goes over 100)
#define MAX_GARIBS 150

//#define GARIB_DRAW_SIZE 300
//#define GARIB_COLL_W 10
//#define GARIB_COLL_H 12

#define GARIB_DRAW_SIZE 240
#define ELIFE_DRAW_SIZE 300
#define GARIB_COLL_W 8
#define GARIB_COLL_H 10

void	   	Update_Garibs();
void	   	Update_Garibs_Cabonus();
void	   	Draw_Garibs();

void Effects_LevelStart();
void Effects_LoadShapes();


/*********************************************/

// Again, Fred's been horrible for a while...
/*
#define MAX_MR_TIPS 8

typedef struct tagMRTIPS{
	SHORT x,y,z,num;
}MRTIPS;

extern	MRTIPS *mrtippositions;
extern ULONG numberofmrtips; //set to garibs on THIS level, including extra lives;
void	   	Update_MrTips();
void	   	Draw_MrTips();
*/

/*************************************************************/

void	Draw_Enemies();


// vec is the (small-numbers, not *4096) 3d coords of the shadow. It's always drawn "flat" at the mo
// colour = 0x7f7f7f for a black shadow, f'rinstance
// radius = 4 or 5 for small (garib), 10 for smallish enemies/balls/gloves...
// matrix is assumed to be set to world-level (gte_SetRotMatrix(&GsWSMATRIX); gte_SetTransMatrix(&GsWSMATRIX))
// set otz = -1 to have it calculated
void Draw_RawShadow(SVECTOR *vec, LONG radius, ULONG colour, LONG otz);





#if (GOLDCD==YES) || (RELEASE==YES)
	#define Draw_RadCheckRing
#else
	void Draw_RadCheckRing2(SVECTOR *vec, LONG radius, ULONG colour);
#endif




#define MAX_DEBRIS 60
typedef struct DEBRISTAG
{
	struct DEBRISTAG *next;
	VECTOR pos;
//	VECTOR vel;
	unsigned char type;
	unsigned char timer;
	int value;
}DEBRISSTR;

enum								
{
	DEBRIS_FREE,		// 0
	DEBRIS_BLUESTAR,	// 1
	DEBRIS_POINTS,		// 2
	DEBRIS_LIFEGLOW,	// 3
	DEBRIS_RINGSTAR,	// 4
	DEBRIS_WISP,		// 5
	DEBRIS_SPELLDUST,	// 6
	DEBRIS_SPELLFLASH,	// 7
	DEBRIS_FLAME,		// 8
	DEBRIS_STUNSTAR,	// 9
	DEBRIS_AIMBLOB,		// 10
	DEBRIS_DUST,		// 11
	DEBRIS_PORTALPUFF,	// 12
	DEBRIS_PORTALPUFF2,	// 13
	DEBRIS_STINGEXPLODE,
	DEBRIS_HOOPHOVER,
	DEBRIS_SMOKE,
	DEBRIS_TRACY_HEART,
	DEBRIS_OPEC_HOVER,
	DEBRIS_FASTFLAME,
	DEBRIS_ROBOTHOVER,
	DEBRIS_STEAM,
	DEBRIS_CANNON,
	DEBRIS_FRANKLECCY,
	DEBRIS_FRANKLECCY2,
};

void KillAllDebris();
void DebrisInit();
void DebrisFree();


// use of "value" is debris-type dependant
DEBRISSTR *New_Debris(int type,VECTOR *pos, int value);
//DEBRISSTR *New_VelocityDebris(int type,VECTOR *pos, VECTOR *vel, int value);
void New_StarRingDebris(VECTOR *pos, int num_stars);
void New_PortalDebris(VECTOR *pos);
void New_RobotHoverDebris(VECTOR *pos);

// bgrcolour = 0x808000 for cyan lightening
void effectsDrawLightningStrand(SVECTOR *v1, SVECTOR *v2, LONG bgr_colour);
void effectsStartBlastRing(VECTOR *pos, int minrad, int maxrad, int time);
void effectsStartNMEBlastRing(VECTOR *pos, int minrad, int maxrad, int time);

#define MAXBLASTRINGS 3
typedef struct BLASTRINGTAG
{
	VECTOR v;
	int time;
	int count;
	int minrad;
	int maxrad;
	char active;
	char enemy;
}BLASTRING;
void effectsDraw_BlastRing(BLASTRING *br);


void effectsStartOverlay(int timer, int colour);


void Kill_Debris(DEBRISSTR *debris, DEBRISSTR **prev);
void Update_Debris();
void Draw_Debris();

extern int sinewave1;
extern int sinewave2;

#define MAX_SPELLS 6

// what a spell's doing
// (homing on the ball/glove/...)
enum
{
	SPELLACTION_BALLTRANS,
	SPELLACTION_NMETRANS,
	SPELLACTION_RUNOUT,
	SPELLACTION_GLOVETRANS
};


enum
{
// this lot match up with "ball_mode_normal" onwards
	SPELL_BALL_NORMAL,
	SPELL_BALL_BOWLING,
	SPELL_BALL_POWER,
	SPELL_BALL_BEARING,
	SPELL_BALL_BEACH,
	SPELL_BALL_SNOW,
	SPELL_BALL_CRYSTAL,

// others
 // The ball can certainly be hit by a boomerang spell, for a start...

 // you fire these at baddies
	SPELL_DEATH,
	SPELL_FROGGY,			// you'll be hit by a froggy spell when you collect the powerup

// pickups fire these at the glove
	SPELL_SUCTION,
	SPELL_HERCULES,
	SPELL_SPEEDUP,
	SPELL_ROTORBLADES,
	
// pickups fire these at the ball
	SPELL_BOOMERANG,
	SPELL_VANISH,

// special cases
	SPELL_CARNIVAL_CAMEO,	// evil glove fires at Kloset
	SPELL_FROGGIFY,			// Ethel fires these at you at the moment. (Different from "froggy")
	SPELL_PIRATES_UNFROG,
	SPELL_PIRATES_SPANK,

	SPELL_CANCERBALL,

	NUM_SPELLS

};


typedef struct TAGSPELL
{
	int timer;
	int headcolour;
	int tailcolour;
	VECTOR pos;
//	VECTOR *targ;

	void *target;	// pointer to an "enemypos" if action's "nmetrans"

	SHORT angles[2];
	SHORT turnrate;
	SHORT type;
	SHORT duration;
	char action;
}SPELLSTR;


// the general version
SPELLSTR *pickupFireSpell(int type, VECTOR *pos, SHORT dirn, void *target, char action);

int pickupFireGloveSpell(int type);	// fire spell from glove
// fire spell from pickup to glove/ball
int pickupFirePickupSpell(int action,VECTOR *pos, int type, int duration);

// for calling from puzzle-related routines...
void EnableGaribGroup(int group, int enable);
void DropGaribGroup(int group, int height);
void ReleaseEnemyGarib(VECTOR *pos);
void pickupHomer(VECTOR *pos, SHORT *angs, VECTOR *targ, SHORT turnrate, int speed);

unsigned int effectsColourNear(unsigned int bgr, int range);
// returns psx-style bgr
// hex = 0...5, dist = 0...255, pastel = 0...127
unsigned int effectsGetPrimary(int hex, int dist, int pastel);

// "flat" as in 3d-flat
#define P3DS_ADD	(0x20000000)
#define P3DS_SUB	(0x40000000)
#define P3DS_ADD2	(0x60000000)
#define P3DS_SEMI	(0x80000000)

void drawFlatPolygon(SPRITEX *sprite, VECTOR *pos, LONG radius, int spin, ULONG colour);
int Print3DSprite(SPRITEX *spr,VERT *vect,SHORT scale, unsigned long colour);

int Print3DAlphaSprite(SPRITEX *spr,VERT *vect,SHORT scale, unsigned long colour);

#define BALLGARIBCOLLRADIUS 15
#define GLOVEGARIBCOLLRADIUS 15
#define GARIBCOLLRADIUS 10
#define GARIBSCORINGTIME 30


// spritex of the test tube
extern SPRITEX *SPR_tubebase;
extern SPRITEX *SPR_fairbase;
extern SPRITEX *SPR_aiglowbase;

#define EFFECT_BOXCOLL_BALL  1
#define EFFECT_BOXCOLL_GLOVE 2
int effect_BoxCollideWithPlayer(int test,SVECTOR *pos, int radius);

int AngleHomer(int ang, int targ, int speed);
int IntHomer(int val, int targ, int speed);
int RadiusCheck4096(VECTOR *vec, LONG radius, int maxdist);

#define MAX_SCENERIES 20

#define gte_SetLDDQA( r0 ) __asm__ volatile (		\
	"ctc2	%0, $27"					\
	:							\
	: "r"( r0 ) )

#define gte_SetLDDQB( r0 ) __asm__ volatile (		\
	"ctc2	%0, $28"					\
	:							\
	: "r"( r0 ) )


// ============================================================
// al-vars


extern SPRITEX*	overlayssprpointer;
extern ULONG numberofgaribs; //set to garibs on THIS level, including extra lives;
extern ULONG numGaribs;	// normal garib count, including ones inside enemies
extern GARIBPOS *garibpositions;
extern ULONG garibscollected;


//extern MRTIPS *mrtippositions;
//extern ULONG numberofmrtips; 


//extern ENEMYPOS *enemies;
//extern ULONG numberofenemies;

//extern SCENERYPOS *sceneries;
//extern ULONG numberofsceneries;


extern SPRITEX *cardbase;
extern SPRITEX *extralifebase;
extern SPRITEX *mrtipbase;
extern SPRITEX *glowbase;
extern SPRITEX *sparklebase;
extern SPRITEX *garibscorebase;
extern SPRITEX *shadbase;
extern SPRITEX *bstarbase;
extern SPRITEX *starbase;
extern SPRITEX *wispbase;
extern SPRITEX *SPR_tubebase;
extern SPRITEX *SPR_fairbase;
extern SPRITEX *SPR_aiglowbase;

extern SPRITEX *SPR_fardabase;
extern SPRITEX *SPR_fardsbase;

extern SPRITEX *SPR_firebbase;
extern SPRITEX *SPR_smokebase;
extern SPRITEX *SPR_bringbase;
extern SPRITEX *SPR_puffbase;

//extern SPRITEX *SPR_cheatbase;
extern SPRITEX *SPR_cheats[4];

extern ULONG garibbulging;
extern ULONG lastgaribframe;
extern BYTE  currentgaribscore;

extern int garibsparkrad;
extern int garibsparky;
extern int garibsparkvel;

extern int sinewave1;
extern int sinewave2;

extern DEBRISSTR *debris;
extern DEBRISSTR *active_debris;
extern DEBRISSTR *free_debris;

extern int effectsOVduration;
extern int effectsOVtimer;
extern int effectsOVcolour;


extern NEWMODEL *orbiterpsas[NUM_SPELLS];
extern BLASTRING glove_br;


extern int current_spell;
extern SPELLSTR spells[MAX_SPELLS];

extern SPRITEX *gar_frame;


/*************************************************************/
#endif /*EFFECTS*/


