


#include "generic.h"
#include "lfptypes.h"
#include "define.h"
#include "ml.h"

#include "skel.h"
#include "playgfx.h"

#include "audio.h"

#ifdef PAL

 #define ANIM_SPEED1	 (0x600/5)
 #define BLEND_SPEED	 0x40
 #define BLEND_SPEED_LEG 0x20

#else

 #ifdef FLAG60
  #define ANIM_SPEED1	   0x80
  #define BLEND_SPEED	   0x20
  #define BLEND_SPEED_LEG  0x10
 #else
  #define ANIM_SPEED1	   0x100
  #define BLEND_SPEED	   0x40
  #define BLEND_SPEED_LEG  0x20
 #endif 


#endif

/***************************************************************************
 *
 * bool blend_to_end(playert *plyr, int top, int legs, int time)
 *
 ***************************************************************************
 *
 * blend current end of current animation with top and legs over time t
 *
 * return true when blending has finished
 *
 ***************************************************************************/

global bool blend_to_end(playert *plyr, int top, int legs, int time)
{
	if (plyr->top_anim == top)
	{
		if (plyr->top_blend_ctr == 0)	return TRUE;
		else							return FALSE;
	}

	if ( (frames_to_go(plyr)*0x100) <= (time*plyr->top_rate) )
	{
		int r;

		r = plyr->top_rate;
		start_blend_anim(plyr,top);
		plyr->top_rate = r;

		plyr->top_blend_ctr	  = 0x200;
		plyr->top_blend_speed = 0x100/time;

		if (legs)
		{
			start_blend_leg_anim(plyr,legs);
			plyr->leg_rate = r;
			plyr->leg_blend_ctr	  = 0x200;
			plyr->leg_blend_speed = 0x100/time;
		}
	}
	return FALSE;
}


global bool blend_to_end2(playert *plyr, int top, int legs, int time)
{
	if (plyr->top_anim == top)
	{
		if (plyr->top_blend_ctr == 0)	return TRUE;
		else							return FALSE;
	}

	if ( (frames_to_go2(plyr)*0x100) <= (time*plyr->top_rate) )
	{
		int r;

		r = plyr->top_rate;
		start_blend_anim(plyr,top);
		plyr->top_rate = r;

		plyr->top_blend_ctr	  = 0x200;
		plyr->top_blend_speed = 0x100/time;

		if (legs)
		{
			start_blend_leg_anim(plyr,legs);
			plyr->leg_rate = r;
			plyr->leg_blend_ctr	  = 0x200;
			plyr->leg_blend_speed = 0x100/time;
		}
	}
	return FALSE;
}





global void animate(playert *plyr)
{
SI fr;
SW an;
int blend_val;




	/*
		plyr->leg_blend_ctr = 0;
		plyr->top_blend_ctr = 0;
		plyr->leg_anim = LEG_RDY;
		plyr->top_anim = TOP_RDY;
		plyr->top_frame =
		plyr->leg_frame = (lp_ctr % 25) << 8;
		return;
		*/
	





	if (plyr->ikBlendSpeed)
	{
		plyr->ikBlend += plyr->ikBlendSpeed;
		if (plyr->ikBlend>0x100)
		{
			plyr->ikBlend	   = 0x100;
			SetIkBlendSpeed(animate,plyr,0);
		}

		if (plyr->ikBlend<0)
		{
			plyr->ikBlend	   = 0;
			SetIkBlendSpeed(animate,plyr,0);
		}
	}


	/* stand up straight after turn */
	if (plyr->pitch)
	{
		if (plyr->pitch > 0) plyr->pitch--;
		else				 plyr->pitch++;
	}


	head_turn(plyr);
	
    if ( plyr->top_blend_ctr > 0)
    {
		blend_val = plyr->top_blend_ctr;
		blend_val -= plyr->top_blend_speed;

		if (plyr->top_blend_ctr > 0x100)
		{
			if (blend_val <= 0x100)	blend_val = 0;
		}
		else
		{
			if (blend_val < 0)	   	blend_val = 0;
		}
		plyr->top_blend_ctr = blend_val;
    }

    if ( plyr->leg_blend_ctr > 0)
    {
		blend_val = plyr->leg_blend_ctr;
		blend_val -= plyr->leg_blend_speed;

		if (plyr->leg_blend_ctr > 0x100)
		{
			if (blend_val <= 0x100)	blend_val = 0;
		}
		else
		{
			if (blend_val < 0)		blend_val = 0;
		}
		plyr->leg_blend_ctr = blend_val;
    }




    an =  abs(plyr->top_anim);
    fr =  plyr->top_frame;
    fr += plyr->top_rate;

	if (playerAnims[an].loopFlag)
	{
		if (fr > (playerAnims[an].a->numFrames<<8))
		{
			/*loop back*/
			do{
				fr -= playerAnims[an].a->numFrames<<8;
			}while (fr >= playerAnims[an].a->numFrames<<8); 
		}
	}
	else
	{
		if ( fr > (playerAnims[an].a->numFrames-1)<<8)
		{
			/*end frame*/
			fr = (playerAnims[an].a->numFrames-1)<<8;
		}
	}

	if (fr<0)	fr=0;
    plyr->top_frame = fr;

    fr =  plyr->leg_frame;
	an =  abs(plyr->leg_anim);
	if (an <= LEG_KSPNLGOR)
	{
		if (an)
		{
			fr += plyr->leg_rate;

			if (legAnims[an].loopFlag)
			{
				if (fr > (legAnims[an].a->numFrames<<8))
				{
					/*loop back*/
					do{
						fr -= legAnims[an].a->numFrames<<8;
					}while (fr >= legAnims[an].a->numFrames<<8); 
				}
			}
			else
			{
				if ( fr > (legAnims[an].a->numFrames-1)<<8)
				{
					/*end frame*/
					fr = (legAnims[an].a->numFrames-1)<<8;
				}
			}

			if (fr<0)	fr=0;
			plyr->leg_frame = fr;
		}
	}					  
	else
	{
		plyr->leg_anim = 0;
//		printf("error!\n");
	}


	/*
	* advance last frame values
	* used for run/jog blends
	*/

	if (plyr->top_blend_ctr & 0x100)
	{
		an =  abs(plyr->last_top_anim);
		fr =  plyr->last_top_frame;
		fr += plyr->top_rate;

		if (playerAnims[an].loopFlag)
		{
			if (fr > (playerAnims[an].a->numFrames<<8))
			{
				/*loop back*/
				do{
					fr -= playerAnims[an].a->numFrames<<8;
				}while (fr >= playerAnims[an].a->numFrames<<8); 
			}
		}
		else
		{
			if ( fr > (playerAnims[an].a->numFrames-1)<<8)
			{
				/*end frame*/
				fr = (playerAnims[an].a->numFrames-1)<<8;
			}
		}
		plyr->last_top_frame = fr;
	}

	if (plyr->leg_blend_ctr & 0x100)
	{
		an =  abs(plyr->last_leg_anim);
		fr =  plyr->last_leg_frame;
		fr += plyr->leg_rate;

		if (legAnims[an].loopFlag)
		{
			if (fr > (legAnims[an].a->numFrames<<8))
			{
				/*loop back*/
				do{
					fr -= legAnims[an].a->numFrames<<8;
				}while (fr >= legAnims[an].a->numFrames<<8); 
			}
		}
		else
		{
			if ( fr > (legAnims[an].a->numFrames-1)<<8)
			{
				/*end frame*/
				fr = (legAnims[an].a->numFrames-1)<<8;
			}
		}
		plyr->last_leg_frame = fr;
	}
}

global void start_next_anim2(playert *plyr, int time)
{
	start_anim2(plyr,(plyr->top_anim > 0) ? plyr->top_anim+1: plyr->top_anim-1, time);
}

global void start_next_leg_anim2(playert *plyr, int time)
{
	start_leg_anim2(plyr,(plyr->leg_anim > 0) ? plyr->leg_anim+1: plyr->leg_anim-1, time);
}

global void start_anim2(playert *plyr, int an, int time)
{
	if (abs(an) >	TOP_KSPNLGOR)
	{
		return;
	}

	
	if ( an != plyr->top_anim)
  {
		plyr->last_top_anim  = plyr->top_anim;
		plyr->last_top_frame = plyr->top_frame;

		plyr->top_frame = 0;
		plyr->top_blend_ctr = 0;
		plyr->leg_blend_ctr = 0;
		plyr->top_anim  = an;

		if (playerAnims[abs(an)].rootFlag)
		{
			plyr->last_leg_anim  = plyr->leg_anim;
			plyr->last_leg_frame = plyr->leg_frame;
			plyr->leg_anim       = 0;

			if (!(plyr->flags&HOLD_ROOT))
				plyr->rlx=plyr->rly=plyr->rlz=0;
		}

		if ( time)
		{
			plyr->top_rate = (((playerAnims[abs(an)].a->numFrames-1)<<8) + time)/time;
		}
	}
}


extern s8 ShowDebug;

static u32 ReturnAddress;

global void start_blend_anim2(playert *plyr, int an, int time)
{
	if (abs(an) >	TOP_KSPNLGOR)
	{
		asm( "sw $31,ReturnAddress" );

		if (ShowDebug)
		{
			char
				text[64];
			s32
				i;

			memset( text, 0, 64 );
			IntToHexStr( ReturnAddress, text );
			strcat( text, " " );

			i = strlen( text );
			IntToHexStr( (int)current_dunk, &text[i] );
			strcat( text, " " );

			i = strlen( text );
			IntToDecStr( an, &text[i] );
			strcat( text, " " );

			i = strlen( text );
			IntToDecStr( time, &text[i] );
			strcat( text, " " );

			i = strlen( text );
			IntToDecStr( project_flag, &text[i] );
			strcat( text, " " );

			i = strlen( text );
			IntToDecStr( dunk_flag, &text[i] );

			BreakMessage( text, __FILE__, __LINE__ );
		}

		return;
	}

  if ( an != plyr->top_anim)
  {
		plyr->last_top_anim  = plyr->top_anim;
		plyr->last_top_frame = plyr->top_frame;
		plyr->top_blend_ctr  = 0xff;
		plyr->top_frame		 = 0;
		plyr->top_anim		 = an;
		plyr->top_blend_speed= BLEND_SPEED;

		if (playerAnims[abs(an)].rootFlag)
		{
			plyr->last_leg_anim  = plyr->leg_anim;
			plyr->last_leg_frame = plyr->leg_frame;
			plyr->leg_blend_ctr  = 0xff;
			plyr->leg_anim       = 0;
			plyr->leg_blend_speed= BLEND_SPEED;

			if (!(plyr->flags&HOLD_ROOT))
				plyr->rlx=plyr->rly=plyr->rlz=0;
		}

		if ( time)
		{
			plyr->top_rate = (((playerAnims[abs(an)].a->numFrames-1)<<8) + time)/time;
		}
	}
}


global void start_blend_leg_anim2(playert *plyr, int an, int time)
{
  if ( an != plyr->leg_anim)
  {
		if (plyr->leg_routine == turn_and_burn)
		{
			switch (an)
			{
			case LEG_RUN90:
			case -LEG_RUN90:
			case LEG_SPIN180:
			case -LEG_SPIN180:
			case LEG_REB_TO:
				break;

			default:
				BRK;
			}
		}


		plyr->last_leg_anim  = plyr->leg_anim;
		plyr->last_leg_frame = plyr->leg_frame;
		plyr->leg_blend_ctr  = 0xff;
		plyr->leg_frame		 = 0;
		plyr->leg_anim		 = an;
		plyr->leg_blend_speed= BLEND_SPEED;

		if (!(plyr->flags&HOLD_ROOT))
			plyr->rlx=plyr->rly=plyr->rlz=0;
	}

	if ( time)
	{
		plyr->leg_rate = (((legAnims[abs(an)].a->numFrames-1)<<8) + time)/time;
	}
}


global void start_leg_anim2(playert *plyr, int an, int time)
{
	if ( an != plyr->leg_anim)
	{
		plyr->last_leg_anim  = plyr->leg_anim;
		plyr->last_leg_frame = plyr->leg_frame;

		plyr->leg_frame = 0;
		plyr->leg_anim  = an;

		if (!(plyr->flags&HOLD_ROOT))
			plyr->rlx=plyr->rly=plyr->rlz=0;
	}

	if ( time)
	{
		plyr->leg_rate = (((legAnims[abs(an)].a->numFrames-1)<<8) + time)/time;
	}
}



global void start_next_anim(playert *plyr)
{
	start_anim(plyr,(plyr->top_anim > 0) ? plyr->top_anim+1: plyr->top_anim-1);
}

global void start_next_leg_anim(playert *plyr)
{
	start_leg_anim(plyr,(plyr->leg_anim > 0) ? plyr->leg_anim+1: plyr->leg_anim-1);
}




global void start_anim(playert *plyr, int an)
{
	if (abs(an) >	TOP_KSPNLGOR)
	{
		return;
	}
	
	if ( an != plyr->top_anim)
	{
		plyr->leg_blend_ctr = 0;
		plyr->top_blend_ctr = 0;

		plyr->last_top_anim  = plyr->top_anim;
		plyr->last_top_frame = plyr->top_frame;


		//don't interupt dribble animations
		if ((abs(an) > TOP_HIGH_DRIB) | (abs(plyr->top_anim) > TOP_HIGH_DRIB))
		{
			plyr->top_frame = 0;
		}


		plyr->top_anim  = an;
		plyr->top_rate = ANIM_SPEED1;

		//switch off legs
		if (playerAnims[abs(an)].rootFlag)
		{
			plyr->leg_routine = NULL;

			plyr->last_leg_anim  = plyr->leg_anim;
			plyr->last_leg_frame = plyr->leg_frame;

			plyr->leg_anim    = 0;

			if (!(plyr->flags&HOLD_ROOT))
				plyr->rlx=plyr->rly=plyr->rlz=0;
		}
	}
}


global void start_blend_anim(playert *plyr, int an)
{
	if (abs(an) >	TOP_KSPNLGOR)
	{
		return;
	}
	
	if (an != plyr->top_anim)
	{
		plyr->last_top_anim  = plyr->top_anim;
		plyr->last_top_frame = plyr->top_frame;

		//don't interupt dribble animations
		if ((abs(an) > TOP_TURBO_DRIB) | (abs(plyr->top_anim) > TOP_TURBO_DRIB))
		{
			plyr->top_frame = 0;
		}
		
		plyr->top_anim		  = an;
		plyr->top_blend_ctr	  = 0xff; 
		plyr->top_blend_speed = BLEND_SPEED;

		plyr->top_rate		 = ANIM_SPEED1;
		
		if (playerAnims[abs(an)].rootFlag)
		{
			plyr->last_leg_anim  = plyr->leg_anim;
			plyr->last_leg_frame = plyr->leg_frame;
			plyr->leg_anim       = 0;
			plyr->leg_routine	 = NULL;
			plyr->leg_blend_ctr  = 0xff;
			plyr->leg_blend_speed= BLEND_SPEED;

			if (!(plyr->flags&HOLD_ROOT))
				plyr->rlx=plyr->rly=plyr->rlz=0;
		}
	}
}


global void start_leg_anim(playert *plyr, int an)
{
	if ( an != plyr->leg_anim)
	{

#if 0
		if (plyr->leg_routine == turn_and_burn)
		{
			switch (an)
			{
			case LEG_RUN90:
			case -LEG_RUN90:
			case LEG_SPIN180:
			case -LEG_SPIN180:
			case LEG_REB_TO:
				break;

			default:
				BRK;
			}
		}
#endif

		plyr->last_leg_anim  = plyr->leg_anim;
		plyr->last_leg_frame = plyr->leg_frame;

		plyr->leg_frame = 0;
		plyr->leg_anim  = an;

		if (!(plyr->flags&HOLD_ROOT))
			plyr->rlx=plyr->rly=plyr->rlz=0;
	}
}


global void start_blend_leg_anim(playert *plyr, int an)
{
	if ( an != plyr->leg_anim)
	{
#if 0
		if (plyr->leg_routine == turn_and_burn)
		{
			switch (an)
			{
			case LEG_RUN90:
			case -LEG_RUN90:
			case LEG_SPIN180:
			case -LEG_SPIN180:
			case LEG_REB_TO:
				break;

			default:
				BRK;
			}
		}
#endif

		if ((plyr->leg_blend_ctr & 0xff) < 0x80)
		{
			plyr->last_leg_anim  = plyr->leg_anim;
			plyr->last_leg_frame = plyr->leg_frame;
		}
		plyr->leg_frame = 0;
		plyr->leg_anim  = an;

		plyr->leg_blend_ctr  = 0xff;
		plyr->leg_blend_speed= BLEND_SPEED;

		if (!(plyr->flags&HOLD_ROOT))
			plyr->rlx=plyr->rly=plyr->rlz=0;
	}	
}



global void start_blend_leg_anim_shuffle(playert *plyr, int an)
{
	if ( an != plyr->leg_anim)
	{
		if ((plyr->leg_blend_ctr & 0xff) < 0x80)
		{
			plyr->last_leg_anim  = plyr->leg_anim;
			plyr->last_leg_frame = plyr->leg_frame;
		}

		plyr->leg_anim		= an;
		plyr->leg_blend_ctr = 0x1ff;

		if (!(plyr->flags&HOLD_ROOT))
			plyr->rlx=plyr->rly=plyr->rlz=0;
	}	
}


global bool end_animation_test(playert *plyr)
{
	if (plyr->top_rate >= 0)
	{											    
		return (plyr->top_frame >= ((playerAnims[abs(plyr->top_anim)].a->numFrames-1)<<8));
	}
	else
	{
		return (plyr->top_frame == 0);
	}
}


global int frames_to_go(playert *plyr)
{
	if (playerAnims[abs(plyr->top_anim)].loopFlag)
	{
		return 0;
	}
	return playerAnims[abs(plyr->top_anim)].a->numFrames - (plyr->top_frame>>8);
}


global int frames_to_go2(playert *plyr)
{
	return playerAnims[abs(plyr->top_anim)].a->numFrames - (plyr->top_frame>>8);
}



global int anim_time(playert *plyr)
{
	return ((((playerAnims[abs(plyr->top_anim)].a->numFrames-1)<<8) - plyr->top_frame)/plyr->top_rate);
}

global int leg_frames_to_go(playert *plyr)
{
	return legAnims[abs(plyr->leg_anim)].a->numFrames - (plyr->leg_frame>>8);
}

global bool end_leg_animation_test(playert *plyr)
{
	return (plyr->leg_frame >= ((legAnims[abs(plyr->leg_anim)].a->numFrames-1)<<8));
}


global int time_till_land(playert *plyr)
{
int t;
int z,zv;

    t   =0;
    z   = plyr->zco;
    zv  = plyr->zvel;

    while ( z>=0)
    {
        t++;
        z += zv;
        zv-= LITTLE_G;
    }
    return t;
}


global void start_vels(playert *plyr, int vel, SW angle)
{
//start x & y vel for animation (vel in mm/s)

	vel *= plyr->scale;
	if (plyr->leg_anim)		vel *= plyr->leg_rate;
	else					vel *= plyr->top_rate;

	vel >>= 16;
	plyr->xvel = (vel * LFPCos(angle)) >> 4;
	plyr->yvel = (vel * LFPSin(angle)) >> 4;

	plyr->xvel-=plyr->xvel*((MAX_PLAYER_ENERGY-plyr->plyrRAM->sw___pEnergy)>>8)/(MAX_PLAYER_ENERGY>>8)/4;
	plyr->yvel-=plyr->yvel*((MAX_PLAYER_ENERGY-plyr->plyrRAM->sw___pEnergy)>>8)/(MAX_PLAYER_ENERGY>>8)/4;
}


global void start_vels2(playert *plyr, int vel, SW angle)
{
//start x & y vel for animation (vel in mm/s)

	vel *= plyr->scale;
	if (plyr->leg_anim)		vel *= plyr->leg_rate;
	else					vel *= plyr->top_rate;

	vel >>= 16;
	plyr->xvel = (vel * LFPCos(angle)) >> 4;
	plyr->yvel = (vel * LFPSin(angle)) >> 4;
}


