/* * Alizarin Tetris * The game menu file. * * Copyright 2000, Kiri Wagstaff & Westley Weimer */ #include /* go autoconf! */ #include #include /* header files */ #include "atris.h" #include "ai.h" #include "display.h" #include "grid.h" #include "piece.h" #include "button.h" #include "sound.h" #include "menu.h" #include "options.h" /* function prototypes */ #include "ai.pro" #include "event.pro" #include "piece.pro" #include "button.pro" #include "menu.pro" #include "display.pro" typedef enum { ColorStyleMenu = 0, SoundStyleMenu = 1, PieceStyleMenu = 2, GameMenu = 3, OptionsMenu = 4, MainMenu = 5, } MainMenuChoice; typedef enum { Opt_ToggleFullScreen, Opt_ToggleFlame, Opt_ToggleSpecial, Opt_FasterLevels, Opt_LongSettleDelay, Opt_UpwardRotation, Opt_KeyRepeat, } OptionMenuChoice; #define MAX_MENU_CHOICE 6 static int start_playing = 0; static sound_styles *_ss; static color_styles *_cs; static piece_styles *_ps; static WalkRadioGroup *wrg = NULL; static GT _local_gametype; /***************************************************************************/ /* Update the given choice on the main menu */ static void updateMenu(int whichSubMenu, int choice) { wrg->wr[MainMenu].label[whichSubMenu] = wrg->wr[whichSubMenu].label[choice]; clear_radio(&wrg->wr[MainMenu]); setup_radio(&wrg->wr[MainMenu]); wrg->wr[MainMenu].x = (screen->w/3 - wrg->wr[MainMenu].area.w)/2; wrg->wr[MainMenu].y = (screen->h - wrg->wr[MainMenu].area.h)/2; } char key_repeat_label[] = "Key Repeat: 16 " ; static void OptionsMenu_setup() { wrg->wr[OptionsMenu].label[Opt_ToggleFullScreen] = "Toggle Full Screen"; if (Options.flame_wanted) wrg->wr[OptionsMenu].label[Opt_ToggleFlame] = "Background Flame: On"; else wrg->wr[OptionsMenu].label[Opt_ToggleFlame] = "Background Flame: Off"; if (Options.special_wanted) wrg->wr[OptionsMenu].label[Opt_ToggleSpecial] = "Power Pieces: On"; else wrg->wr[OptionsMenu].label[Opt_ToggleSpecial] = "Power Pieces: Off"; if (Options.faster_levels) wrg->wr[OptionsMenu].label[Opt_FasterLevels] = "Double Difficulty: On"; else wrg->wr[OptionsMenu].label[Opt_FasterLevels] = "Double Difficulty: Off"; if (Options.long_settle_delay) wrg->wr[OptionsMenu].label[Opt_LongSettleDelay] = "Long Settle Delay: On"; else wrg->wr[OptionsMenu].label[Opt_LongSettleDelay] = "Long Settle Delay: Off"; if (Options.upward_rotation) wrg->wr[OptionsMenu].label[Opt_UpwardRotation] = "Upward Rotation: On"; else wrg->wr[OptionsMenu].label[Opt_UpwardRotation] = "Upward Rotation: Off"; SPRINTF(key_repeat_label,"Key Repeat: %.2d", Options.key_repeat_delay); wrg->wr[OptionsMenu].label[Opt_KeyRepeat] = key_repeat_label; } static int OptionsMenu_action(WalkRadio *wr) { switch (wr->defaultchoice) { case Opt_ToggleFullScreen: SDL_WM_ToggleFullScreen(screen); break; case Opt_ToggleFlame: Options.flame_wanted = ! Options.flame_wanted; break; case Opt_ToggleSpecial: Options.special_wanted = ! Options.special_wanted; break; case Opt_FasterLevels: Options.faster_levels = ! Options.faster_levels; break; case Opt_LongSettleDelay: Options.long_settle_delay = ! Options.long_settle_delay; break; case Opt_UpwardRotation: Options.upward_rotation = ! Options.upward_rotation; break; case Opt_KeyRepeat: Options.key_repeat_delay = pick_key_repeat(screen); break; default: break; } OptionsMenu_setup(); clear_radio(&wrg->wr[OptionsMenu]); setup_radio(&wrg->wr[OptionsMenu]); return 0; } static int ColorStyleMenu_action(WalkRadio *wr) { _cs->choice = wr->defaultchoice; /* Update this choice on the main menu */ updateMenu((int)ColorStyleMenu, wr->defaultchoice); return 1; } static int SoundStyleMenu_action(WalkRadio *wr) { _ss->choice = wr->defaultchoice; play_all_sounds(_ss->style[_ss->choice]); /* Update this choice on the main menu */ updateMenu((int)SoundStyleMenu, wr->defaultchoice); return 1; } static int PieceStyleMenu_action(WalkRadio *wr) { _ps->choice = wr->defaultchoice; /* Update this choice on the main menu */ updateMenu((int)PieceStyleMenu, wr->defaultchoice); return 1; } static int GameMenu_action(WalkRadio *wr) { _local_gametype = wr->defaultchoice; /* start_playing = 1;*/ /* Update this choice on the main menu */ updateMenu((int)GameMenu, wr->defaultchoice); return 1; } static int MainMenu_action(WalkRadio *wr) { int i; /* If they selected a submenu, activate it */ switch (wr->defaultchoice) { case ColorStyleMenu: case SoundStyleMenu: case PieceStyleMenu: case GameMenu: case OptionsMenu: /* Make sure everything is inactive (not including the main menu) */ for (i=0; iwr[i].inactive == FALSE) { wrg->wr[i].inactive = TRUE; clear_radio(&wrg->wr[i]); } /* now activate the proper submenu */ wrg->wr[wr->defaultchoice].inactive = FALSE; wrg->cur = wr->defaultchoice; break; case 5: /* they chose go! */ start_playing = 1; gametype = _local_gametype; break; case 6: /* they chose quit */ start_playing = 1; gametype = QUIT; break; default: Debug("Invalid menu choice %d.\n", wr->defaultchoice); } return 1; } /*************************************************************************** * menu_handler() * Play the MENU-style game. ***************************************************************************/ static int menu_handler(const SDL_Event *event) { int retval; if (event->type == SDL_KEYDOWN) { switch (event->key.keysym.sym) { case SDLK_q: start_playing = 1; _local_gametype = gametype = QUIT; return 1; case SDLK_RETURN: if ((event->key.keysym.mod & KMOD_LCTRL) || (event->key.keysym.mod & KMOD_RCTRL)) { SDL_WM_ToggleFullScreen(screen); return 1; } default: break; } } retval = handle_radio_event(wrg, event); if (retval != -1) return 1; return 0; } /*************************************************************************** * play_MENU() * Play the MENU-style game. ***************************************************************************/ static int play_MENU(color_styles cs, piece_styles ps, sound_styles ss, Grid g[], int my_level, AI_Player *aip) { int curtimeleft; int match; int level[2]; /* level array: me + dummy slot */ int adjustment[2] = {-1, -1}; /* result of playing a match */ int my_adj[3]; /* my three winnings so far */ int result; color_style *event_cs[2]; /* pass these to event_loop */ sound_style *event_ss[2]; AI_Player *event_ai[2]; extern int Score[]; level[0] = my_level; /* starting level */ Score[0] = Score[1] = 0; SeedRandom(0); while (1) { /* until they give up by pressing 'q'! */ /* 5 total minutes for three matches */ curtimeleft = 300; my_adj[0] = 0; my_adj[1] = 1; my_adj[2] = 2; for (match=0; match<3 && curtimeleft > 0; match++) { /* generate the board */ /* draw the background */ g[0] = generate_board(10,20,level[0]); draw_background(screen, cs.style[0]->w, g, level, my_adj, NULL, &(aip->name)); { int i; for (i=0; iwr[i], i == wrg->cur); } /* get the result, but don't update level yet */ event_cs[0] = event_cs[1] = cs.style[cs.choice]; event_ss[0] = event_ss[1] = ss.style[ss.choice]; event_ai[0] = aip; event_ai[1] = NULL; result = event_loop(screen, ps.style[ps.choice], event_cs, event_ss, g, level, 0, &curtimeleft, 1, adjustment, menu_handler, time(NULL), AI_PLAYER, NO_PLAYER, event_ai); if (result < 0) { /* explicit quit */ return -1; } /* reset board */ my_adj[match] = adjustment[0]; } } } /*************************************************************************** * choose_gametype() * User selects the desired game type, which is returned. Uses walking * radio menus. *********************************************************************PROTO*/ int choose_gametype(piece_styles *ps, color_styles *cs, sound_styles *ss, AI_Players *ai) { /* walk-radio menu */ int i; _local_gametype = gametype; if (!wrg) { Calloc(wrg , WalkRadioGroup * , sizeof(*wrg)); wrg->n = MAX_MENU_CHOICE; Calloc(wrg->wr, WalkRadio *, wrg->n * sizeof(*wrg->wr)); wrg->cur = MainMenu; wrg->wr[PieceStyleMenu].n = ps->num_style; Malloc(wrg->wr[PieceStyleMenu].label, char**, sizeof(char*)*ps->num_style); for (i=0; inum_style; i++) wrg->wr[PieceStyleMenu].label[i] = ps->style[i]->name; wrg->wr[PieceStyleMenu].defaultchoice = ps->choice; wrg->wr[PieceStyleMenu].action = PieceStyleMenu_action; wrg->wr[ColorStyleMenu].n = cs->num_style; Malloc(wrg->wr[ColorStyleMenu].label, char**, sizeof(char*)*cs->num_style); for (i=0; inum_style; i++) wrg->wr[ColorStyleMenu].label[i] = cs->style[i]->name; wrg->wr[ColorStyleMenu].defaultchoice = cs->choice; wrg->wr[ColorStyleMenu].action = ColorStyleMenu_action; wrg->wr[SoundStyleMenu].n = ss->num_style; Malloc(wrg->wr[SoundStyleMenu].label, char**, sizeof(char*)*ss->num_style); for (i=0; inum_style; i++) wrg->wr[SoundStyleMenu].label[i] = ss->style[i]->name; wrg->wr[SoundStyleMenu].defaultchoice = ss->choice; wrg->wr[SoundStyleMenu].action = SoundStyleMenu_action; _ss = ss; _cs = cs; _ps = ps; wrg->wr[GameMenu].n = 6; Malloc(wrg->wr[GameMenu].label, char**, sizeof(char*)*wrg->wr[GameMenu].n); wrg->wr[GameMenu].label[0] = "Solo Normal Game"; wrg->wr[GameMenu].label[1] = "Solo Scoring Marathon"; wrg->wr[GameMenu].label[2] = "Solo vs. Computer"; wrg->wr[GameMenu].label[3] = "2 Players @ 1 Keyboard"; wrg->wr[GameMenu].label[4] = "2 Players, Use Network"; wrg->wr[GameMenu].label[5] = "Computer vs. Computer"; wrg->wr[GameMenu].defaultchoice = 0; wrg->wr[GameMenu].action = GameMenu_action; wrg->wr[OptionsMenu].n = 7; Malloc(wrg->wr[OptionsMenu].label, char**, sizeof(char*)*wrg->wr[OptionsMenu].n); OptionsMenu_setup(); wrg->wr[OptionsMenu].defaultchoice = 0; wrg->wr[OptionsMenu].action = OptionsMenu_action; /* Make the main menu */ wrg->wr[MainMenu].n = 7; Malloc(wrg->wr[MainMenu].label, char**, sizeof(char*)*wrg->wr[MainMenu].n); /* Main menu displays the current value for each choice */ wrg->wr[MainMenu].label[0] = wrg->wr[ColorStyleMenu].label[wrg->wr[ColorStyleMenu].defaultchoice]; wrg->wr[MainMenu].label[1] = wrg->wr[SoundStyleMenu].label[wrg->wr[SoundStyleMenu].defaultchoice]; wrg->wr[MainMenu].label[2] = wrg->wr[PieceStyleMenu].label[wrg->wr[PieceStyleMenu].defaultchoice]; wrg->wr[MainMenu].label[3] = wrg->wr[GameMenu].label[(int)_local_gametype]; wrg->wr[MainMenu].label[4] = "Special Options"; wrg->wr[MainMenu].label[5] = "Play!"; wrg->wr[MainMenu].label[6] = "Quit"; wrg->wr[MainMenu].defaultchoice = 5; wrg->wr[MainMenu].action = MainMenu_action; for (i=0; iwr[i]); } wrg->wr[ColorStyleMenu].x = 2*(screen->w/3) + (screen->w/3 - wrg->wr[ColorStyleMenu].area.w)/2; wrg->wr[ColorStyleMenu].y = (screen->h - wrg->wr[ColorStyleMenu].area.h)/2; wrg->wr[ColorStyleMenu].inactive = TRUE; wrg->wr[SoundStyleMenu].x = 2*(screen->w/3) + (screen->w/3 - wrg->wr[SoundStyleMenu].area.w)/2; wrg->wr[SoundStyleMenu].y = (screen->h - wrg->wr[SoundStyleMenu].area.h)/2; wrg->wr[SoundStyleMenu].inactive = TRUE; wrg->wr[OptionsMenu].x = 2*(screen->w/3) + (screen->w/3 - wrg->wr[OptionsMenu].area.w)/2; wrg->wr[OptionsMenu].y = (screen->h - wrg->wr[OptionsMenu].area.h)/2; wrg->wr[OptionsMenu].inactive = TRUE; wrg->wr[PieceStyleMenu].x = 2*(screen->w/3) + (screen->w/3 - wrg->wr[PieceStyleMenu].area.w)/2; wrg->wr[PieceStyleMenu].y = (screen->h - wrg->wr[PieceStyleMenu].area.h)/2; wrg->wr[PieceStyleMenu].inactive = TRUE; wrg->wr[GameMenu].x = 2*(screen->w/3) + (screen->w/3 - wrg->wr[GameMenu].area.w)/2; wrg->wr[GameMenu].y = (screen->h - wrg->wr[GameMenu].area.h)/2; wrg->wr[GameMenu].inactive = TRUE; wrg->wr[MainMenu].x = (screen->w/3 - wrg->wr[MainMenu].area.w)/2; wrg->wr[MainMenu].y = (screen->h - wrg->wr[MainMenu].area.h)/2; wrg->wr[MainMenu].inactive = FALSE; } clear_screen_to_flame(); SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY*10, SDL_DEFAULT_REPEAT_INTERVAL*10); start_playing = 0; while (1) { Grid g[2]; gametype = DEMO; play_MENU(*cs, *ps, *ss, g, Options.faster_levels ? 5 : 10, &ai->player[ZEROTO(ai->n)]); if (start_playing) { return 0; } } } /* * $Log: gamemenu.c,v $ * Revision 1.30 2001/01/06 00:25:23 weimer * changes so that we remember things ... * * Revision 1.29 2001/01/05 21:38:01 weimer * more key changes * * Revision 1.28 2001/01/05 21:12:32 weimer * advance to atris 1.0.5, add support for ".atrisrc" and changing the * keyboard repeat rate * * Revision 1.27 2000/11/10 18:16:48 weimer * changes for Atris 1.0.4 - three new special options * * Revision 1.26 2000/11/06 04:16:10 weimer * "power pieces" plus images * * Revision 1.25 2000/11/06 04:06:44 weimer * option menu * * Revision 1.24 2000/11/06 01:24:43 wkiri * Removed 'quit' from the game type menu. * * Revision 1.23 2000/11/06 01:22:40 wkiri * Updated menu system. * * Revision 1.22 2000/11/02 03:06:20 weimer * better interface for walk-radio menus: we are now ready for Kiri to change * them to add run-time options ... * * Revision 1.21 2000/11/01 03:53:06 weimer * modifications for version 1.0.1: you can pick your starting level, you can * pick the AI difficulty factor, the game is better about placing new pieces * when there is garbage, when things fall out of your control they now fall * at a uniform rate ... * * Revision 1.20 2000/10/29 22:55:01 weimer * networking consistency checks (you must have the same number of doodads): * special hotkey 'f' in main menu toggles full screen mode * added depth specification on the command line * automatically search for the darkest non-black color ... * * Revision 1.19 2000/10/29 21:23:28 weimer * One last round of header-file changes to reflect my newest and greatest * knowledge of autoconf/automake. Now if you fail to have some bizarro * function, we try to go on anyway unless it is vastly needed. * * Revision 1.18 2000/10/29 17:23:13 weimer * incorporate "xflame" flaming background for added spiffiness ... * * Revision 1.17 2000/10/29 00:17:39 weimer * added support for a system independent random number generator * * Revision 1.16 2000/10/28 21:52:56 weimer * you can now press 'Q' to quit from the main menu! * * Revision 1.15 2000/10/28 16:40:17 weimer * Further changes: we can now build .tar.gz files and RPMs! * * Revision 1.14 2000/10/22 22:05:51 weimer * Added a few new sounds ... * * Revision 1.13 2000/10/21 01:14:42 weimer * massic autoconf/automake restructure ... * * Revision 1.12 2000/10/18 23:57:49 weimer * general fixup, color changes, display changes. * Notable: "Safe" Blits and Updates now perform "clipping". No more X errors, * we hope! * * Revision 1.11 2000/10/18 02:04:02 weimer * playability changes ... * * Revision 1.10 2000/10/13 15:41:53 weimer * revamped AI support, now you can pick your AI and have AI duels (such fun!) * the mighty Aliz AI still crashes a bit, though ... :-) * * Revision 1.9 2000/10/12 22:21:25 weimer * display changes, more multi-local-play threading (e.g., myScore -> * Score[0]), that sort of thing ... * * Revision 1.8 2000/10/12 19:17:08 weimer * Further support for AI players and multiple game types. * * Revision 1.7 2000/10/12 01:38:07 weimer * added initial support for persistent player identities * * Revision 1.6 2000/10/12 00:49:08 weimer * added "AI" support and walking radio menus for initial game configuration * * Revision 1.5 2000/09/09 17:05:35 wkiri * Hideous log changes (Wes: how dare you include a comment character!) * * Revision 1.4 2000/09/09 16:58:27 weimer * Sweeping Change of Ultimate Mastery. Main loop restructuring to clean up * main(), isolate the behavior of the three game types. Move graphic files * into graphics/-, style files into styles/-, remove some unused files, * add game flow support (breaks between games, remembering your level within * this game), multiplayer support for the event loop, some global variable * cleanup. All that and a bag of chips! * * Revision 1.3 2000/09/04 22:49:51 wkiri * gamemenu now uses the new nifty menus. Also, added delete_menu. * * Revision 1.2 2000/09/04 19:48:02 weimer * interim menu for choosing among game styles, button changes (two states) * * Revision 1.1 2000/09/03 19:41:30 wkiri * Now allows you to choose the game type (though it doesn't do anything yet). * */