2014-05-29 12:50:57 -04:00
/*
* Intelligent SNAKE
*
* Description : A simple snake clone written in C and SDL
* Author : Kevin MacMartin
* E - Mail : prurigro @ gmail . com
*
* This project is licensed under the the MIT License ( MIT ) :
*
* Copyright ( c ) 2014 Kevin MacMartin
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
* This projected is licensed under the terms of the MIT license
*
*/
# include <stdio.h>
# include <stdbool.h>
# include <time.h>
# include <SDL/SDL.h>
# include <SDL/SDL_ttf.h>
2020-10-23 16:43:41 -04:00
// TITLE OF THE WINDOW
2014-05-29 12:50:57 -04:00
# define GAMENAME "Intelligent Snake"
2020-10-23 16:43:41 -04:00
// FONT AND FONTSIZE
2014-05-29 12:50:57 -04:00
# define DEFAULT_FONT_FILE "DroidSans-Bold.ttf"
# define DEFAULT_FONT_SIZE 22
2020-10-23 16:43:41 -04:00
// HEIGHT AND WIDTH OF EACH TILE
2014-05-29 12:50:57 -04:00
# define TILEWIDTH 20
# define TILEHEIGHT 20
2020-10-23 16:43:41 -04:00
// MIN+MAX+DEFAULT TILE ROWS AND COLUMNS
2014-05-29 12:50:57 -04:00
# define MIN_TILESWIDE 30
# define MIN_TILESHIGH 20
# define MAX_TILESWIDE 80
# define MAX_TILESHIGH 50
# define DEFAULT_TILESWIDE 50
# define DEFAULT_TILESHIGH 30
2020-10-23 16:43:41 -04:00
// MIN+MAX+DEFAULT SNAKESPEED
2014-05-29 12:50:57 -04:00
# define MIN_SNAKESPEED 1
# define MAX_SNAKESPEED 9
# define DEFAULT_SNAKESPEED 1
2020-10-23 16:43:41 -04:00
// SNAKE LENGTH (+1 FOR BUFFER)
2014-05-29 12:50:57 -04:00
# define MIN_SNAKELENGTH 4
# define MAX_SNAKELENGTH 36
# define DEFAULT_SNAKELENGTH 4
2020-10-23 16:43:41 -04:00
// NUMBER OF NPCs (# OF BLOCKS + 1 FOR FOOD)
2014-05-29 12:50:57 -04:00
# define MIN_NPCCOUNT 1
# define MAX_NPCCOUNT 41
# define DEFAULT_NPCCOUNT 21
2020-10-23 16:43:41 -04:00
// AMOUNT OF FOOD EATEN BEFORE SNAKESPEED INCREASES
2014-05-29 12:50:57 -04:00
# define ACCEL_FREQ 3
2020-10-23 16:43:41 -04:00
// WHETHER TO DISPLAY COMMANDLINE OUTPUT DURING GAMEPLAY
2014-05-29 12:50:57 -04:00
# define CONSOLE_OUTPUT true
2020-10-23 16:43:41 -04:00
// CONSTANT VALUES
const int colourFood [ 3 ] = { 255 , 0 , 0 } ; // Bright Red
const int colourHead [ 3 ] = { 215 , 95 , 95 } ; // Red
const int colourBody [ 3 ] = { 135 , 215 , 255 } ; // Blue
const int colourTail [ 3 ] = { 255 , 215 , 135 } ; // Yellow
const int colourBlock [ 3 ] = { 234 , 234 , 234 } ; // White
const int colourTiles [ 3 ] = { 38 , 38 , 38 } ; // Dark Grey
const int colourBackground [ 3 ] = { 48 , 48 , 48 } ; // Light Grey
const int colourTextGameOver [ 3 ] = { 234 , 234 , 234 } ; // White
const int colourTextLabel [ 3 ] = { 215 , 95 , 95 } ; // Red
const int colourTextData [ 3 ] = { 135 , 215 , 255 } ; // Blue
// ENUMERATIONS FOR MORE READABLE CODE
enum direction { Up , Down , Left , Right } ; // Movement directions
2014-05-29 12:50:57 -04:00
enum gameParams { QuitGame , TilesHigh , TilesWide , NPCCount , SnakeSpeed , SnakeLength , SnakeDirection , SnakeScore } ;
2020-10-23 16:43:41 -04:00
// GAME FUNCTIONS
2014-05-29 12:50:57 -04:00
void gameLoop ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] , SDL_Event * event ) ;
2020-10-23 16:43:41 -04:00
void moveSnake ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] , enum direction newDirection ) ;
2014-05-29 12:50:57 -04:00
bool collisionDetect ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] , enum direction newDirection ) ;
void collisionDetectFood ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] ) ;
bool gameEventPoll ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] , SDL_Event * event ) ;
bool scrollSnake ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] ) ;
void updateSnake ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] ) ;
void loadNPCs ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] ) ;
void randomLocation ( int * * ppSprites , int ( * gameParameters ) [ 8 ] , int * location [ 2 ] ) ;
void drawText ( SDL_Surface * screen , char * string , int size , int x , int y , SDL_Colour colour ) ;
void updateRect ( SDL_Surface * screen , SDL_Rect * * ppTiles , int position [ 2 ] , const int colour [ 3 ] ) ;
2020-10-23 16:43:41 -04:00
// COMMANDLINE FUNCTIONS
2014-05-29 12:50:57 -04:00
void configureGame ( int argc , char * * args , int ( * gameParameters ) [ 8 ] ) ;
void printHelpMenu ( char filename [ ] ) ;
void printErrorHelp ( char filename [ ] ) ;
2020-10-23 16:43:41 -04:00
// MAIN LOOP
int main ( int argc , char * args [ ] ) {
2014-05-29 12:50:57 -04:00
int x , y , gameParameters [ 8 ] ;
int * * ppSprites = NULL ;
int * pSprites = NULL ;
SDL_Surface * screen = NULL ;
SDL_Rect * * ppTiles = NULL ;
SDL_Rect * pTiles = NULL ;
SDL_Event event ;
2020-10-23 16:43:41 -04:00
// START RANDOM SEED TO HELP MAKE RANDOM NUMBERS MORE RANDOM
2014-05-29 12:50:57 -04:00
srand ( time ( NULL ) ) ;
2020-10-23 16:43:41 -04:00
// CONFIGURE GAME SETTINGS USING DEFAULTS AND USER INPUT
2014-05-29 12:50:57 -04:00
configureGame ( argc , args , & gameParameters ) ;
2020-10-23 16:43:41 -04:00
// INITIALIZE SDL
if ( SDL_Init ( SDL_INIT_VIDEO | SDL_INIT_TIMER ) ! = 0 ) {
2014-08-20 03:44:01 -04:00
fprintf ( stderr , " \n Unable to initialize SDL: %s \n " , SDL_GetError ( ) ) ;
2014-05-29 12:50:57 -04:00
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
2014-05-29 12:50:57 -04:00
atexit ( SDL_Quit ) ;
2020-10-23 16:43:41 -04:00
// INITIALIZE SDL_ttf
if ( TTF_Init ( ) ! = 0 ) {
2014-08-20 03:44:01 -04:00
fprintf ( stderr , " \n Unable to initialize SDL: %s \n " , SDL_GetError ( ) ) ;
2014-05-29 12:50:57 -04:00
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
2014-05-29 12:50:57 -04:00
atexit ( TTF_Quit ) ;
2020-10-23 16:43:41 -04:00
// INITIALIZE THE MAIN SURFACE
if ( ( screen = SDL_SetVideoMode ( ( TILEWIDTH * gameParameters [ TilesWide ] ) , ( TILEHEIGHT * gameParameters [ TilesHigh ] ) + 35 , 32 , SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_ANYFORMAT ) ) = = NULL ) {
2014-08-20 03:44:01 -04:00
fprintf ( stderr , " \n Unable to initialize SDL: %s \n " , SDL_GetError ( ) ) ;
2014-05-29 12:50:57 -04:00
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
// SET THE INPUT QUEUE TO IGNORE INPUT VIA MOUSE MOVEMENT
2014-05-29 12:50:57 -04:00
SDL_EventState ( SDL_MOUSEMOTION , SDL_IGNORE ) ;
2020-10-23 16:43:41 -04:00
// SET WINDOW TITLE
2014-05-29 12:50:57 -04:00
SDL_WM_SetCaption ( GAMENAME , NULL ) ;
2020-10-23 16:43:41 -04:00
// SET BACKGROUND COLOUR
2014-05-29 12:50:57 -04:00
SDL_FillRect ( screen , NULL , SDL_MapRGB ( screen - > format , colourBackground [ 0 ] , colourBackground [ 1 ] , colourBackground [ 2 ] ) ) ;
2020-10-23 16:43:41 -04:00
while ( gameParameters [ QuitGame ] = = 0 ) {
// INIT TILES ARRAY
2014-05-29 12:50:57 -04:00
pTiles = malloc ( gameParameters [ TilesWide ] * sizeof ( SDL_Rect ) ) ;
ppTiles = malloc ( gameParameters [ TilesHigh ] * sizeof ( SDL_Rect * ) ) ;
2020-10-23 16:43:41 -04:00
for ( x = 0 ; x < gameParameters [ TilesHigh ] ; x + + ) {
2014-05-29 12:50:57 -04:00
ppTiles [ x ] = malloc ( gameParameters [ TilesWide ] * sizeof ( SDL_Rect ) ) ;
2020-10-23 16:43:41 -04:00
}
for ( x = 0 ; x < gameParameters [ TilesHigh ] ; x + + ) {
for ( y = 0 ; y < gameParameters [ TilesWide ] ; y + + ) {
2014-05-29 12:50:57 -04:00
ppTiles [ x ] [ y ] . w = TILEWIDTH - ( TILEWIDTH / 10 ) ;
ppTiles [ x ] [ y ] . h = TILEHEIGHT - ( TILEHEIGHT / 10 ) ;
ppTiles [ x ] [ y ] . x = ( ( ppTiles [ x ] [ y ] . w + ( TILEWIDTH / 10 ) ) * y ) ;
ppTiles [ x ] [ y ] . y = ( ( ppTiles [ x ] [ y ] . h + ( TILEHEIGHT / 10 ) ) * x ) ;
SDL_FillRect ( screen , & ppTiles [ x ] [ y ] , SDL_MapRGB ( screen - > format , colourTiles [ 0 ] , colourTiles [ 1 ] , colourTiles [ 2 ] ) ) ;
}
2020-10-23 16:43:41 -04:00
}
2014-05-29 12:50:57 -04:00
2020-10-23 16:43:41 -04:00
// INIT SPRITES ARRAY
2014-05-29 12:50:57 -04:00
pSprites = malloc ( 2 * sizeof ( int ) ) ;
2020-10-23 16:43:41 -04:00
ppSprites = malloc ( ( gameParameters [ NPCCount ] + MAX_SNAKELENGTH ) * sizeof ( int * ) ) ; // The array is defined by the snake's maximum size so it can grow during gameplay
for ( x = 0 ; x < gameParameters [ NPCCount ] + MAX_SNAKELENGTH ; x + + ) {
2014-05-29 12:50:57 -04:00
ppSprites [ x ] = malloc ( 2 * sizeof ( int ) ) ;
ppSprites [ x ] [ 0 ] = 0 ;
ppSprites [ x ] [ 1 ] = 0 ;
}
2020-10-23 16:43:41 -04:00
// SET SNAKE START POSITION
for ( x = gameParameters [ NPCCount ] ; x < gameParameters [ NPCCount ] + gameParameters [ SnakeLength ] ; x + + ) {
2014-05-29 12:50:57 -04:00
ppSprites [ x ] [ 0 ] = 3 ;
ppSprites [ x ] [ 1 ] = ( 3 + gameParameters [ NPCCount ] + gameParameters [ SnakeLength ] - DEFAULT_SNAKELENGTH + 2 - x ) ;
}
2020-10-23 16:43:41 -04:00
// SET NPC LOCATIONS
for ( x = 0 ; x < gameParameters [ NPCCount ] ; x + + ) {
2014-05-29 12:50:57 -04:00
randomLocation ( ppSprites , & gameParameters , & ( ppSprites ) [ x ] ) ;
2020-10-23 16:43:41 -04:00
}
2014-05-29 12:50:57 -04:00
2020-10-23 16:43:41 -04:00
// GAME LOOP
2014-05-29 12:50:57 -04:00
gameLoop ( screen , ppTiles , ppSprites , & gameParameters , & event ) ;
2020-10-23 16:43:41 -04:00
// FREE MEMORY AND RESET POINTERS
2014-05-29 12:50:57 -04:00
free ( ppTiles ) ;
free ( ppSprites ) ;
ppSprites = NULL ;
pSprites = NULL ;
2020-10-23 16:43:41 -04:00
// RESET GAME SETTINGS USING DEFAULTS AND USER INPUT
if ( gameParameters [ QuitGame ] = = 0 ) {
configureGame ( argc , args , & gameParameters ) ;
}
2014-05-29 12:50:57 -04:00
}
2020-10-23 16:43:41 -04:00
// FREEING THE SCREEN SURFACE BEFORE EXITING
2014-05-29 12:50:57 -04:00
SDL_FreeSurface ( screen ) ;
2020-10-23 16:43:41 -04:00
// EXIT THE PROGRAM
2014-05-29 12:50:57 -04:00
exit ( EXIT_SUCCESS ) ;
}
2020-10-23 16:43:41 -04:00
// GAME LOOP
void gameLoop ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] , SDL_Event * event ) {
2014-05-29 12:50:57 -04:00
SDL_Colour SDL_ColourBackground = { colourBackground [ 0 ] , colourBackground [ 1 ] , colourBackground [ 2 ] } ;
SDL_Colour SDL_ColourTextLabel = { colourTextLabel [ 0 ] , colourTextLabel [ 1 ] , colourTextLabel [ 2 ] } ;
SDL_Colour SDL_ColourTextData = { colourTextData [ 0 ] , colourTextData [ 1 ] , colourTextData [ 2 ] } ;
SDL_Colour SDL_ColourTextGameOver = { colourTextGameOver [ 0 ] , colourTextGameOver [ 1 ] , colourTextGameOver [ 2 ] } ;
int scoreLabelPosition [ 2 ] = { 15 , ( TILEHEIGHT * ( * gameParameters ) [ TilesHigh ] ) + 4 } ;
int scoreDataPosition [ 2 ] = { 95 , ( TILEHEIGHT * ( * gameParameters ) [ TilesHigh ] ) + 4 } ;
int speedLabelPosition [ 2 ] = { ( TILEWIDTH * ( * gameParameters ) [ TilesWide ] ) - 100 , ( TILEHEIGHT * ( * gameParameters ) [ TilesHigh ] ) + 4 } ;
int speedDataPosition [ 2 ] = { ( TILEWIDTH * ( * gameParameters ) [ TilesWide ] ) - 25 , ( TILEHEIGHT * ( * gameParameters ) [ TilesHigh ] ) + 4 } ;
int gameOverMsgPosition [ 5 ] = { ( TILEWIDTH * ( ( * gameParameters ) [ TilesWide ] / 2 ) ) - 147 , ( TILEWIDTH * ( ( * gameParameters ) [ TilesWide ] / 2 ) ) - 50 , ( TILEWIDTH * ( ( * gameParameters ) [ TilesWide ] / 2 ) ) + 61 , ( TILEWIDTH * ( ( * gameParameters ) [ TilesWide ] / 2 ) ) + 82 , ( TILEHEIGHT * ( * gameParameters ) [ TilesHigh ] ) + 9 } ;
char * gameOverMsg [ 4 ] = { " GAME OVER " , " SPACE to RESTART " , " or " , " ESC to QUIT " } ;
char tempString [ 2 ] [ 3 ] = { " -1 " , " -1 " } ;
2020-10-23 16:43:41 -04:00
// LOAD BLOCKS AND FOOD
2014-05-29 12:50:57 -04:00
loadNPCs ( screen , ppTiles , ppSprites , gameParameters ) ;
2020-10-23 16:43:41 -04:00
// DRAW LABELS FOR SCORE AND SPEED RESPECTIVELY
2014-05-29 12:50:57 -04:00
drawText ( screen , " SCORE " , DEFAULT_FONT_SIZE , scoreLabelPosition [ 0 ] , scoreLabelPosition [ 1 ] , SDL_ColourTextLabel ) ;
drawText ( screen , " SPEED " , DEFAULT_FONT_SIZE , speedLabelPosition [ 0 ] , speedLabelPosition [ 1 ] , SDL_ColourTextLabel ) ;
2020-10-23 16:43:41 -04:00
// LOOP UNTIL GAME IS FINISHED
while ( 1 ) {
// UPDATE THE SNAKE'S SCORE WHEN IT CHANGES
if ( atoi ( tempString [ 0 ] ) ! = ( * gameParameters ) [ SnakeScore ] ) {
if ( atoi ( tempString [ 0 ] ) ! = - 1 ) {
2014-05-29 12:50:57 -04:00
drawText ( screen , tempString [ 0 ] , DEFAULT_FONT_SIZE , scoreDataPosition [ 0 ] , scoreDataPosition [ 1 ] , SDL_ColourBackground ) ;
2020-10-23 16:43:41 -04:00
}
2014-05-29 12:50:57 -04:00
sprintf ( tempString [ 0 ] , " %d " , ( * gameParameters ) [ SnakeScore ] ) ;
drawText ( screen , tempString [ 0 ] , DEFAULT_FONT_SIZE , scoreDataPosition [ 0 ] , scoreDataPosition [ 1 ] , SDL_ColourTextData ) ;
}
2020-10-23 16:43:41 -04:00
// UPDATE THE SNAKE'S SPEED WHEN IT CHANGES
if ( atoi ( tempString [ 1 ] ) ! = ( * gameParameters ) [ SnakeSpeed ] ) {
if ( atoi ( tempString [ 1 ] ) ! = - 1 ) {
2014-05-29 12:50:57 -04:00
drawText ( screen , tempString [ 1 ] , DEFAULT_FONT_SIZE , speedDataPosition [ 0 ] , speedDataPosition [ 1 ] , SDL_ColourBackground ) ;
2020-10-23 16:43:41 -04:00
}
2014-05-29 12:50:57 -04:00
sprintf ( tempString [ 1 ] , " %d " , ( * gameParameters ) [ SnakeSpeed ] ) ;
drawText ( screen , tempString [ 1 ] , DEFAULT_FONT_SIZE , speedDataPosition [ 0 ] , speedDataPosition [ 1 ] , SDL_ColourTextData ) ;
}
2020-10-23 16:43:41 -04:00
if ( gameEventPoll ( screen , ppTiles , ppSprites , gameParameters , event ) = = false ) {
break ;
}
2014-05-29 12:50:57 -04:00
updateSnake ( screen , ppTiles , ppSprites , gameParameters ) ;
SDL_Flip ( screen ) ;
SDL_Delay ( 250 / ( ( * gameParameters ) [ SnakeSpeed ] + 3 ) ) ;
2020-10-23 16:43:41 -04:00
if ( scrollSnake ( screen , ppTiles , ppSprites , gameParameters ) = = false ) {
break ;
}
2014-05-29 12:50:57 -04:00
updateSnake ( screen , ppTiles , ppSprites , gameParameters ) ;
SDL_Flip ( screen ) ;
SDL_Delay ( 250 / ( ( * gameParameters ) [ SnakeSpeed ] + 3 ) ) ;
2020-10-23 16:43:41 -04:00
if ( gameEventPoll ( screen , ppTiles , ppSprites , gameParameters , event ) = = false ) {
break ;
}
2014-05-29 12:50:57 -04:00
updateSnake ( screen , ppTiles , ppSprites , gameParameters ) ;
SDL_Flip ( screen ) ;
}
2020-10-23 16:43:41 -04:00
// DISPLAY GAME OVER MESSAGE AND WAIT FOR INPUT
if ( ( * gameParameters ) [ QuitGame ] = = 0 ) {
// DISPLAY GAMEOVER MESSAGES
2014-05-29 12:50:57 -04:00
drawText ( screen , gameOverMsg [ 0 ] , DEFAULT_FONT_SIZE - 7 , gameOverMsgPosition [ 0 ] , gameOverMsgPosition [ 4 ] , SDL_ColourTextGameOver ) ;
drawText ( screen , gameOverMsg [ 1 ] , DEFAULT_FONT_SIZE - 9 , gameOverMsgPosition [ 1 ] , gameOverMsgPosition [ 4 ] , SDL_ColourTextData ) ;
drawText ( screen , gameOverMsg [ 2 ] , DEFAULT_FONT_SIZE - 9 , gameOverMsgPosition [ 2 ] , gameOverMsgPosition [ 4 ] , SDL_ColourTextGameOver ) ;
drawText ( screen , gameOverMsg [ 3 ] , DEFAULT_FONT_SIZE - 9 , gameOverMsgPosition [ 3 ] , gameOverMsgPosition [ 4 ] , SDL_ColourTextData ) ;
SDL_Flip ( screen ) ;
2020-10-23 16:43:41 -04:00
// WAIT A MOMENT TO ENSURE INPUT FROM THE GAME ISN'T CAUGHT
2014-05-29 12:50:57 -04:00
SDL_Delay ( 250 / ( ( * gameParameters ) [ SnakeSpeed ] + 3 ) ) ;
2020-10-23 16:43:41 -04:00
// CAPTURE SDL_QUIT TO EXIT, ESCAPE TO EXIT, OR SPACEBAR TO RESTART
while ( 1 ) {
if ( SDL_PollEvent ( event ) ) {
if ( ( * event ) . type = = SDL_QUIT ) {
2014-05-29 12:50:57 -04:00
( * gameParameters ) [ QuitGame ] = 1 ;
break ;
2020-10-23 16:43:41 -04:00
} else if ( ( * event ) . type = = SDL_KEYDOWN ) {
if ( ( ( * event ) . key . keysym . sym = = SDLK_ESCAPE ) | | ( ( * event ) . key . keysym . sym = = SDLK_q ) ) {
2014-05-29 12:50:57 -04:00
( * gameParameters ) [ QuitGame ] = 1 ;
break ;
2020-10-23 16:43:41 -04:00
} else if ( ( ( * event ) . key . keysym . sym = = SDLK_SPACE ) | | ( ( * event ) . key . keysym . sym = = SDLK_RETURN ) ) {
break ;
2014-05-29 12:50:57 -04:00
}
}
}
}
2020-10-23 16:43:41 -04:00
2014-05-29 12:50:57 -04:00
drawText ( screen , gameOverMsg [ 0 ] , DEFAULT_FONT_SIZE - 7 , gameOverMsgPosition [ 0 ] , gameOverMsgPosition [ 4 ] , SDL_ColourBackground ) ;
drawText ( screen , gameOverMsg [ 1 ] , DEFAULT_FONT_SIZE - 9 , gameOverMsgPosition [ 1 ] , gameOverMsgPosition [ 4 ] , SDL_ColourBackground ) ;
drawText ( screen , gameOverMsg [ 2 ] , DEFAULT_FONT_SIZE - 9 , gameOverMsgPosition [ 2 ] , gameOverMsgPosition [ 4 ] , SDL_ColourBackground ) ;
drawText ( screen , gameOverMsg [ 3 ] , DEFAULT_FONT_SIZE - 9 , gameOverMsgPosition [ 3 ] , gameOverMsgPosition [ 4 ] , SDL_ColourBackground ) ;
SDL_Flip ( screen ) ;
}
drawText ( screen , " SCORE " , DEFAULT_FONT_SIZE , scoreLabelPosition [ 0 ] , scoreLabelPosition [ 1 ] , SDL_ColourBackground ) ;
drawText ( screen , " SPEED " , DEFAULT_FONT_SIZE , speedLabelPosition [ 0 ] , speedLabelPosition [ 1 ] , SDL_ColourBackground ) ;
2020-10-23 16:43:41 -04:00
if ( atoi ( tempString [ 0 ] ) ! = - 1 ) {
2014-05-29 12:50:57 -04:00
drawText ( screen , tempString [ 0 ] , DEFAULT_FONT_SIZE , scoreDataPosition [ 0 ] , scoreDataPosition [ 1 ] , SDL_ColourBackground ) ;
2020-10-23 16:43:41 -04:00
}
if ( atoi ( tempString [ 1 ] ) ! = - 1 ) {
2014-05-29 12:50:57 -04:00
drawText ( screen , tempString [ 1 ] , DEFAULT_FONT_SIZE , speedDataPosition [ 0 ] , speedDataPosition [ 1 ] , SDL_ColourBackground ) ;
2020-10-23 16:43:41 -04:00
}
2014-05-29 12:50:57 -04:00
}
2020-10-23 16:43:41 -04:00
// MOVES THE SNAKE IN THE DESIRED DIRECTION
void moveSnake ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] , enum direction newDirection ) {
2014-05-29 12:50:57 -04:00
int x ;
2020-10-23 16:43:41 -04:00
// MOVEMENT
for ( x = ( * gameParameters ) [ NPCCount ] + ( * gameParameters ) [ SnakeLength ] - 1 ; x > = ( * gameParameters ) [ NPCCount ] ; x - - ) {
if ( x = = ( * gameParameters ) [ NPCCount ] ) {
// MOVE THE HEAD OF THE SNAKE TO THE NEW DIRECTION
switch ( newDirection ) {
case Up :
ppSprites [ x ] [ 0 ] = ppSprites [ x ] [ 0 ] - 1 ;
( * gameParameters ) [ SnakeDirection ] = 0 ;
break ;
case Down :
ppSprites [ x ] [ 0 ] = ppSprites [ x ] [ 0 ] + 1 ;
( * gameParameters ) [ SnakeDirection ] = 1 ;
break ;
case Left :
ppSprites [ x ] [ 1 ] = ppSprites [ x ] [ 1 ] - 1 ;
( * gameParameters ) [ SnakeDirection ] = 2 ;
break ;
case Right :
ppSprites [ x ] [ 1 ] = ppSprites [ x ] [ 1 ] + 1 ;
( * gameParameters ) [ SnakeDirection ] = 3 ;
break ;
2014-05-29 12:50:57 -04:00
}
2020-10-23 16:43:41 -04:00
} else {
// MOVE THE BODY/TAIL OF THE SNAKE TO THE PIECE AHEAD OF IT
2014-05-29 12:50:57 -04:00
ppSprites [ x ] [ 0 ] = ppSprites [ x - 1 ] [ 0 ] ;
ppSprites [ x ] [ 1 ] = ppSprites [ x - 1 ] [ 1 ] ;
}
}
}
2020-10-23 16:43:41 -04:00
// DETECT+HANDLE WHEN THE SNAKE COLLIDES WITH WALLS, BLOCKS, ITSELF OR FOOD
bool collisionDetect ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] , enum direction newDirection ) {
2014-05-29 12:50:57 -04:00
int x ;
2020-10-23 16:43:41 -04:00
switch ( newDirection ) {
case Up :
for ( x = 0 ; x < ( * gameParameters ) [ NPCCount ] + ( * gameParameters ) [ SnakeLength ] - 2 ; + + x ) {
if ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 0 ] - 1 ) = = ppSprites [ x ] [ 0 ] ) & & ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 1 ] = = ppSprites [ x ] [ 1 ] ) ) {
if ( x = = 0 ) {
collisionDetectFood ( screen , ppTiles , ppSprites , gameParameters ) ;
} else {
return false ;
}
}
2014-05-29 12:50:57 -04:00
}
2020-10-23 16:43:41 -04:00
if ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 0 ] - 1 ) < 0 ) {
return false ;
2014-05-29 12:50:57 -04:00
}
2020-10-23 16:43:41 -04:00
moveSnake ( screen , ppTiles , ppSprites , gameParameters , Up ) ;
break ;
case Down :
for ( x = 0 ; x < ( * gameParameters ) [ NPCCount ] + ( * gameParameters ) [ SnakeLength ] - 2 ; + + x ) {
if ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 0 ] + 1 ) = = ppSprites [ x ] [ 0 ] ) & & ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 1 ] = = ppSprites [ x ] [ 1 ] ) ) {
if ( x = = 0 ) {
collisionDetectFood ( screen , ppTiles , ppSprites , gameParameters ) ;
} else {
return false ;
}
}
2014-05-29 12:50:57 -04:00
}
2020-10-23 16:43:41 -04:00
if ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 0 ] + 1 ) > = ( * gameParameters ) [ TilesHigh ] ) {
return false ;
2014-05-29 12:50:57 -04:00
}
2020-10-23 16:43:41 -04:00
moveSnake ( screen , ppTiles , ppSprites , gameParameters , Down ) ;
break ;
case Left :
for ( x = 0 ; x < ( * gameParameters ) [ NPCCount ] + ( * gameParameters ) [ SnakeLength ] - 2 ; + + x ) {
if ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 1 ] - 1 ) = = ppSprites [ x ] [ 1 ] ) & & ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 0 ] = = ppSprites [ x ] [ 0 ] ) ) {
if ( x = = 0 ) {
collisionDetectFood ( screen , ppTiles , ppSprites , gameParameters ) ;
} else {
return false ;
}
}
}
if ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 1 ] - 1 ) < 0 ) {
return false ;
}
moveSnake ( screen , ppTiles , ppSprites , gameParameters , Left ) ;
break ;
case Right :
for ( x = 0 ; x < ( * gameParameters ) [ NPCCount ] + ( * gameParameters ) [ SnakeLength ] - 2 ; + + x ) {
if ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 1 ] + 1 ) = = ppSprites [ x ] [ 1 ] ) & & ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 0 ] = = ppSprites [ x ] [ 0 ] ) ) {
if ( x = = 0 ) {
collisionDetectFood ( screen , ppTiles , ppSprites , gameParameters ) ;
} else {
return false ;
}
}
}
if ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 1 ] + 1 ) > = ( * gameParameters ) [ TilesWide ] ) {
return false ;
}
moveSnake ( screen , ppTiles , ppSprites , gameParameters , Right ) ;
break ;
2014-05-29 12:50:57 -04:00
}
2020-10-23 16:43:41 -04:00
2014-05-29 12:50:57 -04:00
return true ;
}
2020-10-23 16:43:41 -04:00
// HANDLES COLLISION WITH FOOD
void collisionDetectFood ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] ) {
// INCREASE THE SNAKE'S SIZE IF IT'S NOT ALREADY THE MAXIMUM
if ( ( * gameParameters ) [ SnakeLength ] < MAX_SNAKELENGTH ) {
( * gameParameters ) [ SnakeLength ] + + ;
}
2014-05-29 12:50:57 -04:00
2020-10-23 16:43:41 -04:00
// INCREASE THE SNAKE'S SPEED WHEN THE SCORE IS DIVISIBLE BY ACCEL_FREQ
if ( ( ( ( * gameParameters ) [ SnakeScore ] % ACCEL_FREQ ) = = 0 ) & & ( ( * gameParameters ) [ SnakeScore ] ! = 0 ) & & ( ( * gameParameters ) [ SnakeSpeed ] < MAX_SNAKESPEED ) ) {
( * gameParameters ) [ SnakeSpeed ] + + ;
}
2014-05-29 12:50:57 -04:00
2020-10-23 16:43:41 -04:00
// INCREASE THE SNAKE'S SCORE
2014-05-29 12:50:57 -04:00
( * gameParameters ) [ SnakeScore ] + + ;
2020-10-23 16:43:41 -04:00
// SET FOOD PIECE IN NEW LOCATION
2014-05-29 12:50:57 -04:00
randomLocation ( ppSprites , gameParameters , & ( ppSprites ) [ 0 ] ) ;
updateRect ( screen , ppTiles , ppSprites [ 0 ] , colourFood ) ;
SDL_Flip ( screen ) ;
}
2020-10-23 16:43:41 -04:00
// CAPTURES INPUT AND GENERATES APPROPRIATE RESPONSE
bool gameEventPoll ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] , SDL_Event * event ) {
2014-05-29 12:50:57 -04:00
bool playerAlive = true ;
2020-10-23 16:43:41 -04:00
if ( SDL_PollEvent ( event ) ) {
switch ( ( * event ) . type ) {
case SDL_QUIT :
2014-05-29 12:50:57 -04:00
playerAlive = false ;
( * gameParameters ) [ QuitGame ] = 1 ;
break ;
2020-10-23 16:43:41 -04:00
case SDL_KEYDOWN :
// WHEN KEY IS PRESSED, CHECK WHICH AND RESPOND ACCORDINGLY
switch ( ( * event ) . key . keysym . sym ) {
case SDLK_UP :
case SDLK_w :
case SDLK_k :
if ( ( ( * gameParameters ) [ SnakeDirection ] ! = Up ) & & ( ( * gameParameters ) [ SnakeDirection ] ! = Down ) ) {
playerAlive = ( collisionDetect ( screen , ppTiles , ppSprites , gameParameters , Up ) ) ;
}
break ;
case SDLK_DOWN :
case SDLK_s :
case SDLK_j :
if ( ( ( * gameParameters ) [ SnakeDirection ] ! = Down ) & & ( ( * gameParameters ) [ SnakeDirection ] ! = Up ) ) {
playerAlive = ( collisionDetect ( screen , ppTiles , ppSprites , gameParameters , Down ) ) ;
}
break ;
case SDLK_LEFT :
case SDLK_a :
case SDLK_h :
if ( ( ( * gameParameters ) [ SnakeDirection ] ! = Left ) & & ( ( * gameParameters ) [ SnakeDirection ] ! = Right ) & & ( ( * gameParameters ) [ SnakeDirection ] ! = - 1 ) ) {
playerAlive = ( collisionDetect ( screen , ppTiles , ppSprites , gameParameters , Left ) ) ;
}
break ;
case SDLK_RIGHT :
case SDLK_d :
case SDLK_l :
if ( ( ( * gameParameters ) [ SnakeDirection ] ! = Right ) & & ( ( * gameParameters ) [ SnakeDirection ] ! = Left ) ) {
playerAlive = ( collisionDetect ( screen , ppTiles , ppSprites , gameParameters , Right ) ) ;
}
break ;
case SDLK_ESCAPE :
case SDLK_q :
playerAlive = false ;
( * gameParameters ) [ QuitGame ] = 1 ;
break ;
default :
break ;
}
break ;
default :
break ;
2014-05-29 12:50:57 -04:00
}
}
2020-10-23 16:43:41 -04:00
2014-05-29 12:50:57 -04:00
return playerAlive ;
}
2020-10-23 16:43:41 -04:00
// MOVES SNAKE AUTOMATICALLY IN WHICHEVER DIRECTION IT WENT LAST
bool scrollSnake ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] ) {
2014-05-29 12:50:57 -04:00
bool playerAlive = true ;
2020-10-23 16:43:41 -04:00
switch ( ( * gameParameters ) [ SnakeDirection ] ) {
case Up :
playerAlive = ( collisionDetect ( screen , ppTiles , ppSprites , gameParameters , Up ) ) ;
break ;
case Down :
playerAlive = ( collisionDetect ( screen , ppTiles , ppSprites , gameParameters , Down ) ) ;
break ;
case Left :
playerAlive = ( collisionDetect ( screen , ppTiles , ppSprites , gameParameters , Left ) ) ;
break ;
case Right :
playerAlive = ( collisionDetect ( screen , ppTiles , ppSprites , gameParameters , Right ) ) ;
break ;
default :
break ;
2014-05-29 12:50:57 -04:00
}
2020-10-23 16:43:41 -04:00
2014-05-29 12:50:57 -04:00
return playerAlive ;
}
2020-10-23 16:43:41 -04:00
// REDRAW THE SNAKE BASED ON CURRENT VALUES
void updateSnake ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] ) {
2014-05-29 12:50:57 -04:00
int x ;
2020-10-23 16:43:41 -04:00
for ( x = ( * gameParameters ) [ NPCCount ] ; x < ( * gameParameters ) [ NPCCount ] + ( * gameParameters ) [ SnakeLength ] ; x + + ) {
if ( x = = ( * gameParameters ) [ NPCCount ] ) {
updateRect ( screen , ppTiles , ppSprites [ x ] , colourHead ) ;
} else if ( x = = ( ( * gameParameters ) [ NPCCount ] + ( * gameParameters ) [ SnakeLength ] - 1 ) ) {
updateRect ( screen , ppTiles , ppSprites [ x ] , colourTiles ) ;
} else if ( x = = ( ( * gameParameters ) [ NPCCount ] + ( * gameParameters ) [ SnakeLength ] - 2 ) ) {
updateRect ( screen , ppTiles , ppSprites [ x ] , colourTail ) ;
} else {
updateRect ( screen , ppTiles , ppSprites [ x ] , colourBody ) ;
}
2014-05-29 12:50:57 -04:00
}
}
2020-10-23 16:43:41 -04:00
// DRAW NPCs BASED ON ON CURRENT VALUES
void loadNPCs ( SDL_Surface * screen , SDL_Rect * * ppTiles , int * * ppSprites , int ( * gameParameters ) [ 8 ] ) {
2014-05-29 12:50:57 -04:00
int x , startNPCs = 0 ;
2020-10-23 16:43:41 -04:00
for ( x = startNPCs ; x < ( * gameParameters ) [ NPCCount ] ; x + + ) {
if ( x = = startNPCs ) {
updateRect ( screen , ppTiles , ppSprites [ x ] , colourFood ) ;
} else {
updateRect ( screen , ppTiles , ppSprites [ x ] , colourBlock ) ;
}
2014-05-29 12:50:57 -04:00
}
}
2020-10-23 16:43:41 -04:00
// A HELPER FUNCTION TO RANDOMLY PLACE NPCs WITH SOME INTELLIGENCE
void randomLocation ( int * * ppSprites , int ( * gameParameters ) [ 8 ] , int * location [ 2 ] ) {
2014-05-29 12:50:57 -04:00
int x , randLocation [ 2 ] ;
bool isAcceptable = false ;
2020-10-23 16:43:41 -04:00
while ( ! isAcceptable ) {
2014-05-29 12:50:57 -04:00
isAcceptable = true ;
randLocation [ 0 ] = ( rand ( ) % ( ( * gameParameters ) [ TilesHigh ] - 2 ) ) + 1 ;
randLocation [ 1 ] = ( rand ( ) % ( ( * gameParameters ) [ TilesWide ] - 2 ) ) + 1 ;
2020-10-23 16:43:41 -04:00
// DON'T LOAD NPCs ONTO SNAKE OR OTHER NPCs
for ( x = 0 ; x < ( * gameParameters ) [ NPCCount ] + ( * gameParameters ) [ SnakeLength ] ; + + x ) {
if ( ( ( ppSprites [ x ] [ 0 ] ) = = randLocation [ 0 ] ) & & ( ( ppSprites [ x ] [ 1 ] ) = = randLocation [ 1 ] ) ) {
isAcceptable = false ;
}
}
// DON'T LOAD NPCs DIRECTLY NEXT TO THE SNAKE'S HEAD
if ( ( ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 0 ] ) - 1 ) = = randLocation [ 0 ] ) & & ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 1 ] ) ) = = randLocation [ 1 ] ) ) | | // ABOVE THE SNAKE'S HEAD
( ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 0 ] ) + 1 ) = = randLocation [ 0 ] ) & & ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 1 ] ) ) = = randLocation [ 1 ] ) ) | | // BELOW THE SNAKE'S HEAD
( ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 0 ] ) ) = = randLocation [ 0 ] ) & & ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 1 ] ) - 1 ) = = randLocation [ 1 ] ) ) | | // LEFT OF THE SNAKE'S HEAD
( ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 0 ] ) ) = = randLocation [ 0 ] ) & & ( ( ( ppSprites [ ( * gameParameters ) [ NPCCount ] ] [ 1 ] ) + 1 ) = = randLocation [ 1 ] ) ) ) { // RIGHT OF THE SNAKE'S HEAD
2014-05-29 12:50:57 -04:00
isAcceptable = false ;
2020-10-23 16:43:41 -04:00
}
2014-05-29 12:50:57 -04:00
}
2020-10-23 16:43:41 -04:00
// SET THE GIVEN NPC'S LOCATION TO THE GENERATED COORDINATES
2014-05-29 12:50:57 -04:00
( * location ) [ 0 ] = randLocation [ 0 ] ;
( * location ) [ 1 ] = randLocation [ 1 ] ;
}
2020-10-23 16:43:41 -04:00
// DRAW TEXT WHEN REQUIRED
void drawText ( SDL_Surface * screen , char * string , int size , int x , int y , SDL_Colour colour ) {
2014-05-29 12:50:57 -04:00
SDL_Colour SDL_ColourBackground = { colourBackground [ 0 ] , colourBackground [ 1 ] , colourBackground [ 2 ] } ;
SDL_Rect coordinates = { x , y } ;
SDL_Surface * newString = NULL ;
TTF_Font * font ;
2020-10-23 16:43:41 -04:00
// LOAD THE FONT
2014-05-29 12:50:57 -04:00
font = TTF_OpenFont ( DEFAULT_FONT_FILE , size ) ;
2020-10-23 16:43:41 -04:00
if ( ! font ) {
fprintf ( stderr , " Error loading %s " , DEFAULT_FONT_FILE ) ;
}
2014-05-29 12:50:57 -04:00
newString = TTF_RenderText_Shaded ( font , string , colour , SDL_ColourBackground ) ;
SDL_BlitSurface ( newString , NULL , screen , & coordinates ) ;
TTF_CloseFont ( font ) ;
SDL_FreeSurface ( newString ) ;
}
2020-10-23 16:43:41 -04:00
// LOW LEVEL FUNCTION TO BE RUN BY HIGHER LEVEL ONES FOR UPDATING TILES
void updateRect ( SDL_Surface * screen , SDL_Rect * * ppTiles , int position [ 2 ] , const int colour [ 3 ] ) {
2014-05-29 12:50:57 -04:00
SDL_FillRect ( screen , & ppTiles [ position [ 0 ] ] [ position [ 1 ] ] , SDL_MapRGB ( screen - > format , colour [ 0 ] , colour [ 1 ] , colour [ 2 ] ) ) ;
}
2020-10-23 16:43:41 -04:00
// PARSES COMMANDLINE OPTIONS AND GENERATES APPROPRIATE RESPONSE
void configureGame ( int argc , char * * args , int ( * gameParameters ) [ 8 ] ) {
2014-05-29 12:50:57 -04:00
int parsecount = 1 ;
2020-10-23 16:43:41 -04:00
// SET DEFAULT GAME PARAMETERS
2014-05-29 12:50:57 -04:00
( * gameParameters ) [ QuitGame ] = 0 ;
( * gameParameters ) [ TilesWide ] = DEFAULT_TILESWIDE ;
( * gameParameters ) [ TilesHigh ] = DEFAULT_TILESHIGH ;
( * gameParameters ) [ NPCCount ] = DEFAULT_NPCCOUNT ;
( * gameParameters ) [ SnakeSpeed ] = DEFAULT_SNAKESPEED ;
( * gameParameters ) [ SnakeLength ] = DEFAULT_SNAKELENGTH ;
( * gameParameters ) [ SnakeDirection ] = - 1 ;
( * gameParameters ) [ SnakeScore ] = 0 ;
2020-10-23 16:43:41 -04:00
// PARSE COMMANDLINE FOR SETTINGS
while ( parsecount < argc ) {
if ( strcmp ( args [ parsecount ] , " -h " ) = = 0 ) {
// HELP MENU
2014-05-29 12:50:57 -04:00
printHelpMenu ( args [ 0 ] ) ;
exit ( EXIT_SUCCESS ) ;
2020-10-23 16:43:41 -04:00
} else if ( strcmp ( args [ parsecount ] , " -g " ) = = 0 ) {
// RESOLUTION
if ( ( parsecount + 2 ) < argc ) {
if ( ( ( atoi ( args [ parsecount + 1 ] ) > = MIN_TILESWIDE ) & & ( atoi ( args [ parsecount + 1 ] ) < = MAX_TILESWIDE ) ) & & ( ( atoi ( args [ parsecount + 2 ] ) > = MIN_TILESHIGH ) & & ( atoi ( args [ parsecount + 2 ] ) < = MAX_TILESHIGH ) ) ) {
2014-05-29 12:50:57 -04:00
( * gameParameters ) [ TilesWide ] = atoi ( args [ parsecount + 1 ] ) ;
( * gameParameters ) [ TilesHigh ] = atoi ( args [ parsecount + 2 ] ) ;
parsecount = parsecount + 3 ;
2020-10-23 16:43:41 -04:00
} else {
2014-05-29 12:50:57 -04:00
printErrorHelp ( args [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
} else {
2014-05-29 12:50:57 -04:00
printErrorHelp ( args [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
} else if ( strcmp ( args [ parsecount ] , " -b " ) = = 0 ) {
// NUMBER OF BLOCKS
if ( ( parsecount + 1 ) < argc ) {
if ( ( atoi ( args [ parsecount + 1 ] ) > = ( MIN_NPCCOUNT - 1 ) ) & & ( atoi ( args [ parsecount + 1 ] ) < = ( MAX_NPCCOUNT - 1 ) ) ) {
2014-05-29 12:50:57 -04:00
( * gameParameters ) [ NPCCount ] = atoi ( args [ parsecount + 1 ] ) + 1 ;
parsecount = parsecount + 2 ;
2020-10-23 16:43:41 -04:00
} else {
2014-05-29 12:50:57 -04:00
printErrorHelp ( args [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
} else {
2014-05-29 12:50:57 -04:00
printErrorHelp ( args [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
} else if ( strcmp ( args [ parsecount ] , " -l " ) = = 0 ) {
// SNAKE'S LENGTH
if ( ( parsecount + 1 ) < argc ) {
if ( ( atoi ( args [ parsecount + 1 ] ) > = ( MIN_SNAKELENGTH - 1 ) ) & & ( atoi ( args [ parsecount + 1 ] ) < = ( MAX_SNAKELENGTH - 1 ) ) ) {
2014-05-29 12:50:57 -04:00
( * gameParameters ) [ SnakeLength ] = atoi ( args [ parsecount + 1 ] ) + 1 ;
parsecount = parsecount + 2 ;
2020-10-23 16:43:41 -04:00
} else {
2014-05-29 12:50:57 -04:00
printErrorHelp ( args [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
} else {
2014-05-29 12:50:57 -04:00
printErrorHelp ( args [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
} else if ( strcmp ( args [ parsecount ] , " -s " ) = = 0 ) {
// SNAKE'S SPEED
if ( ( parsecount + 1 ) < argc ) {
if ( ( atoi ( args [ parsecount + 1 ] ) > = MIN_SNAKESPEED ) & & ( atoi ( args [ parsecount + 1 ] ) < = MAX_SNAKESPEED ) ) {
2014-05-29 12:50:57 -04:00
( * gameParameters ) [ SnakeSpeed ] = atoi ( args [ parsecount + 1 ] ) ;
parsecount = parsecount + 2 ;
2020-10-23 16:43:41 -04:00
} else {
2014-05-29 12:50:57 -04:00
printErrorHelp ( args [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
} else {
2014-05-29 12:50:57 -04:00
printErrorHelp ( args [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
2020-10-23 16:43:41 -04:00
} else {
// FAIL IF ANYTHING ELSE
2014-05-29 12:50:57 -04:00
printErrorHelp ( args [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
}
}
}
2020-10-23 16:43:41 -04:00
// PRINT THE HELP MENU TO THE COMMANDLINE
void printHelpMenu ( char filename [ ] ) {
2014-05-29 12:50:57 -04:00
fprintf ( stdout , " Usage: %s [options] \n " , filename ) ;
fprintf ( stdout , " Options: \n " ) ;
fprintf ( stdout , " -g [width] [height] \t Set the grid size: between [%d]x[%d] and [%d]x[%d] (DEFAULT: [%d]x[%d]) \n " , MIN_TILESWIDE , MIN_TILESHIGH , MAX_TILESWIDE , MAX_TILESHIGH , DEFAULT_TILESWIDE , DEFAULT_TILESHIGH ) ;
fprintf ( stdout , " -b [blocks] \t \t Set the number of blocks: between [%d] and [%d] (DEFAULT: [%d]) \n " , MIN_NPCCOUNT - 1 , MAX_NPCCOUNT - 1 , DEFAULT_NPCCOUNT - 1 ) ;
fprintf ( stdout , " -l [length] \t \t Set the snake's starting length: between [%d] and [%d] (DEFAULT: [%d]) \n " , MIN_SNAKELENGTH - 1 , MAX_SNAKELENGTH - 1 , DEFAULT_SNAKELENGTH - 1 ) ;
fprintf ( stdout , " -s [speed] \t \t Set the snake's starting speed: between [%d] and [%d] (DEFAULT: [%d]) \n " , MIN_SNAKESPEED , MAX_SNAKESPEED , DEFAULT_SNAKESPEED ) ;
fprintf ( stdout , " -h \t \t \t Display help information \n " ) ;
}
2020-10-23 16:43:41 -04:00
// DISPLAYS AN ERROR MESSAGE BEFORE CALLING THE HELP MENU FUNCTION
void printErrorHelp ( char filename [ ] ) {
2014-05-29 12:50:57 -04:00
fprintf ( stderr , " Error: invalid input \n \n " ) ;
printHelpMenu ( filename ) ;
}