1: /* File: snake3d.h
     2:    Submitted as part of Project 4 for EECS 672, Spring 2007
     3:    by Douglas McClendon, KUID 0536810
     4: */
     5: 
     6: /*
     7:  * snake3d.h
     8:  *
     9:  * 3-D snake game
    10:  *
    11:  * Doug McClendon
    12:  */
    13: 
    14: /*
    15:  * Defines and Constants
    16:  */
    17: 
    18: // how many frame's fps number to store, for looking at the average
    19: #define FPS_ARRAY_SIZE 256 
    20: #define FPS_INIT_VALUE 60 
    21: 
    22: // for code readability in functions which got passed snake_id
    23: #define SNAKE (game.snake[snake_id]) 
    24: 
    25: // HACK PACKAGING
    26: #define SCORE_FILE /usr/local/share/games/snake3d/scores 
    27: 
    28: // hi score parameters
    29: #define NUM_HI_SCORES 5 
    30: #define DEFAULT_CLASSIC_HI_SCORE 9 
    31: #define DEFAULT_QUEST_HI_SCORE 9 
    32: 
    33: // Animation parameters for cycling the hi score display between gametypes.
    34: // Values are in seconds and must be integers (for now)
    35: #define HI_SCORE_FADE_TIME     1 
    36: #define HI_SCORE_DISPLAY_TIME 10 
    37: // derived parameters
    38: #define HI_SCORE_FADE_TIME_USEC (HI_SCORE_FADE_TIME * 1000000) 
    39: #define HI_SCORE_DISPLAY_TIME_USEC (HI_SCORE_DISPLAY_TIME * 1000000) 
    40: #define HI_SCORE_CYCLE (2 * HI_SCORE_DISPLAY_TIME + 4 * HI_SCORE_FADE_TIME) 
    41: #define HI_SCORE_CYCLE_USEC (HI_SCORE_CYCLE * 1000000) 
    42: 
    43: // this leaves open the idea of things like 10 snakes at a time
    44: #define MAX_SNAKES 2 
    45: 
    46: // readable ascii values
    47: #define ENTERKEY 13 
    48: #define ESCAPEKEY 27 
    49: 
    50: // default controls
    51: #define P1_UPKEY 'w' 
    52: #define P1_DOWNKEY 's' 
    53: #define P1_LEFTKEY 'a' 
    54: #define P1_RIGHTKEY 'd' 
    55: 
    56: #define P2_UPKEY 'i' 
    57: #define P2_DOWNKEY 'k' 
    58: #define P2_LEFTKEY 'j' 
    59: #define P2_RIGHTKEY 'l' 
    60: 
    61: // back is increase z, right is increase x, up is increase y 
    62: #define TRANSLATE_CAMERA_FORWARD '!' 
    63: #define TRANSLATE_CAMERA_BACK '@' 
    64: #define TRANSLATE_CAMERA_LEFT '#' 
    65: #define TRANSLATE_CAMERA_RIGHT '$' 
    66: #define TRANSLATE_CAMERA_DOWN '%' 
    67: #define TRANSLATE_CAMERA_UP '^' 
    68: 
    69: #define DEBUG_DUMP_MATRIX_KEY '~' 
    70: 
    71: #define MAX_GAME_WIDTH 128 
    72: #define MAX_GAME_HEIGHT 128 
    73: 
    74: // These define the virtual
    75: // range of the geometry I draw, i.e. all vertices lie within
    76: // a rectangular solid defined by these values
    77: //
    78: // QUESTION(OpenGL): What range should I draw geometry within to get
    79: //     the most precision.  I'm doing +/-100.0f.  Should I do +/- the max
    80: //     float value???  Perhaps this is a question of the precision of IEEE 
    81: //     floats
    82: #define SCREEN_WIDTH 100.0f 
    83: #define SCREEN_HEIGHT 100.0f 
    84: #define SCREEN_DEPTH 100.0f 
    85: 
    86: /*
    87: * Typedefs
    88: */
    89: 
    90: typedef enum {LEFT, RIGHT, UP, DOWN} Direction;
    91: 
    92: typedef enum {CLASSIC, VS, QUEST} GameType;
    93: 
    94: // QUESTION(C): Can I have the same values in two enumerated types without
    95: //     them conflicting?  Or are enum's implemented as integers&#define's?
    96: typedef enum {
    97:   MENU, 
    98:   INSTRUCTIONS,
    99:   GAME_CLASSIC,
   100:   GAME_VS,
   101:   GAME_QUEST_LEVEL1,
   102:   GAME_QUEST_LEVEL2,
   103:   GAME_PAUSED,
   104:   GAME_OVER, 
   105:   ENTER_INITIALS, 
   106:   HI_SCORES, 
   107:   OFF, 
   108: } GameState;
   109: 
   110: // QUESTION(C): I use MAINMENUSTATES here as a way to find the integer number
   111: //     of elements in the enumerated type.  Is there a better way?
   112: typedef enum {
   113:   MENU_INSTRUCTIONS, 
   114:   MENU_CLASSIC, 
   115:   MENU_VS, 
   116:   MENU_QUEST, 
   117:   MENU_HI_SCORES,
   118:   MENU_QUIT,
   119:   MAINMENUSTATES,
   120: } MainMenuState;
   121: 
   122: typedef struct HiScoreEntry_tag{
   123:   int score;
   124:   char initials[3];
   125: } HiScoreEntry;
   126: 
   127: typedef struct GameHistory_tag{
   128:   HiScoreEntry classic_hiscores[NUM_HI_SCORES];
   129:   HiScoreEntry quest_hiscores[NUM_HI_SCORES];
   130: } GameHistory;
   131: 
   132: typedef struct StateDataClassic_tag{
   133:   int score;
   134: } StateDataClassic;
   135: 
   136: typedef struct StateDataQuest_tag{
   137:   int score;
   138: } StateDataQuest;
   139: 
   140: typedef struct StateDataEnter_Initials_tag{
   141:   GameType gametype;
   142:   char gametype_string[32];
   143:   int score, place;
   144:   HiScoreEntry *hiscores;
   145: 
   146:   int current_initial;
   147: } StateDataEnter_Initials;
   148: 
   149: typedef struct StateDataHi_Scores_tag{
   150:   struct timeval starttime; 
   151: } StateDataHi_Scores;
   152: 
   153: typedef struct StateData_tag{
   154:   StateDataClassic classic;
   155:   StateDataQuest quest;
   156:   StateDataEnter_Initials enter_initials;
   157:   StateDataHi_Scores hi_scores;
   158: } StateData;
   159: 
   160: /*
   161:  * This defines a position on the "game board", typically
   162:  * of size 20 X 11.  X increases left to right, starting with 0 
   163:  * Y increases bottome to top, starting with 0
   164:  */
   165: typedef struct position_tag{
   166:   int x;
   167:   int y;
   168: } Position;
   169: 
   170: typedef struct matrixnode{
   171:   // ID of the snake inhabiting this coordinate, 0 if uninhabited 
   172:   int snake;
   173:   // rotational offset of inhabitant snake segment, in degrees if any 
   174:   // 0<=sr<360
   175:   float snake_segment_angle_value;
   176:   // velocity, in revolutions per second
   177:   float snake_segment_angle_velocity;
   178:   // pointer to the next part of the snake (towards the head) that occupies 
   179:   // this coordinate.  Meaningless if snake==0, or a snake's head points to 
   180:   // this node 
   181:   Position next;
   182: } MatrixNode;
   183: 
   184: typedef struct snake{
   185:   // next_dir is used to check for valid input, 
   186:   // i.e. so the player cannot reverse direction
   187:   Direction current, next_dir;
   188:   Position head;
   189:   Position tail;
   190:   // last_tail is used for the rendering of frames between
   191:   // gameticks, to tell what direction a snake segment is moving in
   192:   Position last_tail;
   193:   int belly;
   194:   int length;
   195:   int active;
   196:   // non-intuitive, a solution to rendering the snake
   197:   int tail_hidden; 
   198: } Snake;
   199: 
   200: typedef struct GameOptionsClassic_tag{
   201:   int init_snake_length;
   202:   int init_snake_belly;
   203:   // the game matrix
   204:   int game_width;
   205:   int game_height;
   206:   int food_amount;
   207:   // the amount of time between motion in the game, in usec, 
   208:   // must be less than 1,000,000 
   209:   int timeslice;
   210: } GameOptionsClassic;
   211: 
   212: typedef struct GameOptionsVS_tag{
   213:   int init_snake_length;
   214:   int init_snake_belly;
   215:   int game_width;
   216:   int game_height;
   217:   int food_amount;
   218:   int timeslice;
   219: } GameOptionsVS;
   220: 
   221: typedef struct GameOptionsQuestLevel1_tag{
   222:   int length, food;
   223:   int width, height;
   224: } GameOptionsQuestLevel1;
   225: 
   226: typedef struct GameOptionsQuestLevel2_tag{
   227:   int length, food;
   228:   int width, height;
   229: } GameOptionsQuestLevel2;
   230: 
   231: typedef struct GameOptionsQuest_tag{
   232:   GameOptionsQuestLevel1 level1;
   233:   GameOptionsQuestLevel2 level2;
   234:   int timeslice;
   235: } GameOptionsQuest;
   236: 
   237: typedef struct GameOptions_tag{
   238:   GameOptionsClassic classic;
   239:   GameOptionsVS vs;
   240:   GameOptionsQuest quest;
   241: 
   242:   // the window size
   243:   int win_width;
   244:   int win_height;
   245:   int use_sound;
   246:   int fullscreen;
   247:   int show_fps;
   248: 
   249:   // HACK HACK HACK get rid of this
   250:   int num_snakes;
   251: 
   252:   GLubyte snake_segment_color[MAX_SNAKES][4];
   253: } GameOptions;
   254: 
   255: typedef struct Game_tag{
   256:   // current and previous states
   257:   GameState state;
   258:   GameState previous_state;
   259: 
   260:   // keep track of this so that when we return to the menu
   261:   // the same thing is highlighted as before
   262:   MainMenuState mainmenu;
   263: 
   264:   // Seperate some globals by which state they are used in.  In the
   265:   // case of a multi-state gametype, there are members like GAME_CLASSIC
   266:   StateData statedata;
   267: 
   268:   GameOptions options;
   269: 
   270:   Position food;
   271:   Snake snake[MAX_SNAKES];
   272:   // The playing board
   273:   MatrixNode matrix[MAX_GAME_WIDTH][MAX_GAME_HEIGHT];
   274:   // The current gamespeed, i.e. the amount of time between motion in the 
   275:   // game, in usec, must be less than 1,000,000 
   276:   int timeslice;
   277:   int game_width, game_height;
   278:   int food_amount;
   279: 
   280: /*
   281:  * Notes on gametime, and what happens during a pause
   282:  * --------------------------------------------------
   283:  * 
   284:  * The concept of time is maintained with two game state variables, 
   285:  * numticks, and time_of_last_gametick.  TOLG is the exact moment at
   286:  * which the snake was last moved, or the game was "ticked".  Numticks
   287:  * is incremented every tick.  During pause however, we changed the sense
   288:  * of the variable TOLG into the amount of time between the time of the 
   289:  * pause, and the time of the last game tick.  Then when the game is 
   290:  * unpuased, we use this value and the current time to compute a new value
   291:  * for TOLG which will maintain a consistency of what TOLG means.  This 
   292:  * results in smooth rendering.
   293:  */
   294: 
   295:   // time tracking 
   296:   int numticks;
   297:   struct timeval time_of_last_gametick; 
   298: 
   299:   //
   300:   // Notes on fps tracking
   301:   // ---------------------
   302:   // S3D's FPS tracking involves-
   303:   // -the number of frames rendered since beginning of a game (frames_rendered)
   304:   // -the exact time the last frame render occurred(time_of_last_render)
   305:   // -the framerate of _just_ the last frame (fps_last_frame)
   306:   // -the framerate average of the last FPS_ARRAY_SIZE frames, calculated
   307:   //      using a rotating buffer of framerates(fps_history, 
   308:   //      fps_history_pointer, fps_history_total)
   309:   // -a pseudo "worst framerate of the last FPS_ARRAY_SIZE frames"
   310:   //      (fps_recent_worst_value, fps_recent_worst_index)
   311:   int frames_rendered;
   312:   struct timeval time_of_last_render; // time of last frame render 
   313:   int fps_last_frame; // current rendering rate, only for the last frame 
   314:   int *fps_history;
   315:   int fps_history_pointer; 
   316:   int fps_history_total; 
   317:   int fps_recent_worst_value;
   318:   int fps_recent_worst_index;
   319: 
   320:   // various frequently used (by rendering) values calculated at the start of 
   321:   // each game
   322:   float render_width;
   323:   float render_height;
   324:   float screen_unit_length;
   325: } Game;
   326: 
   327: typedef struct JoystickState_tag{
   328:   int j1_fd;
   329:   int j1_axis[2];
   330:   char j1_button[10];
   331:   int j1_button_buffer[10];
   332: 
   333:   int j2_fd;
   334:   int j2_axis[2];
   335:   char j2_button[10];
   336:   int j2_button_buffer[10];
   337: } JoystickState;
   338: 
   339: /*
   340:  * Macros
   341:  */
   342: 
   343: // subtract one timeval from another, result in usec
   344: #define TIMEDIFF(TIMEA, TIMEB) \ 
   345:    (1000000 * (TIMEA.tv_sec - TIMEB.tv_sec) + (TIMEA.tv_usec - TIMEB.tv_usec))
   346: #define MAX(X, Y) ( (X < Y) ? Y : X ) 
   347: #define MIN(X, Y) ( (X < Y) ? X : Y ) 
   348: 
   349: /*
   350:  * Prototypes
   351:  */
   352: 
   353: //
   354: // joystick engine functions
   355: //
   356: void JoystickInit(void);
   357: void JoystickFini(void);
   358: 
   359: //
   360: // registered callbacks
   361: //
   362: void reshape(int w, int h);
   363: 
   364: // timer call, one for each game(playable) state
   365: void timer_classic(int value);
   366: void timer_vs(int value);
   367: void timer_quest_level1(int value);
   368: void timer_quest_level2(int value);
   369: 
   370: // one key function for each game.state
   371: void key_shared(unsigned char k, int x, int y);
   372: void key_menu(unsigned char k, int x, int y);
   373: void key_game_shared(unsigned char k, int x, int y);
   374: void key_game_paused(unsigned char k, int x, int y);
   375: void key_game_over(unsigned char k, int x, int y);
   376: void key_enter_initials(unsigned char k, int x, int y);
   377: void key_hi_scores(unsigned char k, int x, int y);
   378: 
   379: // only one special and joy function which just translate the 
   380: // special key or joystick event into a normal key. It then
   381: // calls key() which is a wrapper wich calls key_* according 
   382: // to current gamestate
   383: void joy(void);
   384: void special(int k, int x, int y);
   385: void key(unsigned char k, int x, int y);
   386: 
   387: // currently every state uses idle_shared which just checks for joy events,
   388: // and translates them into key() calls
   389: void idle_shared(void);
   390: 
   391: // one draw function for each game.state and nothing placeholder
   392: void draw_nothing(void);
   393: void draw_menu(void);
   394: void draw_game(void);
   395: void draw_game_paused(void);
   396: void draw_game_over(void);
   397: void draw_enter_initials(void);
   398: void draw_hi_scores(void);
   399: 
   400: // drawing subroutines (called from draw_*)
   401: void draw_arena(void);
   402: void draw_snake(int snake_id, float partial_factor);
   403: void draw_food(void);
   404: void draw_text(void);
   405: void draw_brick(float x, float y);
   406: 
   407: // other game functions
   408: void GraphicsInit(void);
   409: void S3DInit(void);
   410: void SetState(GameState new_state);
   411: void SetTimePausing(void);
   412: void SetTimeIfUnpausing(void);
   413: void movesnake(int snake_id);     
   414: void movesnake_gameover(int snake_id);     
   415: void HideTail(int snake_id);     
   416: void ShrinkTail(int snake_id);     
   417: void UnhideTail(int snake_id);     
   418: int  InsertNewHiScore(void);
   419: void StartNewGameClassic(void);
   420: void StartNewGameVS(void);
   421: void StartNewGameQuest(void);
   422: void StartQuestLevel1(void);
   423: void StartQuestLevel2(void);
   424: void InitLevel(void);
   425: void InitSnake(int snake_id);
   426: 
   427: // History functions
   428: void ReadGameHistory(void);
   429: void WriteGameHistory(void);
   430: 
   431: // usage
   432: void Usage(void);
   433: 
   434: // debug functions
   435: void debug_dump_matrix(void);
   436: 
   437: