Dumb-ways-to-memorize
2D game
menu.c
Go to the documentation of this file.
1 #include "globals.h"
2 #include "graphics.h"
3 #include "menu.h"
4 #include "mystrings.h"
5 #include <stdio.h>
6 #include <math.h>
7 #include <string.h>
8 #include "parsepowerup.h"
9 #include "parselevel.h"
10 #include "player.h"
11 
12 menu_t *gMenus = NULL;
14 
15 /**
16  * Deselect item by number.
17  *
18  * @param [in,out] self If non-null, the class instance that this method operates on.
19  * @param item The item number to deselect.
20  *
21  * @author Anthony Rios
22  * @date 3/29/2016
23  */
24 
25 void DeselectItemByNum(menu_t *self, int item)
26 {
27  if(!self)
28  {
29  printf("Deselect item not given menu");
30  return;
31  }
32  self->mItems[item].State = MENU_ITEM_STATE_NOT_SELECTED;
33 }
34 
35 /**
36  * Select item by number.
37  *
38  * @param [in,out] self If non-null, the class instance that this method operates on.
39  * @param item The item number to select.
40  *
41  * @author Anthony Rios
42  * @date 3/29/2016
43  */
44 
45 void SelectItemByNum(menu_t *self, int item)
46 {
47  if(!self)
48  {
49  printf("Select item not given menu");
50  return;
51  }
52  self->mItems[item].State = MENU_ITEM_STATE_SELECTED;
53 }
54 
55 /**
56  * Uses gSelectedItem. Updates input and state of menu items.
57  *
58  * @param [in,out] self If non-null, the class instance that this method operates on.
59  * @param button The button.
60  *
61  * @author Anthony Rios
62  * @date 3/29/2016
63  */
64 
65 void UpdateVerticalMenu(menu_t *self, SDL_GameControllerButton button)
66 {
67  if(!self)
68  {
69  printf("NULL menu updated \n");
70  return;
71  }
72  switch(button)
73  {
74  case(SDL_CONTROLLER_BUTTON_DPAD_UP):
75  {
77  {
78  break;
79  }
81  if(gCurrentSelectedItem-1 < 0)
82  {
84  break;
85  }
88  break;
89  }
90  case(SDL_CONTROLLER_BUTTON_DPAD_DOWN):
91  {
93  if(gCurrentSelectedItem+1 == CountMem(self->mItems, sizeof(menu_item_t)))
94  {
96  break;
97  }
100  break;
101  }
102  case(SDL_CONTROLLER_BUTTON_A):
103  {
104  gGameState = self->mItems[gCurrentSelectedItem].NextState;
105  break;
106  }
107  default:
108  {
109  break;
110  }
111  }
112 }
113 
114 /**
115  * Uses mSelectedItem. Updates the menu's selected item, and checks for number of power ups selected, to
116  * determine whether to switch game states.
117  *
118  * @param [in,out] self If non-null, the class instance that this method operates on.
119  * @param button The button.
120  *
121  * @author Anthony Rios
122  * @date 3/29/2016
123  */
124 
125 void UpdatePowerUpMenu(menu_t *self, SDL_GameControllerButton button)
126 {
127  int i, powerUps, selected_power_ups;
128  object_t *temp, *choose_obj;
129  jsmntok_t *choose_tok;
130  char *choose_data;
131  if(!self)
132  {
133  printf("NULL menu updated \n");
134  return;
135  }
136  switch(button)
137  {
138  case(SDL_CONTROLLER_BUTTON_DPAD_UP):
139  {
140  if(!self->mSelectedItem)
141  {
142  self->mSelectedItem = self->mItems;
143  }
144  if(self->mSelectedItem-1 < self->mItems)
145  {
146  break;
147  }
148  self->mSelectedItem--;
149  break;
150  }
151  case(SDL_CONTROLLER_BUTTON_DPAD_DOWN):
152  {
153  if(!self->mSelectedItem)
154  {
155  self->mSelectedItem = self->mItems;
156  }
157  if(self->mSelectedItem+1 == self->mItems+self->mItemCount)
158  {
159  break;
160  }
161  self->mSelectedItem++;
162  break;
163  }
164  case(SDL_CONTROLLER_BUTTON_A):
165  {
166  if(!self->mSelectedItem)
167  {
168  self->mSelectedItem = self->mItems;
169  }
170  if(self->mSelectedItem->NextState == SPLASH)
171  {
172  self->mSelectedItem->State = (menu_item_state_t) (~self->mSelectedItem->State & MENU_ITEM_STATE_PICKED);
173  } else
174  {
175  powerUps = CountMem(gPowerUps, sizeof(power_t));
176  gSelectedPowerUps = (char**) malloc(sizeof(char*)*(powerUps+1));
177  memset(gSelectedPowerUps, 0, sizeof(char*)*(powerUps+1));
178  selected_power_ups = 0;
179  for(i = 0; i < powerUps; i++)
180  {
181  if(self->mItems[i].State & MENU_ITEM_STATE_PICKED)
182  {
183  gSelectedPowerUps[selected_power_ups] = gPowerUps[i].name;
184  selected_power_ups++;
185  }
186  }
187  if(selected_power_ups != gLevelsPerGame)
188  {
189  printf("Too many or not enough power_ups selected");
190  for(i = 0; i < selected_power_ups; i++)
191  {
192  gSelectedPowerUps[i] = NULL;
193  }
195  break;
196  }
197  gUsedPowerUps = (char**) malloc(sizeof(char*)*(selected_power_ups+1));
198  memset(gUsedPowerUps, 0, sizeof(char*)*(selected_power_ups+1));
199  gSelectedPowerUps[selected_power_ups] = NULL;
200  temp = FindObject(gGameObject, "Menus");
201  ConvertFileToUseable(JsmnToString(&temp->values[2], gGameData), NULL, &choose_data, &choose_tok);
202  choose_obj = ParseToObject(choose_tok, choose_data);
203  if(!LoadMenu(choose_obj, choose_data, CHOOSE, GUESS))
204  {
205  printf("Failure to load Choose Menu \n");
206  return;
207  }
208  for(i = 0; i < self->mItemCount; i++)
209  {
210  self->mItems[i].State = MENU_ITEM_STATE_NOT_SELECTED;
211  }
212  self->mSelectedItem = NULL;
213  gGameState = CHOOSE;
214  }
215  break;
216  }
217  default:
218  {
219  break;
220  }
221  }
222 }
223 
224 /**
225  * Updates the power select menu, sets current powerup of the player.
226  *
227  * @param [in,out] self If non-null, the class instance that this method operates on.
228  * @param button The button.
229  *
230  * @author Anthony Rios
231  * @date 3/29/2016
232  */
233 
234 void UpdatePowerSelectMenu(menu_t* self, SDL_GameControllerButton button)
235 {
236  int i, powerUps, usedPower = 1;
237  if(!self)
238  {
239  printf("NULL menu updated \n");
240  return;
241  }
242  switch(button)
243  {
244  case(SDL_CONTROLLER_BUTTON_DPAD_UP):
245  {
246  if(self->mSelectedItem-1 < self->mItems)
247  {
248  break;
249  }
250  self->mSelectedItem--;
251  break;
252  }
253  case(SDL_CONTROLLER_BUTTON_DPAD_DOWN):
254  {
255  if(self->mSelectedItem+1 == self->mItems+self->mItemCount)
256  {
257  break;
258  }
259  self->mSelectedItem++;
260  break;
261  }
262  case(SDL_CONTROLLER_BUTTON_A):
263  {
264  if(self->mSelectedItem->State != MENU_ITEM_STATE_NULL)
265  {
266  powerUps = CountMem(gSelectedPowerUps, sizeof(char*));
267  for(i = 0; i < powerUps; i++)
268  {
269  if(!gUsedPowerUps[i])
270  {
271  gUsedPowerUps[i] = self->mSelectedItem[i].Name;
272  usedPower = 0;
273  break;
274  } else if(!strcmp(self->mSelectedItem[i].Name, gUsedPowerUps[i]))
275  {
276  break;
277  }
278  }
279  if(!usedPower)
280  {
281  gCurrentPowerUpName = self->mSelectedItem[i].Name;
283 
285  gGameState = self->mSelectedItem[i].NextState;
286  if(gGameState == PLAYING)
287  {
288  InitPlayer();
289  }
290  }
291  }
292  }
293  default:
294  break;
295  }
296 
297 }
298 
300 {
301  if(gMenus)
302  {
303  printf("gMenus already initialized");
304  return -1;
305  }
306  gMenus = (menu_t*) malloc(sizeof(menu_t)*MAX_MENUS);
307  if(!gMenus)
308  {
309  printf("Allocate menu error");
310  return -1;
311  }
312  memset(gMenus, 0, sizeof(menu_t)*MAX_MENUS);
313  return 0;
314 }
315 
316 //Draw Function through gCurrentSelectedItm
317 void DrawMenuByNum(menu_t *self)
318 {
319  int i;
320  SDL_Rect selection_rect = {0,0,10,10};
321 
322  if(!self)
323  {
324  printf("Null menu tried to be drawn \n");
325  return;
326  }
327 
328  if(self->mBackground)
329  {
330  if(DrawSprite(self->mBackground, NULL , NULL, gRenderer))
331  {
332  printf("Failed to draw Background \n");
333  return;
334  }
335  }
336 
337  for(i = 0; i < self->mItemCount; i++)
338  {
339  if( i == gCurrentSelectedItem )
340  {
341  if(DrawSprite(self->mItems[i].Image, NULL , &self->mItems[i].Position, gRenderer))
342  {
343  printf("Failed to draw Menu Item : %d \n", i);
344  return;
345  }
346  selection_rect.x = self->mItems[i].Position.x;
347  selection_rect.y = self->mItems[i].Position.y;
348  SDL_RenderCopy(gRenderer, gRedTexture, &selection_rect,&selection_rect);
349  } else {
350  if(DrawSprite(self->mItems[i].Image, NULL, &self->mItems[i].Position, gRenderer))
351  {
352  printf("Failed to draw Menu Item : %d \n", i);
353  return;
354  }
355  }
356  }
357 
358 }
359 
360 //Draw Function through mItem State
361 void DrawMenuByState(menu_t *self)
362 {
363  int i;
364  SDL_Rect selection_rect = {0,0,10,10};
365 
366  if(!self)
367  {
368  printf("Null menu tried to be drawn \n");
369  return;
370  }
371 
372  if(self->mBackground)
373  {
374  DrawSprite(self->mBackground, NULL , NULL, gRenderer);
375  }
376 
377  for(i = 0; i < self->mItemCount; i++)
378  {
379  if( (self->mItems[i].State & MENU_ITEM_STATE_PICKED) || (&self->mItems[i] == self->mSelectedItem))
380  {
381  if(DrawSprite(self->mItems[i].Image, NULL , &self->mItems[i].Position, gRenderer))
382  {
383  printf("Failed to draw Menu Item : %d \n", i);
384  return;
385  }
386  selection_rect.x = self->mItems[i].Position.x;
387  selection_rect.y = self->mItems[i].Position.y;
388  SDL_RenderCopy(gRenderer, gRedTexture, &selection_rect,&selection_rect);
389  }
390  else
391  {
392 
393  if(DrawSprite(self->mItems[i].Image, NULL , &self->mItems[i].Position, gRenderer))
394  {
395  printf("Failed to draw Menu Item : %d \n", i);
396  return;
397  }
398  }
399  }
400 
401 }
402 
403 /**
404  * Sets the positions of the menu items based on the type of layout.
405  *
406  * @param [in,out] items If non-null, the items.
407  * @param type The type.
408  *
409  * @author Anthony Rios
410  * @date 3/16/2016
411  */
412 
413 void ProcessMenuItemsByType(menu_item_t *items,menu_type_t type)
414 {
415  SDL_Rect format;
416  int itemCount, i, width, height, divisor;
417  float radius;
418  itemCount = CountMem(items, sizeof(menu_item_t));
419  divisor = 0; radius = 0;
422 
423 
424  switch(type)
425  {
426  case(MENU_TYPE_H):
427  {
428  SDL_SetRect(&format, 0, height/(itemCount+1), 0, 0);
429  break;
430  }
431  case(MENU_TYPE_V) :
432  {
433  SDL_SetRect(&format, width/(itemCount+1), 0, 0, 0);
434  break;
435  }
436  case(MENU_TYPE_GRID):
437  {
438  SDL_SetRect(&format, width/(itemCount+1), height/(itemCount+1), 0, 0);
439  divisor = LargestDivisor(itemCount);
440  break;
441  }
442  case(MENU_TYPE_POWER):
443  {
444  //Center of Screen
445  SDL_SetRect(&format, width/2, height/2, 0, 0);
446  radius = (float) height/3;
447  break;
448  }
449  default:
450  {
451  SDL_SetRect(&format, 0, height/(itemCount+1), 0, 0);
452  break;
453  }
454  }
455 
456  for(i = 0; i < itemCount; i++)
457  {
458  if(type & (MENU_TYPE_H | MENU_TYPE_V | MENU_TYPE_CHOOSE))
459  {
460  items[i].Position.x = format.x * i;
461  items[i].Position.y = format.y * i;
462  }
463  if(type & MENU_TYPE_GRID)
464  {
465  items[i].Position.x = format.x * i%divisor;
466  items[i].Position.y = format.y * i/divisor;
467  }
468  if(type & MENU_TYPE_POWER)
469  {
470  items[i].Position.x = format.x - (float) radius*sinf( 3.14 * (float) i/(itemCount+1));
471  items[i].Position.y = format.y - (float) radius*cosf( 3.14 * (float) i/(itemCount+1));
472  }
473  }
474 
475 
476 }
477 
478 menu_t *LoadMenu(object_t* object, char *g_str ,GameState curr_state, GameState previous_state)
479 {
480  menu_t *menu, *ref_menu;
481  menu_item_t *ref_menu_item;
482  object_t *temp_obj;
483  char *temp_str, *type_str, *bg_str;
484  int i, temp_i, choose_i;
485 
486  //Check Vars given
487  if(!object || !g_str)
488  {
489  printf("No object / str given to load menu \n");
490  return NULL;
491  }
492 
493  //Look for free menu slot
494  menu = FindFreeMenu();
495  if(!menu)
496  {
497  printf("Could not find free menu \n");
498  return NULL;
499  }
500 
501  menu->mPreviousState = previous_state;
502  menu->mCurrentState = curr_state;
503 
504  temp_obj = FindObject(object, MENU_ITEMS);
505  if(!temp_obj)
506  {
507  printf("No items in menu %s \n", object->name);
508  return NULL;
509  }
510 
511  //Load Background
512  bg_str = FindValue(object, MENU_BACKGROUND, g_str);
513  if(!bg_str)
514  {
515  printf("No background loaded for menu %s \n", object->name);
516  } else
517  {
518  menu->mBackground = LoadSprite(bg_str, 0);
519  }
520 
521  //Check menu type
522  type_str = FindValue(object, MENU_TYPE, g_str);
523  if(!type_str)
524  {
525  printf("Not found menu layout type for %s. Switching to default vertical layout", object->name);
526  type_str = strdup(MENU_TYPE_STR_V);
527  }
528 
529  //Load Items
530  temp_i = CountObjectChildren(temp_obj);
531  if(temp_i >= MENU_ITEM_MAX)
532  {
533  printf("Max menu items for menu %s \n", object->name);
534  temp_i = MENU_ITEM_MAX -1;
535  }
536 
537  menu->mItemCount = temp_i;
538  for(i = 0; i < temp_i; i++)
539  {
540  menu->mItems[i].State = MENU_ITEM_STATE_NOT_SELECTED;
541  menu->mItems[i].Info = NULL;
542 
543  temp_str = FindValue(&temp_obj->children[i], MENU_ITEM_SPRITE, g_str);
544  if(temp_str)
545  {
546  menu->mItems[i].Image = LoadSprite(temp_str, 0);
547  }
548 
549  temp_str = FindValue(&temp_obj->children[i], MENU_ITEM_TEXT, g_str);
550  if(temp_str)
551  {
552  menu->mItems[i].Name = temp_str;
553  }
554 
555  temp_str = FindValue(&temp_obj->children[i], MENU_ITEM_LINK, g_str);
556  if(temp_str)
557  {
558  menu->mItems[i].NextState = StrToGameState(temp_str);
559  if(temp_str) free(temp_str);
560  } else
561  {
562  menu->mItems[i].NextState = SPLASH;
563  }
564 
565  temp_str = FindValue(&temp_obj->children[i], MENU_ITEM_EXTRA, g_str);
566  if(temp_str)
567  {
568  menu->mItems[i].Info = temp_str;
569  if(!menu->mItems[i].Name)
570  {
571  menu->mItems[i].Name = temp_str;
572  }
573  } else
574  {
575  menu->mItems[i].Info = NULL;
576  }
577 
578  }
579 
580  //Load extra items
581  if(!strcmp(type_str, MENU_TYPE_STR_CHOOSE))
582  {
583 
584  choose_i = CountMem(gSelectedPowerUps, sizeof(char*));
585  ref_menu = FindMenuFromGameState(GUESS);
586  if(!ref_menu)
587  {
588  printf("Trouble loading choose menu , no GUESS menu found \n");
589  }
590  else
591  {
592  for(i = 0; i < choose_i; i++)
593  {
594  ref_menu_item = FindMenuItem(ref_menu, gSelectedPowerUps[i]);
595  if(!ref_menu_item)
596  {
597  continue;
598  }
599  memcpy(&menu->mItems[menu->mItemCount+i], ref_menu_item, sizeof(menu_item_t));
600  menu->mItems[menu->mItemCount+i].State = MENU_ITEM_STATE_NOT_SELECTED;
601  menu->mItems[menu->mItemCount+i].NextState = PLAYING;
602  }
603  menu->mItemCount += choose_i;
604  }
605 
606  }
607 
608  //Calculate Menu Item Positions
609  ProcessMenuItemsByType(menu->mItems, (menu_type_t) StrToMenuType(type_str));
610  menu->mSelectedItem = menu->mItems;
611  menu->mSelectedItem->State = MENU_ITEM_STATE_SELECTED;
612  //gCurrentSelectedItem = 0;
613 
614  //Set Up Different Menu Types
615  if(!strcmp(type_str, MENU_TYPE_STR_V))
616  {
617  menu->Update = UpdateVerticalMenu;
618  menu->Draw = DrawMenuByNum;
619  } else if(!strcmp(type_str, MENU_TYPE_STR_POWER))
620  {
621  menu->Update = UpdatePowerUpMenu;
622  menu->Draw = DrawMenuByState;
623  } else if (!strcmp(type_str, MENU_TYPE_STR_CHOOSE))
624  {
625  menu->Update = UpdatePowerSelectMenu;
626  menu->Draw = DrawMenuByState;
627  } else
628  {
629  menu->Update = UpdateVerticalMenu;
630  menu->Draw = DrawMenuByNum;
631  }
632 
633  return menu;
634 
635 }
636 
637 menu_t* FindMenuFromGameState(GameState curr_state)
638 {
639  int i;
640  if(!gMenus)
641  {
642  printf("Menu Sys not Initialized");
643  return NULL;
644  }
645  for(i = 0; i < MAX_MENUS; i++)
646  {
647  if(!gMenus[i].Update)
648  {
649  continue;
650  }
651  if(gMenus[i].mCurrentState == curr_state)
652  {
653  return &gMenus[i];
654  }
655  }
656  return NULL;
657 }
658 
659 menu_t* FindFreeMenu()
660 {
661  int i, *menuCmp;
662  if(!gMenus)
663  {
664  printf("Menu System not initialized");
665  return NULL;
666  }
667  menuCmp = (int*) malloc(sizeof(menu_t));
668  memset(menuCmp, 0, sizeof(menu_t));
669  for(i = 0; i < MAX_MENUS; i++)
670  {
671  if(!memcmp(menuCmp, &gMenus[i], sizeof(menu_t)))
672  {
673  return &gMenus[i];
674  }
675  }
676  return NULL;
677 }
678 
679 menu_item_t* FindMenuItem(menu_t* menu, char* item)
680 {
681  int i, items;
682  items = CountMem(menu->mItems, sizeof(menu_item_t));
683  for(i = 0; i < items; i++)
684  {
685  if(!menu->mItems[i].Name)
686  {
687  continue;
688  }
689  if(!strcmp(item, menu->mItems[i].Name))
690  {
691  return &menu->mItems[i];
692  }
693  }
694  return NULL;
695 }
696 
697 int StrToMenuType(char *str)
698 {
699  if(!strcmp(str, MENU_TYPE_STR_H))
700  {
701  return MENU_TYPE_H;
702  }
703  if(!strcmp(str, MENU_TYPE_STR_V))
704  {
705  return MENU_TYPE_V;
706  }
707  if(!strcmp(str, MENU_TYPE_STR_GRID))
708  {
709  return MENU_TYPE_GRID;
710  }
711  if(!strcmp(str, MENU_TYPE_STR_POWER))
712  {
713  return MENU_TYPE_POWER;
714  }
715  if(!strcmp(str, MENU_TYPE_STR_CHOOSE))
716  {
717  return MENU_TYPE_CHOOSE;
718  }
719  return MENU_TYPE_NULL;
720 }
Definition: jsmn.h:40
int CountMem(void *src, int size_type)
Definition: mymath.c:51
Definition: globals.h:87
int CountObjectChildren(object_t *obj)
Definition: parseobject.c:170
GameState StrToGameState(char *str)
Definition: mystrings.c:274
object_t * FindObject(object_t *obj, char *name)
Definition: parseobject.c:120
char * JsmnToString(jsmntok_t *token, char *g_str)
Definition: mystrings.c:34
SDL_Renderer * gRenderer
Definition: graphics.c:10
int ConvertFileToUseable(char *fileName, jsmn_parser *parser, char **stringStorage, jsmntok_t **jsmnStorage)
Definition: mystrings.c:192
int gScreenWidth
Definition: graphics.c:16
int LargestDivisor(int num)
Definition: mymath.c:5
int gScreenHeight
Definition: graphics.c:17
char ** gUsedPowerUps
Definition: game.c:29
power_t * gPowerUps
Definition: game.c:42
SDL_Texture * gRedTexture
Definition: graphics.c:12
Definition: globals.h:88
object_t * gGameObject
Definition: game.c:33
menu_item_state_t
Definition: globals.h:61
GameState gGameState
Definition: game.c:44
void SDL_SetRect(SDL_Rect *rect, int x, int y, int w, int h)
Definition: graphics.c:276
int LoadSelectedLevel(int level)
Definition: game.c:390
power_t * FindPower(char *str)
Definition: parsepowerup.c:264
char ** gSelectedPowerUps
Definition: game.c:28
sprite_t * LoadSprite(const char *name, int flags)
Definition: graphics.c:107
#define SCREEN_RES_W
Definition: graphics.h:9
int DrawSprite(sprite_t *sprite, int *frame, vec2_t *position, SDL_Renderer *renderer)
Definition: graphics.c:152
void Update()
Definition: game.c:458
char * FindValue(struct object_s *obj, char *key, char *g_str)
Definition: mystrings.c:53
#define SCREEN_RES_H
Definition: graphics.h:10
char * gGameData
Definition: game.c:36
GameState
Definition: globals.h:83
void InitPlayer()
Definition: player.c:12
object_t * ParseToObject(jsmntok_t *token, char *g_str)
Definition: parseobject.c:8
power_t * gCurrentPowerUp
Definition: parsepowerup.c:16
int gLevelsPerGame
Definition: game.c:24
Definition: globals.h:85
char * gCurrentPowerUpName
Definition: game.c:43