//========================================================================================================================================
// F4 Racing
//----------------------------------------------------------------------------------------------------------------------------------------
// This is an advancement in my game making skills, building off the back of my work on the "Collect the Balls" game.
//----------------------------------------------------------------------------------------------------------------------------------------
// created by Rune
// black box code by Sigonasr2 from the OLC (one lone coder) Discord server
//========================================================================================================================================
# define OLC_PGE_APPLICATION
# include "pixelGameEngine.h" // used for drawing the game
//========================================================================================================================================
// protected variables
//========================================================================================================================================
class Racer : public olc : : PixelGameEngine
{
public :
Racer ( )
{
sAppName = " F4 Racing " ;
}
private :
float car_pos = 0.f ; // track the horizontal location of player
float distance = 0.f ; // track the "vertical" location of player; basically, they're somewhere on the track between the start and finish line
float speed = 0.f ;
float curvature = 0.f ; // probably the player's horizontal position in relation to the track's curve
float track_curve = 0.f ;
float car_curve = 0.f ; // wtf....
float track_dist = 0.f ; // total distance of the circuit
float cur_lap_time = 0.f ;
std : : vector < std : : pair < float , float > > vecTrack ;
std : : list < float > list_times ;
bool bothKeysPressed = false ; // checking for dual key press; could probably work with more than 2 keys
// custom controls template
olc : : Key Move_Up = olc : : UP ;
olc : : Key Move_Down = olc : : DOWN ;
olc : : Key Move_Left = olc : : LEFT ;
olc : : Key Move_Right = olc : : RIGHT ;
std : : array < std : : string , 4 > keyslist = { " UP " , " DOWN " , " LEFT " , " RIGHT " } ;
int configKeyIndex = - 1 ;
char pressedKey ;
// selection screen variables
int cup = - 1 ;
int track = - 1 ;
int player = 0 ;
//========================================================================================================================================
// Menu Setup
//========================================================================================================================================
public :
bool activeOption = true ; // highlighting current option
int highlighted ;
struct MenuItem
{
std : : string label ; // label
olc : : vi2d pos ; // label's position
std : : string label2 ; // another label to right of label
} ;
struct Object
{
olc : : vf2d pos { 0 , 0 } ; // the x position represents how far to the left/right it is from the center. -1 ~ 1: road's range; the y position is how far along the track it is
olc : : vf2d size { 1 , 1 } ;
olc : : Decal * decal = nullptr ;
olc : : vf2d offset { 0 , 0 } ; // how far off the image will be
bool rendered = false ;
olc : : vf2d drawPos ;
olc : : vf2d drawSize ;
olc : : vf2d drawOffsetPos ;
} ;
std : : vector < MenuItem > mainMenu ;
std : : vector < MenuItem > playGame ;
std : : vector < MenuItem > pickTrack ;
std : : vector < MenuItem > grandPrix ;
std : : vector < MenuItem > selectCar ;
std : : vector < MenuItem > controls ;
std : : vector < MenuItem > pause ;
std : : vector < std : : string > gameOver ;
std : : vector < Object > gameObjects ;
enum class state
{
MAIN_MENU , PLAY_GAME , RUN_GAME , CONTROLS , PAUSED , RESUME , // main
TRACK_SELECT , CUP_SELECT , CAR_SELECT , // game
INDIE , STREET , PRO , GRAND_PRIX // cups
} ;
state gameState = state : : MAIN_MENU ;
//========================================================================================================================================
// Variables
//========================================================================================================================================
// lap times
// player
int score = 0 ; // score at end of track; based on final place
int lap = 0 ; // current lap player is on
int place ; // current place player is in
int tracks_left ;
// initialize sprites
olc : : Decal * car ;
olc : : Decal * cars ;
olc : : Decal * hill ;
olc : : Decal * grass ;
olc : : Decal * road ;
olc : : Decal * banner ;
olc : : Decal * title ;
olc : : Decal * cups ;
//olc::Decal* select;
std : : string KeyToString ( olc : : Key key )
{
const std : : array < std : : string , 98 > keyStrings =
{
" NONE " , " A " , " B " , " C " , " D " , " E " , " F " , " G " , " H " , " I " , " J " , " K " , " L " , " M " , " N " , " O " , " P " , " Q " , " R " , " S " , " T " , " U " , " V " , " W " , " X " , " Y " , " Z " , " 0 " , " 1 " , " 2 " , " 3 " , " 4 " , " 5 " , " 6 " , " 7 " , " 8 " , " 9 " ,
" F1 " , " F2 " , " F3 " , " F4 " , " F5 " , " F6 " , " F7 " , " F8 " , " F9 " , " F10 " , " F11 " , " F12 " , " UP " , " DOWN " , " LEFT " , " RIGHT " , " SPACE " , " TAB " , " SHIFT " , " CTRL " , " INS " , " DEL " , " HOME " , " END " , " PGUP " , " PGDN " , " BACK " , " ESCAPE " , " ENTER " , " ENTER " ,
" PAUSE " , " SCROLL LK " , " Kp-0 " , " Kp-1 " , " Kp-2 " , " Kp-3 " , " Kp-4 " , " Kp-5 " , " Kp-6 " , " Kp-7 " , " Kp-8 " , " Kp-9 " , " Kp-* " , " Kp-/ " , " Kp-+ " , " Kp-- " , " Kp-. " , " . " , " = " , " , " , " - " , " OEM_1 " ,
" OEM_2 " , " OEM_3 " , " OEM_4 " , " OEM_5 " , " OEM_6 " , " OEM_7 " , " OEM_8 " , " CAPS LOCK " , " END "
} ;
return keyStrings [ key ] ;
}
// add laps to a new track struct
struct Track
{
std : : vector < std : : pair < float , float > > curves ; // curves
std : : string name ; // names
int laps ; // laps
} ;
// special track ;)
Track javidx9 =
{
// they'll likely be wonky for the game as it's not really modified to fit my units of
// these happen to be measured in meters, as per Javid's original construction measure
{ { 0.f , 10.f } , { 0.f , 200.f } , { 1.f , 200.f } , { 0.f , 400.f } , { - 1.f , 100.f } ,
{ 0.f , 200.f } , { - 1.f , 200.f } , { 1.f , 200.f } , { 0.f , 200.f } , { 0.2f , 500.f } , { 0.f , 200.f } } , " JAVIDX9 " , 3
} ;
// all 9 tracks below are running on yards for their distance units
// this means the end results are in miles; rather than kilometers
// enjoy the US measures of Burgers per Freedom Eagle
//==================================================================================================
Track circuit =
{
// Classic Oval; 1 mile loop, 1,760 yards
{ { 0.f , 10.f } , { 0.f , 270.f } , { - 1.f , 330.f } , { 0.f , 550.f } , { - 1.f , 330.f } , { 0.f , 270.f } } , " CIRCUIT " , 3
} ;
Track infinity =
{
// figure eight
{ { 0.f , 10.f } , // flag (straight); this is positioned somewhere after the intersection
{ 0.f , 190.f } , { - 1.f , 200.f } ,
{ 0.f , 500.f } , // straight; this crosses the first straight, to provide for chances of crashing
{ 1.f , 200.f } , { 0.f , 300.f } } , " INFINITY " , 3
} ;
Track arrow_head =
{
// fancy triangle
{ { 0.f , 10.f } , { 0.f , 490.f } , { 1.f , 130.f } , { 0.f , 1000.f } , { 1.f , 130.f } ,
{ 0.f , 500.f } , { - 1.f , 130.f } , { 0.f , 500.f } , { 1.f , 130.f } , { 0.f , 500.f } } , " ARROW HEAD " , 3
} ;
Track track_4 = // ???
{
{ { 0.f , 10.f } , } , " Track 4 " , 3
} ;
Track overpass =
{
// kind of a folded figure eight
{ { 0.f , 10.f } ,
{ 0.f , 0.f } ,
{ 1.f , 0.f } ,
{ 0.f , 0.f } ,
{ 1.f , 0.f } ,
{ 1.f , 0.f } ,
{ 0.f , 0.f } ,
{ 1.f , 0.f } ,
{ 0.f , 0.f } } , " OVERPASS " , 3
} ;
Track peanut =
{
// No more rhymes now. I mean it!
// Anybody want a peanut?
// GAH!!!
{ { 0.f , 10.f } , } , " PEANUT " , 4
} ;
Track track_7 = // ???
{
{ { 0.f , 10.f } , } , " Track 7 " , 3
} ;
Track trident =
{
// is your preferred Neptune or Poseidon?
{ { 0.f , 10.f } , } , " TRIDENT " , 3
} ;
Track star =
{
// spangled banner; oh say can you see....
// look, I suck at singing, and not gonna look up the lyrics, just, enjoy American awesomeness
{ { 0.f , 10.f } , } , " STAR " , 3
} ;
std : : vector < Track > trackList =
{
javidx9 ,
circuit , infinity , arrow_head ,
track_4 , overpass , peanut ,
track_7 , trident , star
} ;
//========================================================================================================================================
// Create Game Objects
//========================================================================================================================================
bool OnUserCreate ( ) override
{
mainMenu = // show menu options
{
{ " START GAME " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 5 * 3 } } ,
{ " CONTROLS " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 5 * 3 + 64 } } ,
{ " QUIT " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 5 * 3 + 128 } }
} ;
playGame =
{
{ " TRACK SELECTION " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 4 } } ,
{ " GRAND PRIX " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 2 } } ,
{ " BACK " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 6 * 5 } }
} ;
pickTrack = // show track options
{
{ " CIRCUIT " , { ScreenWidth ( ) / 4 , ScreenHeight ( ) / 4 } } , { " INFINITY " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 4 } } ,
{ " ARROWHEAD " , { ScreenWidth ( ) / 4 * 3 , ScreenHeight ( ) / 4 } } , { " Track 4 " , { ScreenWidth ( ) / 4 , ScreenHeight ( ) / 2 } } ,
{ " OVERPASS " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 2 } } , { " PEANUT " , { ScreenWidth ( ) / 4 * 3 , ScreenHeight ( ) / 2 } } ,
{ " Track 7 " , { ScreenWidth ( ) / 4 , ScreenHeight ( ) / 4 * 3 } } , { " TRIDENT " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 4 * 3 } } ,
{ " STAR " , { ScreenWidth ( ) / 4 * 3 , ScreenHeight ( ) / 4 * 3 } } , { " BACK " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 6 * 5 } }
} ;
grandPrix = // show race cups
{
{ " INDIE CUP " , { ScreenWidth ( ) / 3 , ScreenHeight ( ) / 3 } } , { " STREET CUP " , { ScreenWidth ( ) / 3 * 2 , ScreenHeight ( ) / 3 } } ,
{ " PRO CUP " , { ScreenWidth ( ) / 3 , ScreenHeight ( ) / 3 * 2 } } , { " GRAND PRIX " , { ScreenWidth ( ) / 3 * 2 , ScreenHeight ( ) / 3 * 2 } } ,
{ " BACK " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 6 * 5 } }
} ;
selectCar = // pick a color
{
{ " RED " , { ScreenWidth ( ) / 5 , ScreenHeight ( ) / 3 } } , { " BLUE " , { ScreenWidth ( ) / 5 * 2 , ScreenHeight ( ) / 3 } } ,
{ " GREEN " , { ScreenWidth ( ) / 5 * 3 , ScreenHeight ( ) / 3 } } , { " GOLD " , { ScreenWidth ( ) / 5 * 4 , ScreenHeight ( ) / 3 } } ,
{ " PURPLE " , { ScreenWidth ( ) / 5 , ScreenHeight ( ) / 3 * 2 } } , { " WHITE " , { ScreenWidth ( ) / 5 * 2 , ScreenHeight ( ) / 3 * 2 } } ,
{ " ORANGE " , { ScreenWidth ( ) / 5 * 3 , ScreenHeight ( ) / 3 * 2 } } , { " BLACK " , { ScreenWidth ( ) / 5 * 4 , ScreenHeight ( ) / 3 * 2 } } ,
{ " BACK " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 6 * 5 } }
} ;
controls = // customize controls
{
{ " FORWARD " , { ScreenWidth ( ) / 3 , ScreenHeight ( ) / 9 * 2 } , KeyToString ( Move_Up ) } , { " BACK " , { ScreenWidth ( ) / 3 , ScreenHeight ( ) / 9 * 3 } , KeyToString ( Move_Down ) } ,
{ " LEFT " , { ScreenWidth ( ) / 3 , ScreenHeight ( ) / 9 * 4 } , KeyToString ( Move_Left ) } , { " RIGHT " , { ScreenWidth ( ) / 3 , ScreenHeight ( ) / 9 * 5 } , KeyToString ( Move_Right ) } ,
{ " DEFAULT " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 9 * 6 } } , { " BACK " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 6 * 5 } }
} ;
pause =
{
{ " RESUME " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 9 * 3 } } , { " RESTART " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 9 * 4 } } ,
{ " MENU " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 9 * 5 } } , { " QUIT " , { ScreenWidth ( ) / 2 , ScreenHeight ( ) / 9 * 6 } }
} ;
gameOver = { " Return to Main Menu " } ;
//========================================================================================================================================
// load sprites
car = new olc : : Decal ( new olc : : Sprite ( " art/car.png " ) ) ; // will contain 8 cars, with 3 angles per car
cars = new olc : : Decal ( new olc : : Sprite ( " art/cars.png " ) ) ; // temp file; holds all 8 cars
hill = new olc : : Decal ( new olc : : Sprite ( " art/hills.png " ) , false , false ) ;
grass = new olc : : Decal ( new olc : : Sprite ( " art/grass.png " ) , false , false ) ;
road = new olc : : Decal ( new olc : : Sprite ( " art/road.png " ) , false , false ) ; // holds both road and flag line
banner = new olc : : Decal ( new olc : : Sprite ( " art/start.png " ) , false , false ) ;
title = new olc : : Decal ( new olc : : Sprite ( " art/title.png " ) ) ;
cups = new olc : : Decal ( new olc : : Sprite ( " art/cups.png " ) ) ; // 64 px tiles; 128 px image
//select = new olc::Decal(new olc::Sprite("art/selection.png"));
// track stuff
list_times = { 0 , 0 , 0 , 0 , 0 } ; // this needs modification, as most tracks will likely have 4 laps, some with 3, and some with 5
gameObjects . push_back ( { /*{-1.5,track_dist - 50}, {10,6}, {0,240}*/ } ) ;
return true ;
}
//========================================================================================================================================
// reset game
//========================================================================================================================================
void Reset ( )
{
car_pos = 0.0f ;
distance = 0.0f ;
speed = 0.0f ;
curvature = 0.0f ;
track_curve = 0.0f ;
car_curve = 0.0f ;
track_dist = 0.0f ;
cur_lap_time = 0.0f ;
lap = 0 ;
// Note: the following all need to be reset during the process, when they've been implemented
// -player position (on screen)
// -player position (on track)
// -track section
// -all lap times
// -score
//
// if called from other parts of the program, other than the 'F1' key, it should be resetting to the menu
// the 'F1' key is meant to reset the player on the current track they're on
//
}
void DrawTrack ( )
{
vecTrack . clear ( ) ;
for ( int i = 0 ; i < trackList [ track ] . curves . size ( ) ; i + + )
{
vecTrack . push_back ( trackList [ track ] . curves [ i ] ) ;
track_dist + = vecTrack [ i ] . second ;
}
}
//========================================================================================================================================
// main menu
//========================================================================================================================================
void DisplayMenu ( std : : vector < MenuItem > list )
{
// drawing and coloring menu selections
for ( int i = 0 ; i < list . size ( ) ; i + + )
{
olc : : vi2d textSize = GetTextSize ( list [ i ] . label ) / 2 * 4 ;
olc : : Pixel textCol = olc : : GREY ; // greys out unselected options
if ( highlighted = = i )
{
textCol = olc : : Pixel ( 255 , 201 , 14 ) ; // gold
}
DrawStringDecal ( list [ i ] . pos - textSize , list [ i ] . label , textCol , { 4.0f , 4.0f } ) ;
if ( list [ i ] . label2 . size ( ) > 0 )
{
olc : : vi2d offset = { ScreenWidth ( ) / 3 , - textSize . y / 2 } ;
DrawStringDecal ( list [ i ] . pos + offset , list [ i ] . label2 , textCol , { 4.0f , 4.0f } ) ;
}
}
// selecting options
highlighted = std : : clamp ( highlighted , 0 , ( int ) list . size ( ) - 1 ) ; // loop if out of range
int shortest = 9999999 ;
int largest = - 9999999 ;
int targetItem = highlighted ;
//========================================================================================================================================
if ( GetKey ( olc : : Key : : DOWN ) . bPressed )
{
for ( int i = 0 ; i < list . size ( ) ; i + + )
{
if ( highlighted ! = i )
{
if ( list [ highlighted ] . pos . x = = list [ i ] . pos . x )
{
if ( list [ highlighted ] . pos . y < list [ i ] . pos . y )
{
// it's below us
int dist = abs ( list [ highlighted ] . pos . y - list [ i ] . pos . y ) ;
if ( dist < shortest )
{
targetItem = i ;
shortest = dist ;
}
}
}
}
}
for ( int i = 0 ; i < list . size ( ) ; i + + )
{
if ( highlighted ! = i )
{
if ( list [ highlighted ] . pos . y < list [ i ] . pos . y )
{
// it's above us
int dist = abs ( list [ highlighted ] . pos . y - list [ i ] . pos . y ) ;
if ( dist < shortest )
{
targetItem = i ;
shortest = dist ;
}
}
}
}
// it failed, try another method
if ( highlighted = = targetItem )
{
targetItem = 0 ;
}
highlighted = targetItem ;
}
//========================================================================================================================================
if ( GetKey ( olc : : Key : : UP ) . bPressed )
{
for ( int i = 0 ; i < list . size ( ) ; i + + )
{
if ( highlighted ! = i )
{
if ( list [ highlighted ] . pos . x = = list [ i ] . pos . x )
{
if ( list [ highlighted ] . pos . y > list [ i ] . pos . y )
{
// it's above us
int dist = abs ( list [ highlighted ] . pos . y - list [ i ] . pos . y ) ;
if ( dist < shortest )
{
targetItem = i ;
shortest = dist ;
}
}
}
}
}
for ( int i = 0 ; i < list . size ( ) ; i + + )
{
if ( highlighted ! = i )
{
if ( list [ highlighted ] . pos . y > list [ i ] . pos . y )
{
// it's below us
int dist = abs ( list [ highlighted ] . pos . y - list [ i ] . pos . y ) ;
if ( dist < shortest )
{
targetItem = i ;
shortest = dist ;
}
}
}
}
// it failed, try another method
if ( highlighted = = targetItem )
{
targetItem = list . size ( ) - 1 ;
}
highlighted = targetItem ;
}
//========================================================================================================================================
if ( GetKey ( olc : : Key : : RIGHT ) . bPressed )
{
for ( int i = 0 ; i < list . size ( ) ; i + + )
{
if ( highlighted ! = i )
{
if ( list [ highlighted ] . pos . y = = list [ i ] . pos . y )
{
if ( list [ highlighted ] . pos . x < list [ i ] . pos . x )
{
// it's to the right
int dist = abs ( list [ highlighted ] . pos . x - list [ i ] . pos . x ) ;
if ( dist < shortest )
{
targetItem = i ;
shortest = dist ;
}
}
}
}
}
if ( highlighted = = targetItem )
{
for ( int i = 0 ; i < list . size ( ) ; i + + )
{
if ( highlighted ! = i )
{
if ( list [ highlighted ] . pos . y = = list [ i ] . pos . y )
{
if ( list [ highlighted ] . pos . x > list [ i ] . pos . x )
{
// it's to the left
int dist = abs ( list [ highlighted ] . pos . x - list [ i ] . pos . x ) ;
if ( dist > largest )
{
targetItem = i ;
largest = dist ;
}
}
}
}
}
}
highlighted = targetItem ;
}
//========================================================================================================================================
if ( GetKey ( olc : : Key : : LEFT ) . bPressed )
{
for ( int i = 0 ; i < list . size ( ) ; i + + )
{
if ( highlighted ! = i )
{
if ( list [ highlighted ] . pos . y = = list [ i ] . pos . y )
{
if ( list [ highlighted ] . pos . x > list [ i ] . pos . x )
{
// it's to the right
int dist = abs ( list [ highlighted ] . pos . x - list [ i ] . pos . x ) ;
if ( dist < shortest )
{
targetItem = i ;
shortest = dist ;
}
}
}
}
}
if ( highlighted = = targetItem )
{
for ( int i = 0 ; i < list . size ( ) ; i + + )
{
if ( highlighted ! = i )
{
if ( list [ highlighted ] . pos . y = = list [ i ] . pos . y )
{
if ( list [ highlighted ] . pos . x < list [ i ] . pos . x )
{
// it's to the left
int dist = abs ( list [ highlighted ] . pos . x - list [ i ] . pos . x ) ;
if ( dist > largest )
{
targetItem = i ;
largest = dist ;
}
}
}
}
}
}
highlighted = targetItem ;
}
//========================================
if ( highlighted > = ( int ) list . size ( ) )
{
highlighted = 0 ; // wrap around when above max
}
if ( highlighted < 0 )
{
highlighted = list . size ( ) - 1 ; // wrap around when below zero
}
}
//========================================================================================================================================
// controls
//========================================================================================================================================
void GetAnyKeyPress ( olc : : Key keypress ) override
{
if ( configKeyIndex ! = - 1 )
{
switch ( configKeyIndex )
{
case 0 :
{
Move_Up = keypress ;
} break ;
case 1 :
{
Move_Right = keypress ;
} break ;
case 2 :
{
Move_Left = keypress ;
} break ;
case 3 :
{
Move_Down = keypress ;
} break ;
}
controls [ configKeyIndex ] . label2 = KeyToString ( keypress ) ;
configKeyIndex = - 1 ;
}
}
//========================================================================================================================================
// Main Game Function
//========================================================================================================================================
bool OnUserUpdate ( float fElapsedTime ) override
{
if ( GetKey ( olc : : Key : : CTRL ) . bHeld & & GetKey ( olc : : Key : : F12 ) . bHeld & & ! bothKeysPressed )
{
return false ;
}
// draw skybox
GradientFillRectDecal ( { 0.0f , 0.0f } , { ScreenWidth ( ) + 0.0f , ScreenHeight ( ) / 2 + 0.0f } , olc : : DARK_BLUE , olc : : BLUE , olc : : BLUE , olc : : DARK_BLUE ) ;
// the hills have eyes; y'know, like in Super Mario Bros. What reference did you think was going to be here?
DrawPartialDecal ( { 0.0f , ScreenHeight ( ) / 2 - 100.0f } , hill , { 0.0f + track_curve * 200 , 0.0f } , { ScreenWidth ( ) + 0.0f , ( float ) hill - > sprite - > height } , { 1.5f , 1.0f } ) ;
//DrawPartialDecal({ 180.0f, ScreenHeight() / 2 - 100.0f }, hill, { 0.0f + track_curve * 200, 0.0f }, { ScreenWidth() + 0.0f, (float)hill->sprite->height });
DrawPartialWarpedDecal // draw grass
(
grass , { { 0.0f , ScreenHeight ( ) / 2 + 0.0f } ,
{ - ScreenWidth ( ) * 2 + 0.0f , ScreenHeight ( ) + 0.0f } ,
{ ScreenWidth ( ) * 2 + ScreenWidth ( ) + 0.0f , ScreenHeight ( ) + 0.0f } ,
{ ScreenWidth ( ) + 0.0f , ScreenHeight ( ) / 2 + 0.0f } } ,
{ 0.0f , - distance } , { 1 * 32 , 4 * 64 }
) ;
//========================================================================================================================================
if ( gameState = = state : : MAIN_MENU )
{
FillRectDecal ( { 0 , 0 } , { ScreenWidth ( ) + 0.f , ScreenHeight ( ) + 0.f } , olc : : Pixel ( 0 , 0 , 0 , 16 ) ) ;
// display title
DrawDecal ( { 95.5f , 95.5f } , title /*, {0.4f, 0.4f}*/ ) ;
DisplayMenu ( mainMenu ) ;
//DrawStringDecal({ ScreenWidth() / 2 + 0.0f, ScreenHeight() / 2 + 0.0f }, "START GAME", olc::WHITE, { 4.0f, 4.0f });
if ( GetKey ( olc : : Key : : ENTER ) . bPressed | | GetKey ( olc : : Key : : SPACE ) . bPressed )
{
// vertical menu
if ( highlighted = = 0 )
{
gameState = state : : PLAY_GAME ;
highlighted = 0 ;
}
else if ( highlighted = = 1 )
{
gameState = state : : CONTROLS ;
highlighted = 0 ;
}
else
{
return false ; // quit game
}
}
if ( GetKey ( olc : : Key : : ESCAPE ) . bPressed )
{
return false ; // exit via Escape key
}
}
//========================================================================================================================================
else if ( gameState = = state : : PLAY_GAME )
{
FillRectDecal ( { 0 , 0 } , { ScreenWidth ( ) + 0.f , ScreenHeight ( ) + 0.f } , olc : : Pixel ( 0 , 0 , 0 , 16 ) ) ;
DisplayMenu ( playGame ) ;
if ( GetKey ( olc : : Key : : ENTER ) . bPressed | | GetKey ( olc : : Key : : SPACE ) . bPressed )
{
// vertical menu
if ( highlighted = = 0 )
{
gameState = state : : TRACK_SELECT ;
highlighted = 0 ;
}
else if ( highlighted = = 1 )
{
gameState = state : : CUP_SELECT ;
highlighted = 0 ;
}
else
{
gameState = state : : MAIN_MENU ; // return to menu
highlighted = 0 ;
}
}
if ( GetKey ( olc : : Key : : ESCAPE ) . bPressed | | GetKey ( olc : : Key : : BACK ) . bPressed )
{
gameState = state : : MAIN_MENU ;
highlighted = 0 ;
}
}
//========================================================================================================================================
else if ( gameState = = state : : TRACK_SELECT )
{
FillRectDecal ( { 0 , 0 } , { ScreenWidth ( ) + 0.f , ScreenHeight ( ) + 0.f } , olc : : Pixel ( 0 , 0 , 0 , 16 ) ) ;
DisplayMenu ( pickTrack ) ;
if ( GetKey ( olc : : Key : : ENTER ) . bPressed | | GetKey ( olc : : Key : : SPACE ) . bPressed )
{
if ( highlighted > = 0 & & highlighted < = 8 )
{
track = highlighted + 1 ;
gameState = state : : CAR_SELECT ;
highlighted = 0 ;
}
else
{
gameState = state : : PLAY_GAME ;
highlighted = 0 ;
track = - 1 ;
}
}
if ( GetKey ( olc : : Key : : CTRL ) . bHeld & & GetKey ( olc : : Key : : F9 ) . bHeld )
{
// cheat code for Javidx9's original track
track = 0 ;
gameState = state : : CAR_SELECT ;
}
if ( GetKey ( olc : : Key : : ESCAPE ) . bPressed | | GetKey ( olc : : Key : : BACK ) . bPressed )
{
gameState = state : : PLAY_GAME ;
highlighted = 0 ;
}
}
//========================================================================================================================================
else if ( gameState = = state : : CUP_SELECT )
{
FillRectDecal ( { 0 , 0 } , { ScreenWidth ( ) + 0.f , ScreenHeight ( ) + 0.f } , olc : : Pixel ( 0 , 0 , 0 , 16 ) ) ;
DrawPartialDecal ( { ScreenWidth ( ) / 3 - 96.f , ScreenHeight ( ) / 3 - 192.f } , cups , { 0 , 0 } , { 64 , 64 } , { 3.0f , 3.0f } , ( highlighted = = 0 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // bronze
DrawPartialDecal ( { ScreenWidth ( ) / 3 * 2 - 96.f , ScreenHeight ( ) / 3 - 192.f } , cups , { 64 , 0 } , { 64 , 64 } , { 3.0f , 3.0f } , ( highlighted = = 1 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // silver
DrawPartialDecal ( { ScreenWidth ( ) / 3 - 96.f , ScreenHeight ( ) / 3 * 2 - 192.f } , cups , { 0 , 64 } , { 64 , 64 } , { 3.0f , 3.0f } , ( highlighted = = 2 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // gold
DrawPartialDecal ( { ScreenWidth ( ) / 3 * 2 - 96.f , ScreenHeight ( ) / 3 * 2 - 192.f } , cups , { 64 , 64 } , { 64 , 64 } , { 3.0f , 3.0f } , ( highlighted = = 3 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // platinum
DisplayMenu ( grandPrix ) ;
if ( GetKey ( olc : : Key : : ENTER ) . bPressed | | GetKey ( olc : : Key : : SPACE ) . bPressed )
{
// 2 x 2 menu
std : : array < state , 4 > gameStates = { state : : INDIE , state : : STREET , state : : PRO , state : : GRAND_PRIX } ;
if ( highlighted > = 0 & & highlighted < = 3 )
{
gameState = gameStates [ highlighted ] ;
cup = highlighted + 1 ;
gameState = state : : CAR_SELECT ;
tracks_left = 3 ;
track = 1 + highlighted * 3 ;
if ( highlighted = = 3 )
{
tracks_left = 9 ;
}
highlighted = 0 ;
}
//if (highlighted == 0)
//{
// gameState = state::INDIE;
// cup = 1;
// gameState = state::CAR_SELECT;
// highlighted = 0;
//}
//else if (highlighted == 1)
//{
// gameState = state::STREET;
// cup = 2;
// gameState = state::CAR_SELECT;
// highlighted = 0;
//}
//else if (highlighted == 2)
//{
// gameState = state::PRO;
// cup = 3;
// gameState = state::CAR_SELECT;
// highlighted = 0;
//}
//else if (highlighted == 3)
//{
// gameState = state::GRAND_PRIX;
// cup = 4;
// gameState = state::CAR_SELECT;
// highlighted = 0;
//}
else
{
gameState = state : : PLAY_GAME ; // return to menu
cup = - 1 ;
highlighted = 0 ;
}
}
if ( GetKey ( olc : : Key : : CTRL ) . bHeld & & GetKey ( olc : : Key : : F9 ) . bHeld )
{
// cheat code for Javidx9 Grand Prix Cup
// add's Javid's track to the end of the standard Grand Prix
cup = 0 ;
gameState = state : : CAR_SELECT ;
tracks_left = 10 ;
}
if ( GetKey ( olc : : Key : : ESCAPE ) . bPressed | | GetKey ( olc : : Key : : BACK ) . bPressed )
{
gameState = state : : PLAY_GAME ;
cup = - 1 ;
highlighted = 0 ;
}
}
//========================================================================================================================================
else if ( gameState = = state : : CAR_SELECT )
{
FillRectDecal ( { 0 , 0 } , { ScreenWidth ( ) + 0.f , ScreenHeight ( ) + 0.f } , olc : : Pixel ( 0 , 0 , 0 , 16 ) ) ;
DrawPartialDecal ( { ScreenWidth ( ) / 5 - 96.f , ScreenHeight ( ) / 3 - 192.f } , cars , { 0 , 0 } , { 256 , 192 } , { .75f , .75f } , ( highlighted = = 0 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // red
DrawPartialDecal ( { ScreenWidth ( ) / 5 * 2 - 96.f , ScreenHeight ( ) / 3 - 192.f } , cars , { 256 , 0 } , { 256 , 192 } , { .75f , .75f } , ( highlighted = = 1 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // blue
DrawPartialDecal ( { ScreenWidth ( ) / 5 * 3 - 96.f , ScreenHeight ( ) / 3 - 192.f } , cars , { 512 , 0 } , { 256 , 192 } , { .75f , .75f } , ( highlighted = = 2 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // green
DrawPartialDecal ( { ScreenWidth ( ) / 5 * 4 - 96.f , ScreenHeight ( ) / 3 - 192.f } , cars , { 768 , 0 } , { 256 , 192 } , { .75f , .75f } , ( highlighted = = 3 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // gold
DrawPartialDecal ( { ScreenWidth ( ) / 5 - 96.f , ScreenHeight ( ) / 3 * 2 - 192.f } , cars , { 0 , 192 } , { 256 , 192 } , { .75f , .75f } , ( highlighted = = 4 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // purple
DrawPartialDecal ( { ScreenWidth ( ) / 5 * 2 - 96.f , ScreenHeight ( ) / 3 * 2 - 192.f } , cars , { 256 , 192 } , { 256 , 192 } , { .75f , .75f } , ( highlighted = = 5 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // white
DrawPartialDecal ( { ScreenWidth ( ) / 5 * 3 - 96.f , ScreenHeight ( ) / 3 * 2 - 192.f } , cars , { 512 , 192 } , { 256 , 192 } , { .75f , .75f } , ( highlighted = = 6 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // orange
DrawPartialDecal ( { ScreenWidth ( ) / 5 * 4 - 96.f , ScreenHeight ( ) / 3 * 2 - 192.f } , cars , { 768 , 192 } , { 256 , 192 } , { .75f , .75f } , ( highlighted = = 7 ) ? olc : : WHITE : olc : : DARK_GREY ) ; // black
DisplayMenu ( selectCar ) ;
if ( GetKey ( olc : : Key : : ENTER ) . bPressed | | GetKey ( olc : : Key : : SPACE ) . bPressed )
{
if ( highlighted > = 0 & & highlighted < = 7 )
{
player = highlighted ;
gameState = state : : RUN_GAME ;
DrawTrack ( ) ;
//vecTrack.clear();
//for (int i = 0; i < trackList[track].size(); i++)
//{
// vecTrack.push_back(trackList[track][i]);
// track_dist += vecTrack[i].second;
//}
}
else
{
if ( cup ! = - 1 )
{
// return to cup select
gameState = state : : CUP_SELECT ;
}
if ( track ! = - 1 )
{
// return to track select
gameState = state : : TRACK_SELECT ;
}
highlighted = 0 ;
}
}
if ( GetKey ( olc : : Key : : ESCAPE ) . bPressed | | GetKey ( olc : : Key : : BACK ) . bPressed )
{
if ( cup ! = - 1 )
{
// return to cup select
gameState = state : : CUP_SELECT ;
}
if ( track ! = - 1 )
{
// return to track select
gameState = state : : TRACK_SELECT ;
}
highlighted = 0 ;
}
}
//========================================================================================================================================
else if ( gameState = = state : : CONTROLS )
{
FillRectDecal ( { 0 , 0 } , { ScreenWidth ( ) + 0.f , ScreenHeight ( ) + 0.f } , olc : : Pixel ( 0 , 0 , 0 , 16 ) ) ;
DisplayMenu ( controls ) ;
if ( GetKey ( olc : : Key : : ENTER ) . bPressed | | GetKey ( olc : : Key : : SPACE ) . bPressed )
{
if ( highlighted > = 0 & & highlighted < = 3 )
{
configKeyIndex = highlighted ;
}
else if ( highlighted = = 4 )
{
// reset default controls
DisplayMenu ( controls ) ;
Move_Up = olc : : W ;
Move_Down = olc : : S ;
Move_Left = olc : : A ;
Move_Right = olc : : D ;
}
else
{
gameState = state : : MAIN_MENU ;
highlighted = 0 ;
}
}
if ( GetKey ( olc : : Key : : ESCAPE ) . bPressed | | GetKey ( olc : : Key : : BACK ) . bPressed )
{
gameState = state : : MAIN_MENU ;
}
}
//========================================================================================================================================
else if ( gameState = = state : : PAUSED ) // pause menu
{
FillRectDecal ( { 0 , 0 } , { ScreenWidth ( ) + 0.f , ScreenHeight ( ) + 0.f } , olc : : Pixel ( 0 , 0 , 0 , 64 ) ) ;
DisplayMenu ( pause ) ;
if ( GetKey ( olc : : Key : : ENTER ) . bPressed | | GetKey ( olc : : Key : : SPACE ) . bPressed )
{
if ( highlighted = = 0 )
{
gameState = state : : RUN_GAME ;
highlighted = 0 ;
}
if ( highlighted = = 1 )
{
// restart the track
// this will ONLY work on tracks after the track selection screen
// or on the first track in each cup (1, 4, 7, 1)
Reset ( ) ;
gameState = state : : RUN_GAME ;
highlighted = 0 ;
}
if ( highlighted = = 2 )
{
// main menu
Reset ( ) ;
gameState = state : : MAIN_MENU ;
highlighted = 0 ;
}
if ( highlighted = = 3 )
{
return false ;
}
}
}
//========================================================================================================================================
//========================================================================================================================================
else if ( gameState = = state : : RUN_GAME ) // run main game loop
{
Clear ( olc : : BLACK ) ; // this still needed? we've since replaced it with the gradient sky box
if ( GetKey ( olc : : Key : : ESCAPE ) . bPressed | | GetKey ( olc : : Key : : PAUSE ) . bPressed )
{
gameState = state : : PAUSED ;
}
// debug quick-reset
if ( GetKey ( olc : : Key : : F4 ) . bPressed )
{
Reset ( ) ;
}
// jump to end of lap
if ( GetKey ( olc : : Key : : F12 ) . bPressed )
{
distance = track_dist - 50.f ;
}
// get a point on the track
float offset = 0 ;
int TrackSection = 0 ;
cur_lap_time + = fElapsedTime ;
// record lap time
if ( distance > = track_dist )
{
distance - = track_dist ;
list_times . push_front ( cur_lap_time ) ; // push time to front
list_times . pop_back ( ) ; // pop time to back
cur_lap_time = 0.0f ;
lap + + ;
}
if ( cup > = 0 & & lap > = 1 )
{
track + + ;
Reset ( ) ;
DrawTrack ( ) ;
}
if ( track ! = - 1 )
{
//olc::vi2d textSize = GetTextSize() / 2 * 4;
olc : : vi2d textSize0 = GetTextSize ( " JAVIDX9 " ) / 2 * 4 ;
olc : : vi2d textSize1 = GetTextSize ( " CIRCUIT " ) / 2 * 4 ;
switch ( track )
{
case 0 :
DrawStringDecal ( { ScreenWidth ( ) / 2 - 0.f , ScreenHeight ( ) / 8 + 0.f } , " JAVIDX9 " , olc : : WHITE , { 3.f , 3.f } ) ;
break ;
case 1 :
DrawStringDecal ( { ScreenWidth ( ) / 2 - 0.f , ScreenHeight ( ) / 8 + 0.f } , " CIRCUIT " , olc : : WHITE , { 3.f , 3.f } ) ;
break ;
case 2 :
DrawStringDecal ( { ScreenWidth ( ) / 2 - 0.f , ScreenHeight ( ) / 8 + 0.f } , " INFINITY " , olc : : WHITE , { 3.f , 3.f } ) ;
break ;
case 3 :
DrawStringDecal ( { ScreenWidth ( ) / 2 - 0.f , ScreenHeight ( ) / 8 + 0.f } , " ARROWHEAD " , olc : : WHITE , { 3.f , 3.f } ) ;
break ;
case 4 :
DrawStringDecal ( { ScreenWidth ( ) / 2 - 0.f , ScreenHeight ( ) / 8 + 0.f } , " TRACK 4 " , olc : : WHITE , { 3.f , 3.f } ) ;
break ;
case 5 :
DrawStringDecal ( { ScreenWidth ( ) / 2 - 0.f , ScreenHeight ( ) / 8 + 0.f } , " OVERPASS " , olc : : WHITE , { 3.f , 3.f } ) ;
break ;
case 6 :
DrawStringDecal ( { ScreenWidth ( ) / 2 - 0.f , ScreenHeight ( ) / 8 + 0.f } , " PEANUT " , olc : : WHITE , { 3.f , 3.f } ) ;
break ;
case 7 :
DrawStringDecal ( { ScreenWidth ( ) / 2 - 0.f , ScreenHeight ( ) / 8 + 0.f } , " TRACK 7 " , olc : : WHITE , { 3.f , 3.f } ) ;
break ;
case 8 :
DrawStringDecal ( { ScreenWidth ( ) / 2 - 0.f , ScreenHeight ( ) / 8 + 0.f } , " TRIDENT " , olc : : WHITE , { 3.f , 3.f } ) ;
break ;
case 9 :
DrawStringDecal ( { ScreenWidth ( ) / 2 - 0.f , ScreenHeight ( ) / 8 + 0.f } , " STAR " , olc : : WHITE , { 3.f , 3.f } ) ;
break ;
}
}
// find position on track (could optimize) << should probably optimize given the complexity of this game
while ( TrackSection < vecTrack . size ( ) & & offset < = distance )
{
offset + = vecTrack [ TrackSection ] . second ;
TrackSection + + ;
}
float TargetCurvature = vecTrack [ TrackSection - 1 ] . first ; // drawing curves to screen
float TrackCurveDiff = ( TargetCurvature - curvature ) * fElapsedTime * speed ; // correcting the drawing of curves to the screen
curvature + = TrackCurveDiff ; // update track curve difference
track_curve + = ( curvature ) * fElapsedTime * speed ;
//========================================================================================================================================
// | | draw racetrack canvas
//========================================================================================================================================
std : : vector < olc : : vf2d > pos ;
std : : vector < olc : : vf2d > uvs ;
for ( int y = 0 ; y < ScreenHeight ( ) / 2 ; y + + )
{
// racetrack canvas variables
float perspective = ( float ) y / ( ScreenHeight ( ) / 2.0f ) ;
float mid_point = 0.5f + curvature * powf ( ( 1.0f - perspective ) , 3 ) ;
float road_width = 0.1f + perspective * 0.8f ;
float curb_width = road_width * 0.15f ;
road_width * = 0.5f ;
int lf_curb = ( mid_point - road_width ) * ScreenWidth ( ) ;
int rt_curb = ( mid_point + road_width ) * ScreenWidth ( ) ;
int row = ScreenHeight ( ) / 2 + y ;
float horizon = powf ( 1.0f - perspective , 2 ) * 80 ;
// check for finish line
if ( distance + horizon > track_dist - 20 & & distance + horizon < track_dist )
{
// draw checkerboard pattern
uvs . push_back ( { 0 , ( float ) fmod ( ( ( distance + horizon ) - ( track_dist - 20 ) ) / 20.0f , 0.5f ) + 0.5f } ) ;
uvs . push_back ( { 1 , ( float ) fmod ( ( ( distance + horizon ) - ( track_dist - 20 ) ) / 20.0f , 0.5f ) + 0.5f } ) ;
}
else
{
// draw standard track piece
uvs . push_back ( { 0 , sinf ( 80.0f * powf ( 1.0f - perspective , 2 ) + distance ) / 4 + 0.25f } ) ;
uvs . push_back ( { 1 , sinf ( 80.0f * powf ( 1.0f - perspective , 2 ) + distance ) / 4 + 0.25f } ) ;
}
// drawing grass and curb
pos . push_back ( { lf_curb + 0.0f , row + 0.0f } ) ;
pos . push_back ( { rt_curb + 0.0f , row + 0.0f } ) ;
// black box rendering shenanigans; if I ever understand programming enough at a later date, I can figure out wtf is going on here
int i = 0 ;
for ( Object & obj : gameObjects )
{
float horizonRange = powf ( 1.0f - perspective , 2 ) * ( ( distance + horizon ) - obj . pos . y ) / horizon ;
if ( ! obj . rendered & & ( distance + horizon ) > obj . pos . y & & ( distance + horizon ) < obj . pos . y + 80 & & row > = ScreenHeight ( ) / 2 + ScreenHeight ( ) / 2 * horizonRange )
{
obj . drawPos = { ( mid_point + road_width * obj . pos . x ) * ScreenWidth ( ) , horizonRange * ( ScreenHeight ( ) / 2 ) + ScreenHeight ( ) / 2 } ;
obj . drawOffsetPos = { obj . offset . x , obj . size . y * road_width * - obj . offset . y } ;
obj . drawSize = { obj . size . x * road_width , obj . size . y * road_width } ;
obj . rendered = true ;
// yeah.... so, even after copying it manually, i still have no clue what this thing is doing, lol
}
}
}
// on the road again; drawing the track
SetDecalStructure ( olc : : DecalStructure : : STRIP ) ;
DrawPolygonDecal ( road , pos , uvs ) ;
SetDecalStructure ( olc : : DecalStructure : : FAN ) ;
// draw trackside props
for ( Object & obj : gameObjects )
{
if ( obj . rendered )
{
if ( obj . decal ! = nullptr )
{
DrawDecal ( obj . drawPos + obj . drawOffsetPos , obj . decal , obj . drawSize ) ;
}
else
{
FillRectDecal ( obj . drawPos , obj . drawSize , olc : : BLUE ) ;
}
}
}
//========================================================================================================================================
// | | car movement
//========================================================================================================================================
int car_dir = 0 ; // default car facing
if ( GetKey ( Move_Up ) . bHeld )
{
speed + = 2.0f * fElapsedTime ;
}
else // might remove this in a later stage of development
{
speed - = 1.0f * fElapsedTime ;
}
if ( GetKey ( Move_Down ) . bHeld )
{
// move back ?
distance - = 20.0f * fElapsedTime ;
}
if ( GetKey ( Move_Left ) . bHeld )
{
car_curve - = 0.7f * fElapsedTime ;
car_dir = - 1 ;
}
if ( GetKey ( Move_Right ) . bHeld )
{
car_curve + = 0.7f * fElapsedTime ;
car_dir = + 1 ;
}
// slow car if on grass
if ( fabs ( car_curve - track_curve ) > = 0.8f )
{
speed - = 5.0f * fElapsedTime ;
}
// clamp speed
if ( speed < 0.0f ) speed = 0.0f ;
if ( speed > 1.0f ) speed = 1.0f ;
// move car along track according to car speed
distance + = ( 70.0f * speed ) * fElapsedTime ;
// draw car
car_pos = car_curve - track_curve ;
DrawDecal ( { ScreenWidth ( ) / 2 - 128 + car_pos * ScreenWidth ( ) / 2 , ScreenHeight ( ) / 4 * 3.0f - 128 } , car ) ;
SetPixelMode ( olc : : Pixel : : ALPHA ) ;
//========================================================================================================================================
//========================================================================================================================================
// spedometer
std : : string mph = std : : to_string ( speed ) ;
DrawString ( 4 , 4 , mph ) ;
// show time
auto disp_time = [ ] ( float t )
{
int min = t / 60.0f ;
int sec = t - ( min * 60.0f ) ;
int milli = ( t - ( float ) sec ) * 1000.0f ;
// need to change this out to a 'DrawString()' function instead
return std : : to_string ( min ) + " . " + std : : to_string ( sec ) + " : " + std : : to_string ( milli ) ;
} ;
// correct for the first '0' in the seconds timer
//if ()
//{
// // draw min + '0' + sec + milli
// DrawString(4, 16, disp_time(cur_lap_time));
//}
//else
//{
DrawString ( 4 , 16 , disp_time ( cur_lap_time ) ) ;
//}
// display last 5 lap times
int j = 30 ;
for ( auto l : list_times )
{
DrawString ( 10 , j , disp_time ( l ) ) ;
j + = 10 ;
}
// debug code
//std::string numb1 = std::to_string(car_pos);
//DrawString(4, 26, numb1);
//std::string numb2 = std::to_string(track_dist);
//DrawString(4, 38, numb2);
}
return true ;
}
} ;
//========================================================================================================================================
int main ( )
{
std : : vector < std : : string > test = { " Apple " , " Apple " , " Pear " , " Something " , " Tire " , " Orange " , " Orange " , " Orange " } ;
std : : vector < std : : string > : : iterator it = std : : unique ( test . begin ( ) , test . end ( ) ) ;
test . erase ( it , test . end ( ) ) ;
for ( int i = 0 ; i < test . size ( ) ; i + + ) {
std : : cout < < test [ i ] < < " \n " ;
}
Racer game ;
if ( game . Construct ( 1280 , 720 , 1 , 1 ) )
game . Start ( ) ;
return 0 ;
}
//========================================================================================================================================
// END OF FILE
//========================================================================================================================================