/***************************************************************************
 *
 * sub.c
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/


#define phil 1
/*
 * includes
 */

#include "generic.h"
#include "define.h"
#include "ml.h"
#include "main.h"
#include "sub.h"
#include "teamdata.h"
#include "shell.h"
#include "sub.h"
#include "ft.h"

#include "gamefx.h"

extern u8
	*GameBank;

/*
 * Tweakable values
 */

// minimum time in seconds between a team's substitutions/timeouts
#define SUB_MIN_DELAY				30
//#define SUB_MIN_DELAY				15

// energy boost at timeout - be CAREFUL... don't want to re-energise all
// the players we've just pulled off the court too much...
#define SUB_TO_BOOST				5

// energy boost at halftime (%)
#define SUB_HT_BOOST				15

// energy boost at any other quarter break (%)
#define SUB_QT_BOOST				5

// energy expended by a 0% stamina player over 1 quarter (%)
#define QUARTER_ENERGY_DEC_WEAKLING		60
//#define QUARTER_ENERGY_DEC_WEAKLING		50

// energy expended by a 100% stamina player over 1 quarter (%)
#define QUARTER_ENERGY_DEC_POWERHOUSE		35
//#define QUARTER_ENERGY_DEC_POWERHOUSE		25

// how big must the total gain be to do a substitution at the next opportunity?
#define DELTA_THRESH_DEADBALL			15
//#define DELTA_THRESH_DEADBALL			20

// how big must the total gain be to actually call a timeout?
#define DELTA_THRESH_TIMEOUT			30
//#define DELTA_THRESH_TIMEOUT			40

// the fatigue scaling values for 12,9,6,3 minute timeouts (%)
int quarterLenFatigues[]=
{
	100,115,150,200
};

// the percentage of full ratings applied to a type of player in each position
int penaltyTable[]=
{
	// PG
	100,90,70,70,50,
	// SG
	90,100,70,70,50,
	// SF
	70,70,100,90,60,
	// PF
	70,70,90,100,80,
	// C
	50,50,70,80,100,
	// CF
	60,60,80,90,100,
	// FC
   	65,65,90,100,90,
	// FG
	80,90,100,90,60,
	// GF
	90,100,90,80,60,
	// G
	100,100,70,70,50,
	// F
	70,70,100,100,60,
};

// overall rating boost for starters (%)
int	starterBoosts[5]=
{
	//PG
	20,
	//SG
	20,
	//SF
	15,
	//PF
	10,
	//C
	10
};


// the weighted significance of each NBA stat in determining overall player rating
int significanceFactors[]=
{
	20,		// FG
	00,		// 3P
	00,		// FT
	10,		// RebOff
	10,		// RebDef
	10,		// Steal
	00,		// Pass
	10,		// Block
	00,		// Foul
	20,		// Dribble
	20,		// Speed
	00,		// Jump
	00,		// Dunk
	00,		// Strength
	20,		// Stamina

/*
	80,		// FG
	70,		// 3P
	60,		// FT
	70,		// RebOff
	70,		// RebDef
	40,		// Steal
	30,		// Pass
	60,		// Block
	10,		// Foul
	60,		// Dribble
	80,		// Speed
	60,		// Jump
	60,		// Dunk
	50,		// Strength
	100,		// Stamina
*/
};

/*
 * defines
 */

#define QFAC	(QUARTER_ENERGY_DEC_WEAKLING-QUARTER_ENERGY_DEC_POWERHOUSE)

#define SUB_MAX_PLAYERS		16
#define MY_PG		0
#define MY_SG		1
#define MY_SF		2
#define MY_PF		3
#define MY_C		4
#define MY_CF		5
#define MY_FC		6
#define MY_FG		7
#define MY_GF		8
#define MY_G		9
#define MY_F		10

char *posNames[]={ "PG","SG","SF","PF","C","CF","FC","FG","GF","G","F" };

/*
 * typedefs
 */

/*
 * structures
 */

typedef struct _subTeam
{
	int	numPlayers;
	int	ratings[SUB_MAX_PLAYERS];
	int	currentTeam[SUB_MAX_PLAYERS];
	int	myPos[SUB_MAX_PLAYERS];
	int	idealTeam[5];
} subTeam;

/*
 * globals
 */

int			subFirstFrame=0;
int			foFlags[2];
int			subLastSubTime[2];
int			subCallTimeout;
int			subLastDelta[2];
int			subMsgPending=0;
int			subTimeoutPending=0;
int			subTeamPending=0;
int			subIn[5],subOut[5];
int			subNumPlayers;

char			enableGuys[SUB_MAX_PLAYERS];

int			secondCounter=0;

subTeam			subTeams[2];

/*
 * function prototypes
 */

/*
 * code
 */


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 * Get an overall rating, not taking fatigue into consideration.
 *
 ***************************************************************************/

int SubRatePlayer(PlyrRomData_T *p)		//  function local to this file
{
	int		i,j,k;

	i=0;
	j=0;
	k=0;

	i+=(int)(p->ub___pAttrFG)       * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttr3P)       * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrFT)       * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrRebOff)   * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrRebDef)   * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrSteal)    * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrPass)     * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrBlock)    * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrFoul)     * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrDribble)  * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrSpeed)    * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrJump)     * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrDunk)     * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrStrength) * significanceFactors[k]; j+=significanceFactors[k]; k++;
	i+=(int)(p->ub___pAttrStamina)  * significanceFactors[k]; j+=significanceFactors[k]; k++;

	i/=j;
	return(i);
}

#ifdef DEBUG
void SubDumpTeam(int team)
{
	int		i,j,k,p;
	char		tmp[80];
	PlyrRamData_T	*ram;

	strcpy(tmp,"\r\n\r\nTeam: ");
	strcat(tmp,pcl__gMatch->apcl_mTeamRom[team]->pcz__tCityName);
	strcat(tmp,"\r\n");
	PrintToFile(tmp);

	PrintToFile("Current:\r\n");
	for(k=0;k<5;k++)
	{
		for(j=0;j<subTeams[team].numPlayers;j++)
		{
			if(subTeams[team].currentTeam[k]!=j) continue;
			ram=&pcl__gMatch->apcl_mTeamRam[team]->pcl__tPlyrRam[j];

			strcpy(tmp,posNames[k]);
			strcat(tmp," : ");
			strcat(tmp,pcl__gMatch->apcl_mTeamRam[team]->pcl__tPlyrRam[j].pcl__pPlyrRom->pcz__pCName);
			strcat(tmp," ");
			strcat(tmp,pcl__gMatch->apcl_mTeamRam[team]->pcl__tPlyrRam[j].pcl__pPlyrRom->pcz__pSName);
			strcat(tmp," (");
			strcat(tmp,posNames[subTeams[team].myPos[j]]);
			strcat(tmp,") r=");
			IntToStr(subTeams[team].ratings[j],&tmp[strlen(tmp)]);
			strcat(tmp," e=");
			IntToStr(ram->sw___pEnergy>>8,&tmp[strlen(tmp)]);
			strcat(tmp," r*e=");
			i=subTeams[team].ratings[j];
			i=i*(ram->sw___pEnergy>>8)/100;
			IntToStr(i,&tmp[strlen(tmp)]);
			strcat(tmp," p=");
			p=penaltyTable[(subTeams[team].myPos[j])*5+k];
			IntToStr(p,&tmp[strlen(tmp)]);
			i=(i*p)/100;
			strcat(tmp," r*e*p=");
			IntToStr(i,&tmp[strlen(tmp)]);
			strcat(tmp,"\r\n");
			PrintToFile(tmp);
		}
	}


	PrintToFile("Ideal:\r\n");
	for(k=0;k<5;k++)
	{
		for(j=0;j<subTeams[team].numPlayers;j++)
		{
			if(subTeams[team].idealTeam[k]!=j) continue;
			ram=&pcl__gMatch->apcl_mTeamRam[team]->pcl__tPlyrRam[j];

			strcpy(tmp,posNames[k]);
			strcat(tmp," : ");
			strcat(tmp,pcl__gMatch->apcl_mTeamRam[team]->pcl__tPlyrRam[j].pcl__pPlyrRom->pcz__pCName);
			strcat(tmp," ");
			strcat(tmp,pcl__gMatch->apcl_mTeamRam[team]->pcl__tPlyrRam[j].pcl__pPlyrRom->pcz__pSName);
			strcat(tmp," (");
			strcat(tmp,posNames[subTeams[team].myPos[j]]);
			strcat(tmp,") r=");
			IntToStr(subTeams[team].ratings[j],&tmp[strlen(tmp)]);
			strcat(tmp," e=");
			IntToStr(ram->sw___pEnergy>>8,&tmp[strlen(tmp)]);
			strcat(tmp," r*e=");
			i=subTeams[team].ratings[j];
			i=i*(ram->sw___pEnergy>>8)/100;
			IntToStr(i,&tmp[strlen(tmp)]);
			strcat(tmp," p=");
			p=penaltyTable[(subTeams[team].myPos[j])*5+k];
			IntToStr(p,&tmp[strlen(tmp)]);
			i=(i*p)/100;
			strcat(tmp," r*e*p=");
			IntToStr(i,&tmp[strlen(tmp)]);
			strcat(tmp,"\r\n");
			PrintToFile(tmp);
		}
	}
}
#endif

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

//int SubGetMyPos(int p)
int TranslatePositionToIndex(int p)	// p is a bunch of bits
{
	switch(p)
	{
		case POS_C:  return(MY_C); break;
		case POS_F:  return(MY_F); break;
		case POS_G:  return(MY_G); break;
		case POS_PF: return(MY_PF); break;
		case POS_SF: return(MY_SF); break;
		case POS_PG: return(MY_PG); break;
		case POS_SG: return(MY_SG); break;
		case POS_CF: return(MY_CF); break;
		case POS_FC: return(MY_FC); break;
		case POS_GF: return(MY_GF); break;
		case POS_FG: return(MY_FG); break;
		default: while(1); break;
	}
}

UW PosIndexToTrueIndexArray[11] = {
	POS_PG,POS_SG,POS_SF,POS_PF,POS_C,POS_CF,POS_FC,POS_FG,POS_GF,POS_G,POS_F
};

int PosIndexToTruePosition(int index)	
{	// index = MY_C to MY_FG

	return(PosIndexToTrueIndexArray[index]);
}
/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

void SubInitTeams(void)		// called at game start (GameOpen)
{
	int		i,j,k;
	PlyrRamData_T	*p;
	TeamRamData_T	*t;


	for(i=0; i<2; i++)
	{
		foFlags[i] = 0;

		t = pcl__gMatch->apcl_mTeamRam[i];
		subTeams[i].numPlayers = t->sb___tPlayers;

		for(j=0; j<t->sb___tPlayers; j++)
		{
			p = &t->pcl__tPlyrRam[j];
			subTeams[i].ratings[j] = SubRatePlayer(p->pcl__pPlyrRom);
			subTeams[i].myPos[j] = TranslatePositionToIndex(p->pcl__pPlyrRom->ub___pPos);
			p->sw___pEnergy = MAX_PLAYER_ENERGY;
		}

		for(j=0; j<t->sb___tPlayers; j++)
		{
			subTeams[i].currentTeam[j]=(t->ppcl_tPlyrLst[j])-(t->pcl__tPlyrRam);
		}

		for(j=0;j<5;j++)
		{
			subTeams[i].idealTeam[j] = subTeams[i].currentTeam[j];
			subTeams[i].ratings[subTeams[i].currentTeam[j]] += starterBoosts[j];
		}
	}

	subMsgPending=0;
	subTeamPending=0;
	secondCounter=0;


	SubInitQuarter();
}

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

void SubUpdateTeams(void)	// called from PAUSE menu if subs
{
	int		i,j,k;
	PlyrRamData_T	*p;
	TeamRamData_T	*t;

	for(i=0; i<2; i++)
	{
		t = pcl__gMatch->apcl_mTeamRam[i];
		subTeams[i].numPlayers = t->sb___tPlayers;
		for(j=0; j<t->sb___tPlayers; j++)
		{
			subTeams[i].currentTeam[j] = (t->ppcl_tPlyrLst[j]) - (t->pcl__tPlyrRam);
		}
		for(j=0;j<5;j++)
		{
			subTeams[i].idealTeam[j] = subTeams[i].currentTeam[j];
		}
		subLastSubTime[i] = time_left;
	}
	Caption_Reset();
}


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

void SubInitQuarter(void)	// called @ gameint and EOQ
{
	int		i;

	for(i=0; i<2; i++)
	{
		subLastSubTime[i] = -1;
	}

	subFirstFrame = 1;
}


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

int SubRatePlayerInPos(int team,int pos,int p)	//function local to this file
{
#ifdef phil
	int		i,j,q;
	int		t;
	int fouls;
	PlyrRamData_T	*ram;

	// get ram data
	ram = &pcl__gMatch->apcl_mTeamRam[team]->pcl__tPlyrRam[p];

	// ensure he's not fouled out
	if(ram->cl___pStatGame.uw___pDQ)
	{
		return(-99999);
	}

	// ensure the player isn't about to take a free throw...
//	if(free_throws && (free_thrower/5) == team)
	if(free_throws && ((free_thrower/5) == team ) )
	{
		i = free_thrower%5;
		if(subTeams[team].currentTeam[i] == p 
		   &&  pos == p)
		{
			return(100);
		}
	}

	// check fouls, disable player if necessary
	fouls = ram->cl___pStatGame.uw___pPF;
	q = pcl__gMatch->sb___mQuarter;
	
	t = (4-pcl__gMatch->pcl__mOptions->sb___QuarterLen)*3;	// 12,9,6,3
	
	t *= 60*ONE_SEC; t/=3;
	
	if(fouls>1 && q<2  && time_left>(t))
	{
		return(0);
	}
	if(fouls>3 && q==2 && time_left>(t))
	{
		return(0);
	}
	if(fouls>4 && q==3 && time_left>(t))
	{
		return(0);
	}

	// get penalty for playing out of position, if any
	j = penaltyTable[(subTeams[team].myPos[p]) * 5 + pos];

	// get overall rating
	i = subTeams[team].ratings[p];

	// apply current energy...
	i = i*(ram->sw___pEnergy>>8)/100;

	// apply position penalty
	i = (i*j)/100;

	return(i);
#else
	return( 0 );
#endif
}

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

void SubProcessEndOfQuarter(int which)	// called from nba.c
{
	int		i,j,k,b;
	PlyrRamData_T	*p;
	TeamRamData_T	*t;

	if(which==999)
	{
		b=SUB_TO_BOOST;
	}
	else
	{		// end of 2nd qtr (zero-based qtr HAS NOT been inc'ed yet)
		b=(which==1)?SUB_HT_BOOST:SUB_QT_BOOST;
	}
	
	for(i=0; i<2; i++)
	{
		t = pcl__gMatch->apcl_mTeamRam[i];
		for(j=0; j<subTeams[i].numPlayers; j++)
		{
			p = &t->pcl__tPlyrRam[j];
			if(which == 1)// end of 2nd qtr (zero-based qtr HAS NOT been inc'ed yet)
			{
				p->sw___pEnergy = MAX_PLAYER_ENERGY;
			}
			else
			{
				p->sw___pEnergy += (b<<8);
				if(p->sw___pEnergy > MAX_PLAYER_ENERGY) p->sw___pEnergy = MAX_PLAYER_ENERGY;
	//			if(p->sw___pEnergy > (100<<8)) p->sw___pEnergy=100<<8;
			}
		}
	}

	// prep for next time
	SubInitQuarter();
}

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

int SubFindBestPlayerInPos(int team,int pos)	// function local to this file
{
int score, hiscore;
int		i,bestp;

	hiscore = -9999;
	bestp = -1;

	for(i=0; i<subTeams[team].numPlayers; i++)
	{
		if(!enableGuys[i]) continue;

		score = SubRatePlayerInPos(team,pos,i);
		if(score > hiscore)
		{
			hiscore = score;	// new high score
			bestp = i;	// new high player
		}
	}
	
	if(bestp == -1)
	{	// didn't find anybody
		bestp = 0;	
	}

	return(bestp);
}

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

/**********  this doesn't seem to be called from anywhere 5/27/99 - mjk
int SubRateCurrentTeam(int team)	
{
	int	i,j,k;

	j=0;
	for(i=0;i<5;i++)
	{
		j+=SubRatePlayerInPos(team,i,subTeams[team].currentTeam[i]);
	}
	return(j);
}
************/

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

/**********  this doesn't seem to be called from anywhere 5/27/99 - mjk

int SubRateIdealTeam(int team)
{
	int	i,j,k;

	j=0;
	for(i=0;i<5;i++)
	{
		j+=SubRatePlayerInPos(team,i,subTeams[team].idealTeam[i]);
	}
	return(j);
}
********************/

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

void SubFindBestTeam(int team)	// function local to this file
{
	int	i,j,k,l,q,r;

	// enable all guys
	for(i=0; i<SUB_MAX_PLAYERS; i++) enableGuys[i]=1;

	// find best guy for each position...
	for(i=0; i<5; i++)
	{
		subTeams[team].idealTeam[i] = SubFindBestPlayerInPos(team,i);
	}

	// remove duplicates...
	for(i=0; i<5; i++) enableGuys[subTeams[team].idealTeam[i]]=0;

	for(i=0;i<5;i++)
	{
		for(j=i+1;j<5;j++)
		{
			if(subTeams[team].idealTeam[i] != subTeams[team].idealTeam[j]) continue;

			// evaluate both positions... keep best
			k = SubRatePlayerInPos(team,i,subTeams[team].idealTeam[i]);
			l = SubRatePlayerInPos(team,j,subTeams[team].idealTeam[j]);
			if(l>k)
			{
				subTeams[team].idealTeam[i] = SubFindBestPlayerInPos(team,i);
				enableGuys[subTeams[team].idealTeam[i]] = 0;
			}
			else
			{
				subTeams[team].idealTeam[j] = SubFindBestPlayerInPos(team,j);
				enableGuys[subTeams[team].idealTeam[j]] = 0;
			}

		}
	}
}




/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/
void refresh_player(playert *plyr);
void RefreshAllPlayers(void);

void SubDoSubstitution(int team)	// called from  ProcessAutoSubMenu()
{
	int		i,j,p;
	subTeam		*s;
	TeamRamData_T	*t;
	char		invalid[10];
int		freethrowerpos;
int		lastfreethrower;


#if 0
	{
		char tmp[40];

		strcpy(tmp,"T=");
		IntToStr((time_left/30)/60,&tmp[strlen(tmp)]);
		strcat(tmp,"m");
		IntToStr((time_left/30)%60,&tmp[strlen(tmp)]);
		strcat(tmp,"s remaining\r\n");
		if(subCallTimeout) strcat(tmp,"  (timeout)\r\n");
		PrintToFile(tmp);
		SubDumpTeam(team);

		strcpy(tmp,"Delta=");
		IntToStr(subLastDelta[team],&tmp[strlen(tmp)]);
		strcat(tmp,"\r\n");
		PrintToFile(tmp);
	}
#endif

/*******  nope - can't do here as players are already in postion for the free throw
	if(free_throws && ((free_thrower/5) == team ) )	// fix bug #61
	{
		freethrowerpos = free_thrower%5;
		lastfreethrower = s->currentTeam[freethrowerpos];

		for(i=0; i<5; i++)
		{	// see where he's at now  - he shouldn't have been subbed out, but he could have changed positions
			if(s->idealTeam[i] == lastfreethrower)
			{	// found him
				free_thrower = i + team*5;	// reset to new position
				break
			}
		}

		if(i == 5)
		{	// big boo-boo - he DID get subbed out
#ifdef DEBUG
			BRK;
#endif
		}
	}

*********/

	// get pointers
	s = &subTeams[team];
	t = pcl__gMatch->apcl_mTeamRam[team];

	// invalidate players, update current team
	memset(invalid,0,10);

	// remove everyone
	for(i=0; i<s->numPlayers; i++) t->pcl__tPlyrRam[i].sb___pOnCourt = -1;

	// add new team
	for(i=0; i<5; i++)
	{
		p = s->idealTeam[i];
		t->pcl__tPlyrRam[p].sb___pOnCourt = i;
		t->asb__tPlaying[i] = p;
		if(s->currentTeam[i] != p) invalid[team*5+i] = 1;
		s->currentTeam[i] = p;
	}

	// update roster list.
	MakeRosterList(t->ppcl_tPlyrLst,t);

	// load shell gfx
	LoadMatchTeam(t);

	// update 10 ai players from new roster list
	RefreshAllPlayers();
//	for(i=0; i<10; i++)		refresh_player(&player[i]);


	// Reload player gfx only for those that have changed...

	if (DumpGfxLoaded)
	{
		Gfx_Wait();

		for (i=0; i<5; i++)
		{
			p = (team*5)+i;
			if (invalid[p])
			{
				DeinitPlayer( p);
				InitPlayer( p );
			}
		}
	}

/****  moved to earlier in sub process (before players are loaded)
	// boost all players if this was a timeout
	if(subCallTimeout)
	{
		SubProcessEndOfQuarter(999);
		
//		DecNumberTimeOutsRemaining(team);

		timeout_called=1;
	}
*******/
	// store time
	subLastSubTime[team] = time_left;

	foFlags[team]=0;
}

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

int sec=0;

void SubProcessFatigue(void)	// called in main AI loop
{
#ifdef phil
	int		team,i,j,k,l;
	PlyrRamData_T	*p;

	// if fatigue disabled, just keep everyone at 100%
	if(!pcl__gMatch->pcl__mOptions->sb___Fatigue)
	{
		for(i=0;i<2;i++)
		{
			for(j=0; j<subTeams[i].numPlayers; j++)
			{
				p = pcl__gMatch->apcl_mTeamRam[i]->ppcl_tPlyrLst[j];
				if(p) p->sw___pEnergy = MAX_PLAYER_ENERGY;
			}
		}
		for(i=0;i<10;i++)
		{
			player[i].max_turbo=255;
		}
		return;
	}

	if(time_flag  && time_left > 0)	//time_left > 0 so no fatigue on scoreboard between qtrs(bug #1037)  
	{
		secondCounter = (secondCounter+1) % ONE_SEC;
		if(!secondCounter)
		{
			// get fatigue % factor for the current quarter len...
			l = pcl__gMatch->pcl__mOptions->sb___QuarterLen;
			l = quarterLenFatigues[l];

			// get seconds per quarter (quarter len fatigue factors are used now)
			k = 12*60;

			for(team=0; team<2; team++)
			{
				// tire guys on court
				for(i=0; i<subTeams[team].numPlayers; i++)
				{
					// get player RAM structure
					p = pcl__gMatch->apcl_mTeamRam[team]->ppcl_tPlyrLst[i];

					// stamina 0-100%
					j = p->pcl__pPlyrRom->ub___pAttrStamina;

					// get points to decrease energy by per quarter
					j = QFAC*j/100; j=QUARTER_ENERGY_DEC_WEAKLING-j;
					j = (j*l)/100;

					// get pts per second
					j = j*256/k;

					if(i<5)
					{
						// tire starting players
						p->sw___pEnergy -= j;
						if(p->sw___pEnergy<0) p->sw___pEnergy = 0;
					}
					else
					{
						// restore bench players
						p->sw___pEnergy += (j+1)/2;
						if(p->sw___pEnergy > MAX_PLAYER_ENERGY) p->sw___pEnergy = MAX_PLAYER_ENERGY;
					}
				}
			}
		}
	}

	// process turbo bars..
	for(i=0; i<10; i++)
	{
		p = pcl__gMatch->apcl_mTeamRam[i/5]->ppcl_tPlyrLst[i%5];
		j = p->sw___pEnergy;
		player[i].max_turbo = j*255/MAX_PLAYER_ENERGY;
		if(player[i].max_turbo > 255) player[i].max_turbo = 255;
		if(player[i].max_turbo < 0) player[i].max_turbo = 0;
		if(player[i].turbo > player[i].max_turbo)
			player[i].turbo=player[i].max_turbo;
	}

//	for(i=0;i<2;i++)
//	{
//		if(!ai_team[i].manual_subs)
//		{
//			SubAutoMonitor(i);
//		}
//	}
#endif
}

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/


int SubAutoMonitor(int team)	// used to trigger Autosub in main AI loop
{
#ifdef phil
	int		d1,d2;
	int		i,j,k,p,q;
	int		tr;
	int		tok;
	int		end;
	int		scoredTeam;
	int		action;
	int		numIn,numOut;
	subTeam		*s;
	TeamRamData_T	*t;
	int		fop,fopid;
	int		cpu;
int			savefreethrower;


	// get team ptr
	t = pcl__gMatch->apcl_mTeamRam[team];

	// is this a CPU team?
	if(ai_team[team].controllers[0]==0)	cpu=1;
	else					cpu=0;

	// test for fouled-out player on this team
	fop=0;
	for(j=0; j<5; j++)
	{
		i = pcl__gMatch->apcl_mTeamRam[team]->ppcl_tPlyrLst[j]->cl___pStatGame.uw___pDQ; 
		if(i)	// modified in debugger
		{
			fop = 1;
			fopid = j;
		}
	}
	foFlags[team] = fop;

	if(free_throws && ((free_thrower/5) == team ) )
	{
		i = free_thrower%5;
		savefreethrower =  subTeams[team].currentTeam[i]; 
	}

	// ensure auto subs enabled, or that it's a cpu team, in need of a foulout sub

	if(ai_team[team].manual_subs && !(cpu && fop))
	// do auto sub for fouled out player in manual mode
	// (it's easier than forcing the user to the sub screen)
//	if(ai_team[team].manual_subs && !fop)	
	{
		return(0);
	}
	// find ideal team
	if(ai_team[team].manual_subs)
	{
		// this *must* be a fouled-out player...
		for(i=0;i<5;i++)
		{
			subTeams[team].idealTeam[i] = subTeams[team].currentTeam[i];

			if(i == fopid)
			{
				q=-1;
				for(j=0; j<subTeams[team].numPlayers; j++)
				{
					// ensure player isn't on team already
					for(k=0;k<5;k++) if(subTeams[team].currentTeam[k]==j) break;
					if(k!=5) continue;

					// ensure not fouled out!
					if(t->pcl__tPlyrRam[j].cl___pStatGame.uw___pDQ) continue;

					k=SubRatePlayerInPos(team,i,j);
					if(k>p || q==-1)
					{
						p=k;
						q=j;
					}
				}

				// q should be best replacement
				if(q != -1) 	// paranoia
				{
					subTeams[team].idealTeam[i] = q;
				}
			}
		}
		subLastDelta[team]=10000; // lots
	}
	else
	{
		// find the ideal team
		SubFindBestTeam(team);

		// rate the current team against the ideal team
		d1 = d2 = 0;
		for(i=0; i<5; i++)
		{
			p = subTeams[team].currentTeam[i];
			j = SubRatePlayerInPos(team,i,p);
			d1 += j;

			p = subTeams[team].idealTeam[i];
			j = SubRatePlayerInPos(team,i,p);
			d2 += j;
		}

		// get difference
		subLastDelta[team] = d2 - d1;
	}

	// get timeouts remaining
	tr = GetNumberTimeOutsRemaining(team);

	// should we call timeouts?
	q = pcl__gMatch->sb___mQuarter;
	if( (q == 3) && time_left<(60*ONE_SEC))
	{
		end=1;
	}
	else
	{
		end=0;
	}

	if(!fop)
	{
		// don't allow fatigue based subs if fatigue disabled...
		// unless there's a fouled-out player
		if(!pcl__gMatch->pcl__mOptions->sb___Fatigue) subLastDelta[team]=0;
	}

	// see if timeouts are allowed
	tok = 1;
	if(fop)
	{
		// fouled-out player... wait for dead-ball
		tok=0;

		// ensure it's allowed!
		subLastSubTime[team] = -1;
	}
	else if(!tr)
	{
		// no timeouts left
		tok=0;
	}
	else if(time_left < 5*ONE_SEC)
	{
		tok=0;
	}
	else if(timeout_called)
	{
		tok = 0;
	}
	else if(tr==1 && !end)
	{
		// one timeout - save it for later
		tok=0;
	}
	else if(tr && end && TIMEOUT_CPU_ALLOWED(team))
	{
		// compare points... (last minute of half)...
		if(pcl__gMatch->apcl_mTeamRam[team]->uw___tPoints <
		   pcl__gMatch->apcl_mTeamRam[1-team]->uw___tPoints)
		{
			// see if other team just scored...
			scoredTeam = (scored_flag==1) ? 0: ((scored_flag == -1) ? 1 : -1);
			if(scoredTeam == (1-team))
			{
				// if so, force timeout
				tok=2;
			}
		}
	}

	// ensure we don't call subs or timeouts too often...
	action=0;
	
	if(subLastSubTime[team] == -1
	  || subLastSubTime[team]-time_left > (SUB_MIN_DELAY*ONE_SEC))
	{
		// consider substitution based on situation
		if(subLastDelta[team] > DELTA_THRESH_DEADBALL
			 && ((SUBS_ALLOWED) || subFirstFrame)
			 && tok!=2)
		{
			action=1;
		}
		else if(	(subLastDelta[team] > DELTA_THRESH_TIMEOUT
						&& TIMEOUT_CPU_ALLOWED(team)
						&& tok
					 )
				 
				  || (tok==2)
			   ) 
		{
			// ensure we have the ball, in our half...
			if(( (bhp-&player[0])/5 == team) &&
		   	((ball.yco<0 && team==0) || (ball.yco>0 && team==1)))
			{
				action=2;
			}
		}
	}

	subFirstFrame=0;

	if(!action) return(0);

	// prepare info for message box
	s=&subTeams[team];


/*******************
	numIn=numOut=0;
	for(i=0;i<s->numPlayers;i++)
	{
		for(j=0;j<5;j++) if(s->currentTeam[j]==i) break;
		if(j!=5)
		{
			for(j=0;j<5;j++) if(s->idealTeam[j]==i) break;
			if(j==5) subOut[numOut++]=i;
		}
		for(j=0;j<5;j++) if(s->idealTeam[j]==i) break;
		if(j!=5)
		{
			for(j=0;j<5;j++) if(s->currentTeam[j]==i) break;
			if(j==5) subIn[numIn++]=i;
		}
	}
*************/
	numIn=numOut=0;
	for(i=0; i < s->numPlayers; i++)
	{
		for(j=0;j<5;j++)
		{	// see if on current team
			if(s->currentTeam[j] == i)
			{
				break;
			}
		}

		if(j != 5)
		{	// he's on current team
			for(j=0;j<5;j++)
			{
				if(s->idealTeam[j]==i)
				{
					break;
				}
			}
			if(j==5)
			{	// he's not on ideal team...
				subOut[numOut++]=i;	//..., so he's outta here
			}
		}

		for(j=0;j<5;j++)
		{	// see if on ideal team
			if(s->idealTeam[j]==i)
			{
				break;
			}
		}
		if(j!=5)
		{	// he's on ideal team
			for(j=0;j<5;j++)
			{
				if(s->currentTeam[j]==i)
				{
					break;
				}
			}
			if(j==5)
			{	// he's not on current team...
				subIn[numIn++] = i;	// so he goes in
			}
		}
	}
	// paranoid check!!
	subNumPlayers=numIn;
	if(!subNumPlayers) return(0);


	// bug #61 - free thrower not in same position - don't sub
	if(free_throws && ((free_thrower/5) == team ) )
	{
		i = free_thrower%5;
		
		if(savefreethrower !=  s->idealTeam[i])
		{
			return(0);
		}
	}


	subNumPlayers = numIn;
	subTeamPending = team;
	subCallTimeout = (action==2)?1:0;

	if(subCallTimeout)
	{
		SubProcessEndOfQuarter(999);
//		DecNumberTimeOutsRemaining(team);
		timeout_called=1;
		process_timeout();		// this does whistle
	}
	else
	{
		Audio_SfxPlay( GameBank, SFX_WHISTLE, SfxVolume );

	}
	return(action);
#else
	return( 0 );
#endif
}



#ifdef DEBUG		// -----------------------------------------------------

void CheckPlayers(void)
{
	int		i,j,k,l;
	PlyrRamData_T	*ram1,*ram2;

	for(i=0;i<2;i++)
	{
		for(j=0;j<5;j++)
		{
			ram1=pcl__gMatch->apcl_mTeamRam[i]->ppcl_tPlyrLst[j];
			ram2=player[i*5+j].plyrRAM;
			if(ram1!=ram2)
			{
				printf("oh dear");
			}
		}
	}
}

void FuckPlayers(void)
{
	int		i,j,k;
	PlyrRamData_T	*ram1,*ram2;

	for(i=0;i<2;i++)
	{
		for(j=0;j<subTeams[i].numPlayers;j++)
		{
			subTeams[i].ratings[j]=100;
		}
		for(j=0;j<5;j++)
		{
			subTeams[i].ratings[subTeams[i].currentTeam[j]]=0;
		}
	}
}

#endif  //ifdef DEBUG		// -----------------------------------------------------



#undef phil

/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/


/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/



/***************************************************************************
 *
 *
 *
 ***************************************************************************
 *
 *
 *
 ***************************************************************************/

