You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OutRun/src/main.cc

1371 lines
50 KiB

#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>
#define DEBUGXXX 0
11 months ago
extern bopti_image_t player;
extern font_t speedfont, startseq, plate, autofont;
11 months ago
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;
11 months ago
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;
11 months ago
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 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;
11 months ago
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((!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 ) );
}
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
11 months ago
prof_leave(perf_create);
time_create = prof_time(perf_create);
11 months ago
//--------------
int indexstart = 0;
int indexend = 0;
float dt=0;
uint16_t l=0;
uint32_t remaining_time;
11 months ago
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);
11 months ago
//--------------
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;
11 months ago
indexend = indexstart+nbInterestingSegments+1;
//if (indexstart>MAX_SEGMENT-nbInterestingSegments-2) indexstart=MAX_SEGMENT-nbInterestingSegments-2;
11 months ago
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++ )
{