#include "stdtypes.h"
#include "reg_tool_3.h"
#include "rt3_redline.h"


#include <OpenGL/gl.h>
#include <string.h>
#include <stdio.h>
#include "gametime.h"
#include "gamemem.h"
#include "fileio.h"
#include "rendercar.h"
#include "carphysics.h"
#include "screen.h"
#include "controls.h"
#include "environment.h"
#include "transparency.h"
#include "renderframe.h"
#include "text.h"
#include "interface.h"
#include "gameinitexit.h"
#include "carselection.h"
#include "config.h"
#include "interfaceutil.h"
#include "stencil.h"
#include "gamesystem.h"
#include "textures.h"
#include "challenges.h"
#include "gamesound.h"
#include "random.h"

#define REGISTERED (RT3_IsRegistered())

char *StripName(char *aName);

int CompareCars(const void *a,const void *b)
{
	tCarDefinition *cara=(tCarDefinition*)FileGetParsedDataPtr(*(tFileRef*)a,kParserTypeCarDesc,sizeof(tCarDefinition));
	tCarDefinition *carb=(tCarDefinition*)FileGetParsedDataPtr(*(tFileRef*)b,kParserTypeCarDesc,sizeof(tCarDefinition));
	if(!REGISTERED)
		if(cara->demoAvailable!=carb->demoAvailable)
			return carb->demoAvailable-cara->demoAvailable;
	return _stricmp(StripName(cara->carName),StripName(carb->carName));	
}

void GetAvailableCars(tFileRef *availableCars,int *carCount,int onlyBuiltIn,int onlyAvailable)
{
	*carCount=0;
	for(int i=0;i<gFileTableSize;i++)
		if(*carCount<kMaxCars)
			if(char *extension=FileGetExtension(i))
				if(!_stricmp(extension,kFileTypeCarDefinition))
				{
					tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(i,kParserTypeCarDesc,sizeof(tCarDefinition));
					if((car->builtIn||!onlyBuiltIn)&&HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData))
						availableCars[(*carCount)++]=i;
					if(car->shiftUpRPM<car->maxRPM*0.8)
						printf("%s: %f/%f\n",car->carName,car->shiftUpRPM,car->maxRPM);
				}
	if(!onlyAvailable)
		for(int i=0;i<gFileTableSize;i++)
			if(*carCount<kMaxCars)
				if(char *extension=FileGetExtension(i))
					if(!_stricmp(extension,kFileTypeCarDefinition))
					{
						tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(i,kParserTypeCarDesc,sizeof(tCarDefinition));
						if((car->builtIn||!onlyBuiltIn)&&!HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData)&&!car->secret)
							availableCars[(*carCount)++]=i;
					}
	qsort(availableCars,*carCount,sizeof(tFileRef),CompareCars);
}

#define kSpecsXPos 0.9
#define kSpecsYPos 0.6
#define kSpecsSize 0.03
#define kSpecsOffset 0.07
#define kSpecsAlign kTextAlignRight

//#define kColorsXPos 0.5
//#define kColorsYPos 0.2
#define kColorsXPos 0.42
#define kColorsYPos -0.3
#define kColorsWidth 0.04
#define kColorsHeight 0.02
//#define kColorsOffset 0.025
#define kColorsOffset 0.05
#define kPointerSize 0.03

void CarSelectionDrawBackground(int mode)
{
	char title[256];
	
	switch(mode)
	{
		case kCarSelectionQuickMode:
			strcpy(title,"Select Car:");
			break;
			
		case kCarSelectionEnemyMode:
			strcpy(title,"Select Opponent Car:");
			break;
		
		case kCarSelectionDisplayMode:
			strcpy(title,"New Car Unlocked!");
			break;
			
	}
	InterfaceDrawBackground(-1,-1,0,0,0,0,1);
	TextPrintfToBufferFormated(Vector(kTitlePosX,kTitlePosY),0.08,kTextAlignLeft,title);
}

void CarSelectionDrawCar(tFileRef carRef,float time,int addOns,int color)
{
	tGameEntity carEntity,cameraEntity;
	tCarPhysics *phys=(tCarPhysics*)MemoryAllocateZeroedBlock(sizeof(tCarPhysics));
	cameraEntity.pos=Vector(0,1.5,0);
	carEntity.pos=Vector(0,0,7);
	*MatrixGetZVector(cameraEntity.dir)=!(carEntity.pos-cameraEntity.pos);
	*MatrixGetYVector(cameraEntity.dir)=Vector(0,1,0);
	MatrixReAdjust(cameraEntity.dir);
	carEntity.pos.x-=0.5;
	carEntity.pos.y-=1.0;
	MatrixIdentity(carEntity.dir);
	MatrixRotY(carEntity.dir,time*PI/4);

	carEntity.renderType=kRenderTypeCar;
	carEntity.physicsType=kPhysicsTypeCar;
	carEntity.physicsData=carRef;
	carEntity.physics=phys;

	tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(carRef,kParserTypeCarDesc,sizeof(tCarDefinition));
	phys->car=*car;
	phys->car.wheels=(tWheelDefinition*)MemoryAllocateBlock(sizeof(tWheelDefinition)*car->numWheels);
	MemoryMove(phys->car.wheels,car->wheels,sizeof(tWheelDefinition)*car->numWheels);
	phys->addOns=addOns;
	phys->color=color;
	InstallCarAddOns(phys);
	car=&phys->car;
	
	for(int i=0;i<car->numWheels;i++)
		phys->wheels[i].suspension=car->wheels[i].maxSuspension/2;
		
	tGameEntity *oldCameraEntity=gCameraEntity;
	gCameraEntity=&cameraEntity;
	SetupTranslation(carEntity.pos,carEntity.dir);
	glColorMask(0,0,0,0);
	glBegin(GL_QUADS);
	glVertex3f(-100,0,100);
	glVertex3f(100,0,100);
	glVertex3f(100,0,-100);
	glVertex3f(-100,0,-100);
	glEnd();			
	glColorMask(1,1,1,1);

	carEntity.pos.y=-1-car->wheels->pos.y+car->wheels->maxSuspension/2+car->wheels->radius;	
	SetupTranslation(carEntity.pos,carEntity.dir);

	glPushAttrib(GL_LIGHTING_BIT+GL_POLYGON_BIT+GL_COLOR_BUFFER_BIT+GL_TEXTURE_BIT);
	CarRenderEntity(&carEntity,gConfig->interiorDisplay?true:false,false);
	glPopAttrib();
	
	for(int i=1;i<=gConfig->stencil;i++)
	{
		gStencilZoom=0.9+0.1*i/(float)gConfig->stencil;
		SetupTranslation(carEntity.pos,carEntity.dir);
		glPushAttrib(GL_ENABLE_BIT+GL_POLYGON_BIT);
		CarRenderEntityShadow(&carEntity,6);
		glPopAttrib();
		RenderStencilLayer(true,gConfig->stencil);
	}
	DrawTransparentPolys(NULL);

	MemoryFreeBlock(phys->car.wheels);
	MemoryFreeBlock(phys);

	gCameraEntity=oldCameraEntity;

}

void CarSelectionDrawSpecs(tFileRef *availableCars,int numAvailable,int selected,int mode,int *available)
{
	//if(fadeName)
		//gTextOpacity=1;

	for(int i=-3;i<=3;i++)
	{
		tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[(selected+i+numAvailable)%numAvailable],kParserTypeCarDesc,sizeof(tCarDefinition));
		TextPrintfToBufferFormatedColored(Vector(-kSpecsXPos,0.4-i*0.1-fabs(i)*0.008),0.05-fabs(i)*0.008,kTextAlignLeft,1,1,1,1-fabs(i*0.15)-(i?0.3:0),car->carName);
	}
	tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selected],kParserTypeCarDesc,sizeof(tCarDefinition));
//	TextPrintfToBufferFormated(Vector(kSpecsXPos,0.5),0.05,kTextAlignLeft,car->carName);
	

//	gTextOpacity=opacity;
	float yPos=kSpecsYPos;
	
	if(car->magic)
	{
//		TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-5*kSpecsOffset),kSpecsSize,kSpecsAlign,"Where we're going, we don't need specifications.");
		TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-0*kSpecsOffset),kSpecsSize,kSpecsAlign,"Where we're going, we don't need specifications.");
	}
	else
	{		
		if(car->numWheels>=4)
			if(car->wheels[0].powered&&car->wheels[2].powered)
				TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-0.0),kSpecsSize,kSpecsAlign,"Drivetrain: \255#a\2554WD");
			else if(car->wheels[0].powered)
				TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-0.0),kSpecsSize,kSpecsAlign,"Drivetrain: \255#a\255FWD");
			else if(car->wheels[2].powered)
				TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-0.0),kSpecsSize,kSpecsAlign,"Drivetrain: \255#a\255RWD");
		
		TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-5*kSpecsOffset),kSpecsSize,kSpecsAlign,"Gearbox: \255#a\255%d Gears",car->numGears-2);
		if(gConfig->metricUnits)
		{
			TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-1*kSpecsOffset),kSpecsSize,kSpecsAlign,"Displacement: \255#a\255%1.1f L",car->displacement);
			TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-2*kSpecsOffset),kSpecsSize,kSpecsAlign,"Mass: \255#a\255%4.0f kg",car->mass);
			TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-3*kSpecsOffset),kSpecsSize,kSpecsAlign,"Power: \255#a\255%3.0f kw @ %4.0f RPM",car->power/1000,car->powerRPM);
			TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-4*kSpecsOffset),kSpecsSize,kSpecsAlign,"Torque: \255#a\255%3.0f Nm @ %4.0f RPM",car->torque,car->torqueRPM);
		}
		else
		{
			TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-1*kSpecsOffset),kSpecsSize,kSpecsAlign,"Displacement: \255#a\255%3.0f cui",car->displacement*61.023744);
			TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-2*kSpecsOffset),kSpecsSize,kSpecsAlign,"Mass: \255#a\255%4.0f lbs",car->mass*2.2046);
			TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-3*kSpecsOffset),kSpecsSize,kSpecsAlign,"Power: \255#a\255%3.0f hp @ %4.0f RPM",car->power/745.69987,car->powerRPM);
			TextPrintfToBufferFormated(Vector(kSpecsXPos,yPos-4*kSpecsOffset),kSpecsSize,kSpecsAlign,"Torque: \255#a\255%3.0f lb-ft @ %4.0f RPM",car->torque/1.35628105,car->torqueRPM);
		}	
	}
	if(!car->demoAvailable&&!REGISTERED&&mode!=kCarSelectionEnemyMode)		
		TextPrintfToBufferFormatedColored(Vector(0.2,0),0.15,kTextAlignMiddle,1,1,1,0.5,"DEMO");
//		TextPrintfToBufferFormatedColored(Vector(0.2,0.2),0.25,kTextAlignMiddle,1,1,1,0.8,"\255demo_car.png\255");
	else if(!HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData)&&mode!=kCarSelectionEnemyMode)		
		TextPrintfToBufferFormatedColored(Vector(0.2,0),0.15,kTextAlignMiddle,1,1,1,0.5,"LOCKED");
	if(available)
		*available=((car->demoAvailable||REGISTERED)&&HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData))||mode==kCarSelectionEnemyMode;	
	gTextOpacity=1;
}

void CarSelectionDrawColors(tFileRef carRef,int color)
{
/*	gTexturesQualityModifier=-255;
	glPushAttrib(GL_COLOR_BUFFER_BIT+GL_CURRENT_BIT);
	glDisable(GL_LIGHTING);
	tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(carRef,kParserTypeCarDesc,sizeof(tCarDefinition));

	glLoadIdentity();
	glTranslatef(0.0f,0.0f,-1.0f);
	TexturesSelectTex(FileGetReference("colorbevel.pct"));
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	
	for(int i=0;i<car->numColors;i++)
	{
		glColor3fv(&(car->colors[i].x));
		glBegin(GL_TRIANGLE_STRIP);								
		glTexCoord2d(1,1); glVertex2f(kColorsXPos+kColorsWidth,kColorsYPos-kColorsHeight/2-i*kColorsOffset);		
		glTexCoord2d(1,0); glVertex2f(kColorsXPos+kColorsWidth,kColorsYPos+kColorsHeight/2-i*kColorsOffset); 	
		glTexCoord2d(0,1); glVertex2f(kColorsXPos,kColorsYPos-kColorsHeight/2-i*kColorsOffset); 	
		glTexCoord2d(0,0); glVertex2f(kColorsXPos,kColorsYPos+kColorsHeight/2-i*kColorsOffset); 		
		glEnd();					
	}
	if(car->numColors)
	{
		if(color>=car->numColors)
			color=car->numColors-1;
		glColor3f(1,1,1);
		TexturesSelectTex(FileGetReference("menupointer.tif"));
		glBegin(GL_TRIANGLE_STRIP);								
		glTexCoord2d(1,1); glVertex2f(kColorsXPos-kColorsWidth+kPointerSize,kColorsYPos-kPointerSize/2-color*kColorsOffset);		
		glTexCoord2d(1,0); glVertex2f(kColorsXPos-kColorsWidth+kPointerSize,kColorsYPos+kPointerSize/2-color*kColorsOffset); 	
		glTexCoord2d(0,1); glVertex2f(kColorsXPos-kColorsWidth,kColorsYPos-kPointerSize/2-color*kColorsOffset); 	
		glTexCoord2d(0,0); glVertex2f(kColorsXPos-kColorsWidth,kColorsYPos+kPointerSize/2-color*kColorsOffset); 		
		glEnd();					
	}

	glPopAttrib();
	gTexturesQualityModifier=0;*/

	gTexturesQualityModifier=-255;
	glPushAttrib(GL_COLOR_BUFFER_BIT+GL_CURRENT_BIT);
	glDisable(GL_LIGHTING);
	tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(carRef,kParserTypeCarDesc,sizeof(tCarDefinition));

	glLoadIdentity();
	glTranslatef(0.0f,0.0f,-1.0f);
	TexturesSelectTex(FileGetReference("colorbevel.pct"));
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	
	for(int i=0;i<car->numColors;i++)
	{
		glColor3fv(&(car->colors[i].x));
		glBegin(GL_TRIANGLE_STRIP);								
		glTexCoord2d(1,1); glVertex2f(kColorsXPos-i*kColorsOffset+kColorsWidth,kColorsYPos-kColorsHeight/2);		
		glTexCoord2d(1,0); glVertex2f(kColorsXPos-i*kColorsOffset+kColorsWidth,kColorsYPos+kColorsHeight/2); 	
		glTexCoord2d(0,1); glVertex2f(kColorsXPos-i*kColorsOffset,kColorsYPos-kColorsHeight/2); 	
		glTexCoord2d(0,0); glVertex2f(kColorsXPos-i*kColorsOffset,kColorsYPos+kColorsHeight/2); 		
		glEnd();					
	}
	if(car->numColors)
	{
		if(color>=car->numColors)
			color=car->numColors-1;
		glColor3f(1,1,1);
		TexturesSelectTex(FileGetReference("menupointer.tif"));
		glBegin(GL_TRIANGLE_STRIP);								
		glTexCoord2d(0,1); glVertex2f(kColorsXPos-color*kColorsOffset+kColorsWidth/2+kPointerSize/2,kColorsYPos-kColorsHeight*2);		
		glTexCoord2d(1,1); glVertex2f(kColorsXPos-color*kColorsOffset+kColorsWidth/2+kPointerSize/2,kColorsYPos-kColorsHeight*2+kPointerSize); 	
		glTexCoord2d(0,0); glVertex2f(kColorsXPos-color*kColorsOffset+kColorsWidth/2-kPointerSize/2,kColorsYPos-kColorsHeight*2); 	
		glTexCoord2d(1,0); glVertex2f(kColorsXPos-color*kColorsOffset+kColorsWidth/2-kPointerSize/2,kColorsYPos-kColorsHeight*2+kPointerSize); 		
		glEnd();					
	}

	glPopAttrib();
	gTexturesQualityModifier=0;
}


void InterfaceCarSelectionRenderLoadScreen(float time,tFileRef *availableCars,int numAvailable,int selected,int mode,int addOns,int color,int drawColor,int *demoAvailable,float carFade,float totalFade)
{
	glPushMatrix();
	glPushAttrib(GL_LIGHTING_BIT);
	glDisable(GL_LIGHTING);
	glClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT);

	CarSelectionDrawBackground(mode);

	CarSelectionDrawSpecs(availableCars,numAvailable,selected,mode,demoAvailable);

	InterfaceDrawBackgroundFade(carFade,false);	

	TextPrintfToBufferFormated(Vector(0.2,0.1),0.05,kTextAlignMiddle,"Loading...");

	CarSelectionDrawColors(availableCars[selected],color);

	TextPrintBuffer(1,false);
	TextClearBuffer();

	InterfaceDrawBackgroundFade(totalFade,false);	
		
	ScreenBlit();
	glPopAttrib();
	glPopMatrix();
}

void InterfaceCarSelectionRender(float time,tFileRef *availableCars,int numAvailable,int selected,int mode,int addOns,int color,int drawColor,int *demoAvailable,float carFade,float totalFade)
{
	glPushMatrix();
	glPushAttrib(GL_LIGHTING_BIT);
	glEnable(GL_LIGHTING);
	SetupLighting();

	glClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT);

	CarSelectionDrawBackground(mode);
	/*tInterfaceMenuDescribtion menu;
	InterfaceInitMenu(&menu,0,"");

	InterfaceRenderReplay(NULL,0,&menu);*/

	if(selected!=-1)
	{
		if(carFade<1)
			CarSelectionDrawCar(availableCars[selected],time,addOns,drawColor);
		CarSelectionDrawSpecs(availableCars,numAvailable,selected,mode,demoAvailable);
	}

	InterfaceDrawBackgroundFade(carFade,false);	

	if(selected!=-1&&mode!=kCarSelectionDisplayMode)
		CarSelectionDrawColors(availableCars[selected],color);
							
	TextPrintBuffer(1,false);
	TextClearBuffer();

	InterfaceDrawBackgroundFade(totalFade,false);	
		
	ScreenBlit();
	glPopAttrib();
	glPopMatrix();
}

int SelectCarByChar(char ch)
{
	tFileRef availableCars[kMaxCars];
	int carCount;
	GetAvailableCars(availableCars,&carCount,false,false);

	for(int i=0;i<carCount;i++)
	{
		tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[i],kParserTypeCarDesc,sizeof(tCarDefinition));
		if(toupper(StripName(car->carName)[0])>=ch)
			return i;
	}
	return carCount-1;
}

/*
int InterfaceCarSelectionQuick(int *selection,int mode)//,int (*Callback)(void*),void *userData,int *callbackResponse)
{
	tInterfaceMenuDescribtion menu;
	tFileRef availableCars[kMaxCars];
	int carCount;
	GetAvailableCars(availableCars,&carCount,false,false);

	InterfaceInitMenu(&menu,carCount,"Car Quick-Selection");

	menu.scrollEnable=true;
	menu.returnOnSpace=true;
	for(int i=0;i<menu.numItems;i++)
	{
		tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[i],kParserTypeCarDesc,sizeof(tCarDefinition));
		strcpy(menu.items[i].label,car->carName);
		menu.items[i].size*=0.7;
		menu.items[i].lineSpacing*=0.7;
		if(!HasChallengeRequirements(car->challengeRequirements,gConfig->challengeData)&&mode!=kCarSelectionEnemyMode)
			menu.items[i].flags |= kInterfaceMenuItemDisabled;
		if(!car->demoAvailable&&!REGISTERED&&mode!=kCarSelectionEnemyMode)		
			menu.items[i].flags |= kInterfaceMenuItemDisabled;
	}
//	menu.TimerCallback=Callback;
//	menu.userData=userData;
	menu.initialSelection=*selection;
	*selection=InterfaceGetUserMenuSelection(&menu);
	if(*selection == kInterfaceMenuEsc)
	{
		*selection=-2;
		return true;
	}
	if(*selection & kInterfaceMenuSpaceFlag)
	{
		*selection&=kInterfaceMenuItemMask;
		return false;
	}
	InterfaceDisposeMenu(&menu);
	return true;
}
*/
int InterfaceCarSelectionInput(int carCount,int *selection,int mode,int *color,int demoAvailable,int maxColors,int *drawImmediate)
{
	int key;
	char ch=toupper(GetKeyInput(&key));
	if(ch>='A'&&ch<='Z')
		*selection=SelectCarByChar(ch);
	*drawImmediate=false;
	switch(key)
	{
//		case kInterfaceKeyLeft:
		case kInterfaceKeyUp:
			(*selection)--;
			*color=0;
			PlayInterfaceSound(FileGetReference("menu.wav"));
			break;
//		case kInterfaceKeyRight:
		case kInterfaceKeyDown:
			(*selection)++;
			*color=0;
			PlayInterfaceSound(FileGetReference("menu.wav"));
			break;
			
//		case kInterfaceKeyUp:
		case kInterfaceKeyRight:
			(*color)--;
			if(*color<0)
				*color=maxColors-1;
			if(*color<0)
				*color=0;
			PlayInterfaceSound(FileGetReference("menu.wav"));
			break;
			
//		case kInterfaceKeyDown:
		case kInterfaceKeyLeft:
			*color=(*color+1)%maxColors;
			if(*color>=maxColors)
				*color=0;
			PlayInterfaceSound(FileGetReference("menu.wav"));
			break;
			
		case kInterfaceKeyEsc:
		case kInterfaceKeyDelete:
			PlayInterfaceSound(FileGetReference("esc.wav"));
			*selection=-2;
			return true;
	
		case kInterfaceKeyReturn:
		case kInterfaceKeyEnter:
			if(demoAvailable)
			{
				PlayInterfaceSound(FileGetReference("select.wav"));
				return true;	
			}
			break;

/*		case kInterfaceKeySpace:
			*drawImmediate=true;
			return InterfaceCarSelectionQuick(selection,mode);//,mode,Callback,userData,callbackResponse);
			break;*/
	}		
	return false;
}

void SelectNextCar(tFileRef *car,UInt8 *color,int onlyAvailable,int onlyDemo)
{
	int availableCars[kMaxCars];
	int carCount;
	int selection=0;
	GetAvailableCars(availableCars,&carCount,false,onlyAvailable);
	
	for(int i=0;i<carCount;i++)
		if(*car==availableCars[i])
			selection=i;

	tCarDefinition *c;
	do{
		selection=(selection+1)%carCount;
		c=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));
		if(color)
			if(c->numColors)
				*color=RandomInt(0,c->numColors);
			else
				*color=0;
	}while(!c->demoAvailable&&!REGISTERED&&onlyDemo);

	*car=availableCars[selection];
//	gConfig->lastCar=*car;
}

void SelectPrevCar(tFileRef *car,UInt8 *color,int onlyAvailable,int onlyDemo)
{
	int availableCars[kMaxCars];
	int carCount;
	int selection=0;
	GetAvailableCars(availableCars,&carCount,false,onlyAvailable);
	
	for(int i=0;i<carCount;i++)
		if(*car==availableCars[i])
			selection=i;

	tCarDefinition *c;
	do{
		selection--;
		if(selection<0)
			selection+=carCount;
		c=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));
		if(color)
			if(c->numColors)
				*color=RandomInt(0,c->numColors);
			else
				*color=0;
	}while(!c->demoAvailable&&!REGISTERED&&onlyDemo);
	
	*car=availableCars[selection];
//	gConfig->lastCar=*car;
}

void SetupLighting();

int InterfaceCarSelection(tFileRef *car,int mode,UInt8 *pColor,int (*Callback)(void*),void *userData,int *callbackResponse)
{
	int availableCars[kMaxCars];
	int selection=1;
	int carCount;
	int color=*pColor;
	int oldColor=*pColor;
	int demoAvailable=true;
	int drawImmediate=false;
	tFileRef curCar;
	float carFade=0;
			
	GetAvailableCars(availableCars,&carCount,false,false);			
	for(int i=0;i<carCount;i++)
		if(*car==availableCars[i])
			selection=i;

	tEnvironment *oldEnv=gEnvironment;
	tMapEnv* oldMapEnv=gMapEnv;
	gMapEnv=NULL;
	LoadEnvironment(FileGetReference("showroom.senv"));
	glDisable(GL_LIGHTING);
	
	float startTime=TimeGetSeconds();
	float curTime=0;

	int maxColors=1;
	
	curCar=selection==-1?-1:availableCars[selection];

	do{
		selection=selection%carCount;
		if(selection<0) selection+=carCount;		
		float dt=curTime;
		curTime=TimeGetSeconds()-startTime;
		dt=curTime-dt;

		if((curCar!=(selection==-1?-1:availableCars[selection]))||color!=oldColor)
		{
			if(selection!=-1)
			{
				tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));			
				int colorLoaded=false;
				if(car->numColors>0)
					colorLoaded=car->colorLoaded[color];
				if(carFade>=3||(colorLoaded&&carFade>=1))
				{
					curCar=availableCars[selection];
					oldColor=color;
				}
				else
					carFade+=dt/0.2;
			}
			else if(carFade>=1)
			{
				curCar=-1;
				oldColor=color;
			}
			else
				carFade+=dt/0.2;	
		}
		else
		{
			carFade-=dt/0.2;
			if(carFade<1&&carFade+dt/0.2>=1&&curCar!=-1)
			{
				tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));			
				int colorLoaded=false;
				if(car->numColors>0)
					colorLoaded=car->colorLoaded[color];
				if(!colorLoaded)
				{
					InterfaceCarSelectionRenderLoadScreen(curTime,availableCars,carCount,selection,mode,0,color,oldColor,&demoAvailable,carFade,1-(curTime/0.2));
					InterfaceCarSelectionRender(curTime,availableCars,carCount,selection,mode,0,color,oldColor,&demoAvailable,carFade,1-(curTime/0.2));
					FlushKeys();
					curTime=TimeGetSeconds()-startTime;
				}
			}
		}
		if(drawImmediate)
		{
			carFade=1;
			tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));			
			car->colorLoaded[color]=true;
		}
		if(carFade<0)carFade=0;
		InterfaceCarSelectionRender(curTime,availableCars,carCount,selection,mode,0,color,oldColor,&demoAvailable,carFade,1-(curTime/0.2));	
		SystemPoll(false);	
		if(Callback)
		{
			*callbackResponse=Callback(userData);
			if(*callbackResponse!=-1)
			{
				gEnvironment=oldEnv;
				gMapEnv=oldMapEnv;
				return false;
			}
		}
		if(selection!=-1)
		{
			tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(availableCars[selection],kParserTypeCarDesc,sizeof(tCarDefinition));
			maxColors=car->numColors;
			if(maxColors==1)maxColors=1;
		}
		else
			maxColors=1;
	}
	while(!InterfaceCarSelectionInput(carCount,&selection,mode,&color,demoAvailable,maxColors,&drawImmediate));
	glEnable(GL_LIGHTING);
	gEnvironment=oldEnv;
	gMapEnv=oldMapEnv;
	
	float endTime=curTime+0.2;
	if(selection>=0)
		while(curTime<endTime)
		{
			curTime=TimeGetSeconds()-startTime;
			InterfaceCarSelectionRender(curTime,availableCars,carCount,selection,mode,0,color,oldColor,&demoAvailable,carFade,1-((endTime-curTime)/0.2));			
		}
	if(selection!=-2)
	{
		*car=availableCars[selection];
		*pColor=color;
	}
	return selection!=-2;
}

enum{
	kOpponentNumOpponents,
	kOpponent1,
	kOpponent2,
	kOpponent3,
	kOpponent4,
	kOpponent5,
	kOpponent6orOK,
	kOpponent7orNumOptions,
	kOpponent8,
	kOpponent9,
	kOpponent10,
	kOpponent11,
	kOpponentOK,
	kOpponentNumOptions
};

int InterfaceSelectOpponentCars(int *numOpponents,tFileRef *opponents,UInt8 *colors,int (*Callback)(void*),void *userData)
{
	int setNumOpponents=gConfig->numEnemies;
	if(setNumOpponents>(gConfig->allowHugeGames?11:5))
		setNumOpponents=(gConfig->allowHugeGames?11:5);
	int callBackResponse;
	tInterfaceMenuDescribtion menu;
	InterfaceInitMenu(&menu,gConfig->allowHugeGames?kOpponentNumOptions:kOpponent7orNumOptions,"Select Opponents");

	int availableCars[kMaxCars];
	int carCount;
	GetAvailableCars(availableCars,&carCount,false,false);


//	for(int i=0;i<menu.numItems;i++)
//		strcpy(menu.items[i].describtion,itemStrings[i]);


	strcpy(menu.items[(gConfig->allowHugeGames?kOpponentOK:kOpponent6orOK)].label,"Accept");
	menu.items[(gConfig->allowHugeGames?kOpponentOK:kOpponent6orOK)-1].lineSpacing*=1.5;
	menu.items[kOpponent1-1].lineSpacing*=1.5;
	menu.TimerCallback=Callback;
	menu.userData=userData;
	
	menu.items[kOpponentNumOpponents].flags|=kInterfaceMenuItemArrowInput;

	for(int i=0;i<11;i++)
	{
		opponents[i]=gConfig->opponentCars[i];
		colors[i]=gConfig->opponentColors[i];
		if(opponents[i]==-1||opponents[i]==0)
		{
			opponents[i]=availableCars[0];
			colors[i]=0;
		}
	}
	
	for(int i=kOpponent1;i<=(gConfig->allowHugeGames?kOpponent11:kOpponent5);i++)
	{
		menu.items[i].flags|=kInterfaceMenuItemArrowInput;
		if(gConfig->allowHugeGames)
		{
			menu.items[i].size*=0.6;
			menu.items[i].lineSpacing*=0.6;			
		}
	}	
	
	int exit=false;
	int zoom=false;
	do{
		sprintf(menu.items[kOpponentNumOpponents].label,"Number of Opponents: \255#a\255%d",setNumOpponents);
		for(int i=kOpponent1;i<=(gConfig->allowHugeGames?kOpponent11:kOpponent5);i++)
		{
			if(i-kOpponent1<setNumOpponents)
				menu.items[i].flags&=~kInterfaceMenuItemDisabled;
			else
				menu.items[i].flags|=kInterfaceMenuItemDisabled;
			tCarDefinition *c=(tCarDefinition*)FileGetParsedDataPtr(opponents[i-kOpponent1],kParserTypeCarDesc,sizeof(tCarDefinition));			
			sprintf(menu.items[i].label,"Opponent %d: \255#a\255%s",i-kOpponent1+1,c->carName);
		}	
		int sel=InterfaceGetUserMenuSelection(&menu);
		switch(menu.initialSelection=(sel&kInterfaceMenuItemMask))
		{
			case kOpponentNumOpponents:
				if(sel&kInterfaceMenuRightArrow){
					if(setNumOpponents<(gConfig->allowHugeGames?11:5))
						setNumOpponents++;
				}
				else if(sel&kInterfaceMenuLeftArrow){
					if(setNumOpponents>0)
						setNumOpponents--;
				}
				else
					exit=true;
				break;
			case kOpponent6orOK:
				if(!gConfig->allowHugeGames)
				{
					exit=true;
					break;
				}
			case kOpponent1:
			case kOpponent2:
			case kOpponent3:
			case kOpponent4:
			case kOpponent5:
			case kOpponent7orNumOptions:
			case kOpponent8:
			case kOpponent9:
			case kOpponent10:
			case kOpponent11:

				if(sel&kInterfaceMenuLeftArrow)
					SelectPrevCar(&opponents[menu.initialSelection-kOpponent1],&colors[menu.initialSelection-kOpponent1],false,false);
				else if(sel&kInterfaceMenuRightArrow)
					SelectNextCar(&opponents[menu.initialSelection-kOpponent1],&colors[menu.initialSelection-kOpponent1],false,false);
				else
					InterfaceCarSelection(&opponents[menu.initialSelection-kOpponent1],kCarSelectionEnemyMode,&colors[menu.initialSelection-kOpponent1],Callback,userData,&callBackResponse);
				break;
			case kOpponentOK:
			case kInterfaceMenuEsc:
				exit=true;
				break;

		}
	}while(!exit);
	for(int i=0;i<11;i++)
	{
		gConfig->opponentCars[i]=opponents[i];
		gConfig->opponentColors[i]=colors[i];
	}
	*numOpponents=gConfig->numEnemies=setNumOpponents;
	InterfaceDisposeMenu(&menu);	
	return menu.initialSelection!=kInterfaceMenuEsc;
}