#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 "clock.h" #define DEBUGXXX 0 #define OVERCLCK_ACTIVABLE 0 char version[5] = {'V','1','.','0','4'}; extern bopti_image_t player; 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; 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; // for multilap bool multilap = false; uint8_t numlap = 1; uint8_t currentLap = 1; 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; 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; } 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 ); // very hard to turn in Finland with snow else if (CurrentCircuitBiome==AFRICA) cam->decX( CC*dt*speed/75 ); // hard in Africa with dirt else cam->decX( CC*dt*speed/100 ); // more easy on normal roads } else if (CC>0) { viewside=+1; if (CurrentCircuitBiome==FINLAND) cam->decX( CC*dt*speed/50 ); // very hard to turn in Finland with snow else if (CurrentCircuitBiome==AFRICA) cam->decX( CC*dt*speed/75 ); // hard in Africa with dirt else cam->decX( CC*dt*speed/100 ); // more easy on normal roads } if(keydown(KEY_LEFT)) { cam->decX(5.0*speed*direction); viewside=-1; if (CC<0) viewside=-2; // We are in a curve and turning if (CC>0) viewside=0; } if(keydown(KEY_RIGHT)) { cam->incX(5.0*speed*direction); viewside=1; if (CC>0) viewside=+2; if (CC<0) viewside=0; } if(keydown(KEY_SHIFT)) // 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)) // 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_F1)) BDrawDeco = !BDrawDeco; if(keydown(KEY_F2)) BDrawClds = !BDrawClds; if(keydown(KEY_F3)) BDrawCars = !BDrawCars; if(keydown(KEY_F4)) BDrawBack = !BDrawBack; if(keydown(KEY_F5)) BDrawFPS = !BDrawFPS; 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) } } static void get_minimum_inputs( void ) { key_event_t ev; while((ev = pollevent()).type != KEYEV_NONE) { } if(keydown(KEY_EXIT)) drawPauseQuit(); if(keydown(KEY_OPTN)) drawOptions(); #if IS_FXLIB==1 if(keydown(KEY_F1)) BDrawDeco = !BDrawDeco; if(keydown(KEY_F2)) BDrawClds = !BDrawClds; if(keydown(KEY_F3)) BDrawCars = !BDrawCars; if(keydown(KEY_F4)) BDrawBack = !BDrawBack; if(keydown(KEY_F5)) BDrawFPS = !BDrawFPS; 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) //Check if we can overclock i.e. if we have a CG50/Graph 90+E if (gint[HWCALC] == HWCALC_FXCG50) 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 { /* _uram_stats = kmalloc_get_gint_stats(_uram); sprintf( texttosend, "[Begining of loop] Memory Status - Used: %d - Free: %d - Peak Used: %d", _uram_stats->used_memory, _uram_stats->free_memory, _uram_stats->peak_used_memory); usb_fxlink_text(texttosend, 0); */ // 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; 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 && isOCActivated == true) clock_overclock( OC_PtuneF4 ); else if (gint[HWCALC] == HWCALC_FXCG50 && isOCActivated == false) clock_overclock( OC_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) { //stage = selectedCircuit; 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(); //uint32_t maxDistance = (MAX_SEGMENT-nbInterestingSegments-5)*SEGMENT_LENGTH; double maxDistance = (double) ((MAX_SEGMENT-1)*SEGMENT_LENGTH); putBillBoards(); 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 if (selectedCircuit==4) // except for Africa which is very heavy so we need more memory { if (CarsNumb==0) NB_CARS_TRAFFIC=50; else if (CarsNumb==1) NB_CARS_TRAFFIC=75; else if (CarsNumb==2) NB_CARS_TRAFFIC=100; else if (CarsNumb==3) NB_CARS_TRAFFIC=150; else NB_CARS_TRAFFIC=75; } */ 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) #if DEBUGXXX==1 _uram_stats = kmalloc_get_gint_stats(_uram); extram_stats = kmalloc_get_gint_stats(&extended_ram); sprintf( texttosend, "[_U RAM] Memory Status - Used: %d - Free: %d - Peak Used: %d", _uram_stats->used_memory, _uram_stats->free_memory, _uram_stats->peak_used_memory); if (usb_is_open()) usb_fxlink_text(texttosend, 0); sprintf( texttosend, "[EXT RAM] Memory Status - Used: %d - Free: %d - Peak Used: %d", extram_stats->used_memory, extram_stats->free_memory, extram_stats->peak_used_memory); if (usb_is_open()) usb_fxlink_text(texttosend, 0); #endif // DEBUGXXX 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); //if (fround(cam->cZ)>=maxDistance) cam->cZ=fixdouble(maxDistance); indexstart = fround(cam->cZ) / SEGMENT_LENGTH; if (indexstart<0) indexstart=0; indexend = indexstart+nbInterestingSegments+1; //if (indexstart>MAX_SEGMENT-nbInterestingSegments-2) indexstart=MAX_SEGMENT-nbInterestingSegments-2; 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 && CarSegmentvisible = true; circuit[CarSegment]->CarList.push_back(k); } //else //traffic[k]->visible = false; } 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]; /* if (traffic[k]->Turn == -1) { traffic[k]->wX -= 0.10; if (traffic[k]->wX==-0.75 || traffic[k]->wX==-0.25 || traffic[k]->wX==0.25) traffic[k]->Turn = 0; } else if (traffic[k]->Turn == 1) { traffic[k]->wX += 0.10; if (traffic[k]->wX==-0.25 || traffic[k]->wX==0.25 || traffic[k]->wX==0.75) traffic[k]->Turn = 0; } */ 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 (k!= indexend && circuit[k]->Y < minYRoad) // This is a trick to save precious time while drawing the Sky 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; #if DEBUGXXX==1 if (usb_is_open()) { //sprintf( texttosend, "CKPT : Chrono %D - %D", elapsed_time/1000000, start_time/1000000 ); sprintf( texttosend, "CKPT : 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 == 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 (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" } 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); if (finishSequence) { if (mode==1 && !skipranking) { #if DEBUGXXX==1 if (usb_is_open()) usb_fxlink_text("save perf", 0); #endif bool donerank = false; int k=0; while (!donerank && k<5) { #if DEBUGXXX==1 if (usb_is_open()) usb_fxlink_text("in the loop", 0); #endif if (FinalTime<=HallOfFame[selectedCircuit][k].bestTime) { #if DEBUGXXX==1 if (usb_is_open()) usb_fxlink_text("found", 0); #endif 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) { 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