#include #include #include #include "entities.h" #include "gameframe.h" #include "carphysics.h" #include "controls.h" #include "config.h" #include "renderframe.h" #include "gameinitexit.h" #include "particles.h" #include "gametime.h" #include "network.h" #include "random.h" #include "initexit.h" #include "text.h" #define kThrottleTime 0.3 #define kThrottleReleaseTime 0.2 #define kThrottleTCRReleaseTime 0.7 #define kThrottleTimeSpinning 0.6 #define kBrakeTime 0.4 #define kBrakeReleaseTime 0.2 #define kSteerReleaseTime 0.6 #define kVeloSteerReleaseTime 0 //#define kSteerTime 1.2 #define kSteerTime 0.6 #define kVeloSteerTime 0.05 #define kHandbrakeTime 0.2 #define kHandbrakeReleaseTime 0.01 #define sign(x) ((x)<0?-1:1) #define kMaxThottleSlip 0.033 #define kMinSpinAngularVelo (4*PI) #define kMaxBrakeSlip 0.05 int gGearUpPress=false; int gGearDownPress=false; int gLightPress=false; int gCameraPress=false; int gReplayCameraPress=false; int gTauntPress=false; int gArrowPress=false; int gEscPress=false; int gPausePress=false; float gSteerAxis=0; float gThrottleAxis=0; int gAxisSteering=false; int gAxisThrottleBrake=false; int gInputChatMode=false; int gInputEscMode=kInputEscModeNone; int gInputEscSelection; int gGameChatMessageSize=0; #define kMaxGameChatMessageSize 128 char gGameChatMessage[kMaxGameChatMessageSize]=""; void ButtonThrottle(tCarDefinition *car,tCarPhysics *phys,float driveSlip,float angularVelo,float velo,float throttleInput,int tcr) { float maxSlip=velo<20?0.2-velo/20*(0.2-kMaxThottleSlip):kMaxThottleSlip; if(throttleInput<0) throttleInput=0; if(throttleInput>phys->throttle){ if(driveSlip*sign(phys->gear)clutch<1&&phys->rpm>car->clutchRPM)) { phys->throttle+=kFrameTime*(1/kThrottleTime); if(throttleInput>phys->throttle) throttleInput=phys->throttle; } else { phys->throttle-=kFrameTime*(1/kThrottleTCRReleaseTime); if(throttleInputthrottle) throttleInput=phys->throttle; } } else { phys->throttle-=kFrameTime*(1/kThrottleReleaseTime); if(throttleInputthrottle) throttleInput=phys->throttle; } if(phys->throttle>1) phys->throttle=1; else if(phys->throttleidleThrottle&&phys->rpm<=car->idleRPM) phys->throttle=phys->idleThrottle; phys->clutch=1; } void ButtonBrake(tCarPhysics *phys,float slip,float angularVelo,float brakeInput,int als) { if(brakeInput>1) brakeInput=1; else if(brakeInput<0) brakeInput=0; if(brakeInput<0) brakeInput=0; if(brakeInput>phys->brake) { if((-slip*sign(angularVelo)brake<0.1)||!als) phys->brake+=kFrameTime*(1/kBrakeTime); else phys->brake-=kFrameTime*(1/kBrakeTime); phys->arcadeBrake+=kFrameTime*(1/kBrakeTime); if(brakeInputbrake) phys->brake=brakeInput; if(brakeInputarcadeBrake) phys->arcadeBrake=brakeInput; } else { phys->brake-=kFrameTime*(1/kBrakeReleaseTime); phys->arcadeBrake-=kFrameTime*(1/kBrakeReleaseTime); if(brakeInput>phys->brake) phys->brake=brakeInput; if(brakeInput>phys->arcadeBrake) phys->arcadeBrake=brakeInput; } } void CalcThrottleBrake(tCarDefinition *car,tCarPhysics *phys,float driveSlip,float angularVelo,float velo,float slip) { if(car->clutchRPM==0) car->clutchRPM=3000; int raceOver=(phys->lapCount>gGameInfo->numLaps&&gGameInfo->numLaps!=-1); if(!raceOver) { float gas,brake,gasbrake; if(gConfig->seperateGasBrake) { if(gConfig->reverseGas) { gas=GetAxisInput(kInputThrottleAxis); brake=GetAxisInput(kInputBrakeAxis); } else { gas=1-GetAxisInput(kInputThrottleAxis); brake=1-GetAxisInput(kInputBrakeAxis); } gasbrake=gas-brake; } else { gasbrake=GetAxisInput(kInputThrottleBrakeAxis); if(gConfig->reverseGas) gasbrake=-gasbrake; gas=gasbrake; brake=-gasbrake; } if(gAxisThrottleBrake) { if(gConfig->automatic&&phys->gear==-1) { ButtonBrake(phys,slip,angularVelo,gas,true); ButtonThrottle(car,phys,driveSlip,angularVelo,velo,brake,(brake<0.95)&&!gConfig->disableAnalogueTCS); } else { ButtonBrake(phys,slip,angularVelo,brake,true); ButtonThrottle(car,phys,driveSlip,angularVelo,velo,gas,(gas<0.95)&&!gConfig->disableAnalogueTCS); } if(GetButtonInput(kInputKickdownButton)||GetButtonInput(kInputBrakeButton)||GetButtonInput(kInputGasButton)) gAxisThrottleBrake=false; } else { int brake=GetButtonInput(kInputBrakeButton); int gas=GetButtonInput(kInputGasButton); int kickdown=GetButtonInput(kInputKickdownButton); int gasInput=(gConfig->automatic?(phys->gear>=0?gas||kickdown:brake):(gas||kickdown))?1:0; ButtonThrottle(car,phys,driveSlip,angularVelo,velo,gasInput,!kickdown); int brakeInput=(gConfig->automatic?(phys->gear>=0?brake:gas||kickdown):brake)?1:0; ButtonBrake(phys,slip,angularVelo,brakeInput,true); if(gThrottleAxis!=gasbrake) gAxisThrottleBrake=true; } gThrottleAxis=gasbrake; } else { ButtonBrake(phys,slip,angularVelo,1,true); ButtonThrottle(car,phys,driveSlip,angularVelo,velo,0,true); } } void ButtonSteering(tGameEntity *entity,tCarDefinition *car,tCarPhysics *phys,float velo,float input) { if(input>1) input=1; else if(input<-1) input=-1; tVector3 carDir=!Vector(MatrixGetZVector(entity->dir)->x,0,MatrixGetZVector(entity->dir)->z); tVector3 veloDir=!Vector(entity->velo.x,0,entity->velo.z); float angleSin=(veloDir%carDir).y; if(fabs(angleSin)>1.0) angleSin=sign(angleSin); float angle=-asin(angleSin); float optimalSteering=angle/car->wheels[0].maxAngle; if(velo<1) optimalSteering=0; if(input>phys->steering) { float steerSpeed=(phys->steering<0)?(1/(kSteerReleaseTime+kVeloSteerReleaseTime*velo)) :(1/(kSteerTime+kVeloSteerTime*velo)); if(phys->steeringsteering)*4; if(gGameInfo->arcade==kGameModeTurbo) steerSpeed*=2; phys->steering+=kFrameTime*steerSpeed; if(inputsteering) phys->steering=input; } else if(inputsteering) { float steerSpeed=(phys->steering>0)?(1/(kSteerReleaseTime+kVeloSteerReleaseTime*velo)) :(1/(kSteerTime+kVeloSteerTime*velo)); if(phys->steering>optimalSteering) steerSpeed*=1+(phys->steering-optimalSteering)*4; if(gGameInfo->arcade==kGameModeTurbo) steerSpeed*=2; phys->steering-=kFrameTime*steerSpeed; if(input>phys->steering) phys->steering=input; } } void CalcSteering(tGameEntity *entity,tCarDefinition *car,tCarPhysics *phys,float velo) { if(gAxisSteering) { gSteerAxis=GetAxisInput(kInputSteerAxis); float ax3=gSteerAxis*gSteerAxis*gSteerAxis; float ax=0.3*gSteerAxis+0.7*ax3; ButtonSteering(entity,car,phys,velo,ax); if(GetButtonInput(kInputSteerLeftButton)||GetButtonInput(kInputSteerRightButton)) gAxisSteering=false; } else { float input=0; int l=GetButtonInput(kInputSteerLeftButton); int r=GetButtonInput(kInputSteerRightButton); if(l&&r) input=phys->steering; else if(l) input=1; else if(r) input=-1; ButtonSteering(entity,car,phys,velo,input); if(gSteerAxis!=GetAxisInput(kInputSteerAxis)) gAxisSteering=true; } } typedef struct{ char *name; int numCopies; }tRegData; void ControlEntityUserInput(tGameEntity *entity) { if(entity->physicsType!=kPhysicsTypeCar) return; tCarPhysics *phys=(tCarPhysics*)entity->physics; tCarDefinition *car=&(phys->car); float velo=~entity->velo; float driveSlip=0,slip=0,angularVelo=0; int wheelsOnGround=0; for(int i=0;inumWheels;i++) { if(phys->wheels[i].onGround) { driveSlip+=phys->wheels[i].slip*car->wheels[i].powered; slip+=phys->wheels[i].slip; wheelsOnGround++; } angularVelo+=phys->wheels[i].angularVelo*car->wheels[i].powered; } if(wheelsOnGround) slip/=wheelsOnGround; else slip=0; CalcThrottleBrake(car,phys,driveSlip,angularVelo,velo,slip); CalcSteering(entity,car,phys,velo); if(GetButtonInput(kInputHandbrakeButton)) phys->handbrake+=kFrameTime*(1/kHandbrakeTime); else phys->handbrake-=kFrameTime*(1/kHandbrakeReleaseTime); if(phys->handbrake>1) phys->handbrake=1; else if(phys->handbrake<0) phys->handbrake=0; if(gFrameCount*kFrameTime>=kStartGameDelaySeconds) { if(gConfig->automatic) { if((gFrameCount-1)*kFrameTime>phys->lastGearSwitch+car->gearSwitchTime) { if(phys->gear>=1) { int shiftUp=false; if(car->shiftUpRPMFix) shiftUp=phys->rpm>car->shiftUpRPMFix; else shiftUp=phys->rpm>car->maxRPM; if(shiftUp&&phys->gearnumGears-2) { if(!GetButtonInput(kInputKickdownButton)&&phys->gear>0&&gFrameCount*kFrameTime>=kStartGameDelaySeconds+1) { phys->lastGear=phys->gear; phys->gear++; phys->lastGearSwitch=gFrameCount*kFrameTime; if(gGameInfo->arcade==kGameModeTurbo) phys->lastGearSwitch-=car->gearSwitchTime*0.5; } } else if(phys->rpmshiftDownRPM&&phys->gear>1) { phys->lastGear=phys->gear; phys->gear--; phys->lastGearSwitch=gFrameCount*kFrameTime; if(gGameInfo->arcade==kGameModeTurbo) phys->lastGearSwitch-=car->gearSwitchTime*0.5; } } if(phys->gear==0||velo<1) { if(phys->gear<1&&((GetButtonInput(kInputKickdownButton)||GetButtonInput(kInputGasButton)))||(gAxisThrottleBrake&&gThrottleAxis>0)) { phys->lastGear=phys->gear; phys->gear=1; phys->lastGearSwitch=gFrameCount*kFrameTime; } else if(phys->gear>=0&&GetButtonInput(kInputBrakeButton)||(gAxisThrottleBrake&&gThrottleAxis<0)) { phys->lastGear=phys->gear; phys->gear=-1; phys->lastGearSwitch=gFrameCount*kFrameTime; } } } } else { if(GetButtonInput(kInputGearUp)){ if(phys->gearnumGears-2&&!gGearUpPress){ phys->lastGear=phys->gear; phys->gear++; gGearUpPress=true; phys->lastGearSwitch=gFrameCount*kFrameTime; if(gGameInfo->arcade==kGameModeTurbo) phys->lastGearSwitch-=car->gearSwitchTime*0.5; } } else gGearUpPress=false; if(GetButtonInput(kInputGearDown)){ if(phys->gear>-1&&!gGearDownPress){ phys->lastGear=phys->gear; phys->gear--; gGearDownPress=true; phys->lastGearSwitch=gFrameCount*kFrameTime; if(gGameInfo->arcade==kGameModeTurbo) phys->lastGearSwitch-=car->gearSwitchTime*0.5; } } else gGearDownPress=false; } float gearSwitchTime=phys->gear<=1?0.3:car->gearSwitchTime; if(gFrameCount*kFrameTimelastGearSwitch+gearSwitchTime) { float switchTime=(gFrameCount*kFrameTime-phys->lastGearSwitch)/gearSwitchTime; phys->clutch=switchTime; if(phys->rpmclutchRPM) phys->clutch=(phys->rpm-car->idleRPM*1.5)/(car->clutchRPM-car->idleRPM*1.5); if(switchTime<0.5&&phys->gear>1) if(phys->lastGear>phys->gear) phys->throttle=0.7; else phys->throttle=phys->idleThrottle; } else if(phys->rpmclutchRPM) phys->clutch=(phys->rpm-car->idleRPM*1.5)/(car->clutchRPM-car->idleRPM*1.5); else phys->clutch=1; if(phys->clutch<0) phys->clutch=0; } if(GetButtonInput(kInputHorn)) phys->lightFlags|=kLightFlagHorn; else phys->lightFlags&=~kLightFlagHorn; if(GetButtonInput(kInputLeftIndicator)) phys->lightFlags|=kLightFlagLIndLight; else if(GetButtonInput(kInputRightIndicator)) phys->lightFlags|=kLightFlagRIndLight; else phys->lightFlags&=~(kLightFlagLIndLight+kLightFlagRIndLight); if(GetButtonInput(kInputLightButton)){ if(!gLightPress) { gLightPress=true; phys->lightFlags^=kLightFlagDriveLight; } }else gLightPress=false; } void ControlEntityAIInput(tGameEntity *entity); extern float gEscDisplay; void HandleEscModeInput() { if(GetInterfaceKey(kInterfaceKeyEsc)||GetInterfaceKey(kInterfaceKeyDelete)) { if(!gEscPress) { gInputEscMode=kInputEscModeNone; gEscPress=true; if(!gGameInfo->network) UnPauseGame(); } } else gEscPress=false; if(GetInterfaceKey(kInterfaceKeyDown)) { if(!gArrowPress) { gInputEscSelection--; if(gInputEscSelection<0) gInputEscSelection=(gGameInfo->network?1:2); gArrowPress=true; } } else if(GetInterfaceKey(kInterfaceKeyUp)) { if(!gArrowPress) { gInputEscSelection=(gInputEscSelection+1)%(gGameInfo->network?2:3); gArrowPress=true; } } else gArrowPress=false; if(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)) { if(gInputEscSelection==1) if(gInputEscMode==kInputEscModeQuit) Exit(); else gGameEnd=kEndGame; if(gInputEscSelection==2) gGameEnd=kEndGameRestart; if(gInputEscMode==kInputEscModeQuit) gEscDisplay=0; gInputEscMode=kInputEscModeNone; if(!gGameInfo->network) UnPauseGame(); } } void HandleChatModeInput() { while(char ch=GetKeyInput(NULL)) { if(ch=='\r') { if(ch=='\r'&&strlen(gGameChatMessage)>0) { tChatMessage msg; memset((void*)&msg,0,sizeof(tChatMessage)); sprintf(msg.str,"%s: \255#a\255%s",gConfig->playerName,gGameChatMessage); msg.flags=0; NetworkSendPacket(kMessageTypeChat,&msg,sizeof(tChatMessage),kMessagePriorityHigh,kMessageSendToAll); } gGameChatMessage[0]='\0'; gGameChatMessageSize=0; gInputChatMode=false; } if((ch==0x7f||ch==0x08)&&gGameChatMessageSize>0) gGameChatMessage[--gGameChatMessageSize]='\0'; if(ch>=' '&&ch<='z'&&gGameChatMessageSizetaunts[i-kInputTaunt1]) { tChatMessage msg; memset((void*)&msg,0,sizeof(tChatMessage)); snprintf(msg.str,256,"%s: \255#a\255%s",gConfig->playerName,gConfig->taunts[i-kInputTaunt1]); msg.flags=0; NetworkSendPacket(kMessageTypeChat,&msg,sizeof(tChatMessage),kMessagePriorityHigh,kMessageSendToAll); } } gTauntPress=tauntPress; if(gInputChatMode) HandleChatModeInput(); } void HandleGameInput() { tCarPhysics *phys=(tCarPhysics*)gCarEntities[gGameInfo->playerID]->physics; if(GetButtonInput(kInputCamera)) { if(!gCameraPress) { ParticlesClearScreen(); gCameraMode=(++gCameraMode)%(gConfig->allCams||gReplay||phys->lapCount>gGameInfo->numLaps&&gGameInfo->numLaps!=-1?kCameraNumModes:kCameraLeftWheel); gReplayAutoCam=false; } gCameraPress++; if(gCameraPress>=kFPS&&gCameraMode!=kCameraFree) { gCameraMode=kCameraFree; TextPrintfToBufferFormatedFading(Vector(0,1),0.03,kTextAlignMiddle,1,2,"freecam mode."); } } else gCameraPress=0; if(GetButtonInput(kInputCameraChangeCar)){ if(!gReplayCameraPress) { if(gReplay||phys->lapCount>gGameInfo->numLaps) { do{ gReplayViewedEntityID=(gReplayViewedEntityID+1)%gGameInfo->numPlayers; }while(gGameInfo->netID[gReplayViewedEntityID]==-1&&gGameInfo->network); if(gReplay) gReplayAutoCam=false; gReplayCameraPress=true; } } }else gReplayCameraPress=false; if(gReplay&&!gGameInfo->network) { float oldStretch=gTimeStretch; if(GetButtonInput(kInputChat)) gTimeStretch=0.25; else gTimeStretch=1.0; if(gTimeStretch!=oldStretch) { float curTime=gStartTime+(gFrameCount*kFrameTime)/oldStretch; gStartTime=curTime-(gFrameCount*kFrameTime)/gTimeStretch; } } gCameraReverse=GetButtonInput(kInputCameraReverse); if(GetButtonInput(kInputPause)&&!gReplay&&!gPaused&&!gPausePress) { if(!gGameInfo->network) PauseGame(); else { int pauseFrameCount=gFrameCount+kFPS*0.5; S32Swap(pauseFrameCount); NetworkSendPacket(kMessageTypePause,&pauseFrameCount,sizeof(int),kMessagePriorityHigh,kMessageSendToAll); } gPausePress=true; } if(((GetButtonInput(kInputPause)&&!gPausePress))&&gPaused&&!gInputChatMode) { if(!gGameInfo->network) UnPauseGame(); else NetworkSendPacket(kMessageTypeResume,NULL,0,kMessagePriorityHigh,kMessageSendToAll); gPausePress=true; } if(!GetButtonInput(kInputPause)) gPausePress=false; if(gGameInfo->network) HandleNetworkInput(); /* if(GetInterfaceKey(kInterfaceKeyCmd)&&GetInterfaceKey(kInterfaceKeyQ)) { gInputEscMode=kInputEscModeQuit; gInputEscSelection=1; if(!gGameInfo->network) PauseGame(); }*/ if(GetInterfaceKey(kInterfaceKeyEsc))//||(GetInterfaceKey(kInterfaceKeyDelete)&&!gInputChatMode)) { if(gInputChatMode) { gGameChatMessage[0]='\0'; gGameChatMessageSize=0; gInputChatMode=false; gEscPress=true; } else if(!gEscPress) // if(!gGameInfo->network&&((phys->lapCount>gGameInfo->numLaps&&gGameInfo->numLaps!=-1)||(gFrameCount*kFrameTime-kStartGameDelaySeconds>gGameInfo->maxTime&&gGameInfo->maxTime>0))) if((gReplay||((phys->lapCount>gGameInfo->numLaps&&gGameInfo->numLaps!=-1)))&&(!gGameInfo->network||gGameInfo->playerID==0))//||(gFrameCount*kFrameTime-kStartGameDelaySeconds>gGameInfo->maxTime&&gGameInfo->maxTime>0))) gGameEnd=kEndGame; else { gEscPress=true; gInputEscMode=kInputEscModeNormal; gInputEscSelection=1; if(!gGameInfo->network) PauseGame(); } } else gEscPress=false; } void ControlFrame() { if(!gPaused&&!gReplay) { tGameEntity *entity=(tGameEntity*)gFirstEntity->next; while(entity!=gFirstEntity) { if(entity->physicsMachine==kPhysicsLocal) { switch(entity->controlType) { case kControlTypeUserInput: ControlEntityUserInput(entity); break; case kControlTypeAIInput: ControlEntityAIInput(entity); break; } } entity=(tGameEntity*)entity->next; } } if(!gInputEscMode) HandleGameInput(); else HandleEscModeInput(); }