Redline/source/carselection.cpp

819 lines
26 KiB
C++
Raw Normal View History

#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;
}