#include #include #include #include #include #include #include #include #include #include #include #include #include "parameters.h" #include "colors.h" #include "include/camera.h" #include "include/segment.h" #include "include/circuit.h" #include "include/drawstuff.h" #include "include/clouds.h" #include "include/cars.h" #include "include/menus.h" #include "include/saves.h" #include #include #include #define DEBUGXXX 0 #define OVERCLCK_ACTIVABLE 1 char version[5] = {'V','1','.','0','8'}; extern bopti_image_t player, smoke1, smoke2, smoke3; extern font_t speedfont, startseq, plate, autofont; extern bopti_image_t speedhud; extern bopti_image_t flag, bigflag; int CurrentCircuitBiome = PLAINS; std::vector circuit; std::vector nuages; std::vector traffic; std::vector jalons; int MAX_SEGMENT=0; camera *cam; char texttosend[1024]; int32_t start_time = 100000000; uint32_t elapsed_time = 0; uint32_t score=0; uint8_t stage=0, mode=0; int8_t selectedCircuit=0, secondvalidation=0; uint32_t time_update=0, time_create=0, time_project=0, time_render=0; uint8_t DiffLevel = 1; uint8_t CarsNumb = 1; char PlayerName[3] = { 'S', 'L', 'Y' }; Parameters PlayerPara[1]; struct DataPerf { uint8_t update=0; uint8_t project=0; uint8_t render=0; }; extern bool saveexist; BestRanking HallOfFame[10][5]; // Table of score : 10 levels * 5 best scores uint32_t FinalTime=0; bool skipranking=false; int ranking = -1; // ranking is -1 if not ranked and between 1 and 5 if ranked #define MAXDATA 120 DataPerf GraphPerf[ MAXDATA ]; unsigned int DataIndex=0; uint16_t NB_CARS_TRAFFIC=200; bool stop = false; bool exitToOS = false; bool record = false; bool screenshot = false; bool ShowDebug1 = false; bool ShowDebug2 = false; bool ShowDebug3 = false; bool BDrawDeco = true; bool BDrawClds = true; bool BDrawCars = true; bool BDrawBack = true; bool BDrawFPS = false; bool isOCPossible = false; bool isOCActivated = false; bool OptionMode = false; bool PauseMode = false; bool SkipTime = false; ///HUD options bool visualspeedindicator = false; bool visualnextpoint = true; // for multilap bool multilap = false; uint8_t numlap = 1; uint8_t currentLap = 1; int currentpoint = 0; uint16_t currentcurve=0; uint8_t shiftcolor=0; float speed = 0.0; float maxspeedforward = 5.0; float maxspeedbackward = 2.0; int direction = 1; bool speedcontrol = false; uint8_t minYRoad = 224; // We will track the upper Y (in fact the minimum Y during the RoadDrawing to optimize the rendering of the Sky int8_t viewside = 0; int deltaFarbackground = 0; int deltaNearbackground = 0; int lastindex=0; int CC=0; // current curve int CS=0; int EntryLevel; void initEverything( void ) { CurrentCircuitBiome = PLAINS; circuit.clear(); nuages.clear(); traffic.clear(); MAX_SEGMENT=0; DataIndex=0; stop = false; record = false; screenshot = false; ShowDebug1 = false; ShowDebug2 = false; ShowDebug3 = false; BDrawDeco = true; BDrawClds = true; BDrawCars = true; BDrawFPS = false; currentcurve=0; shiftcolor=0; speed = 0.0; maxspeedforward = 5.0; maxspeedbackward = 2.0; direction = 1; speedcontrol = false; minYRoad = 224; // We will track the upper Y (in fact the minimum Y during the RoadDrawing to optimize the rendering of the Sky viewside = 0; deltaFarbackground = 0; deltaNearbackground = 0; lastindex=0; CC=0; // current curve CS=0; multilap = false; numlap = 1; currentLap = 1; } float timepressed = 0.0f; int directionPressed = 0; bool CarIsSliding = false; uint16_t framesmoke = 0; static void get_inputs( float dt, int index ) { CC = circuit[index]->Curve; CS = circuit[index]->Slope; maxspeedforward = 5.0 - (((float) CS)/100.0f) + (((float) CC)*f2float(cam->cX)/ROAD_WIDTH/20.0f); key_event_t ev; while((ev = pollevent()).type != KEYEV_NONE) { } speedcontrol = false; viewside=0; if (CC<0) { viewside=-1; if (CurrentCircuitBiome==FINLAND) cam->decX( CC*dt*speed/50); // 50 ); // very hard to turn in Finland with snow else if (CurrentCircuitBiome==AFRICA) cam->decX( CC*dt*speed/70); //75 ); // hard in Africa with dirt else cam->decX( CC*dt*speed/85); // 100 ); // more easy on normal roads } else if (CC>0) { viewside=+1; if (CurrentCircuitBiome==FINLAND) cam->decX( CC*dt*speed/50); // 50 ); // very hard to turn in Finland with snow else if (CurrentCircuitBiome==AFRICA) cam->decX( CC*dt*speed/70); //75 ); // hard in Africa with dirt else cam->decX( CC*dt*speed/85); // 100 ); // more easy on normal roads } if(keydown(KEY_LEFT) || keydown(KEY_F5)) { cam->decX(5.0*speed*direction); /// This is to implement sliding and speed loss if (directionPressed!=-1) directionPressed=-1, timepressed = 0.0f; else if (directionPressed==-1 && CC<0) timepressed += dt; viewside=-1; if (CC<0) viewside=-2; // We are in a curve and turning if (CC>0) viewside=0; } else if(keydown(KEY_RIGHT) || keydown(KEY_F6)) { cam->incX(5.0*speed*direction); /// This is to implement sliding and speed loss if (directionPressed!=1) directionPressed=1, timepressed = 0.0f; else if (directionPressed==1 && CC>0) timepressed += dt; viewside=1; if (CC>0) viewside=+2; if (CC<0) viewside=0; } else if (!keydown(KEY_RIGHT) && !keydown(KEY_F6) && !keydown(KEY_LEFT) && !keydown(KEY_F5)) { directionPressed=0, timepressed = 0.0f; } if(keydown(KEY_SHIFT) || keydown(KEY_XOT) || keydown(KEY_F1)) // Accelerates { if (direction==-1 && speed > 0) { direction = -1; speed -= 0.5; if (speed<0) speed=0; cam->decZ(speed*dt); } else { direction = 1; speed+=0.05; if (speed>maxspeedforward) speed=maxspeedforward; cam->incZ(speed*dt); } speedcontrol = true; } if(keydown(KEY_ALPHA) || keydown(KEY_FRAC) || keydown(KEY_F2)) // breaks or rear if speed <0 { if (direction==1 && speed > 0) { direction = 1; speed -= 0.5; if (speed<0) speed=0; cam->incZ(speed*dt); } else { direction = -1; speed+=0.025; if (speed>maxspeedbackward) speed=maxspeedbackward; cam->decZ(speed*dt); } speedcontrol = true; } if(keydown(KEY_EXIT)) drawPauseQuit(); if(keydown(KEY_OPTN)) drawOptions(); #if IS_FXLIB==1 if(keydown(KEY_7)) screenshot = true; if(keydown(KEY_8)) record = !record; #endif // IS_FXLIB if (speedcontrol==false) { speed-=0.1; if (speed<0) speed=0; if (direction==1) cam->incZ(speed*dt); else cam->decZ(speed*dt); } // Adjust position of the background if (lastindex!=index) { deltaFarbackground -= CC*speed*dt/250; deltaNearbackground -= CC*speed*dt/100; } lastindex = index; // adjust speed if we drive on the side of the road if (fround(cam->cX)<-1*ROAD_WIDTH && speed>2.0) speed=2.0; if (fround(cam->cX)>ROAD_WIDTH && speed>2.0) speed=2.0; if (fround(cam->cX)<-1.35*ROAD_WIDTH && speed>0.0) { speed=0.0; cam->cX=fix(-0.0*ROAD_WIDTH); //set the car in the center of the road (was formerly -0.75) } if (fround(cam->cX)>1.35*ROAD_WIDTH && speed>0.0) { speed=0.0; cam->cX=fix(0.0*ROAD_WIDTH); //set the car in the center of the road (was formerly 0.75) } /// This part controls the sliding of player's car, if we keep pressed the keys to turn too long, the car starts sliding, smoke will appear and speed is decreasing if (timepressed>=300.0f) // was 500.0f { CarIsSliding = true; cam->decX( CC*dt*speed/50 ); speed = speed * 0.975; framesmoke++; } else { CarIsSliding = false; framesmoke=0; } } static void get_minimum_inputs( void ) { key_event_t ev; while((ev = pollevent()).type != KEYEV_NONE) { } if(keydown(KEY_EXIT) || keydown(KEY_SHIFT)) drawPauseQuit(); if(keydown(KEY_OPTN)) drawOptions(); #if IS_FXLIB==1 if(keydown(KEY_7)) screenshot = true; if(keydown(KEY_8)) record = !record; #endif // IS_FXLIB } int main(void) { __printf_enable_fp(); __printf_enable_fixed(); #if IS_FXLIB==1 usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL }; usb_open(interfaces, GINT_CALL_NULL); #endif gint_world_switch( GINT_CALL( is_save_existing )); if (!saveexist) // if we do not have saves gint_world_switch( GINT_CALL( saveprogress ) ); // we create a progress file which is empty gint_world_switch( GINT_CALL( loadprogress )); // then we load it gint_world_switch( GINT_CALL( is_param_existing )); if (!saveexist) // if we do not have saves gint_world_switch( GINT_CALL( saveparameters ) ); // we create a progress file which is empty gint_world_switch( GINT_CALL( loadparameters )); // then we load it DiffLevel=PlayerPara[0].DiffLevel; CarsNumb=PlayerPara[0].CarsNumb; PlayerName[0]=PlayerPara[0].PlayerName[0]; PlayerName[1]=PlayerPara[0].PlayerName[1]; PlayerName[2]=PlayerPara[0].PlayerName[2]; kmalloc_arena_t *_uram = kmalloc_get_arena("_uram"); kmalloc_gint_stats_t *_uram_stats; /* allow more RAM */ char const *osv = (char*) 0x80020020; static kmalloc_arena_t extended_ram = { 0 }; kmalloc_gint_stats_t *extram_stats; bool canWeAllocate3Mb = false; #if (OVERCLCK_ACTIVABLE==1) if (gint[HWCALC] == HWCALC_FXCG50 || gint[HWCALC] == HWCALC_PRIZM) { EntryLevel = clock_get_speed(); isOCPossible = true; } else isOCPossible = false; #endif if((!strncmp(osv, "03.", 3) && osv[3] <= '6') && gint[HWCALC] == HWCALC_FXCG50) // CG-50 { extended_ram.name = "extram"; extended_ram.is_default = true; extended_ram.start = (void *)0x8c200000; extended_ram.end = (void *)0x8c500000 ; kmalloc_init_arena(&extended_ram, true); kmalloc_add_arena(&extended_ram ); canWeAllocate3Mb = true; } else if (gint[HWCALC] == HWCALC_PRIZM) // CG-10/20 { extended_ram.name = "extram"; extended_ram.is_default = true; uint16_t *vram1, *vram2; dgetvram(&vram1, &vram2); dsetvram(vram1, vram1); extended_ram.start = vram2; extended_ram.end = (char *)vram2 + 396*224*2; kmalloc_init_arena(&extended_ram, true); kmalloc_add_arena(&extended_ram ); canWeAllocate3Mb = false; } else if (gint[HWCALC] == HWCALC_FXCG_MANAGER) // CG-50 EMULATOR { extended_ram.name = "extram"; extended_ram.is_default = true; extended_ram.start = (void *)0x88200000; extended_ram.end = (void *)0x88500000 ; kmalloc_init_arena(&extended_ram, true); kmalloc_add_arena(&extended_ram ); canWeAllocate3Mb = true; } else abort(); srand( rtc_ticks() ); prof_init(); drawStartTitle(); exitToOS = false; do { // Try to restart from very begining initEverything(); prof_t perf_update, perf_create, perf_project, perf_render; start_time = 100000000; elapsed_time = 0; score=0; stage=0; mode=0; selectedCircuit=0; secondvalidation=0; time_update=0; time_create=0; time_project=0; time_render=0; ranking = -1; currentpoint = 0; exitToOS = false; stop = false; bool exitflag = false; do { exitflag = false; mode = drawMainMenu(); if (mode==0) { selectedCircuit = drawMenuCircuitSelect(); if (selectedCircuit != -1) secondvalidation = drawMenuCircuitDetails( selectedCircuit ); if (selectedCircuit != -1 && secondvalidation != -1) exitflag=true; } else if (mode==1) { selectedCircuit = drawMenuCircuitSelect(); if (selectedCircuit != -1) secondvalidation = drawMenuCircuitDetails( selectedCircuit ); if (selectedCircuit != -1 && secondvalidation != -1) secondvalidation = drawMenuBestTime( selectedCircuit ); if (selectedCircuit != -1 && secondvalidation != -1) exitflag=true; } else if (mode==2) { drawGameOptions(); PlayerPara[0].DiffLevel = DiffLevel; PlayerPara[0].CarsNumb = CarsNumb; PlayerPara[0].PlayerName[0]=PlayerName[0]; PlayerPara[0].PlayerName[1]=PlayerName[1]; PlayerPara[0].PlayerName[2]=PlayerName[2]; gint_world_switch( GINT_CALL( saveparameters ) ); if ((gint[HWCALC] == HWCALC_FXCG50 || gint[HWCALC] == HWCALC_PRIZM) && isOCActivated == true) clock_set_speed( CLOCK_SPEED_F5 ); else if ((gint[HWCALC] == HWCALC_FXCG50 || gint[HWCALC] == HWCALC_PRIZM) && isOCActivated == false && EntryLevel != CLOCK_SPEED_UNKNOWN) clock_set_speed( EntryLevel ); else if ((gint[HWCALC] == HWCALC_FXCG50 || gint[HWCALC] == HWCALC_PRIZM) && isOCActivated == false && EntryLevel == CLOCK_SPEED_UNKNOWN) clock_set_speed( CLOCK_SPEED_DEFAULT ); } else if (mode==3) { drawOptions(); } else if (mode==4) { drawCredit(); } else if (mode==5) { exitToOS = true; exitflag=true; } } while (!exitflag); skipranking = false; if (!exitToOS) { if (selectedCircuit==0) CurrentCircuitBiome = PLAINS, multilap = false, currentLap = 1, numlap = 1; else if (selectedCircuit==1) CurrentCircuitBiome = DESERT, multilap = false, currentLap = 1, numlap = 1; else if (selectedCircuit==2) CurrentCircuitBiome = USA, multilap = false, currentLap = 1, numlap = 1; else if (selectedCircuit==3) CurrentCircuitBiome = FINLAND, multilap = false, currentLap = 1, numlap = 1; else if (selectedCircuit==4) CurrentCircuitBiome = AFRICA, multilap = false, currentLap = 1, numlap = 1; else if (selectedCircuit==5) CurrentCircuitBiome = PLAINS, multilap = true, currentLap = 1, numlap = 3; else if (selectedCircuit==6) CurrentCircuitBiome = DESERT, multilap = true, currentLap = 1, numlap = 3; else if (selectedCircuit==7) CurrentCircuitBiome = USA, multilap = true, currentLap = 1, numlap = 3; else if (selectedCircuit==8) CurrentCircuitBiome = FINLAND, multilap = true, currentLap = 1, numlap = 3; else if (selectedCircuit==9) CurrentCircuitBiome = AFRICA, multilap = true, currentLap = 1, numlap = 3; else CurrentCircuitBiome = PLAINS, multilap = false, currentLap = 1, numlap = 1; int nbInterestingSegments = (MAX_RENDER_DISTANCE / SEGMENT_LENGTH); // the number of segments to be projected considering the rendering distance perf_create = prof_make(); prof_enter(perf_create); initData( ); // Positioning of the Camera createCircuit( selectedCircuit ); // Creates the circuit MAX_SEGMENT = circuit.size(); double maxDistance = (double) ((MAX_SEGMENT-1)*SEGMENT_LENGTH); putBillBoards(); createMilestones( numlap ); createClouds(); // Creates the Sky and Clouds if (mode==0) { // linear circuits needs many cars if (selectedCircuit>=0 && selectedCircuit<=3) { if (CarsNumb==0) NB_CARS_TRAFFIC=50; else if (CarsNumb==1) NB_CARS_TRAFFIC=100; else if (CarsNumb==2) NB_CARS_TRAFFIC=200; else if (CarsNumb==3) NB_CARS_TRAFFIC=300; else NB_CARS_TRAFFIC=100; } else // while circular needs much less { if (CarsNumb==0) NB_CARS_TRAFFIC=25; else if (CarsNumb==1) NB_CARS_TRAFFIC=50; else if (CarsNumb==2) NB_CARS_TRAFFIC=100; else if (CarsNumb==3) NB_CARS_TRAFFIC=150; else NB_CARS_TRAFFIC=10; } createTraffic( MAX_SEGMENT ); // Creates the cars prepareTraffic(); // Prepares the multiple variations of Cars (image scaling) } prepareDecoration( CurrentCircuitBiome ); // Prepares the multiple variations of Decoration (image scaling) prof_leave(perf_create); time_create = prof_time(perf_create); //-------------- int indexstart = 0; int indexend = 0; float dt=0; uint16_t l=0; uint32_t remaining_time; DataIndex = 0; bool initiateStart = true; // are we in the start sequence ? int32_t startCount = 6000000; int32_t startRemaining; bool finishSequence = false; // Did we reached the end of the race ? bool failSequence = false; // Did we run out of time ? bool stopcounting = false; while (!stop) { //new position if (!SkipTime) { dt = ((float) (time_update+time_render+time_project) / 1000.0); } else { dt = 0; SkipTime=false; } perf_update = prof_make(); prof_enter(perf_update); if (!initiateStart && !finishSequence && !failSequence) get_inputs( dt, indexstart ); // The racer is not started : no need to get inputs and we are not in fail or finish sequence else get_minimum_inputs(); // the we can just have minimum inputs //former position if (initiateStart) { startCount -= dt*1000; startRemaining = ((float) (startCount) / 100000.0); } if (!stopcounting) start_time -= dt*1000; if (!stopcounting) elapsed_time += dt*1000; if (start_time<0) start_time=0; remaining_time = ((float) (start_time) / 1000000.0); //-------------- if (fround(cam->cZ)<=0) cam->cZ=fixdouble(0.0); indexstart = fround(cam->cZ) / SEGMENT_LENGTH; if (indexstart<0) indexstart=0; indexend = indexstart+nbInterestingSegments+1; prof_leave(perf_update); time_update = prof_time(perf_update); //-------------- perf_project = prof_make(); prof_enter(perf_project); minYRoad = SCREEN_HEIGHT; if (BDrawCars && mode==0) { updateTraffic( dt, maxDistance ); for (unsigned int k=0; kwZ / SEGMENT_LENGTH; if (CarSegment>=indexstart && CarSegmentCarList.push_back(k); } } float roadpart = f2float(cam->cX)/(float) ROAD_WIDTH; // Update car positions : car with higher speed change line not to collide with player for(unsigned int l=0; lCarList.size(); l++ ) // For all cars inside that road segment { uint8_t indexCar = circuit[indexstart]->CarList[l]; if (traffic[indexCar]->wX>(roadpart-0.25f) && traffic[indexCar]->wX<(roadpart+0.25f) && traffic[indexCar]->Speed>speed) { if (traffic[indexCar]->wX>=-0.25) traffic[indexCar]->wX-=0.5; // if we are on one of the most right lanes, we overtake by the left else traffic[indexCar]->wX<-0.25; // else we change to the lane on the right } } for( unsigned int l=0; lCarList.size(); l++ ) // For all cars inside that road segment { uint8_t indexCar = circuit[indexstart+1]->CarList[l]; if (traffic[indexCar]->wX>(roadpart-0.22f) && traffic[indexCar]->wX<(roadpart+0.22f) && traffic[indexCar]->SpeedSpeed - 0.5; score = max(0, score-250); } } if (DiffLevel>=1) // Normal or Hard : cars can overtake the other opponents { for( unsigned int k=indexstart; kCarList.size(); l++ ) // For all cars inside that road segment { uint8_t indexCar = circuit[k]->CarList[l]; for( unsigned int m=0; mCarList.size(); m++ ) { uint8_t indexCar2 = circuit[k+1]->CarList[m]; if (traffic[indexCar]->wX==traffic[indexCar2]->wX && traffic[indexCar]->Speed>=traffic[indexCar2]->Speed) // a car is following and other one just in front of ehr, at the same speed or quicker { //if (traffic[indexCar]->wX>=-0.25) traffic[indexCar]->wX-=0.5; //else traffic[indexCar]->wX=-0.25; if (traffic[indexCar]->wX>=-0.25) traffic[indexCar]->Turn = -1; else traffic[indexCar]->Turn = +1; } } } } if (DiffLevel==2) // if difficulty set to hard, we allo changing lane (random based if not currently overtaking an other car) { for (unsigned int u=indexstart; uCarList.size(); v++) { unsigned int k = circuit[u]->CarList[v]; if (traffic[k]->Turn == 0) { int mov = rand() % 1000; if (mov>=990) // we let the car change its lane in 5% of cases { if (traffic[k]->wX==-0.75) traffic[k]->Turn = +1; else if (traffic[k]->wX==0.75) traffic[k]->Turn = -1; else { int side = -1 + (rand()%3); traffic[k]->Turn = side; } } } } } } for (unsigned int u=indexstart; uCarList.size(); v++) { unsigned int k = circuit[u]->CarList[v]; traffic[k]->wX += (float) traffic[k]->Turn * 0.05f; if (traffic[k]->wX>=-0.775 && traffic[k]->wX<=-0.725) traffic[k]->wX = -0.75, traffic[k]->Turn = 0; else if (traffic[k]->wX>=-0.275 && traffic[k]->wX<=-0.225) traffic[k]->wX = -0.25, traffic[k]->Turn = 0; else if (traffic[k]->wX>=0.225 && traffic[k]->wX<=0.275) traffic[k]->wX = 0.25, traffic[k]->Turn = 0; else if (traffic[k]->wX>=0.725 && traffic[k]->wX<=0.775) traffic[k]->wX = 0.75, traffic[k]->Turn = 0; } } } } uint16_t cumulCurve=0; for (int k=indexstart; k<=indexend; k++) // Need to project 1 more segment than actual drawing { projectCircuitFP( k ); // We project the current segment if (circuit[k]->Y <= minYRoad) minYRoad = circuit[k]->Y; circuit[k]->CumulatedCurve = cumulCurve; // This is the curve accumulated when we are drawing curves cumulCurve += circuit[k]->Curve; if (BDrawCars && mode==0) for( unsigned int l=0; lCarList.size(); l++ ) // For all cars inside that road segment { uint8_t indexCar = circuit[k]->CarList[l]; traffic[indexCar]->Project3DFP( cam, k ); } } prof_leave(perf_project); time_project = prof_time(perf_project); //-------------- perf_render = prof_make(); prof_enter(perf_render); //if (BDrawBack) drawSkyOptimised( DAY_BLUE_SKY ); //else drawSkyFull( DAY_BLUE_SKY ); //drawSkyFull( DAY_BLUE_SKY ); drawSkyQuick( DAY_BLUE_SKY ); if (BDrawClds) { drawClouds( ); } if (BDrawBack) { drawFarBackground( deltaFarbackground, CurrentCircuitBiome ); drawNearBackground( deltaNearbackground, CurrentCircuitBiome ); } cam->cY = fix( 350+2*CS ) + interpolatePositionY(fround(cam->cZ) ); for( int k=indexend-1; k>=indexstart; k--) { currentcurve = circuit[k]->CumulatedCurve; drawCircuitSegment( k ); if (BDrawDeco) drawDecoration( k ); if (BDrawCars && mode==0) for( unsigned int l=0; lCarList.size(); l++ ) // For all cars inside that road segment { uint8_t indexCar = circuit[k]->CarList[l]; drawTraffic( indexCar ); } if (BDrawCars && mode==0) circuit[k]->CarList.clear(); } uint32_t handicap; if (DiffLevel==0) handicap=0; // we use normal additional time when easy else if (DiffLevel==1) handicap=1000000; // we remove 2 seconds when normal else if (DiffLevel==2) handicap=2000000; // we remove 4 seconds when hard else handicap=0; // Action raised when passing through the different points : START, CHECKPOINTS/ FINISH LINE if (circuit[indexstart]->Special == CHECKPOINT && circuit[indexstart]->CheckValidated == false && circuit[indexstart]->CheckLap!=currentLap) { start_time += circuit[indexstart]->Extratime - handicap; circuit[indexstart]->CheckLap=currentLap; stage++; score += 5000; circuit[indexstart]->CheckValidated = true; } else if (circuit[indexstart]->Special == FINISH && circuit[indexstart]->CheckValidated == false && circuit[indexstart]->CheckLap!=currentLap) { circuit[indexstart]->CheckLap=currentLap; stage++; if (currentLapExtratime - handicap; score += 5000; cam->decZ( indexstart*SEGMENT_LENGTH ); if (mode==0) for( unsigned int k=0; kwZ-=indexstart*SEGMENT_LENGTH; } else { circuit[indexstart]->CheckValidated = true; score+=20000; finishSequence=true; stopcounting = true; FinalTime = elapsed_time; } #if DEBUGXXX==1 if (usb_is_open()) { //sprintf( texttosend, "FNSH : Chrono %D - %D", elapsed_time/1000000, start_time/1000000 ); sprintf( texttosend, "FNSH : Chrono %D - Reste %D - Extra %D --> Total %D", elapsed_time/1000000, (start_time-circuit[indexstart]->Extratime+handicap)/1000000, (circuit[indexstart]->Extratime-handicap)/1000000, start_time/1000000 ); usb_fxlink_text(texttosend, 0); } #endif } else if (circuit[indexstart]->Special == START && circuit[indexstart]->CheckValidated == false && circuit[indexstart]->CheckLap!=currentLap) { if (currentLap==1) { score = 0; start_time = circuit[indexstart]->Extratime - handicap; circuit[indexstart]->CheckLap=currentLap; elapsed_time = 0; } else { circuit[indexstart]->CheckLap = currentLap; //start_time += circuit[indexstart]->Extratime - handicap; circuit[indexstart]->CheckValidated = true; } #if DEBUGXXX==1 if (usb_is_open()) { //sprintf( texttosend, "STRT : Chrono %D - %D", elapsed_time/1000000, start_time/1000000 ); sprintf( texttosend, "STRT : Chrono %D - Reste %D - Extra %D --> Total %D", elapsed_time/1000000, (start_time-circuit[indexstart]->Extratime+handicap)/1000000, (circuit[indexstart]->Extratime-handicap)/1000000, start_time/1000000 ); usb_fxlink_text(texttosend, 0); } #endif } // Draw a message when time is over if (start_time<=0 && mode == 0) { failSequence=true; stopcounting = true; } int mod_base=20; int mod_comp=10; if (abs(speed)<1.0) mod_base = 30, mod_comp = 15; else if (abs(speed)<2.0) mod_base = 20, mod_comp = 10; else if (abs(speed)<3.0) mod_base = 16, mod_comp = 8; else if (abs(speed)<4.0) mod_base = 12, mod_comp = 6; else if (abs(speed)<5.0) mod_base = 8, mod_comp = 4; else mod_base = 4, mod_comp = 2; if ((speed==0) || (l%mod_base<=mod_comp)) // the small rick to have the speed impression on wheels and to have the correct view of the car during turns { if (viewside==-2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 99,1,80,46, DIMAGE_NONE); else if (viewside==-1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 181,1,74,46, DIMAGE_NONE); else if (viewside==0) dsubimage( SCREEN_CX-36, SCREEN_HEIGHT-46, &player, 257,1,72,46, DIMAGE_NONE); else if (viewside==1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 331,1,74,46, DIMAGE_NONE); else if (viewside==2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 407,1,80,46, DIMAGE_NONE); } else { if (viewside==-2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 99,49,80,46, DIMAGE_NONE); else if (viewside==-1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 181,49,74,46, DIMAGE_NONE); else if (viewside==0) dsubimage( SCREEN_CX-36, SCREEN_HEIGHT-46, &player, 257,49,72,46, DIMAGE_NONE); else if (viewside==1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 331,49,74,46, DIMAGE_NONE); else if (viewside==2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 407,49,80,46, DIMAGE_NONE); } dfont(&plate); if (viewside==-2) dprint_opt( 205, 203, C_WHITE, C_BLACK, DTEXT_CENTER, DTEXT_CENTER, "%c%c%c", PlayerName[0], PlayerName[1], PlayerName[2] ); else if (viewside==-1) dprint_opt( 202, 203, C_WHITE, C_BLACK, DTEXT_CENTER, DTEXT_CENTER, "%c%c%c", PlayerName[0], PlayerName[1], PlayerName[2] ); else if (viewside==0) dprint_opt( 197, 203, C_WHITE, C_BLACK, DTEXT_CENTER, DTEXT_CENTER, "%c%c%c", PlayerName[0], PlayerName[1], PlayerName[2] ); else if (viewside==1) dprint_opt( 193, 203, C_WHITE, C_BLACK, DTEXT_CENTER, DTEXT_CENTER, "%c%c%c", PlayerName[0], PlayerName[1], PlayerName[2] ); else if (viewside==2) dprint_opt( 189, 203, C_WHITE, C_BLACK, DTEXT_CENTER, DTEXT_CENTER, "%c%c%c", PlayerName[0], PlayerName[1], PlayerName[2] ); if (CarIsSliding) { if (framesmoke>=0 && framesmoke<10) dimage(SCREEN_CX-smoke1.width/2, SCREEN_HEIGHT-smoke1.height, &smoke1 ); else if (framesmoke>=10 && framesmoke<20) dimage(SCREEN_CX-smoke2.width/2, SCREEN_HEIGHT-smoke2.height, &smoke2 ); else if (framesmoke>=30 && framesmoke<30) dimage(SCREEN_CX-smoke3.width/2, SCREEN_HEIGHT-smoke3.height, &smoke3 ); else framesmoke=0; } if (direction==+1) score += speed*dt/10; float drawspeed = (float) (speed*5.0f); dsubimage( 5, 5, &speedhud, 0, 117, 37, 13, DIMAGE_NONE); // speed logo dsubimage( 135, 5, &speedhud, 0, 130, 37, 13, DIMAGE_NONE); // timer logo dsubimage( 245, 5, &speedhud, 37, 117, 38, 13, DIMAGE_NONE); // speed logo dsubimage( 245, 25, &speedhud, 37, 130, 38, 13, DIMAGE_NONE); // timer logo dfont(&speedfont); if (drawspeed==0.0) { dprint_opt(122,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "0 :", drawspeed ); dprint_opt(120,1, C_RGB(255,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "0 :", drawspeed ); } else { dprint_opt(122,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.1f :", drawspeed ); dprint_opt(120,1, C_RGB(255,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.1f :", drawspeed ); //the ':' char corresponds to "Km/h" } if (mode==0) { dprint_opt(238,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D ;", remaining_time ); dprint_opt(237,1, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D ;", remaining_time ); // the ';' char corresponds to "s" } else if (mode==1) { dprint_opt(238,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D ;", elapsed_time/1000000 ); dprint_opt(237,1, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D ;", elapsed_time/1000000 ); // the ';' char corresponds to "s" } dprint_opt(390,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", score ); dprint_opt(388,1, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", score ); // the ';' char corresponds to "s" dprint_opt(390,23, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", stage ); dprint_opt(388,21, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", stage ); // the ';' char corresponds to "s" if (multilap) { dsubimage( 135, 25, &speedhud, 28, 143, 27, 13, DIMAGE_NONE); // Lap logo dprint_opt(233,23, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%d/%d", currentLap, numlap ); dprint_opt(231,21, C_RGB(255,0,255), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%d/%d", currentLap, numlap ); // the ';' char corresponds to "s" } /// Graphical speed indicator if (visualspeedindicator) { if (drawspeed==0.0) dsubimage( 48, 25, &speedhud, 0, 0, 76, 13, DIMAGE_NONE); else if (drawspeed<3.30) dsubimage( 48, 25, &speedhud, 0, 13, 76, 13, DIMAGE_NONE); else if (drawspeed<6.70) dsubimage( 48, 25, &speedhud, 0, 26, 76, 13, DIMAGE_NONE); else if (drawspeed<10.0) dsubimage( 48, 25, &speedhud, 0, 39, 76, 13, DIMAGE_NONE); else if (drawspeed<13.3) dsubimage( 48, 25, &speedhud, 0, 52, 76, 13, DIMAGE_NONE); else if (drawspeed<16.7) dsubimage( 48, 25, &speedhud, 0, 65, 76, 13, DIMAGE_NONE); else if (drawspeed<20.0) dsubimage( 48, 25, &speedhud, 0, 78, 76, 13, DIMAGE_NONE); else if (drawspeed<23.3) dsubimage( 48, 25, &speedhud, 0, 91, 76, 13, DIMAGE_NONE); else dsubimage( 48, 25, &speedhud, 0, 104, 76, 13, DIMAGE_NONE); } /// Checkpoint indicator if (visualnextpoint) { double Z1 = jalons[currentpoint]->wZ; double Z2 = jalons[currentpoint+1]->wZ; double frac = (fround(cam->cZ) - Z1) / (Z2 - Z1 ); if (frac<0) frac=0; if (fround(cam->cZ) >= Z2) currentpoint++; drect( 15, 50, 20, 150, C_WHITE ); drect( 10, 49+frac*100, 25, 51+frac*100, C_RED ); } if (finishSequence) { if (mode==1 && !skipranking) { bool donerank = false; int k=0; while (!donerank && k<5) { if (FinalTime<=HallOfFame[selectedCircuit][k].bestTime) { for( int l=4; l>k; l--) { HallOfFame[selectedCircuit][l].playerName[0] = HallOfFame[selectedCircuit][l-1].playerName[0]; HallOfFame[selectedCircuit][l].playerName[1] = HallOfFame[selectedCircuit][l-1].playerName[1]; HallOfFame[selectedCircuit][l].playerName[2] = HallOfFame[selectedCircuit][l-1].playerName[2]; HallOfFame[selectedCircuit][l].padding = HallOfFame[selectedCircuit][l-1].padding; HallOfFame[selectedCircuit][l].bestScore = HallOfFame[selectedCircuit][l-1].bestScore; HallOfFame[selectedCircuit][l].bestTime = HallOfFame[selectedCircuit][l-1].bestTime; } HallOfFame[selectedCircuit][k].playerName[0] = PlayerName[0]; HallOfFame[selectedCircuit][k].playerName[1] = PlayerName[1]; HallOfFame[selectedCircuit][k].playerName[2] = PlayerName[2]; HallOfFame[selectedCircuit][k].padding = 'X'; HallOfFame[selectedCircuit][k].bestScore = score; HallOfFame[selectedCircuit][k].bestTime = FinalTime; donerank = true; skipranking = true; ranking = k; gint_world_switch( GINT_CALL( saveprogress ) ); } else k++; } } speed = 0; dimage( 198-bigflag.width/2, 112-bigflag.height/2, &bigflag ); if (ranking!=-1 || mode==0) { dfont(&startseq); dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" ); dprint_opt(198,112, C_RGB(0,255,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" ); dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "WIN", ranking ); dprint_opt(198,112, C_RGB(0,255,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "WIN", ranking ); dfont(&autofont); uint32_t temp1 = FinalTime/1000000/60; uint32_t temp2 = FinalTime/1000000 - temp1*60; uint32_t temp3 = (FinalTime - temp1*60*1000000 - temp2*1000000)/1000; dprint_opt(200, 202, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "%d - %D:%D,%D", ranking+1, temp1, temp2, temp3 ); dprint_opt(198, 200, C_RGB(255, 255, 255), C_NONE, DTEXT_CENTER, DTEXT_TOP, "%d - %D:%D,%D", ranking+1, temp1, temp2, temp3 ); } else { dfont(&startseq); dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" ); dprint_opt(198,112, C_RGB(255,0,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" ); dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "LOSE" ); dprint_opt(198,112, C_RGB(255,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "LOSE" ); } } if (failSequence) { speed = 0; dimage( 198-bigflag.width/2, 112-bigflag.height/2, &bigflag ); dfont(&startseq); dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" ); dprint_opt(198,112, C_RGB(255,0,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" ); dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "LOSE" ); dprint_opt(198,112, C_RGB(255,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "LOSE" ); } if (initiateStart) // We are in the start sequence with the countdown { dfont(&startseq); if (startRemaining<54 && startRemaining>46) { dprint_opt(200,114, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">5<" ); dprint_opt(198,112, C_RGB(255,0,255), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">5<" ); } else if (startRemaining<44 && startRemaining>36) { dprint_opt(200,114, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">4<" ); dprint_opt(198,112, C_RGB(255,0,255), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">4<" ); } else if (startRemaining<34 && startRemaining>26) { dprint_opt(200,114, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">3<" ); dprint_opt(198,112, C_RGB(255,0,255), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">3<" ); } else if (startRemaining<24 && startRemaining>16) { dprint_opt(200,114, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">2<" ); dprint_opt(198,112, C_RGB(255,0,255), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">2<" ); } else if (startRemaining<14 && startRemaining>6) { dprint_opt(200,114, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">1<" ); dprint_opt(198,112, C_RGB(255,0,255), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">1<" ); } else if (startRemaining<4 && startRemaining>-4) { dimage( 198-bigflag.width/2, 112-bigflag.height/2, &bigflag ); } else if (startRemaining<-4) { start_time = 99000000; initiateStart=false; } } //dupdate(); //dprint( 3, 202, C_BLACK, "%.0f", dt ); //dprint( 1, 200, C_WHITE, "%.0f", dt ); if (BDrawFPS) { dfont(&speedfont); dsubimage( 5, 205, &speedhud, 0, 143, 27, 13, DIMAGE_NONE); // fps logo dprint_opt(42,202, C_RGB(0,0,0), C_NONE, DTEXT_LEFT, DTEXT_TOP, "%.0f <", (float) (1000.0f/dt) ); // the '>' symbol corresponds to "fps" dprint_opt(40,200, C_RGB(255,255,0), C_NONE, DTEXT_LEFT, DTEXT_TOP, "%.0f <", (float) (1000.0f/dt) ); GraphPerf[DataIndex].update = (uint8_t) (time_update/1000); GraphPerf[DataIndex].project = (uint8_t) (time_project/1000); GraphPerf[DataIndex].render = (uint8_t) (time_render/1000); DataIndex++; DataIndex = DataIndex % MAXDATA; dline( 249, 201, 375, 201, C_BLACK ); dline( 249, 202, 375, 202, C_BLACK ); dline( 249, 200-33, 375, 200-33, C_BLACK ); dline( 249, 200-40, 375, 200-40, C_BLACK ); dline( 249, 200-50, 375, 200-50, C_BLACK ); dline( 249, 201, 249, 100, C_BLACK ); dline( 248, 201, 248, 100, C_BLACK ); for( unsigned int k=0; kused_memory, _uram_stats->free_memory, _uram_stats->peak_used_memory); usb_fxlink_text(texttosend, 0); */ // Free all memory freeDecoration(); for(unsigned int i=0; i