//gameinitexit.cpp //initialize a new game and dispose all the game structures after the game has ended #include #include #include #include "gametime.h" #include "gamemem.h" #include "entities.h" #include "fileio.h" #include "sky.h" #include "carphysics.h" #include "gameframe.h" #include "roads.h" #include "parser.h" #include "network.h" #include "environment.h" #include "config.h" #include "gameinitexit.h" #include "error.h" #include "gamesound.h" #include "text.h" #include "renderframe.h" #include "controls.h" #include "tracks.h" #include "stencil.h" #include "log.h" #include "networkphysics.h" #include "random.h" #include "particles.h" #include "interfaceutil.h" #include "tracker.h" #include "screen.h" #include "textures.h" #include "gamesystem.h" #include "interface.h" #include "interfacemultiplayer.h" #include "initexit.h" /* #if __option(profile) #include #endif */ //the map info structure tMapInfo *gMapInfo=NULL; //the game info structure tGameInfo *gGameInfo=NULL; //pointers to the game entities of the cars participating in the game tGameEntity *gCarEntities[kMaxPlayers]; tGameEntity *gGhostEntity; tMapEnv *gMapEnv=NULL; //the check points along the track (invisible, used only for lead/trail calculation) tCheckPoint gCheckPoints[kNumCheckPoints]; int gNumCornerSigns; tCornerSign gCornerSigns[kMaxCornerSigns]; //is this a replay being watched? int gReplay=false; int gBackgroundReplay=false; int gReplayAutoCam=false; int gReplayViewedEntityID; int gReplayNextCam; int gReplayOldFrameCount; void InitGInfo(tGameInfo *gInfo) { gInfo->inited=false; gInfo->version=0; gInfo->numPlayers=0; gInfo->numNetPlayers=0; gInfo->reverse=0; gInfo->environment=kFileErr; gInfo->numLaps=0; gInfo->map=kFileErr; gInfo->network=false; gInfo->playerID=0; gInfo->arcade=kGameModeSim; gInfo->maxTime=0; gInfo->unused1=false; gInfo->unused2=false; gInfo->carsOnSpeed=gConfig->carsOnSpeed; gInfo->demolition=gConfig->demolition; gInfo->playerInited[0]=true; strcpy(gInfo->environmentName,""); strcpy(gInfo->mapName,""); for(int i=0;iplayerCars[i]=kFileErr; gInfo->playerColors[i]=0; gInfo->playerAddOns[i]=0; gInfo->netID[i]=0; gInfo->ping[i]=0; gInfo->playerVersions[i]=0; strcpy(gInfo->playerCarNames[i],""); strcpy(gInfo->playerNames[i],""); } } //load map describtion from the file refered to by ref. void ProcessMapInfo() { if(gMapInfo->reverse) gGameInfo->reverse=!gGameInfo->reverse; //get road types data gRoadTypes=(tRoadTypeList*)FileGetParsedDataPtr(gMapInfo->roadTypes,kParserTypeRoadTypeDesc,sizeof(tRoadTypeList)); //initialize game entities defined by map for(int i=0;inumObjs;i++) { if(gMapInfo->obj[i].envFlags==0||(gMapInfo->obj[i].envFlags&gEnvironment->envFlags)) { //create a new entity tGameEntity *entity; entity=EntityNew(gFirstEntity); entity->renderType=kRenderTypeModel; //get entity position and direction from map info entity->pos=gMapInfo->obj[i].pos; EulerAnglesToMatrix(gMapInfo->obj[i].dir*kDegreeRadians,entity->dir); //get extension of file describing entity char *extension=FileGetExtension(gMapInfo->obj[i].model); entity->physics=MemoryAllocateBlock(sizeof(int)); *((int*)entity->physics)=gMapInfo->obj[i].color; entity->untouchable=gMapInfo->obj[i].untouchable; if(extension) //is this entity just a model (no interaction with the game, just graphics). if(!_stricmp(extension,kFileTypeModel)) entity->renderData=gMapInfo->obj[i].model; //or is it a solid entity? else if(!_stricmp(extension,kFileTypeSolidEntity)) { //initialize entity entity->physicsType=kPhysicsTypeSolid; entity->physicsData=gMapInfo->obj[i].model; entity->physicsMachine=kPhysicsLocal; tSolidEntityPhysics *ent=(tSolidEntityPhysics*)FileGetParsedDataPtr(entity->physicsData,kParserTypeSolidEntityDesc,sizeof(tSolidEntityPhysics)); if(ent->randomColor) *((int*)entity->physics)=RandomInt(0,ent->numColors); entity->renderData=ent->model; if(ent->movable) entity->lastActivity=-1000; } else if(!_stricmp(extension,kFileTypeCarDefinition)) { //initialize entity entity->renderType=kRenderTypeCar; tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(gMapInfo->obj[i].model,kParserTypeCarDesc,sizeof(tCarDefinition)); entity->renderData=car->model; entity->physicsType=kPhysicsTypeCar; entity->controlType=kControlTypeNone; entity->physicsData=gMapInfo->obj[i].model; entity->physics=MemoryAllocateZeroedBlock(sizeof(tCarPhysics)); entity->physicsMachine=gGameInfo->network?(i==gGameInfo->playerID?kPhysicsLocal:kPhysicsRemote):kPhysicsLocal; entity->lastActivity=-1000; tCarPhysics *phys=(tCarPhysics*)entity->physics; phys->car=*car; phys->car.wheels=(tWheelDefinition*)MemoryAllocateBlock(sizeof(tWheelDefinition)*car->numWheels); MemoryMove(phys->car.wheels,car->wheels,sizeof(tWheelDefinition)*car->numWheels); phys->color=gMapInfo->obj[i].color; } //is it something we don't understand? else { char error[256]; sprintf(error,"Illegal File Type %s Specified for Object",extension); FailWithErrorString(error); } } //else PrintConsoleString("%s: %d/%d",FileGetName(gMapInfo->obj[i].model),gMapInfo->obj[i].envFlags,gEnvironment->envFlags); } gMapEnv=NULL; for(int i=0;inumMapEnvs;i++) if(gMapInfo->mapEnv[i].envFlags&gEnvironment->envFlags) gMapEnv=gMapInfo->mapEnv+i; if(gMapEnv) if(gMapEnv->fogBegin) { GLfloat fogColor[4]; *(tVector3*)fogColor=gMapEnv->fogColor; fogColor[3]=1; glFogfv(GL_FOG_COLOR,fogColor); glFogf(GL_FOG_START,gMapEnv->fogBegin); glFogf(GL_FOG_END,gMapEnv->fogEnd); } //calculate road checkpoints if(gMapInfo->loop) RoadInitCheckPoints(gMapInfo->startPos); else { RoadInitCheckPoints(gMapInfo->startPos,gMapInfo->finishPos); gGameInfo->numLaps=1; } RoadInitCornerSigns(); } void CalcCamera(); void InitCars() { for(int i=0;inumPlayers;i++) { //get car describtion tCarDefinition *car=(tCarDefinition*)FileGetParsedDataPtr(gGameInfo->playerCars[i],kParserTypeCarDesc,sizeof(tCarDefinition)); //initialize car entity tGameEntity *entity; entity=EntityNew(gFirstEntity); entity->renderType=kRenderTypeCar; entity->renderData=car->model; entity->physicsType=kPhysicsTypeCar; entity->controlType=(i==gGameInfo->playerID?kControlTypeUserInput:kControlTypeAIInput); //entity->controlType=kControlTypeAIInput; entity->physicsData=gGameInfo->playerCars[i]; entity->physics=MemoryAllocateZeroedBlock(sizeof(tCarPhysics)); entity->physicsMachine=gGameInfo->network?(i==gGameInfo->playerID?kPhysicsLocal:kPhysicsRemote):kPhysicsLocal; if(i>=gGameInfo->numNetPlayers&&gGameInfo->playerID==0) entity->physicsMachine=kPhysicsLocal; gCarEntities[i]=entity; //position car at start position int startAtEnd=(gGameInfo->reverse&&!gMapInfo->loop); tVector3 startPos=startAtEnd?gMapInfo->finishPos:gMapInfo->startPos; if(gGameInfo->numLaps==-1&&gMapInfo->loop) { int roadIndex=0; float side=0,speed; startPos=RoadGetNextWaypoint(gMapInfo->startPos,&roadIndex,&side,&speed,-700); } tVector3 startDir=RoadGetDir(RoadGetPosition(startPos,0,NULL)); entity->pos=startPos-startDir*((i/2)*10+gMapInfo->startLineOffset+(i%2?gMapInfo->carOffset:0))+!(startDir%Vector(0,1,0))*(i%2?-1:1)*gMapInfo->startCenterOffset; entity->netPos=entity->pos; *MatrixGetZVector(entity->dir)=startDir; *MatrixGetYVector(entity->dir)=Vector(0,1,0); MatrixReAdjust(entity->dir); tCarPhysics *phys=(tCarPhysics*)entity->physics; if(i==gGameInfo->playerID) gViewedEntity=entity; //set up car specs if(startAtEnd) phys->checkPoint=kNumCheckPoints-1; phys->car=*car; phys->car.wheels=(tWheelDefinition*)MemoryAllocateBlock(sizeof(tWheelDefinition)*car->numWheels); MemoryMove(phys->car.wheels,car->wheels,sizeof(tWheelDefinition)*car->numWheels); phys->addOns=gGameInfo->playerAddOns[i]; phys->color=gGameInfo->playerColors[i]; phys->aiPowerCycle=RandomFl(0,2*PI); phys->aiRouteCycle=RandomFl(0,2*PI); phys->position=RoadGetPosition(entity->pos,entity->lastRoadIndex,NULL); if(i>0) { tCarPhysics *phys2=(tCarPhysics*)gCarEntities[0]->physics; if(phys->position>phys2->position&&!gGameInfo->reverse) phys->lap=-1; else if(phys->positionposition&&gGameInfo->reverse) phys->lap=-1; } if(gGameInfo->playerNames[i][0]) phys->plateName=gGameInfo->playerNames[i]; for(int j=0;j<5;j++) phys->dirtStretch[j]=RandomFl(-0.5,0.5); InstallCarAddOns(phys); //if car is on left side, prepare for overtaking //(otherwise ai players will immediatly try to change lanes, not a good idea). if(i%2) { phys->overtaking=gCarEntities[0]; phys->overtakeSide=-1; } } } void InitGameEntities() { //initialize entity list EntityResetCount(); gFirstEntity=(tGameEntity*)MemoryAllocateZeroedBlock(sizeof(tGameEntity)); gFirstEntity->next=gFirstEntity; gFirstEntity->prev=gFirstEntity; //process map info describtion ProcessMapInfo(); //initialize car entities InitCars(); //initialize camera gCameraEntity=EntityNew(gFirstEntity); //initialize ghost if(gGameInfo->numLaps==-1) { gGhostEntity=EntityNew(gFirstEntity); gGhostEntity->physics=MemoryAllocateZeroedBlock(sizeof(tCarPhysics)); MemoryMove(gGhostEntity->physics,gCarEntities[0]->physics,sizeof(tCarPhysics)); gGhostEntity->pos=Vector(10000,10000,10000); gGhostEntity->physicsType=kPhysicsTypeGhost; gGhostEntity->renderType=kRenderTypeGhost; gGhostEntity->controlType=kControlTypeNone; gGhostEntity->physicsData=gGameInfo->playerCars[0]; gGhostEntity->renderData=gCarEntities[0]->renderData; } } void InitInfoDisplay(); //initialize a new game int InitGame() { if(gFileTampered) Exit(); //get map info data gMapInfo=(tMapInfo*)FileGetParsedDataPtr(gGameInfo->map,kParserTypeMapInfoDesc,sizeof(tMapInfo)); //load enivronment describtion LoadEnvironment(gGameInfo->environment); //initialize fog GLfloat fogColor[4]; *(tVector3*)fogColor=gEnvironment->fogColor; fogColor[3]=1; glFogfv(GL_FOG_COLOR,fogColor); glFogf(GL_FOG_START,600); glFogf(GL_FOG_END,800); InitGameEntities(); //initialize game end flags gInterfaceType=false; gGameEnd=false; gPaused=false; gRaceFinished=false; gDisqualified=false; gLightning=false; gInputEscMode=false; gReplayViewedEntityID=gGameInfo->playerID; gCameraMode=gConfig->cameraMode; gCameraReverse=0; gOutboxPos=0; gGameChatMessage[0]='\0'; gGameChatMessageSize=0; gNetPauseTime=0; SoundSilence(); //reset replay log LogReset(); GhostLogReset(); TracksClear(); ParticlesClear(); InitInfoDisplay(); //call once to reset stencil buffer RenderStencilLayer(true,gConfig->stencil); //initialze lighting SetupLighting(); //render a frame to get graphics loaded CalcCamera(); gClipEnable=false; float time=TimeGetSeconds(); gNumGameChatMessages=0; gEnableTextureLoad=false; gNumTexturesRequested=0; RenderFrame(false); gNumTexturesLoaded=0; gEnableTextureLoad=true; gDisabledRestart=0; for(int i=0;i0) InterfaceDrawStatusBar("Loading Textures...","Please Wait",gNumTexturesLoaded/(float)gNumTexturesRequested); gTexturesQualityModifier=gFileTable[i].tagged+1; TexturesSelectTex(i); SystemPoll(true); } } gTexturesQualityModifier=0; // PrintConsoleString("loading took: %f seconds.",TimeGetSeconds()-time); gClipEnable=true; //synchronize players on network if(gGameInfo->network) { InterfaceDrawStrings("Waiting for other Players...","",kFileErr); if(!NetworkSynch(gGameInfo->numNetPlayers)) return false; } //start clock gTimeStretch=1.0; gBestLapTime=0; StartFrameCount(); gPaused=false; return true; } void DisposeEntities() { if(gFirstEntity) { tGameEntity *entity=(tGameEntity*)gFirstEntity->next; while(entity!=gFirstEntity) { tGameEntity *next=(tGameEntity*)entity->next; if(entity->physics) MemoryFreeBlock(entity->physics); SoundFreeEntitySources(entity); //FREE CAR PHYSICS! MemoryFreeBlock(entity); entity=next; } MemoryFreeBlock(gFirstEntity); gFirstEntity=NULL; gViewedEntity=NULL; gCameraEntity=NULL; } } void StartReplay() { SoundSilence(); tCarPhysics physStore[kMaxPlayers]; // for(int i=0;inumPlayers;i++) // physStore[i]=*(tCarPhysics*)gCarEntities[i]->physics; DisposeEntities(); InitGameEntities(); /* for(int i=0;inumPlayers;i++) { *(tCarPhysics*)gCarEntities[i]->physics=physStore[i]; tCarPhysics *phys=(tCarPhysics*)gCarEntities[i]->physics; phys->dirt=0; for(int j=0;jwheels[j].lastTrack=0; }*/ // for(int i=0;ipos=Vector(10000,10000,10000); if(gCameraMode==kCameraFree) gCameraMode=kCameraTripod; if(gGameInfo->numLaps==-1) gGhostEntity->pos=Vector(10000,10000,10000); gFrameCount=gGameInfo->numLaps==-1?(gBestLapTime!=0?gBestLapStart+5:gCurrentLapStart+5):0; gGraphFrameCount=gFrameCount; gStartTime=TimeGetSeconds()-gFrameCount*kFrameTime; gReplayIndex=0; gReplayNextCam=gFrameCount+RandomFl(4,12)*kFPS; TracksClear(); } extern int gIndexPos; extern int gGhostIndexPos; void ReplayProcessNetwork(int *end) { if(gGameInfo->network) { tNetworkPacket message; while(NetworkReceivePacket(&message)) switch(message.what) { case kMessageTypeEndReplay: *end=true; gGameEnd=kEndGameNoLeave; break; case kMessageTypeGameTerminated: *end=true; return; case kMessageTypeChat: InsertGameChatMessage(((tChatMessage*)message.data)->str); ChatBufferInsert(((tChatMessage*)message.data),gChatBuffer); PlayInterfaceSound(FileGetReference("chat.wav")); break; case kMessageTypeBye: { if(message.from==0) sprintf(gDisconnectString,"%s quit and stopped hosting.",gGameInfo->playerNames[0]); int netID=message.from; int id=-1; //find the players id for(int i=0;inumNetPlayers;i++) if(gGameInfo->netID[i]==netID) id=i; if(id!=-1) { tChatMessage m; m.flags=kChatFlagSystem; sprintf(m.str,"### %s is quitting.",gGameInfo->playerNames[id]); SoundReInit(); PlayInterfaceSound(FileGetReference("chat.wav")); InsertGameChatMessage(m.str); ChatBufferInsert(&m,gChatBuffer); } } break; case kMessageTypePlayerLeft: { int netID=message.from; int id=-1; //find the players id for(int i=0;inumPlayers;i++) if(gGameInfo->netID[i]==netID) id=i; if(id!=-1) { char leftMessage[256]; //PrintConsoleString("### Player %d left the game. netID: %d",id,netID); sprintf(leftMessage,"### %s left the game.",gGameInfo->playerNames[id]); InsertGameChatMessage(leftMessage); //KillPlayer(id); gGameInfo->netID[id]=-1; } } break; } } } int ReplayFrame() { int end=false; static int save=false; if(GetInterfaceKey(kInterfaceKeyEsc)&&!gGameInfo->network) end=true; if(GetInterfaceKey(kInterfaceKeyCmd)&&GetInterfaceKey(kInterfaceKeyOpt)&&GetInterfaceKey(kInterfaceKeyS)&&!gBackgroundReplay) { if(!save) { LogSaveToDisk(); save=true; } } else save=false; if(gGameEnd) end=true; ReplayProcessNetwork(&end); if(gFrameCount>=gReplayOldFrameCount||gReplayIndex>=(gGameInfo->numLaps==-1?gGhostIndexPos:gIndexPos)) { if(gMapInfo->reverse) gGameInfo->reverse=!gGameInfo->reverse; StartReplay(); } if(gFrameCount>=gReplayNextCam&&gReplayAutoCam) { ParticlesClearScreen(); gCameraReverse=RandomProb(0.4); gCameraMode=RandomProb(0.3)?kCameraTripod:RandomInt(kCameraChase,kCameraTop+1); int nextViewID; do{ nextViewID=RandomInt(0,gGameInfo->numPlayers); }while(gGameInfo->netID[nextViewID]==-1); tGameEntity *nextView=gCarEntities[nextViewID]; if(sqr(nextView->velo)>=1.0) { gViewedEntity=nextView; gReplayViewedEntityID=nextViewID; } float cameraDuration; switch(gCameraMode) { case kCameraChase: case kCameraChaseClose: cameraDuration=RandomFl(3,10);break; case kCameraLeftSide: case kCameraLeftWheel: cameraDuration=RandomFl(2,5);break; case kCameraTop: cameraDuration=RandomFl(3,6);break; case kCameraTripod: cameraDuration=RandomFl(8,18);break; case kCameraCockpit: case kCameraCockpitCarHidden: cameraDuration=RandomFl(2,5); gCameraReverse=false; break; } gReplayNextCam=gReplayNextCam+cameraDuration*kFPS; } while(!GameReplayFrame()&&gBackgroundReplay); return end; } void RunReplay() { TextClearBufferFading(); //LogLoad(FileGetReference("test.log"),gGameInfo); gReplay=true; if(gGameInfo->numLaps==-1) { tCarPhysics *phys=(tCarPhysics*)gCarEntities[0]->physics; if(phys->lapCount<=1) LogToGhostLog(); } gReplayOldFrameCount=(gGameInfo->numLaps==-1&&gBestLapTime!=0)?gBestLapTime+gBestLapStart:gFrameCount; if(gReplayOldFrameCount<10)return; LogSort(); //LogSaveToDisk(); gReplayAutoCam=true; StartReplay(); while(!ReplayFrame()); if(gGameInfo->network&&gGameInfo->playerID==0) { NetworkSendPacket(kMessageTypeEndReplay,NULL,0,kMessagePriorityHigh,kMessageSendToAllButSelf); } // gReplay=false; } void ExitGame() { /* #ifndef __APPLE_CC__ #if __option(profile) ProfilerDump("\pProfiler Dump"); #endif #endif */ FFBStop(); UnPauseGame(); if(gGameInfo->network) { if(gGameInfo->playerID==0) NetworkSendPacket(kMessageTypeEndGame,NULL,0,kMessagePriorityHigh,kMessageSendToAllButSelf); else if(gGameEnd!=kEndGameNoLeave) { NetworkSendPacket(kMessageTypeBye,NULL,0,kMessagePriorityHigh,kMessageSendToAllButSelf); NetworkSendPacket(kMessageTypeGameTerminated,NULL,0,kMessagePriorityHigh,gGameInfo->netID[gGameInfo->playerID]); } } if((gGameEnd==kEndGameNoLeave||(gGameEnd==kEndGame&&!(gGameInfo->network&&gGameInfo->playerID!=0)))&&!gGameInfo->demolition) { gGameEnd=false; while((GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)||GetInterfaceKey(kInterfaceKeyEsc))); RunReplay(); if(gGameInfo->network) { if(gGameInfo->playerID==0) NetworkSendPacket(kMessageTypeEndGame,NULL,0,kMessagePriorityHigh,kMessageSendToAllButSelf); else if(gGameEnd!=kEndGameNoLeave) { NetworkSendPacket(kMessageTypeBye,NULL,0,kMessagePriorityHigh,kMessageSendToAllButSelf); NetworkSendPacket(kMessageTypeGameTerminated,NULL,0,kMessagePriorityHigh,gGameInfo->netID[gGameInfo->playerID]); } } } /* if(gGameEnd!=kEndGameRestart) { float startTime=TimeGetSeconds(); float t; do{ t=TimeGetSeconds()-startTime; RenderFrame(false); InterfaceDrawBackgroundFade(t/0.3,true); ScreenBlit(); }while(t<0.3); }*/ DisposeEntities(); gInputChatMode=false; gFrameCount=0x7fffffff; TextClearBuffer(); TracksClear(); SoundSilence(); ParticlesClear(); glClear(GL_COLOR_BUFFER_BIT); gMapInfo=NULL; gGameInfo=NULL; gMapEnv=NULL; TrackerLapTimeRegistryClose(); LoadEnvironment(FileGetReference("showroom.senv")); FlushKeys(); } int GetPlayerRanking() { tCarPhysics *phys=(tCarPhysics*)gCarEntities[gGameInfo->playerID]->physics; if(phys->lapCount>gGameInfo->numLaps&&!gDisqualified) { int place=1; for(int i=0;inumPlayers;i++) { tCarPhysics *phys2=(tCarPhysics*)gCarEntities[i]->physics; if(phys2->lapCount>gGameInfo->numLaps) if(phys2->lapTimes[gGameInfo->numLaps]lapTimes[gGameInfo->numLaps]) place++; } if(gGameInfo->maxTime) return phys->lapTimes[gGameInfo->numLaps]; if(gGameInfo->numLaps==-1) return gBestLapTime; return place; } else return -1; } int RunGame(tGameInfo *gInfo) { gReplay=false; int place; int reverse=gInfo->reverse; do{ gGameInfo=gInfo; if(InitGame()) while(!gGameEnd) GameFrame(); place=GetPlayerRanking(); gInfo->reverse=reverse; ExitGame(); gInfo->reverse=reverse; }while(gGameEnd==kEndGameRestart); gInterfaceGInfo=*gInfo; StartBackgroundReplay(); return place; }