//************************************************************************
//	Dependencies
//************************************************************************

//------------------------------------------------------------------------
//	Headers
//------------------------------------------------------------------------
#include "generic.h"
#include "lfptypes.h"

#include "define.h"
#include "ml.h"


#ifdef PC
 #include "kernel.h"
#endif

#include "ctrl.h"


//------------------------------------------------------------------------
//	External References
//------------------------------------------------------------------------
#ifdef PC
extern int cameraMode;
#else
extern int camMode;
extern int camSpecialMode;
#endif

extern int ControllerGameMode[4];
extern int ControllerLockOnPlayer[];



//************************************************************************
//	Defines
//************************************************************************

//------------------------------------------------------------------------
//	Pad Assignments to Teams
//------------------------------------------------------------------------
s32	PAD_0_TEAM = PAD_HOME;
s32	PAD_1_TEAM = PAD_NONE;
s32	PAD_2_TEAM = PAD_NONE;
s32	PAD_3_TEAM = PAD_NONE;


//------------------------------------------------------------------------
//	Miscellany
//------------------------------------------------------------------------
#define CAMERA_MODE_SPECIAL	8
#define NUM_CONTROLS 4
#define ICON_MASK (CTRL_SHUFFLE+CTRL_TURBO)



//************************************************************************
//	Globabl Data Definitions
//************************************************************************
global SI	last_controlled[NUM_CONTROLS+1];
global SI	controls[NUM_CONTROLS];

global UD	controller0;
global UD   m_controller;

global ctrlrT ctrlrs[NUM_CONTROLS+2] =
{
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,

		0,
		0,
		0,
		0,
	},

//1
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,

		0,
		0,
		0,
		0,
	},


//2
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,

		0,
		0,
		0,
		0,
	},


//3
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,

		0,
		0,
		0,
		0,
	},


//4
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,

		0,
		0,
		0,
		0,
	},


//5
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,

		0,
		0,
		0,
		0,
	},

};

global ctrlrT *current_ctrlr;


static int  no_pads;
static int  camTheta;
static playert *cur_plyr;

#ifdef DEBUG
 bool string_flag=TRUE;
#else
 bool string_flag=FALSE;
#endif




static bool mflag;
int qflag;

/****************************************************************
*
* get_dpad(void)
*
****************************************************************
*
* translate raw joystick data to ctrlrs[] structure
*
****************************************************************/



global void get_dpad(SI *v)
{
ctrlrT *ctrlr_ptr;
UI last;
UI jp;
SW pad_no;
SI angle;

SW x,y;
SW plyr_no;

	int mask;
	int	btn;

/*	ReadJoypads();*/


#ifdef PC
	if (mflag)
	{
		mflag = KernelGetKeyStatus(KEY_M) & 1;
	}
	else
	{
		mflag = KernelGetKeyStatus(KEY_M) & 1;
		if (mflag)
		{
			qflag = (qflag+1);
			if (qflag>5)
			{
				qflag=0;
			}
		}
	}
#endif


	
#ifndef PC
	if (camSpecialMode==-1)
	{
		camTheta = si___gCamTheta;
	}
	if(switch_ends_flag) camTheta^=32768;
#else
	camTheta = si___gCamTheta;
#endif

	ctrlr_ptr	= &ctrlrs[1];

	controller0 = v[0];

//	if (!possession_flag)	icon_flag = 0;

	m_controller = 0;

//	v[0] |= (CTRL_SHOOT & ((lp_ctr&16) * (CTRL_SHOOT/16)));

	for (pad_no = 0; pad_no < 4; pad_no++)
	{
		jp   = v[pad_no];

		ctrlr_ptr->raw   = jp;
        ctrlr_ptr->d_pad = jp & 15;

		last = ctrlr_ptr->ctrlr;
		ctrlr_ptr->last = last;

		plyr_no = controls[pad_no];

		if ((plyr_no == ball_handler) && (possession_flag))
		{
			if (ft_flag)
			{
				icon_flag = ICON_OFF;
			}
			else
			{
				//icon_flag = ICON_OFF;
				if ((jp & ICON_MASK) == ICON_MASK)
				{
					//were both buttons pressed within 3 frames
					if (ctrlr_ptr->icon_ctr < 3)
					{
						icon_flag ^= ICON_ALL;		//switch icons on
						jp        ^= ICON_MASK;		//ignore buttons
						ctrlr_ptr->icon_ctr = 3;	//stop toggle next time
					}
				}
			}
		}
		else
		{
			if ( (jp & CTRL_BOX_OUT) && !replay_flag) // "this is a nasty mess in here" (Noah's quote)
			{
				jp |= CTRL_SHUFFLE;
			}
		}


		//clear/increment icon_ctr
		if (v[pad_no] & ICON_MASK)		ctrlr_ptr->icon_ctr++;
		else							ctrlr_ptr->icon_ctr = 0;


		ctrlr_ptr->db_ctrlr = jp & (~last);

		if (ft_flag
			&& (plyr_no == ball_handler)	// bug #20update
			)
		{
			last				= ctrlr_ptr->c_mask|ctrlr_ptr->r_mask;
			last				&=jp;
			ctrlr_ptr->c_mask	= last;
			ctrlr_ptr->mctrlr	= jp & (~last);
			ctrlr_ptr->ctrlr	= jp;
			ctrlr_ptr->r_mask	&=jp;
		}
		else
		{
			last				= ctrlr_ptr->c_mask;
			last				&=jp;
			ctrlr_ptr->c_mask	= last;
			ctrlr_ptr->mctrlr	= jp & ((~last)|(~(ctrlr_ptr->r_mask)));
			ctrlr_ptr->ctrlr	= jp & (~ctrlr_ptr->r_mask);
			ctrlr_ptr->r_mask	&=jp;
		}
		// Determine tap/hold status for buttons
		for (btn=0,mask=1; btn<NUM_BUTTONS; btn++,mask<<=1)
		{
			if (ctrlr_ptr->mctrlr&mask)	// Button being held down
			{
				if (++ctrlr_ptr->htime[btn]>TIME_TAP) // Held down long enough to flag hold
					 ctrlr_ptr->hold|=mask;
			}
			else	// Button is not held down
			{
				if (!ctrlr_ptr->htime[btn])	// Button has not been recently released
					ctrlr_ptr->tap&=~mask;
				else		// Button just released
				{
					if (ctrlr_ptr->htime[btn]>TIME_TAP)	// Was a hold, clear hold flag
						ctrlr_ptr->hold&=~mask;
					else			// Is a tap
						ctrlr_ptr->tap|=mask;

					ctrlr_ptr->htime[btn]=0;
				}
			}
		}

		if (time_left <= 0 && !(ft_flag || free_throws))
		{
			jp = 					//no moves after clock expires
			ctrlr_ptr->ctrlr    =
			ctrlr_ptr->mctrlr   =
			ctrlr_ptr->db_ctrlr = 0;
		}

#ifdef N64
		//if ((controls[pad_no] >= 0) || (no_pads == 0))
#endif

		{
			m_controller |= ctrlr_ptr->mctrlr;
		}


        x = 0;
        if ( jp & CTRL_LEFT)    x = -(char)((jp>>24) & 0xf);
        if ( jp & CTRL_RIGHT)   x = (jp>>24) & 0xf;

        y = 0;
        if ( jp & CTRL_DOWN)    y = -(char)((jp>>28) & 0xf);
        if ( jp & CTRL_UP)      y = (jp>>28) & 0xf;


        if (x | y)
		{
			int j;

			angle = LFPAtn(x,y);
			//move angles back
			for (j=6; j>=0; j--)
			{
				//ctrlr_ptr->last_angles[j+1] = ctrlr_ptr->last_angles[j];
			}

			//new angle
			//ctrlr_ptr->last_angles[0] = angle;

			angle = angle + camTheta;
            ctrlr_ptr->d_angle = angle;

            x = (jp>>24) & 0xf;
            y = (jp>>28) & 0xf;
            if (x>y)   y=x;

			if (x > y)	ctrlr_ptr->force = x << 4;
	  		else		ctrlr_ptr->force = y << 4;

	#ifdef PC
			if (pad_no==0)	//keyboard
			{
				if (KernelGetKeyStatus(KEY_1) & 1)
				{
					ctrlr_ptr->force = 0x10;
				}
      			else if (KernelGetKeyStatus(KEY_2) & 1)
				{
					ctrlr_ptr->force = 0x20;
				}
      			else if (KernelGetKeyStatus(KEY_3) & 1)
				{
					ctrlr_ptr->force = 0x30;
				}
      			else if (KernelGetKeyStatus(KEY_4) & 1)
				{
					ctrlr_ptr->force = 0x40;
				}
      			else if (KernelGetKeyStatus(KEY_5) & 1)
				{
					ctrlr_ptr->force = 0x50;
				}
      			else if (KernelGetKeyStatus(KEY_6) & 1)
				{
					ctrlr_ptr->force = 0x80;
				}
      			else if (KernelGetKeyStatus(KEY_7) & 1)
				{
					ctrlr_ptr->force = 0xa0;
				}
      			else if (KernelGetKeyStatus(KEY_8) & 1)
				{
					ctrlr_ptr->force = 0xc0;
				}
      			else if (KernelGetKeyStatus(KEY_9) & 1)
				{
					ctrlr_ptr->force = 0xd0;
				}
      			else if (KernelGetKeyStatus(KEY_0) & 1)
				{
					ctrlr_ptr->force = 0xe0;
				}
				else
				{
					ctrlr_ptr->force = 0xf0;
				}

				ctrlr_ptr->ctrlr &= 0xf0ffffff;
				ctrlr_ptr->ctrlr |= (ctrlr_ptr->force>>4) << 24;
			}
			else
			{
				if (ctrlr_ptr->force)	ctrlr_ptr->force += 0x10;
			}
	#endif

			if (ctrlr_ptr->force < 0x50)	ctrlr_ptr->force = 0;
		}
		else
		{
			ctrlr_ptr->force = 0;
	        //memset(&(ctrlr_ptr->last_angles[0]), 0, sizeof(ctrlrs[0].last_angles));
		}

		if ((ctrlr_ptr->force == 0) && (ctrlr_ptr->ctrlr == 0))
		{
			if (0)		//(ctrlr_ptr->zero_timer++ > ONE_SEC/2)
			{
				if (controls[pad_no] != ball_handler)
				{
					SW a_diff;

					if (player[controls[pad_no]].ball_dist > 0x40000)
					{
						a_diff = player[controls[pad_no]].ball_angle - player[controls[pad_no]].angle;
						if (abs(a_diff) > 0x100)
						{
							ctrlr_ptr->force   = 0x10;
							ctrlr_ptr->d_angle = player[controls[pad_no]].ball_angle;
						}
					}
				}
			}
		}
		else
		{
			ctrlr_ptr->zero_timer = 0;
		}

		ctrlr_ptr++;
	}


//	ctrlrs[1].d_angle = player[0].basket_angle;
//	ctrlrs[1].force   = 0xf0;
//	ctrlrs[1].ctrlr   |= CTRL_SHUFFLE;
	return;
}

void mask_shoot(void)
{
int i;

	for (i=1;i<5;i++)
	{
		//stop shooting straight away
		ctrlrs[i].c_mask |= CTRL_SHOOT;
	}
}



void rebound_switch_plyr(teamt *tm)
{
playert *plyr2, *nearest_plyr;
int lowest_score;
int score;

	lowest_score = 0x7fff0000;
	nearest_plyr = NULL;

	for (plyr2=tm->plyr1; plyr2<tm->plyr1+5; plyr2++)
	{
		score = MANHATTAN(plyr2->xco - crossX, plyr2->yco - crossY);
		if (score < lowest_score)
		{
			lowest_score = score;
			nearest_plyr = plyr2;
		}
	}

	if (nearest_plyr->control==0)
	{
		get_new_controls(tm, nearest_plyr);
	}
}






void switch_plyr(playert *plyr, teamt *tm, int rou(playert *))
{
playert *plyr2, *nearest_plyr;
int lowest_score;
int score;

	cur_plyr = plyr;

	lowest_score = 0x7fff0000;
	nearest_plyr = NULL;

	for (plyr2 = tm->plyr1; plyr2 < tm->plyr1+5; plyr2++)
	{

#ifdef JAPAN
		if ((plyr2->control == 0) || (plyr == plyr2)) 
#else
		if ((plyr != plyr2) && (plyr2->control == 0))
#endif
		{
			score = rou(plyr2);
			if (score < lowest_score)
			{
				lowest_score = score;
				nearest_plyr = plyr2;
			}
		}
	}

	if (!nearest_plyr)	BRK;

	current_ctrlr->last_switch = lp_ctr;
	change_controls(plyr, nearest_plyr);
}


void auto_switch_plyr(playert *plyr, teamt *tm, int rou(playert *))
{
playert *plyr2, *nearest_plyr;
int lowest_score;
int score;

	lowest_score = 0x7fff0000;
	nearest_plyr = NULL;

	for (plyr2 = tm->plyr1; plyr2 < tm->plyr1+5; plyr2++)
	{
		score = rou(plyr2);
		if (score < lowest_score)
		{
			lowest_score = score;
			nearest_plyr = plyr2;
		}
	}

	if (nearest_plyr != plyr)
	{
		current_ctrlr->last_switch = lp_ctr;
		change_controls(plyr, nearest_plyr);
	}
}






int basket_score(playert *plyr)
{
	if (crossY==0)	return plyr->basket_dist;
	else			return MANHATTAN(plyr->xco-crossX, plyr->yco-crossY);
}

int joy_score(playert *plyr)
{
	if (plyr==cur_plyr)	return 0x8000;
								           
	if (current_ctrlr->force)
	{
		SW a_diff;

		a_diff = current_ctrlr->d_angle - LFPAtn(plyr->xco-cur_plyr->xco, plyr->yco-cur_plyr->yco);
		return abs(a_diff);
	}
	else
	{
		return ball_score(plyr);
	}
}






int ball_score(playert *plyr)
{
	if (ball.main_routine != pass_ball_move)
	{
		return plyr->ball_dist;
	}
	else if (ball.main_routine != shot_ball_move)
	{
		return MANHATTAN(plyr->xco - player[int_recvr].xco,
						 plyr->yco - player[int_recvr].yco);
	}
	else
	{
		return basket_score(plyr);
	}
}



/****************************************************************
*
* init_controls(void)
*
****************************************************************
*
* change control from old player to new player
*
****************************************************************/

global void init_controls(void)
{
char i, j;

//	if (timeout_called)	mjk- this fixes bug #224 (but what other new bugs will it cause)
//		return;

	no_pads = 0;

#ifdef PC
	pcl__gMatch->asb__mPads[1] = 0;

 #ifdef MOVE
	pcl__gMatch->asb__mPads[0] = 0;
 #endif
#endif

#if	defined(N64) && 0
	pcl__gMatch->asb__mPads[0] = PAD_0_TEAM;
	pcl__gMatch->asb__mPads[1] = PAD_1_TEAM;
	pcl__gMatch->asb__mPads[2] = PAD_2_TEAM;
	pcl__gMatch->asb__mPads[3] = PAD_3_TEAM;
#endif

	pcl__gMatch->ud___mNewPads = 0;

	for (i=0;i<5;i++)
	{
		ctrlrs[i].ctrlr= 0;
		ctrlrs[i].db_ctrlr= 0;
		ctrlrs[i].d_pad= 0;
		ctrlrs[i].mctrlr= 0;
		ctrlrs[i].c_mask= -1;
		ctrlrs[i].r_mask=0;

		ctrlrs[i].d_angle= 0;

		ctrlrs[i].tap=0;
		ctrlrs[i].hold=0;

		if (i==0)
			ctrlrs[i].roleplay=CPL_NOLOCK;
		else
			ctrlrs[i].roleplay=ControllerLockOnPlayer[i-1];

		if (i && !C3PT)
			ctrlrs[i].level=ControllerGameMode[i-1];
		else
			ctrlrs[i].level=CL_PRO;

		for (j=0; j<NUM_BUTTONS; j++)
			ctrlrs[i].htime[j]=0;
	}

	init_controls2();
}

void init_controls2(void)
{
char i, j;

	for (i=0;i<10;i++)
	{
		player[i].control=0;
	}


	for (i=0;i<4;i++)
	{
		ai_team[0].controllers[i] = 0;
		ai_team[1].controllers[i] = 0;
	}


	// Set up roleplay controllers first
	for (i=0; i<4; i++)
		if (ctrlrs[i+1].roleplay!=CPL_NOLOCK)
		{
			int	pad_val;

			pad_val=pcl__gMatch->asb__mPads[i];
			player[ctrlrs[i+1].roleplay].control=i+1;
			for (j=0 ;j<4 ;j++)
				if (ai_team[pad_val].controllers[j] == 0)
				{
					ai_team[pad_val].controllers[j] = i+1;
					break;
				}
			no_pads++;
		}

	// Set up non-roleplay controllers
	for (i=0; i<4; i++)
	{
		int pad_val;

		// Skip roleplay pads
		if (ctrlrs[i+1].roleplay!=CPL_NOLOCK)
			continue;

		for (j=0;j<8;j++)
		{
			//ctrlrs[i].last_angles[j]=0;
		}

		pad_val = pcl__gMatch->asb__mPads[i];

		switch (pad_val)
		{
			case 2:		//CPU
			break;

			case 1:		//away
			case 0:		//home
			//set up team controller list

			no_pads++;

			for (j=0 ;j<4 ;j++)
			{
				if (ai_team[pad_val].controllers[j] == 0)
				{
					ai_team[pad_val].controllers[j] = i+1;
					break;
				}
			}


			//is ball handler on this team and uncontrolled
			if (   (possession_flag)
				&& (bhp->control==0)
				&& ((ball_handler<5) ^ (pad_val==1))  )
			{
				bhp->control = i+1;
			}
			else
			{
				//look for uncontrolled player in team
				for (j=4+(pad_val*5); j>=(pad_val*5); j--)
				{
					if (player[j].control == 0)
					{
						player[j].control = i+1;
						break;
					}
				}
			}
			break;
		}
	}

    for (i=0 ;i<NUM_CONTROLS ;i++)
    {
        controls[i] = -1;
        last_controlled[i] = lp_ctr;
    }

    /*screturn passan players structure for human controlled players*/
    for (i=0 ;i<10 ;i++ )
        if (player[i].control > 0)
			controls[player[i].control-1] = i;
}


global int test_and_mask(ctrlrT *ctrlr_ptr, int mask)
{
	if (!(ctrlr_ptr->mctrlr & mask))	return 0;

	ctrlr_ptr->c_mask |= mask;
	return 1;
}




global void change_controls(playert *old_plyr, playert *new_plyr)
{
int last;

	if (project_flag)
		return;

	// Don't switch if the player is in roleplay mode
	if (ctrlrs[old_plyr->control].roleplay!=CPL_NOLOCK)
		return;

	if (old_plyr->team != new_plyr->team)
	{
		return;
		BRK;
		get_new_controls(ai_team+new_plyr->team, new_plyr);
		return;
	}


    if (new_plyr->control)
	{
		last = 0;
		while (ai_team[new_plyr->team].controllers[last] != new_plyr->control)
		{
			last++;
		}

		ai_team[new_plyr->team].last_controller = last;
	}
	else
	{
		new_plyr->control  = old_plyr->control;
		old_plyr->control  = 0;
		controls[new_plyr->control-1] = new_plyr->no;
		if (ICL_ROOKIE(&ctrlrs[new_plyr->control]))
			PadFlash[new_plyr->control-1]=32;
	}

}

/* *************************************************************************/
/* get_new_controls()*/
/* *************************************************************************/
/**/
/* *************************************************************************/
/* Inputs   - ptr to team and new ball handler no*/
/* Output   -*/
/* *************************************************************************/


global void get_new_controls(teamt *tm, playert *plyr)
{
int next;
int last;

	if (project_flag)
		return;

	if (no_pads <= 1)
	{
		/*
		player[controls[0]].control = 0;

		plyr->control = 1;
		controls[0] = plyr->no;

		ai_team[plyr->team].controllers[0]     = 1;
		ai_team[plyr->team].controllers[1]     = 0;
		ai_team[plyr->team ^ 1].controllers[0] = 0;
		return;
		*/
	}

	// CPU team, so leave
	if (tm->controllers[0] == 0)
		return;

	if (plyr->control)
	{
		next = plyr->control;

		last = 0;
		while (tm->controllers[last] != next)
		{
			last++;
		}
	}
	else
	{
		last = tm->last_controller+1;

		next = tm->controllers[last];
		if (next == 0)
		{
			last = 0;
			next = tm->controllers[0];
		}
	}

	tm->last_controller = last;
	change_controls(&player[controls[next-1]], plyr);
}


