OutRun/src/main.cc

1386 lines
51 KiB
C++

#include <gint/display.h>
#include <gint/drivers/r61524.h>
#include <gint/rtc.h>
#include <gint/keyboard.h>
#include <gint/gint.h>
#include <gint/defs/types.h>
#include <fxlibc/printf.h>
#include <libprof.h>
#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>
#include <math.h>
#include <vector>
#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 <gint/kmalloc.h>
#include <stdio.h>
#include "clock.h"
#define DEBUGXXX 0
#define OVERCLCK_ACTIVABLE 1
char version[5] = {'V','1','.','0','6'};
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<Segment*> circuit;
std::vector<Clouds*> nuages;
std::vector<Cars*> 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) || keydown(KEY_F5))
{
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) || keydown(KEY_F6))
{
cam->incX(5.0*speed*direction);
viewside=1;
if (CC>0) viewside=+2;
if (CC<0) viewside=0;
}
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)
}
}
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_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_PtuneF5 );
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; k<traffic.size(); k++) // Need to project 1 more segment than actual drawing
{
uint16_t CarSegment = traffic[k]->wZ / SEGMENT_LENGTH;
if (CarSegment>=indexstart && CarSegment<indexend)
{
//traffic[k]->visible = 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; l<circuit[indexstart]->CarList.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; l<circuit[indexstart+1]->CarList.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]->Speed<speed)
{
speed = traffic[indexCar]->Speed - 0.5;
score = max(0, score-250);
}
}
if (DiffLevel>=1) // Normal or Hard : cars can overtake the other opponents
{
for( unsigned int k=indexstart; k<indexend; k++)
{
for( unsigned int l=0; l<circuit[k]->CarList.size(); l++ ) // For all cars inside that road segment
{
uint8_t indexCar = circuit[k]->CarList[l];
for( unsigned int m=0; m<circuit[k+1]->CarList.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; u<indexend; u++)
{
for (unsigned int v=0; v<circuit[u]->CarList.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; u<indexend; u++)
{
for (unsigned int v=0; v<circuit[u]->CarList.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; l<circuit[k]->CarList.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; l<circuit[k]->CarList.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 (currentLap<numlap)
{
currentLap++;
start_time += circuit[indexstart]->Extratime - handicap;
score += 5000;
cam->decZ( indexstart*SEGMENT_LENGTH );
if (mode==0)
for( unsigned int k=0; k<traffic.size(); k++ )
traffic[k]->wZ-=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; k<MAXDATA-1; k++)
{
dpixel( 250+k, 200-GraphPerf[k].update, C_RGB(255,0,0) );
dpixel( 250+k, 201-GraphPerf[k].update, C_RGB(255,0,0) );
dpixel( 250+k, 200-GraphPerf[k].update-GraphPerf[k].project, C_RGB(0,255,0) );
dpixel( 250+k, 201-GraphPerf[k].update-GraphPerf[k].project, C_RGB(0,255,0) );
dpixel( 250+k, 200-GraphPerf[k].update-GraphPerf[k].project-GraphPerf[k].render, C_RGB(0,0,255) );
dpixel( 250+k, 201-GraphPerf[k].update-GraphPerf[k].project-GraphPerf[k].render, C_RGB(0,0,255) );
}
}
r61524_display(gint_vram, 0, DHEIGHT, R61524_DMA_WAIT);
prof_leave(perf_render);
time_render = prof_time(perf_render);
#if IS_FXLIB==1
if (screenshot && usb_is_open())
{
usb_fxlink_screenshot(false);
screenshot = false;
}
if(record && usb_is_open())
{
usb_fxlink_videocapture(false);
}
#endif
l++;
}
/*
_uram_stats = kmalloc_get_gint_stats(_uram);
sprintf( texttosend, "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);
*/
// Free all memory
freeDecoration();
for(unsigned int i=0; i<circuit.size(); i++ ) delete circuit[i]; // Not to forget to delete each elements
circuit.clear();
for(unsigned int i=0; i<nuages.size(); i++ ) delete nuages[i]; // Not to forget to delete each elements
nuages.clear();
if (mode==0)
{
freeTraffic();
for(unsigned int i=0; i<traffic.size(); i++ )
delete traffic[i]; // Not to forget to delete each elements
traffic.clear();
}
}
}
while (exitToOS==false);
prof_quit();
#if IS_FXLIB==1
usb_close();
#endif
if (gint[HWCALC] == HWCALC_FXCG50 && isOCActivated == true) clock_overclock( OC_Default );
delete cam;
// We set back zeros at the end of the program
memset(extended_ram.start, 0, (char *)extended_ram.end - (char *)extended_ram.start);
return 1;
}