summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSilvan Jegen <silvan@homearch>2019-04-19 16:20:44 +0200
committerSilvan Jegen <silvan@homearch>2019-04-19 16:20:44 +0200
commite168efe028dec4073d85d988de49cc8c642c6b39 (patch)
tree782ec7d8d759ac9d313d284c390f1186430eb0be
parent54591b7d51269554ba672906fb2f9a569fa38287 (diff)
Use Unix line endings
-rw-r--r--echidna_ai.c489
-rw-r--r--game.c404
-rw-r--r--helpscreen.c60
-rw-r--r--level.c466
-rw-r--r--main.c218
-rw-r--r--render.c286
6 files changed, 961 insertions, 962 deletions
diff --git a/echidna_ai.c b/echidna_ai.c
index 64759a4..5803b10 100644
--- a/echidna_ai.c
+++ b/echidna_ai.c
@@ -1,245 +1,244 @@
-
-/* The echidna AI has three modes:
- *
- * MODE_HUNT
- * The echidna tries to close the space between itself and the player
- *
- * MODE_FOLLOW_WALL
- * The echidna has hit a wall and is now following it
- *
- * MODE_CORNER
- * This mode makes the monster move around a corner after it has been following a wall
- *
- * See the developer documentation for more information about how this large algorithm works.
- */
-
-// Give each of the modes a numerical value
-#define MODE_HUNT 1
-#define MODE_FOLLOW_WALL 2
-
-// The echidna structure is declared in 'level.c' so it can be loaded
-
-
-// is_square solid returns 1 if a square is not passable ( ie a wall or closed door )
-// and 0 if it is ( ie floor, button )
-int is_square_solid( struct level_struct *currentlevel, int xpos, int ypos )
-{
-
- switch ( currentlevel->squares[ xpos ][ ypos ] )
- {
- case T_WALL: return 1;
- case T_BLUE_DOOR_UP: return 1;
- case T_YELL_DOOR_UP: return 1;
- case T_RED_DOOR_UP: return 1;
-
- // The default case occurs when none of the above are met
- default: return 0; // ie the square is walkable on
- }
-}
-
-// run_all_echidnaAI_onestep runs one 'step' of echidna AI for every echidna in a level
-void run_all_echidnaAI_onestep( struct level_struct *currentlevel )
-{
- // Ieterate through each and every echinda
- int ech_no; // Echidna number
- for ( ech_no = 0; ech_no < 10; ech_no++ )
- {
- struct echidna *current_echidna = &currentlevel->echidnas[ech_no];
-
-
- if ( current_echidna->this_echidna_exists == 1 )
- {
-
- // This echidna is alive and we can move it
-
- // How the echidna is going to move, similiar to the player code;
- signed int x = 0;
- signed int y = 0;
-
-
- /////////////////////////////////////////////////////////////////////////////////////////////// HUNT MODE
- if ( current_echidna->mode == MODE_HUNT )
- {
- // Find the orthoganol ( x and y, not true or diagonal ) distances between the echidna and player
- // NB abs() returns the absolute value of something, which fixes negative numbers by changing
- // them to be position
- int distx = abs( current_echidna->xpos - currentlevel->px );
- int disty = abs( current_echidna->ypos - currentlevel->py );
-
- if ( distx > disty )
- {
-
- // Now check whether the player is to the left or right of the echidna
- if ( currentlevel->px > current_echidna->xpos )
- {
- // Echidna is left of player
- x = 1;
- }
- else
- {
- // Echidna is right of player
- x = -1;
- }
- }
- else
- {
- // Is the player abov or below the echidna
- if ( currentlevel->py > current_echidna->ypos )
- {
- // Echidna is below player
- y = 1;
- }
- else
- {
- // Echidna is above player
- y = -1;
- }
- }
-
- // Now check if this is going to make the echidna try to walk into a wall
- // If it will, change mode to MODE_FOLLOW_WALL
- if ( is_square_solid( currentlevel, current_echidna->xpos + x, current_echidna->ypos + y ) == 1 )
- {
- current_echidna->mode = MODE_FOLLOW_WALL;
-
- // Make a decision about which way to move
- // This scheme ensures the echidna moves clockwise
- current_echidna->move_x = 0;
- current_echidna->move_y = 0;
- if ( x == 1 ) current_echidna->move_y = 1;
- else if ( x == -1 ) current_echidna->move_y = -1;
- else if ( y == 1 ) current_echidna->move_x = -1;
- else if ( y == -1 ) current_echidna->move_x = 1;
-
- // Make sure the echidna checks the wall its following
- // to see if it still exists
- current_echidna->check_x = x;
- current_echidna->check_y = y;
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////// FOLLOW WALL MODE
- if ( current_echidna->mode == MODE_FOLLOW_WALL )
- {
-
- // Check the wall we are following
- if ( is_square_solid( currentlevel, current_echidna->xpos + current_echidna->check_x, current_echidna->ypos + current_echidna->check_y ) == 1 )
- {
- // The wall is still there, so keep following it
- x = current_echidna->move_x;
- y = current_echidna->move_y;
-
- // Check if a new wall is in the way
- while ( is_square_solid( currentlevel, current_echidna->xpos + x, current_echidna->ypos + y ) == 1 )
- {
- // We need to follow another wall now. Same clockwise logic as before
- current_echidna->check_x = x;
- current_echidna->check_y = y;
- if ( x == 1 ) { x = 0; y = 1; }
- else if ( x == -1 ) { x = 0; y =-1; }
- else if ( y == 1 ) { x =-1; y = 0; }
- else if ( y == -1 ) { x = 1; y = 0; }
- current_echidna->move_x = x;
- current_echidna->move_y = y;
- }
- }
- else
- {
- // The wall has gone, so immediately go around the corner
- x = current_echidna->check_x;
- y = current_echidna->check_y;
-
-
- // And resume HUNT mode next time
- current_echidna->mode = MODE_HUNT;
- }
- }
-
- ////////////////////////////////////////////// MOVE THE ECHIDNA
-
- // Move
- current_echidna->xpos = current_echidna->xpos + x;
- current_echidna->ypos = current_echidna->ypos + y;
-
- // Check if we have moved ontop of an Echidna, and if so then move back to where we started
- // ( it will appear as if we have not moved at all )
-
- int target_num;
- for ( target_num = 0; target_num < ech_no; target_num++ ) // Check all of the echidnas BEFORE the current one, so we can have right of way
- {
- struct echidna target_echidna = currentlevel->echidnas[target_num];
- if ( target_echidna.this_echidna_exists == 1 )
- {
- if ( target_echidna.xpos == current_echidna->xpos && target_echidna.ypos == current_echidna->ypos )
- {
- // We have a clash, so move back to the original square
- current_echidna->xpos = current_echidna->xpos - x;
- current_echidna->ypos = current_echidna->ypos - y;
- }
- }
- }
- }
- }
-}
-
-
-
-// Returns 1 if an echidna is in the same spot as the player
-int check_echidna_proximity( struct level_struct *currentlevel )
-{
- // Ieterate through eacha and every echinda
- int ech_no; // Echidna number
-
-
- for ( ech_no = 0; ech_no < 10; ech_no++ )
- {
- struct echidna currentechidna = currentlevel->echidnas[ech_no];
-
- // First make sure we are checking an echidna that ACTUALLY EXISTS
- // Until I wrote this code to check that, I was mysteriously dieing halfway
- // throught some levels. Fun :)
- if ( currentechidna.this_echidna_exists == 1 )
- {
- if ( currentechidna.xpos == currentlevel->px && currentechidna.ypos == currentlevel->py ) // && means 'and'
- {
- // An echidna is atop a player
- return 1;
- }
- }
- }
-
- // No echidna is atop the player
- return 0;
-}
-
-// Echidnas are the onlt things that can toggler the red levers, and this loop checks to see if that need to happen
-void check_echidna_on_switches( struct level_struct *currentlevel )
-{
- // Ieterate through each and every echinda
- int ech_no; // Echidna number
-
-
- for ( ech_no = 0; ech_no < 10; ech_no++ )
- {
- struct echidna currentechidna = currentlevel->echidnas[ech_no];
-
- if ( currentechidna.this_echidna_exists == 1 )
- {
- // Get the square the echinda is standing on
- char square = currentlevel->squares[ currentechidna.xpos ][ currentechidna.ypos ] ;
-
- if ( square == T_RED_SWITCH_ON )
- {
- level_replace_tiles( currentlevel, T_RED_SWITCH_ON, T_RED_SWITCH_OFF ); // change ALL levers
- level_replace_tiles( currentlevel, T_RED_DOOR_UP, T_RED_DOOR_DOWN ); // open all red doors
- }
- else if ( square == T_RED_SWITCH_OFF )
- {
- level_replace_tiles( currentlevel, T_RED_SWITCH_OFF, T_RED_SWITCH_ON ); // change ALL levers
- level_replace_tiles( currentlevel, T_RED_DOOR_DOWN, T_RED_DOOR_UP ); // close all red doors
- }
- }
- }
-}
-
-
+
+/* The echidna AI has three modes:
+ *
+ * MODE_HUNT
+ * The echidna tries to close the space between itself and the player
+ *
+ * MODE_FOLLOW_WALL
+ * The echidna has hit a wall and is now following it
+ *
+ * MODE_CORNER
+ * This mode makes the monster move around a corner after it has been following a wall
+ *
+ * See the developer documentation for more information about how this large algorithm works.
+ */
+
+// Give each of the modes a numerical value
+#define MODE_HUNT 1
+#define MODE_FOLLOW_WALL 2
+
+// The echidna structure is declared in 'level.c' so it can be loaded
+
+
+// is_square solid returns 1 if a square is not passable ( ie a wall or closed door )
+// and 0 if it is ( ie floor, button )
+int is_square_solid( struct level_struct *currentlevel, int xpos, int ypos )
+{
+
+ switch ( currentlevel->squares[ xpos ][ ypos ] )
+ {
+ case T_WALL: return 1;
+ case T_BLUE_DOOR_UP: return 1;
+ case T_YELL_DOOR_UP: return 1;
+ case T_RED_DOOR_UP: return 1;
+
+ // The default case occurs when none of the above are met
+ default: return 0; // ie the square is walkable on
+ }
+}
+
+// run_all_echidnaAI_onestep runs one 'step' of echidna AI for every echidna in a level
+void run_all_echidnaAI_onestep( struct level_struct *currentlevel )
+{
+ // Ieterate through each and every echinda
+ int ech_no; // Echidna number
+ for ( ech_no = 0; ech_no < 10; ech_no++ )
+ {
+ struct echidna *current_echidna = &currentlevel->echidnas[ech_no];
+
+
+ if ( current_echidna->this_echidna_exists == 1 )
+ {
+
+ // This echidna is alive and we can move it
+
+ // How the echidna is going to move, similiar to the player code;
+ signed int x = 0;
+ signed int y = 0;
+
+
+ /////////////////////////////////////////////////////////////////////////////////////////////// HUNT MODE
+ if ( current_echidna->mode == MODE_HUNT )
+ {
+ // Find the orthoganol ( x and y, not true or diagonal ) distances between the echidna and player
+ // NB abs() returns the absolute value of something, which fixes negative numbers by changing
+ // them to be position
+ int distx = abs( current_echidna->xpos - currentlevel->px );
+ int disty = abs( current_echidna->ypos - currentlevel->py );
+
+ if ( distx > disty )
+ {
+
+ // Now check whether the player is to the left or right of the echidna
+ if ( currentlevel->px > current_echidna->xpos )
+ {
+ // Echidna is left of player
+ x = 1;
+ }
+ else
+ {
+ // Echidna is right of player
+ x = -1;
+ }
+ }
+ else
+ {
+ // Is the player abov or below the echidna
+ if ( currentlevel->py > current_echidna->ypos )
+ {
+ // Echidna is below player
+ y = 1;
+ }
+ else
+ {
+ // Echidna is above player
+ y = -1;
+ }
+ }
+
+ // Now check if this is going to make the echidna try to walk into a wall
+ // If it will, change mode to MODE_FOLLOW_WALL
+ if ( is_square_solid( currentlevel, current_echidna->xpos + x, current_echidna->ypos + y ) == 1 )
+ {
+ current_echidna->mode = MODE_FOLLOW_WALL;
+
+ // Make a decision about which way to move
+ // This scheme ensures the echidna moves clockwise
+ current_echidna->move_x = 0;
+ current_echidna->move_y = 0;
+ if ( x == 1 ) current_echidna->move_y = 1;
+ else if ( x == -1 ) current_echidna->move_y = -1;
+ else if ( y == 1 ) current_echidna->move_x = -1;
+ else if ( y == -1 ) current_echidna->move_x = 1;
+
+ // Make sure the echidna checks the wall its following
+ // to see if it still exists
+ current_echidna->check_x = x;
+ current_echidna->check_y = y;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////// FOLLOW WALL MODE
+ if ( current_echidna->mode == MODE_FOLLOW_WALL )
+ {
+
+ // Check the wall we are following
+ if ( is_square_solid( currentlevel, current_echidna->xpos + current_echidna->check_x, current_echidna->ypos + current_echidna->check_y ) == 1 )
+ {
+ // The wall is still there, so keep following it
+ x = current_echidna->move_x;
+ y = current_echidna->move_y;
+
+ // Check if a new wall is in the way
+ while ( is_square_solid( currentlevel, current_echidna->xpos + x, current_echidna->ypos + y ) == 1 )
+ {
+ // We need to follow another wall now. Same clockwise logic as before
+ current_echidna->check_x = x;
+ current_echidna->check_y = y;
+ if ( x == 1 ) { x = 0; y = 1; }
+ else if ( x == -1 ) { x = 0; y =-1; }
+ else if ( y == 1 ) { x =-1; y = 0; }
+ else if ( y == -1 ) { x = 1; y = 0; }
+ current_echidna->move_x = x;
+ current_echidna->move_y = y;
+ }
+ }
+ else
+ {
+ // The wall has gone, so immediately go around the corner
+ x = current_echidna->check_x;
+ y = current_echidna->check_y;
+
+
+ // And resume HUNT mode next time
+ current_echidna->mode = MODE_HUNT;
+ }
+ }
+
+ ////////////////////////////////////////////// MOVE THE ECHIDNA
+
+ // Move
+ current_echidna->xpos = current_echidna->xpos + x;
+ current_echidna->ypos = current_echidna->ypos + y;
+
+ // Check if we have moved ontop of an Echidna, and if so then move back to where we started
+ // ( it will appear as if we have not moved at all )
+
+ int target_num;
+ for ( target_num = 0; target_num < ech_no; target_num++ ) // Check all of the echidnas BEFORE the current one, so we can have right of way
+ {
+ struct echidna target_echidna = currentlevel->echidnas[target_num];
+ if ( target_echidna.this_echidna_exists == 1 )
+ {
+ if ( target_echidna.xpos == current_echidna->xpos && target_echidna.ypos == current_echidna->ypos )
+ {
+ // We have a clash, so move back to the original square
+ current_echidna->xpos = current_echidna->xpos - x;
+ current_echidna->ypos = current_echidna->ypos - y;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+// Returns 1 if an echidna is in the same spot as the player
+int check_echidna_proximity( struct level_struct *currentlevel )
+{
+ // Ieterate through eacha and every echinda
+ int ech_no; // Echidna number
+
+ for ( ech_no = 0; ech_no < 10; ech_no++ )
+ {
+ struct echidna currentechidna = currentlevel->echidnas[ech_no];
+
+ // First make sure we are checking an echidna that ACTUALLY EXISTS
+ // Until I wrote this code to check that, I was mysteriously dieing halfway
+ // throught some levels. Fun :)
+ if ( currentechidna.this_echidna_exists == 1 )
+ {
+ if ( currentechidna.xpos == currentlevel->px && currentechidna.ypos == currentlevel->py ) // && means 'and'
+ {
+ // An echidna is atop a player
+ return 1;
+ }
+ }
+ }
+
+ // No echidna is atop the player
+ return 0;
+}
+
+// Echidnas are the onlt things that can toggler the red levers, and this loop checks to see if that need to happen
+void check_echidna_on_switches( struct level_struct *currentlevel )
+{
+ // Ieterate through each and every echinda
+ int ech_no; // Echidna number
+
+
+ for ( ech_no = 0; ech_no < 10; ech_no++ )
+ {
+ struct echidna currentechidna = currentlevel->echidnas[ech_no];
+
+ if ( currentechidna.this_echidna_exists == 1 )
+ {
+ // Get the square the echinda is standing on
+ char square = currentlevel->squares[ currentechidna.xpos ][ currentechidna.ypos ] ;
+
+ if ( square == T_RED_SWITCH_ON )
+ {
+ level_replace_tiles( currentlevel, T_RED_SWITCH_ON, T_RED_SWITCH_OFF ); // change ALL levers
+ level_replace_tiles( currentlevel, T_RED_DOOR_UP, T_RED_DOOR_DOWN ); // open all red doors
+ }
+ else if ( square == T_RED_SWITCH_OFF )
+ {
+ level_replace_tiles( currentlevel, T_RED_SWITCH_OFF, T_RED_SWITCH_ON ); // change ALL levers
+ level_replace_tiles( currentlevel, T_RED_DOOR_DOWN, T_RED_DOOR_UP ); // close all red doors
+ }
+ }
+ }
+}
+
+
diff --git a/game.c b/game.c
index bffd98b..a77234c 100644
--- a/game.c
+++ b/game.c
@@ -1,202 +1,202 @@
-#define PLAYER_IS_OK 1
-#define PLAYER_IS_DEAD 2
-#define PLAYER_HAS_WON 3
-
-
-
-// player_action moves the player
-// It returns one of the three PLAYER_ define values ( top of this file )
-int player_action( signed int xdiff, signed int ydiff, struct level_struct *currentlevel )
-{
- // Find the tile the player moved into/onto using the player's current position
- int newx = currentlevel->px + xdiff;
- int newy = currentlevel->py + ydiff;
-
- // Cycle through the player's faces
- currentlevel->player_face++;
- if ( currentlevel->player_face == 4 ) currentlevel->player_face = 0;
-
- // Check to make sure these directions are not solid ( ie walls )
- // and also to see if they are interactive ( ie buttons )
- char targetsquare = currentlevel->squares[newx][newy];
-
- if ( targetsquare == T_WALL || targetsquare == T_YELL_DOOR_UP || targetsquare == T_BLUE_DOOR_UP || targetsquare == T_RED_DOOR_UP ) // remember '||' means 'OR'
- {
- // Cannot move, so do nothing
- return PLAYER_IS_OK;
- }
- else
- {
- // Move onto the new square
- currentlevel->px = newx;
- currentlevel->py = newy;
-
- // Check to see if the new square is interactive ( ie a button )
-
- switch ( targetsquare )
- {
- case T_BLUE_BUTT_UP: // Blue button
- // Change the button to be depressed
- currentlevel->squares[newx][newy] = T_BLUE_BUTT_DOWN;
- // Change all blue doors in the level to be unlocked
- level_replace_tiles( currentlevel, T_BLUE_DOOR_UP, T_BLUE_DOOR_DOWN );
- return PLAYER_IS_OK;
-
- case T_YELL_BUTT_UP: // Yellow button
- // Change the button to be depressed
- currentlevel->squares[newx][newy] = T_YELL_BUTT_DOWN;
- // Change all blue doors in the level to be unlocked
- level_replace_tiles( currentlevel, T_YELL_DOOR_UP, T_YELL_DOOR_DOWN );
- return PLAYER_IS_OK;
-
- case T_EXIT:
- // User is on the exit
- return PLAYER_HAS_WON;
-
- case T_SPIKE:
- // The daft player walked onto spikes
- return PLAYER_IS_DEAD;
-
-
-
- default:
- // This has to be here to stop the compiler complaining
- // Basically the 'default' is run if no other case is run
- return PLAYER_IS_OK;
-
- }
- }
-
- // Code should never reach this point
- // The return line here is just to make the compiler happy
-
- return 0;
-
-}
-
-
-int play_level(SDL_Renderer* renderer, struct level_struct *currentlevel)
-{
- // Loop until the user completes the level
- int player_status = PLAYER_IS_OK;
-
- while ( player_status == PLAYER_IS_OK )
- {
- SDL_Event userinput;
-
- // WaitEvent is like PollEvent, but instead we pause the program's
- // execution until we get input
- SDL_WaitEvent( &userinput );
- render(renderer, currentlevel);
-
- // Player movement
- signed int y, x;
-
- if ( userinput.type == SDL_KEYDOWN )
- {
- switch ( userinput.key.keysym.sym )
- {
- case SDLK_UP:
- x = 0;
- y = -1;
- break;
-
- case SDLK_DOWN:
- x = 0;
- y = 1;
- break;
-
- case SDLK_RIGHT:
- x = 1;
- y = 0;
- break;
-
- case SDLK_LEFT:
- x = -1;
- y = 0;
- break;
-
- case SDLK_q:
- exit(0); // Quit the game
- break;
-
- case SDLK_h:
- // View the help screen
- help(renderer);
- x = 0;
- y = 0;
-
- default:
- // The user hits any other key
- // ( do nothing )
- x = 0;
- y = 0;
- break;
- }
-
- // Now move the player
- player_status = player_action( x, y, currentlevel );
-
- // Move all of the echidnas
- run_all_echidnaAI_onestep( currentlevel );
-
- // And make sure we open/close red doors if any
- // of them are stepping on red levers
- check_echidna_on_switches( currentlevel );
-
- // Check to see if the player has run into an echidna
- if ( check_echidna_proximity( currentlevel ) == 1 ) player_status = PLAYER_IS_DEAD;
-
- // Show a losing screen if applicable
- if (player_status == PLAYER_IS_DEAD) render_a_losingscreen(renderer, currentlevel);
- }
- }
-
- // The code running play_level needs to know if too advance
- // to the next level or just repeat the current one (if the
- // player has died)
- return player_status;
-}
-
-void game_loop(SDL_Renderer* renderer)
-{
- struct level_struct currentlevel;
- level_load_resources(renderer, &currentlevel ); // load pixmaps
-
- // Initialise initial player face
- currentlevel.player_face = 2;
-
- int level_number; // Level's number in progression of game, also used as the filename to load the level from
-
- // Run through each of the levels
-
- for ( level_number = 2; level_number <= 10; level_number++ )
- {
- int level_state = PLAYER_IS_OK;
-
- while ( level_state != PLAYER_HAS_WON )
- {
- // Load the level
- level_load( level_number, &currentlevel );
-
- // Set the player's new position
- currentlevel.px = currentlevel.sx;
- currentlevel.py = currentlevel.sy;
-
- // Main game loop
- level_state = play_level(renderer, &currentlevel);
-
- }
- // When the game loop ends, then the user has successfully completed the level, and we can move on
- }
-
- // The user has now completed all of the game
- // Show them the winning screen
- SDL_RenderClear(renderer);
- SDL_RenderCopy(renderer, currentlevel.winning_screen, NULL, NULL);
- SDL_RenderPresent(renderer);
-
- SDL_Delay(20 * 1000); // 20 * 1000msecs = 20 seconds
-
- // Once this function ends, we return to the menu
-}
+#define PLAYER_IS_OK 1
+#define PLAYER_IS_DEAD 2
+#define PLAYER_HAS_WON 3
+
+
+
+// player_action moves the player
+// It returns one of the three PLAYER_ define values ( top of this file )
+int player_action( signed int xdiff, signed int ydiff, struct level_struct *currentlevel )
+{
+ // Find the tile the player moved into/onto using the player's current position
+ int newx = currentlevel->px + xdiff;
+ int newy = currentlevel->py + ydiff;
+
+ // Cycle through the player's faces
+ currentlevel->player_face++;
+ if ( currentlevel->player_face == 4 ) currentlevel->player_face = 0;
+
+ // Check to make sure these directions are not solid ( ie walls )
+ // and also to see if they are interactive ( ie buttons )
+ char targetsquare = currentlevel->squares[newx][newy];
+
+ if ( targetsquare == T_WALL || targetsquare == T_YELL_DOOR_UP || targetsquare == T_BLUE_DOOR_UP || targetsquare == T_RED_DOOR_UP ) // remember '||' means 'OR'
+ {
+ // Cannot move, so do nothing
+ return PLAYER_IS_OK;
+ }
+ else
+ {
+ // Move onto the new square
+ currentlevel->px = newx;
+ currentlevel->py = newy;
+
+ // Check to see if the new square is interactive ( ie a button )
+
+ switch ( targetsquare )
+ {
+ case T_BLUE_BUTT_UP: // Blue button
+ // Change the button to be depressed
+ currentlevel->squares[newx][newy] = T_BLUE_BUTT_DOWN;
+ // Change all blue doors in the level to be unlocked
+ level_replace_tiles( currentlevel, T_BLUE_DOOR_UP, T_BLUE_DOOR_DOWN );
+ return PLAYER_IS_OK;
+
+ case T_YELL_BUTT_UP: // Yellow button
+ // Change the button to be depressed
+ currentlevel->squares[newx][newy] = T_YELL_BUTT_DOWN;
+ // Change all blue doors in the level to be unlocked
+ level_replace_tiles( currentlevel, T_YELL_DOOR_UP, T_YELL_DOOR_DOWN );
+ return PLAYER_IS_OK;
+
+ case T_EXIT:
+ // User is on the exit
+ return PLAYER_HAS_WON;
+
+ case T_SPIKE:
+ // The daft player walked onto spikes
+ return PLAYER_IS_DEAD;
+
+
+
+ default:
+ // This has to be here to stop the compiler complaining
+ // Basically the 'default' is run if no other case is run
+ return PLAYER_IS_OK;
+
+ }
+ }
+
+ // Code should never reach this point
+ // The return line here is just to make the compiler happy
+
+ return 0;
+
+}
+
+
+int play_level(SDL_Renderer* renderer, struct level_struct *currentlevel)
+{
+ // Loop until the user completes the level
+ int player_status = PLAYER_IS_OK;
+
+ while ( player_status == PLAYER_IS_OK )
+ {
+ SDL_Event userinput;
+
+ // WaitEvent is like PollEvent, but instead we pause the program's
+ // execution until we get input
+ SDL_WaitEvent( &userinput );
+ render(renderer, currentlevel);
+
+ // Player movement
+ signed int y, x;
+
+ if ( userinput.type == SDL_KEYDOWN )
+ {
+ switch ( userinput.key.keysym.sym )
+ {
+ case SDLK_UP:
+ x = 0;
+ y = -1;
+ break;
+
+ case SDLK_DOWN:
+ x = 0;
+ y = 1;
+ break;
+
+ case SDLK_RIGHT:
+ x = 1;
+ y = 0;
+ break;
+
+ case SDLK_LEFT:
+ x = -1;
+ y = 0;
+ break;
+
+ case SDLK_q:
+ exit(0); // Quit the game
+ break;
+
+ case SDLK_h:
+ // View the help screen
+ help(renderer);
+ x = 0;
+ y = 0;
+
+ default:
+ // The user hits any other key
+ // ( do nothing )
+ x = 0;
+ y = 0;
+ break;
+ }
+
+ // Now move the player
+ player_status = player_action( x, y, currentlevel );
+
+ // Move all of the echidnas
+ run_all_echidnaAI_onestep( currentlevel );
+
+ // And make sure we open/close red doors if any
+ // of them are stepping on red levers
+ check_echidna_on_switches( currentlevel );
+
+ // Check to see if the player has run into an echidna
+ if ( check_echidna_proximity( currentlevel ) == 1 ) player_status = PLAYER_IS_DEAD;
+
+ // Show a losing screen if applicable
+ if (player_status == PLAYER_IS_DEAD) render_a_losingscreen(renderer, currentlevel);
+ }
+ }
+
+ // The code running play_level needs to know if too advance
+ // to the next level or just repeat the current one (if the
+ // player has died)
+ return player_status;
+}
+
+void game_loop(SDL_Renderer* renderer)
+{
+ struct level_struct currentlevel;
+ level_load_resources(renderer, &currentlevel ); // load pixmaps
+
+ // Initialise initial player face
+ currentlevel.player_face = 2;
+
+ int level_number; // Level's number in progression of game, also used as the filename to load the level from
+
+ // Run through each of the levels
+
+ for ( level_number = 2; level_number <= 10; level_number++ )
+ {
+ int level_state = PLAYER_IS_OK;
+
+ while ( level_state != PLAYER_HAS_WON )
+ {
+ // Load the level
+ level_load( level_number, &currentlevel );
+
+ // Set the player's new position
+ currentlevel.px = currentlevel.sx;
+ currentlevel.py = currentlevel.sy;
+
+ // Main game loop
+ level_state = play_level(renderer, &currentlevel);
+
+ }
+ // When the game loop ends, then the user has successfully completed the level, and we can move on
+ }
+
+ // The user has now completed all of the game
+ // Show them the winning screen
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, currentlevel.winning_screen, NULL, NULL);
+ SDL_RenderPresent(renderer);
+
+ SDL_Delay(20 * 1000); // 20 * 1000msecs = 20 seconds
+
+ // Once this function ends, we return to the menu
+}
diff --git a/helpscreen.c b/helpscreen.c
index bb298bf..213376f 100644
--- a/helpscreen.c
+++ b/helpscreen.c
@@ -1,30 +1,30 @@
-
-void help(SDL_Renderer* renderer)
-{
- // Load help image
- SDL_Surface* surf_help = IMG_Load("helpscreen.png");
- SDL_Texture* surf_help_tex = SDL_CreateTextureFromSurface(renderer, surf_help);
-
- SDL_RenderClear(renderer);
- SDL_RenderCopy(renderer, surf_help_tex, NULL, NULL);
- SDL_RenderPresent(renderer);
-
- // now free the memory we used to draw this image
- SDL_FreeSurface(surf_help);
-
- // Now wait until the user presses a key
- SDL_Event event;
- int waiting_for_user = 1;
-
- while ( waiting_for_user )
- {
- while ( SDL_PollEvent( &event ) )
- {
- if ( event.type == SDL_KEYDOWN )
- {
- waiting_for_user = 0;
- break;
- }
- }
- }
-}
+
+void help(SDL_Renderer* renderer)
+{
+ // Load help image
+ SDL_Surface* surf_help = IMG_Load("helpscreen.png");
+ SDL_Texture* surf_help_tex = SDL_CreateTextureFromSurface(renderer, surf_help);
+
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, surf_help_tex, NULL, NULL);
+ SDL_RenderPresent(renderer);
+
+ // now free the memory we used to draw this image
+ SDL_FreeSurface(surf_help);
+
+ // Now wait until the user presses a key
+ SDL_Event event;
+ int waiting_for_user = 1;
+
+ while ( waiting_for_user )
+ {
+ while ( SDL_PollEvent( &event ) )
+ {
+ if ( event.type == SDL_KEYDOWN )
+ {
+ waiting_for_user = 0;
+ break;
+ }
+ }
+ }
+}
diff --git a/level.c b/level.c
index d8a82e4..845f59b 100644
--- a/level.c
+++ b/level.c
@@ -1,233 +1,233 @@
-/*
- * Each of the different types of tile in the levels are numbered
- * These are also the values used in the level text files
- *
- * All of the level tiles are stored in one image, hence the 'Rows'
- * below are literally the rows there are positioned in the image.
- * Have a look at tiles.png in the game's folder to see them all.
- */
-
-// Row 1 - main squares
-#define T_WALL 0
-#define T_FLOOR 1
-#define T_SPIKE 2
-#define T_EXIT 3
-// Row two - blue button related
-#define T_BLUE_BUTT_UP 4 // unpressed button
-#define T_BLUE_BUTT_DOWN 5 // depressed button
-#define T_BLUE_DOOR_UP 6 // door unlocked by a button
-#define T_BLUE_DOOR_DOWN 7 // door locked and impassible
-// Row three - yellow button related
-#define T_YELL_BUTT_UP 8
-#define T_YELL_BUTT_DOWN 9
-#define T_YELL_DOOR_UP 10
-#define T_YELL_DOOR_DOWN 11
-// Row four - red lever/switch related
-#define T_RED_SWITCH_ON 12
-#define T_RED_SWITCH_OFF 13
-#define T_RED_DOOR_UP 14
-#define T_RED_DOOR_DOWN 15
-
-// An echidna is one of the monsters
-// The structure is define here in level.c so it can be loaded from the level files
-struct echidna
-{
- int xpos, ypos; // Position on map
- int face; // Which of the echidna pictures to use
-
- int mode; // As described at the top of the document
-
- int this_echidna_exists; // When this is equal to 1, the echidna is alive and on the level
-
- // These movement directions are used in the AI code
- signed int move_x;
- signed int move_y;
- // ditto here
- signed int check_x;
- signed int check_y;
-
-};
-
-/* The level structure is passed to the rendering module, so everything that needs to be seen
- * on-screen is also stored here as well
- *
- * Eg:
- * - player position
- * - resource locations ( graphics )
- */
-struct level_struct
-{
-
- char squares[SCREEN_WIDTH_SQUARES][SCREEN_HEIGHT_SQUARES]; // Squares of the level
-
- // Player details
- int player_face; // Picture number ( player has 4 different looks )
- int px, py; // Player X and Y position, on the tiles
- int sx, sy; // Player X and Y starting positions
-
- // Resources
- SDL_Texture * entities;
- SDL_Texture * tiles;
-
- // A various selection of losing screens
- SDL_Texture * losingscreens[5];
-
- // The screen to display when the game ends
- SDL_Texture * winning_screen;
-
- // Up to ten echidnas
- struct echidna echidnas[10];
-};
-
-
-
-/* eat_until_newline will 'eat' one character at a time from a file until it detects it has
- * finished a line, then stops. This is used to make sure a line of text in the level files
- * has been finished before we move on to the next */
-void eat_until_newline( FILE *currentfile )
-{
- char letter='a';
- while ( letter != '\n' ) // The '\n' represents the invisible line ending characters (either CRLF or LF)
- {
- // Every time a character is read, the current position inside of the file is also moved forward
- // one character
- letter = fgetc( currentfile );
- }
-}
-
-
-
-// Load the graphics used in levels
-void level_load_resources(SDL_Renderer* renderer, struct level_struct *level )
-{
- // Load the images for things into their own 'surfaces'
- SDL_Surface* surf_entities = IMG_Load("entities.png");
- level->entities = SDL_CreateTextureFromSurface(renderer,
- surf_entities);
- SDL_FreeSurface(surf_entities);
-
- SDL_Surface* surf_tiles = IMG_Load("tiles.png");
- level->tiles = SDL_CreateTextureFromSurface(renderer,
- surf_tiles);
- SDL_FreeSurface(surf_tiles);
-
- SDL_Surface* surf_losing = IMG_Load("failscreen_01.png");
- level->losingscreens[0] = SDL_CreateTextureFromSurface(renderer,
- surf_losing);
- SDL_FreeSurface(surf_losing);
-
- SDL_Surface* surf_win = IMG_Load("winningscreen.png");
- level->winning_screen = SDL_CreateTextureFromSurface(renderer,
- surf_win);
- SDL_FreeSurface(surf_win);
-}
-
-
-
-// level_load will load a level from a text file into a level_struct
-void level_load( int level_number, struct level_struct *level )
-{
-
- // Create the level's actual filename from its number
- char levelname[20];
- sprintf( levelname, "level_%02d.level", level_number );
-
- // Attempt to open the file
- FILE *levelfile = fopen( levelname, "r"); // r = reading mode
-
-
- // Check if the file loaded, quit program if this has failed
- if ( levelfile == NULL )
- {
- // For some reason the file cannot be accessed
- // This could be because it does not exist or we don't have permission to open it
-
- fprintf(stderr, "Error: Could not open level file %d, perhaps it is somewhere else or does not exist?\n", level_number );
- fprintf(stderr, "Exiting... \n\n" );
-
- exit(1);
- }
-
- // First we need to skip the first line of the file, which is dedicated to title, author etc information
- eat_until_newline( levelfile );
-
- // The second line contains the starting position of the player
- fscanf( levelfile, "%d %d", &level->sx, &level->sy );
- eat_until_newline(levelfile);
-
- printf("Loading level %s, player at position: %d %d\n", levelname, level->sx, level->sy );
-
- /* Ieterate through the file and load the squares into the level's structure
- * Each row/line in the file represents a row of squares in the level
- * Each square is represented in the rows by a number from 0 to 255
- * Open up one of the level files with a text editor to study its structure further
- */
-
- /* WARNING: This code assumes the file is structured correctly in the first place!
- * The game will behave in an unexpected manner if the level files are not perfect!
- */
-
- int row, column; // Current position
-
- for ( row=0; row < SCREEN_HEIGHT_SQUARES; row++ )
- {
- for ( column=0; column < SCREEN_WIDTH_SQUARES; column++ )
- {
- /* we read each two letter number into a three letter character array ( string )
- * the third character is used to represent the end or 'termination' of the string
- */
- char tempstring[3];
- fgets( tempstring, 3, levelfile );
-
- // atoi() is a standard C function used to covert a string of numbers in character
- // form into an actual number ( integer )
- level->squares[column][row] = atoi( tempstring );
- }
-
- // We need to make sure that we finish the current line of numbers/characters in the
- // level file, and are up to the next, else bad things may happen
- eat_until_newline( levelfile );
- }
-
- /* Now start loading the echidna positions
- * Every line after the main level tile body is an echidna
- * The format for each line is:
- * xpos ypos face
- * Where each of them is a number, face being a number from 0 to 3 choosing the particular face of the echidna
- */
-
- int ech_no; // Echidna number
-
- for ( ech_no = 0; ech_no < 10; ech_no++ )
- {
- level->echidnas[ech_no].this_echidna_exists = 0;
- level->echidnas[ech_no].mode = 1; // Start in hunt mode
-
- // Now load the echidna values in
- if ( fscanf( levelfile, "%d %d %d", &level->echidnas[ech_no].xpos, &level->echidnas[ech_no].ypos, &level->echidnas[ech_no].face ) == 3 )
- {
- // When fscanf returns a number other than '3' ( which is how many numbers we are reading per line )
- // we know there are no more lines in the file and we should stop, hence the == 3
- level->echidnas[ech_no].this_echidna_exists = 1;
-
- printf("Echidna loaded at x:%d y:%d\n", level->echidnas[ech_no].xpos, level->echidnas[ech_no].ypos );
- }
- }
-
-
-}
-
-// Replace every tile in the level of firsttype with secondtype
-// Useful for eg opening doors
-void level_replace_tiles( struct level_struct *currentlevel, char firsttype, char secondtype )
-{
- int tilex, tiley; // Where we are up to
-
- for ( tiley=0; tiley < SCREEN_WIDTH_SQUARES; tiley++ )
- {
- for ( tilex=0; tilex < SCREEN_WIDTH_SQUARES; tilex++ )
- {
- if ( currentlevel->squares[tilex][tiley] == firsttype ) currentlevel->squares[tilex][tiley] = secondtype;
- }
- }
-}
+/*
+ * Each of the different types of tile in the levels are numbered
+ * These are also the values used in the level text files
+ *
+ * All of the level tiles are stored in one image, hence the 'Rows'
+ * below are literally the rows there are positioned in the image.
+ * Have a look at tiles.png in the game's folder to see them all.
+ */
+
+// Row 1 - main squares
+#define T_WALL 0
+#define T_FLOOR 1
+#define T_SPIKE 2
+#define T_EXIT 3
+// Row two - blue button related
+#define T_BLUE_BUTT_UP 4 // unpressed button
+#define T_BLUE_BUTT_DOWN 5 // depressed button
+#define T_BLUE_DOOR_UP 6 // door unlocked by a button
+#define T_BLUE_DOOR_DOWN 7 // door locked and impassible
+// Row three - yellow button related
+#define T_YELL_BUTT_UP 8
+#define T_YELL_BUTT_DOWN 9
+#define T_YELL_DOOR_UP 10
+#define T_YELL_DOOR_DOWN 11
+// Row four - red lever/switch related
+#define T_RED_SWITCH_ON 12
+#define T_RED_SWITCH_OFF 13
+#define T_RED_DOOR_UP 14
+#define T_RED_DOOR_DOWN 15
+
+// An echidna is one of the monsters
+// The structure is define here in level.c so it can be loaded from the level files
+struct echidna
+{
+ int xpos, ypos; // Position on map
+ int face; // Which of the echidna pictures to use
+
+ int mode; // As described at the top of the document
+
+ int this_echidna_exists; // When this is equal to 1, the echidna is alive and on the level
+
+ // These movement directions are used in the AI code
+ signed int move_x;
+ signed int move_y;
+ // ditto here
+ signed int check_x;
+ signed int check_y;
+
+};
+
+/* The level structure is passed to the rendering module, so everything that needs to be seen
+ * on-screen is also stored here as well
+ *
+ * Eg:
+ * - player position
+ * - resource locations ( graphics )
+ */
+struct level_struct
+{
+
+ char squares[SCREEN_WIDTH_SQUARES][SCREEN_HEIGHT_SQUARES]; // Squares of the level
+
+ // Player details
+ int player_face; // Picture number ( player has 4 different looks )
+ int px, py; // Player X and Y position, on the tiles
+ int sx, sy; // Player X and Y starting positions
+
+ // Resources
+ SDL_Texture * entities;
+ SDL_Texture * tiles;
+
+ // A various selection of losing screens
+ SDL_Texture * losingscreens[5];
+
+ // The screen to display when the game ends
+ SDL_Texture * winning_screen;
+
+ // Up to ten echidnas
+ struct echidna echidnas[10];
+};
+
+
+
+/* eat_until_newline will 'eat' one character at a time from a file until it detects it has
+ * finished a line, then stops. This is used to make sure a line of text in the level files
+ * has been finished before we move on to the next */
+void eat_until_newline( FILE *currentfile )
+{
+ char letter='a';
+ while ( letter != '\n' ) // The '\n' represents the invisible line ending characters (either CRLF or LF)
+ {
+ // Every time a character is read, the current position inside of the file is also moved forward
+ // one character
+ letter = fgetc( currentfile );
+ }
+}
+
+
+
+// Load the graphics used in levels
+void level_load_resources(SDL_Renderer* renderer, struct level_struct *level )
+{
+ // Load the images for things into their own 'surfaces'
+ SDL_Surface* surf_entities = IMG_Load("entities.png");
+ level->entities = SDL_CreateTextureFromSurface(renderer,
+ surf_entities);
+ SDL_FreeSurface(surf_entities);
+
+ SDL_Surface* surf_tiles = IMG_Load("tiles.png");
+ level->tiles = SDL_CreateTextureFromSurface(renderer,
+ surf_tiles);
+ SDL_FreeSurface(surf_tiles);
+
+ SDL_Surface* surf_losing = IMG_Load("failscreen_01.png");
+ level->losingscreens[0] = SDL_CreateTextureFromSurface(renderer,
+ surf_losing);
+ SDL_FreeSurface(surf_losing);
+
+ SDL_Surface* surf_win = IMG_Load("winningscreen.png");
+ level->winning_screen = SDL_CreateTextureFromSurface(renderer,
+ surf_win);
+ SDL_FreeSurface(surf_win);
+}
+
+
+
+// level_load will load a level from a text file into a level_struct
+void level_load( int level_number, struct level_struct *level )
+{
+
+ // Create the level's actual filename from its number
+ char levelname[20];
+ sprintf( levelname, "level_%02d.level", level_number );
+
+ // Attempt to open the file
+ FILE *levelfile = fopen( levelname, "r"); // r = reading mode
+
+
+ // Check if the file loaded, quit program if this has failed
+ if ( levelfile == NULL )
+ {
+ // For some reason the file cannot be accessed
+ // This could be because it does not exist or we don't have permission to open it
+
+ fprintf(stderr, "Error: Could not open level file %d, perhaps it is somewhere else or does not exist?\n", level_number );
+ fprintf(stderr, "Exiting... \n\n" );
+
+ exit(1);
+ }
+
+ // First we need to skip the first line of the file, which is dedicated to title, author etc information
+ eat_until_newline( levelfile );
+
+ // The second line contains the starting position of the player
+ fscanf( levelfile, "%d %d", &level->sx, &level->sy );
+ eat_until_newline(levelfile);
+
+ printf("Loading level %s, player at position: %d %d\n", levelname, level->sx, level->sy );
+
+ /* Ieterate through the file and load the squares into the level's structure
+ * Each row/line in the file represents a row of squares in the level
+ * Each square is represented in the rows by a number from 0 to 255
+ * Open up one of the level files with a text editor to study its structure further
+ */
+
+ /* WARNING: This code assumes the file is structured correctly in the first place!
+ * The game will behave in an unexpected manner if the level files are not perfect!
+ */
+
+ int row, column; // Current position
+
+ for ( row=0; row < SCREEN_HEIGHT_SQUARES; row++ )
+ {
+ for ( column=0; column < SCREEN_WIDTH_SQUARES; column++ )
+ {
+ /* we read each two letter number into a three letter character array ( string )
+ * the third character is used to represent the end or 'termination' of the string
+ */
+ char tempstring[3];
+ fgets( tempstring, 3, levelfile );
+
+ // atoi() is a standard C function used to covert a string of numbers in character
+ // form into an actual number ( integer )
+ level->squares[column][row] = atoi( tempstring );
+ }
+
+ // We need to make sure that we finish the current line of numbers/characters in the
+ // level file, and are up to the next, else bad things may happen
+ eat_until_newline( levelfile );
+ }
+
+ /* Now start loading the echidna positions
+ * Every line after the main level tile body is an echidna
+ * The format for each line is:
+ * xpos ypos face
+ * Where each of them is a number, face being a number from 0 to 3 choosing the particular face of the echidna
+ */
+
+ int ech_no; // Echidna number
+
+ for ( ech_no = 0; ech_no < 10; ech_no++ )
+ {
+ level->echidnas[ech_no].this_echidna_exists = 0;
+ level->echidnas[ech_no].mode = 1; // Start in hunt mode
+
+ // Now load the echidna values in
+ if ( fscanf( levelfile, "%d %d %d", &level->echidnas[ech_no].xpos, &level->echidnas[ech_no].ypos, &level->echidnas[ech_no].face ) == 3 )
+ {
+ // When fscanf returns a number other than '3' ( which is how many numbers we are reading per line )
+ // we know there are no more lines in the file and we should stop, hence the == 3
+ level->echidnas[ech_no].this_echidna_exists = 1;
+
+ printf("Echidna loaded at x:%d y:%d\n", level->echidnas[ech_no].xpos, level->echidnas[ech_no].ypos );
+ }
+ }
+
+
+}
+
+// Replace every tile in the level of firsttype with secondtype
+// Useful for eg opening doors
+void level_replace_tiles( struct level_struct *currentlevel, char firsttype, char secondtype )
+{
+ int tilex, tiley; // Where we are up to
+
+ for ( tiley=0; tiley < SCREEN_WIDTH_SQUARES; tiley++ )
+ {
+ for ( tilex=0; tilex < SCREEN_WIDTH_SQUARES; tilex++ )
+ {
+ if ( currentlevel->squares[tilex][tiley] == firsttype ) currentlevel->squares[tilex][tiley] = secondtype;
+ }
+ }
+}
diff --git a/main.c b/main.c
index c1bc2e0..0bc0ec7 100644
--- a/main.c
+++ b/main.c
@@ -1,109 +1,109 @@
-// Standard libraries ( not written by me )
-#include <stdio.h>
-#include <string.h>
-
-// SDL libraries ( not written by me )
-#include "SDL2/SDL.h"
-#include "SDL2/SDL_image.h"
-
-#ifdef __WIN32__
- // Work around a TCC<->SDL bug regarding the redefintion of main.
- // Note: the error messages from TCC make no sense
- #undef main
-#endif
-
-
-// Window dimensions
-#define SCREEN_WIDTH 640
-#define SCREEN_HEIGHT 480
-#define TILE_SIZE 32 // Width and height of 'squares' in the game
-
-#define SCREEN_WIDTH_SQUARES SCREEN_WIDTH / TILE_SIZE
-#define SCREEN_HEIGHT_SQUARES SCREEN_HEIGHT / TILE_SIZE
-
-// Modules of the game I have written ( in directory with this source file )
-#include "level.c" // Level structures, loading, other levely stuff
-#include "helpscreen.c" // Help-screen code
-#include "echidna_ai.c" // Echidna movement A
-#include "render.c" // Normal in-game rendering
-#include "game.c" // Normal in-game code
-
-/* error_sdl is called when SDL 'throws' an error
- * SDL can throw an error if the computer is for example incapable of displaying
- * the game, because it is too old ( ie made before the year 1998 ) */
-void error_sdl( char* reason )
-{
- // Print the error message and then close the game
- fprintf( stderr, "Error (SDL): %s: %s\n", reason, SDL_GetError() );
- exit(1);
-}
-
-int main(int argc, char *argv[])
-{
- // Initialisation
-
- /* First we need to tell SDL to create a window. A 'surface'
- * is created called surf_screen, 'surfaces' are simply images
- * of what we see on-screen.
- *
- * To make things appear on the screen, I copy ('blit') images
- * onto this surface at different locations
- */
-
- // Initialise SDL
- printf("Initialising SDL... ");
- if ( SDL_Init( SDL_INIT_VIDEO ) == -1 ) error_sdl("Could not initialise SDL");
- atexit(SDL_Quit);
-
- SDL_Window * sdlWindow = SDL_CreateWindow("EchidneaMenace", SDL_WINDOWPOS_UNDEFINED,
- SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL );
- SDL_Renderer *renderer = SDL_CreateRenderer(sdlWindow, -1, 0);
-
- printf("done\n");
-
- /// Menu
- printf(" ==== Entered menu\n");
-
- // Load the menu graphic into memory
- SDL_Surface *surf_title = IMG_Load( "titlescreen.png" );
- if (!surf_title) {
- error_sdl("could not get title surface\n");
- }
- SDL_Texture *surf_title_tex = SDL_CreateTextureFromSurface(renderer, surf_title);
- if (!surf_title_tex) {
- error_sdl("could not get title texture from surface\n");
- }
-
- // Need to draw before the while loop otherwise we only do the
- // initial drawing after a keydown-event
- SDL_RenderClear(renderer);
- SDL_RenderCopy(renderer, surf_title_tex, NULL, NULL);
- SDL_RenderPresent(renderer);
-
- // Events are variables used to store user input
- SDL_Event menuevent;
-
- while ( SDL_WaitEvent( &menuevent ) >= 0)
- {
- SDL_RenderClear(renderer);
- SDL_RenderCopy(renderer, surf_title_tex, NULL, NULL);
- SDL_RenderPresent(renderer);
-
- if ( menuevent.type == SDL_KEYDOWN )
- {
- // Menu choice selection
- if ( menuevent.key.keysym.sym == SDLK_p ) game_loop(renderer);
- else if ( menuevent.key.keysym.sym == SDLK_h ) help(renderer);
- else if ( menuevent.key.keysym.sym == SDLK_q || menuevent.key.keysym.sym == SDLK_ESCAPE ) exit(0);
- }
- }
-
- /* Technically the computer will never reach this point,
- * because the while statement above will run forever until the
- * user quits the game.
- *
- * The 'return' statement is still written here so the compiler
- * does not complain */
-
- return 0;
-}
+// Standard libraries ( not written by me )
+#include <stdio.h>
+#include <string.h>
+
+// SDL libraries ( not written by me )
+#include "SDL2/SDL.h"
+#include "SDL2/SDL_image.h"
+
+#ifdef __WIN32__
+ // Work around a TCC<->SDL bug regarding the redefintion of main.
+ // Note: the error messages from TCC make no sense
+ #undef main
+#endif
+
+
+// Window dimensions
+#define SCREEN_WIDTH 640
+#define SCREEN_HEIGHT 480
+#define TILE_SIZE 32 // Width and height of 'squares' in the game
+
+#define SCREEN_WIDTH_SQUARES SCREEN_WIDTH / TILE_SIZE
+#define SCREEN_HEIGHT_SQUARES SCREEN_HEIGHT / TILE_SIZE
+
+// Modules of the game I have written ( in directory with this source file )
+#include "level.c" // Level structures, loading, other levely stuff
+#include "helpscreen.c" // Help-screen code
+#include "echidna_ai.c" // Echidna movement A
+#include "render.c" // Normal in-game rendering
+#include "game.c" // Normal in-game code
+
+/* error_sdl is called when SDL 'throws' an error
+ * SDL can throw an error if the computer is for example incapable of displaying
+ * the game, because it is too old ( ie made before the year 1998 ) */
+void error_sdl( char* reason )
+{
+ // Print the error message and then close the game
+ fprintf( stderr, "Error (SDL): %s: %s\n", reason, SDL_GetError() );
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ // Initialisation
+
+ /* First we need to tell SDL to create a window. A 'surface'
+ * is created called surf_screen, 'surfaces' are simply images
+ * of what we see on-screen.
+ *
+ * To make things appear on the screen, I copy ('blit') images
+ * onto this surface at different locations
+ */
+
+ // Initialise SDL
+ printf("Initialising SDL... ");
+ if ( SDL_Init( SDL_INIT_VIDEO ) == -1 ) error_sdl("Could not initialise SDL");
+ atexit(SDL_Quit);
+
+ SDL_Window * sdlWindow = SDL_CreateWindow("EchidneaMenace", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL );
+ SDL_Renderer *renderer = SDL_CreateRenderer(sdlWindow, -1, 0);
+
+ printf("done\n");
+
+ /// Menu
+ printf(" ==== Entered menu\n");
+
+ // Load the menu graphic into memory
+ SDL_Surface *surf_title = IMG_Load( "titlescreen.png" );
+ if (!surf_title) {
+ error_sdl("could not get title surface\n");
+ }
+ SDL_Texture *surf_title_tex = SDL_CreateTextureFromSurface(renderer, surf_title);
+ if (!surf_title_tex) {
+ error_sdl("could not get title texture from surface\n");
+ }
+
+ // Need to draw before the while loop otherwise we only do the
+ // initial drawing after a keydown-event
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, surf_title_tex, NULL, NULL);
+ SDL_RenderPresent(renderer);
+
+ // Events are variables used to store user input
+ SDL_Event menuevent;
+
+ while ( SDL_WaitEvent( &menuevent ) >= 0)
+ {
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, surf_title_tex, NULL, NULL);
+ SDL_RenderPresent(renderer);
+
+ if ( menuevent.type == SDL_KEYDOWN )
+ {
+ // Menu choice selection
+ if ( menuevent.key.keysym.sym == SDLK_p ) game_loop(renderer);
+ else if ( menuevent.key.keysym.sym == SDLK_h ) help(renderer);
+ else if ( menuevent.key.keysym.sym == SDLK_q || menuevent.key.keysym.sym == SDLK_ESCAPE ) exit(0);
+ }
+ }
+
+ /* Technically the computer will never reach this point,
+ * because the while statement above will run forever until the
+ * user quits the game.
+ *
+ * The 'return' statement is still written here so the compiler
+ * does not complain */
+
+ return 0;
+}
diff --git a/render.c b/render.c
index a972c45..5f3484d 100644
--- a/render.c
+++ b/render.c
@@ -1,143 +1,143 @@
-
-
-/* Different areas of the entities.png image contain different things.
- * For example the first row are player pictures whilst the second are
- * of echidnas.
- *
- * 'SDL_Rect's are simple structures containing the location and size
- * of these individual pictures inside of the larger 'entities.png'
- *
- * The same thing is done for the different level graphics
- */
-
-// Sets the SDL_Rect * crop to the location of specified echinida
-// ( there are four echidna pictures, so which_echidna can be 0-3)
-void get_pixmap_echidna(int which_echidna, SDL_Rect * crop )
-{
- crop->x = which_echidna * TILE_SIZE;
- crop->y = 1 * TILE_SIZE; // all echidnas are in the second row
-}
-
-// Same as above, but for the player (lemon)
-void get_pixmap_lemon(int which_lemon, SDL_Rect * crop )
-{
- crop->x = which_lemon * TILE_SIZE;
- crop->y = 0; // all lemons are in the first row
-}
-
-// Getting the rectangle for level tiles is a little harder, as they are spread
-// across multiple rows. Otherwise this does similarly to above modules
-void get_pixmap_level( char number, SDL_Rect * crop )
-{
- int row, column;
-
- row = 0;
- column = (int)number;
-
- // Compensate for the fact these pictures span multiple rows
- while ( column >= 4 )
- {
- column = column - 4;
- row++; // add one to row's value
- }
-
- crop->x = column * TILE_SIZE;
- crop->y = row * TILE_SIZE;
-}
-
-
-
-
-// render() paints everything onto the screen when called
-void render(SDL_Renderer* renderer, struct level_struct *currentlevel)
-{
- /* The picture on-screen is made in three steps:
- * 1) Draw the level onto the screen surface
- * 2) Draw the player and echidnas ontop of this
- * 3) 'flip' the screen, so the changes can be seen
- */
-
- SDL_Rect destination; // where the image is going to be painted to on-screen
- SDL_Rect pixmap_crop; // where the tile image is on the source image
- destination.w = TILE_SIZE;
- destination.h = TILE_SIZE;
- pixmap_crop.w = TILE_SIZE;
- pixmap_crop.h = TILE_SIZE;
-
- /// Level drawing
-
- // ieterate through each square of the level, drawing the appropriate
- // pictures for each onto the screen
-
- int tilex, tiley; // Where we are up to
-
- for ( tiley=0; tiley < SCREEN_WIDTH_SQUARES; tiley++ )
- {
- for ( tilex=0; tilex < SCREEN_WIDTH_SQUARES; tilex++ )
- {
- /// Determine which section of the entities image we are going to use
- get_pixmap_level( currentlevel->squares[tilex][tiley] , &pixmap_crop );
- // remember that the currentlevel structure contains the array of
- // level squares/tiles
-
- /// Determine where we are going to draw this image on-screen
- destination.x = tilex * TILE_SIZE;
- destination.y = tiley * TILE_SIZE;
-
- /// Render this tile onto the screen
- int ret = SDL_RenderCopy(renderer, currentlevel->tiles,
- &pixmap_crop,
- &destination);
- if (ret < 0 ) {
- printf("Error (SDL): %s: %s\n", "could not render copy tiles", SDL_GetError());
- }
- }
- }
-
- /// Entity drawing
- // First of all the character
- get_pixmap_lemon( currentlevel->player_face, &pixmap_crop );
- destination.x = currentlevel->px * TILE_SIZE;
- destination.y = currentlevel->py * TILE_SIZE;
-
- // Render onto screen
- SDL_RenderCopy(renderer, currentlevel->entities,
- &pixmap_crop,
- &destination);
-
- // Now draw all of the echidnas
- int ech_no; // Echidna number
- for ( ech_no = 0; ech_no < 10; ech_no++ )
- {
- struct echidna current_echidna = currentlevel->echidnas[ech_no];
-
- if ( current_echidna.this_echidna_exists == 1 )
- {
- // This echidnas exists and is alive
-
- // Get its location and face
- get_pixmap_echidna( current_echidna.face, &pixmap_crop );
- destination.x = current_echidna.xpos * TILE_SIZE;
- destination.y = current_echidna.ypos * TILE_SIZE;
-
- // Render it onscreen
- SDL_RenderCopy(renderer, currentlevel->entities,
- &pixmap_crop,
- &destination);
- }
- }
-
- // Flip screen, so everything we have 'blitted' can now be seen
- SDL_RenderPresent(renderer);
-}
-
-void render_a_losingscreen(SDL_Renderer* renderer, struct level_struct *currentlevel)
-{
- // Render a losing screen
- SDL_RenderClear(renderer);
- SDL_RenderCopy(renderer, currentlevel->winning_screen, NULL, NULL);
- SDL_RenderPresent(renderer);
-
- // Wait a second so the user can see the losing screen
- SDL_Delay(2000);
-}
+
+
+/* Different areas of the entities.png image contain different things.
+ * For example the first row are player pictures whilst the second are
+ * of echidnas.
+ *
+ * 'SDL_Rect's are simple structures containing the location and size
+ * of these individual pictures inside of the larger 'entities.png'
+ *
+ * The same thing is done for the different level graphics
+ */
+
+// Sets the SDL_Rect * crop to the location of specified echinida
+// ( there are four echidna pictures, so which_echidna can be 0-3)
+void get_pixmap_echidna(int which_echidna, SDL_Rect * crop )
+{
+ crop->x = which_echidna * TILE_SIZE;
+ crop->y = 1 * TILE_SIZE; // all echidnas are in the second row
+}
+
+// Same as above, but for the player (lemon)
+void get_pixmap_lemon(int which_lemon, SDL_Rect * crop )
+{
+ crop->x = which_lemon * TILE_SIZE;
+ crop->y = 0; // all lemons are in the first row
+}
+
+// Getting the rectangle for level tiles is a little harder, as they are spread
+// across multiple rows. Otherwise this does similarly to above modules
+void get_pixmap_level( char number, SDL_Rect * crop )
+{
+ int row, column;
+
+ row = 0;
+ column = (int)number;
+
+ // Compensate for the fact these pictures span multiple rows
+ while ( column >= 4 )
+ {
+ column = column - 4;
+ row++; // add one to row's value
+ }
+
+ crop->x = column * TILE_SIZE;
+ crop->y = row * TILE_SIZE;
+}
+
+
+
+
+// render() paints everything onto the screen when called
+void render(SDL_Renderer* renderer, struct level_struct *currentlevel)
+{
+ /* The picture on-screen is made in three steps:
+ * 1) Draw the level onto the screen surface
+ * 2) Draw the player and echidnas ontop of this
+ * 3) 'flip' the screen, so the changes can be seen
+ */
+
+ SDL_Rect destination; // where the image is going to be painted to on-screen
+ SDL_Rect pixmap_crop; // where the tile image is on the source image
+ destination.w = TILE_SIZE;
+ destination.h = TILE_SIZE;
+ pixmap_crop.w = TILE_SIZE;
+ pixmap_crop.h = TILE_SIZE;
+
+ /// Level drawing
+
+ // ieterate through each square of the level, drawing the appropriate
+ // pictures for each onto the screen
+
+ int tilex, tiley; // Where we are up to
+
+ for ( tiley=0; tiley < SCREEN_WIDTH_SQUARES; tiley++ )
+ {
+ for ( tilex=0; tilex < SCREEN_WIDTH_SQUARES; tilex++ )
+ {
+ /// Determine which section of the entities image we are going to use
+ get_pixmap_level( currentlevel->squares[tilex][tiley] , &pixmap_crop );
+ // remember that the currentlevel structure contains the array of
+ // level squares/tiles
+
+ /// Determine where we are going to draw this image on-screen
+ destination.x = tilex * TILE_SIZE;
+ destination.y = tiley * TILE_SIZE;
+
+ /// Render this tile onto the screen
+ int ret = SDL_RenderCopy(renderer, currentlevel->tiles,
+ &pixmap_crop,
+ &destination);
+ if (ret < 0 ) {
+ printf("Error (SDL): %s: %s\n", "could not render copy tiles", SDL_GetError());
+ }
+ }
+ }
+
+ /// Entity drawing
+ // First of all the character
+ get_pixmap_lemon( currentlevel->player_face, &pixmap_crop );
+ destination.x = currentlevel->px * TILE_SIZE;
+ destination.y = currentlevel->py * TILE_SIZE;
+
+ // Render onto screen
+ SDL_RenderCopy(renderer, currentlevel->entities,
+ &pixmap_crop,
+ &destination);
+
+ // Now draw all of the echidnas
+ int ech_no; // Echidna number
+ for ( ech_no = 0; ech_no < 10; ech_no++ )
+ {
+ struct echidna current_echidna = currentlevel->echidnas[ech_no];
+
+ if ( current_echidna.this_echidna_exists == 1 )
+ {
+ // This echidnas exists and is alive
+
+ // Get its location and face
+ get_pixmap_echidna( current_echidna.face, &pixmap_crop );
+ destination.x = current_echidna.xpos * TILE_SIZE;
+ destination.y = current_echidna.ypos * TILE_SIZE;
+
+ // Render it onscreen
+ SDL_RenderCopy(renderer, currentlevel->entities,
+ &pixmap_crop,
+ &destination);
+ }
+ }
+
+ // Flip screen, so everything we have 'blitted' can now be seen
+ SDL_RenderPresent(renderer);
+}
+
+void render_a_losingscreen(SDL_Renderer* renderer, struct level_struct *currentlevel)
+{
+ // Render a losing screen
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, currentlevel->winning_screen, NULL, NULL);
+ SDL_RenderPresent(renderer);
+
+ // Wait a second so the user can see the losing screen
+ SDL_Delay(2000);
+}