/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // menu_game.c -- the single player menu and credits #include #ifdef _WIN32 #include #endif #include "client.h" #include "../client/qmenu.h" /* ======================================================================= STATIC FUNCTIONS ======================================================================= */ /* static float ClampCvar( float min, float max, float value ) { if ( value < min ) return min; if ( value > max ) return max; return value; } */ /* ============================================================================= CREDITS MENU ============================================================================= */ static char *menu_out_sound = "misc/menu3.wav"; static char *creditsBuffer; static int credits_start_time; // Knigthtmare added- allow credits to scroll past top of screen static int credits_start_line; static const char **credits; static char *creditsIndex[256]; //static char *creditsBuffer; static const char *idcredits[] = { "^b^s^aQUAKE II BY ID SOFTWARE", "", "^b^s^aPROGRAMMING", "John Carmack", "John Cash", "Brian Hook", "", "^b^s^aART", "Adrian Carmack", "Kevin Cloud", "Paul Steed", "", "^b^s^aLEVEL DESIGN", "Tim Willits", "American McGee", "Christian Antkow", "Paul Jaquays", "Brandon James", "", "^b^s^aBIZ", "Todd Hollenshead", "Barrett (Bear) Alexander", "Donna Jackson", "", "", "^b^s^aSPECIAL THANKS", "Ben Donges for beta testing", "", "", "", "", "", "", "^b^s^aADDITIONAL SUPPORT", "", "^b^s^aLINUX PORT AND CTF", "Dave \"Zoid\" Kirsch", "", "^b^s^aCINEMATIC SEQUENCES", "Ending Cinematic by Blur Studio - ", "Venice, CA", "", "Environment models for Introduction", "Cinematic by Karl Dolgener", "", "Assistance with environment design", "by Cliff Iwai", "", "^b^s^aSOUND EFFECTS AND MUSIC", "Sound Design by Soundelux Media Labs.", "Music Composed and Produced by", "Soundelux Media Labs. Special thanks", "to Bill Brown, Tom Ozanich, Brian", "Celano, Jeff Eisner, and The Soundelux", "Players.", "", "\"Level Music\" by Sonic Mayhem", "www.sonicmayhem.com", "", "\"Quake II Theme Song\"", "(C) 1997 Rob Zombie. All Rights", "Reserved.", "", "Track 10 (\"Climb\") by Jer Sypult", "", "Voice of computers by", "Carly Staehlin-Taylor", "", "^b^s^aTHANKS TO ACTIVISION", "^b^s^aIN PARTICULAR:", "", "John Tam", "Steve Rosenthal", "Marty Stratton", "Henk Hartong", "", "Quake II(tm) (C)1997 Id Software, Inc.", "All Rights Reserved. Distributed by", "Activision, Inc. under license.", "Quake II(tm), the Id Software name,", "the \"Q II\"(tm) logo and id(tm)", "logo are trademarks of Id Software,", "Inc. Activision(R) is a registered", "trademark of Activision, Inc. All", "other trademarks and trade names are", "properties of their respective owners.", 0 }; static const char *xatcredits[] = { "^b^s^aQUAKE II MISSION PACK: THE RECKONING", "^b^s^aBY", "^b^s^aXATRIX ENTERTAINMENT, INC.", "", "^b^s^aDESIGN AND DIRECTION", "Drew Markham", "", "^b^s^aPRODUCED BY", "Greg Goodrich", "", "^b^s^aPROGRAMMING", "Rafael Paiz", "", "^b^s^aLEVEL DESIGN / ADDITIONAL GAME DESIGN", "Alex Mayberry", "", "^b^s^aLEVEL DESIGN", "Mal Blackwell", "Dan Koppel", "", "^b^s^aART DIRECTION", "Michael \"Maxx\" Kaufman", "", "^b^s^aCOMPUTER GRAPHICS SUPERVISOR AND", "^b^s^aCHARACTER ANIMATION DIRECTION", "Barry Dempsey", "", "^b^s^aSENIOR ANIMATOR AND MODELER", "Jason Hoover", "", "^b^s^aCHARACTER ANIMATION AND", "^b^s^aMOTION CAPTURE SPECIALIST", "Amit Doron", "", "^b^s^aART", "Claire Praderie-Markham", "Viktor Antonov", "Corky Lehmkuhl", "", "^b^s^aINTRODUCTION ANIMATION", "Dominique Drozdz", "", "^b^s^aADDITIONAL LEVEL DESIGN", "Aaron Barber", "Rhett Baldwin", "", "^b^s^a3D CHARACTER ANIMATION TOOLS", "Gerry Tyra, SA Technology", "", "^b^s^aADDITIONAL EDITOR TOOL PROGRAMMING", "Robert Duffy", "", "^b^s^aADDITIONAL PROGRAMMING", "Ryan Feltrin", "", "^b^s^aPRODUCTION COORDINATOR", "Victoria Sylvester", "", "^b^s^aSOUND DESIGN", "Gary Bradfield", "", "^b^s^aMUSIC BY", "Sonic Mayhem", "", "", "", "^b^s^aSPECIAL THANKS", "^b^s^aTO", "^b^s^aOUR FRIENDS AT ID SOFTWARE", "", "John Carmack", "John Cash", "Brian Hook", "Adrian Carmack", "Kevin Cloud", "Paul Steed", "Tim Willits", "Christian Antkow", "Paul Jaquays", "Brandon James", "Todd Hollenshead", "Barrett (Bear) Alexander", "Dave \"Zoid\" Kirsch", "Donna Jackson", "", "", "", "^b^s^aTHANKS TO ACTIVISION", "^b^s^aIN PARTICULAR:", "", "Marty Stratton", "Henk \"The Original Ripper\" Hartong", "Kevin Kraff", "Jamey Gottlieb", "Chris Hepburn", "", "^b^s^aAND THE GAME TESTERS", "", "Tim Vanlaw", "Doug Jacobs", "Steven Rosenthal", "David Baker", "Chris Campbell", "Aaron Casillas", "Steve Elwell", "Derek Johnstone", "Igor Krinitskiy", "Samantha Lee", "Michael Spann", "Chris Toft", "Juan Valdes", "", "^b^s^aTHANKS TO INTERGRAPH COMPUTER SYTEMS", "^b^s^aIN PARTICULAR:", "", "Michael T. Nicolaou", "", "", "Quake II Mission Pack: The Reckoning", "(tm) (C)1998 Id Software, Inc. All", "Rights Reserved. Developed by Xatrix", "Entertainment, Inc. for Id Software,", "Inc. Distributed by Activision Inc.", "under license. Quake(R) is a", "registered trademark of Id Software,", "Inc. Quake II Mission Pack: The", "Reckoning(tm), Quake II(tm), the Id", "Software name, the \"Q II\"(tm) logo", "and id(tm) logo are trademarks of Id", "Software, Inc. Activision(R) is a", "registered trademark of Activision,", "Inc. Xatrix(R) is a registered", "trademark of Xatrix Entertainment,", "Inc. All other trademarks and trade", "names are properties of their", "respective owners.", 0 }; static const char *roguecredits[] = { "^b^s^aQUAKE II MISSION PACK 2: GROUND ZERO", "^b^s^aBY", "^b^s^aROGUE ENTERTAINMENT, INC.", "", "^b^s^aPRODUCED BY", "Jim Molinets", "", "^b^s^aPROGRAMMING", "Peter Mack", "Patrick Magruder", "", "^b^s^aLEVEL DESIGN", "Jim Molinets", "Cameron Lamprecht", "Berenger Fish", "Robert Selitto", "Steve Tietze", "Steve Thoms", "", "^b^s^aART DIRECTION", "Rich Fleider", "", "^b^s^aART", "Rich Fleider", "Steve Maines", "Won Choi", "", "^b^s^aANIMATION SEQUENCES", "Creat Studios", "Steve Maines", "", "^b^s^aADDITIONAL LEVEL DESIGN", "Rich Fleider", "Steve Maines", "Peter Mack", "", "^b^s^aSOUND", "James Grunke", "", "^b^s^aGROUND ZERO THEME", "^b^s^aAND", "^b^s^aMUSIC BY", "Sonic Mayhem", "", "^b^s^aVWEP MODELS", "Brent \"Hentai\" Dill", "", "", "", "^b^s^aSPECIAL THANKS", "^b^s^aTO", "^b^s^aOUR FRIENDS AT ID SOFTWARE", "", "John Carmack", "John Cash", "Brian Hook", "Adrian Carmack", "Kevin Cloud", "Paul Steed", "Tim Willits", "Christian Antkow", "Paul Jaquays", "Brandon James", "Todd Hollenshead", "Barrett (Bear) Alexander", "Katherine Anna Kang", "Donna Jackson", "Dave \"Zoid\" Kirsch", "", "", "", "^b^s^aTHANKS TO ACTIVISION", "^b^s^aIN PARTICULAR:", "", "Marty Stratton", "Henk Hartong", "Mitch Lasky", "Steve Rosenthal", "Steve Elwell", "", "^b^s^aAND THE GAME TESTERS", "", "The Ranger Clan", "Dave \"Zoid\" Kirsch", "Nihilistic Software", "Robert Duffy", "", "And Countless Others", "", "", "", "Quake II Mission Pack 2: Ground Zero", "(tm) (C)1998 Id Software, Inc. All", "Rights Reserved. Developed by Rogue", "Entertainment, Inc. for Id Software,", "Inc. Distributed by Activision Inc.", "under license. Quake(R) is a", "registered trademark of Id Software,", "Inc. Quake II Mission Pack 2: Ground", "Zero(tm), Quake II(tm), the Id", "Software name, the \"Q II\"(tm) logo", "and id(tm) logo are trademarks of Id", "Software, Inc. Activision(R) is a", "registered trademark of Activision,", "Inc. Rogue(R) is a registered", "trademark of Rogue Entertainment,", "Inc. All other trademarks and trade", "names are properties of their", "respective owners.", 0 }; int stringLengthExtra ( const char *string); void M_Credits_MenuDraw( void ) { float alpha /*, time = (cls.realtime - credits_start_time) * 0.05*/; int i, y, x, len; if ((viddef.height - ((cls.realtime - credits_start_time)/40.0F) + credits_start_line * scaledVideo(MENU_FONT_SIZE+2)) < 0) { credits_start_line++; if (!credits[credits_start_line]) { credits_start_line = 0; credits_start_time = cls.realtime; } } /* ** draw the credits */ for (i=credits_start_line, y=viddef.height - ((cls.realtime - credits_start_time)/40.0F) + credits_start_line * scaledVideo(MENU_FONT_SIZE+2); credits[i] && y < viddef.height; y += scaledVideo(MENU_FONT_SIZE+2), i++) // was 10 { //int j; int stringoffset = 0; int bold = false; if ( y <= -MENU_FONT_SIZE ) continue; if ( y > viddef.height ) continue; if ( credits[i][0] == '+' ) { bold = true; stringoffset = 1; } else { bold = false; stringoffset = 0; } if (y > 7*viddef.height/8) { float y_test, h_test; y_test = y - (7.0/8.0)*viddef.height; h_test = viddef.height/8; alpha = 1 - (y_test/h_test); if (alpha>1) alpha=1; if (alpha<0) alpha=0; } else if (y < viddef.height/8) { float y_test, h_test; y_test = y; h_test = viddef.height/8; alpha = y_test/h_test; if (alpha>1) alpha=1; if (alpha<0) alpha=0; } else alpha = 1; len = strlen(credits[i]) - stringLengthExtra(credits[i]); x = ( viddef.width - len * scaledVideo(MENU_FONT_SIZE) - stringoffset * scaledVideo(MENU_FONT_SIZE) ) / 2 + ( stringoffset ) * scaledVideo(MENU_FONT_SIZE); Menu_DrawString(x, y, credits[i], alpha*255); //x = ( viddef.width - len * MENU_FONT_SIZE - stringoffset * MENU_FONT_SIZE ) / 2 + ( stringoffset ) * MENU_FONT_SIZE; //DrawString (x, y, credits[i], (int)(alpha*255)); /*for ( j = 0; credits[i][j+stringoffset]; j++ ) { x = (viddef.width - strlen(credits[i]) * scaledVideo(MENU_FONT_SIZE) - stringoffset * scaledVideo(MENU_FONT_SIZE) ) / 2 + (j + stringoffset) * scaledVideo(MENU_FONT_SIZE); if ( bold ) R_DrawChar( x, y, credits[i][j+stringoffset] + 128, alpha*255); else R_DrawChar( x, y, credits[i][j+stringoffset], alpha*255); }*/ } /*if (y < 0) credits_start_time = cls.realtime;*/ } const char *M_Credits_Key( int key ) { char *sound = NULL; switch (key) { case K_ESCAPE: //case K_MOUSE2 if (creditsBuffer) FS_FreeFile (creditsBuffer); M_PopMenu (); sound = menu_out_sound; break; } return sound; } void M_Menu_Credits_f( void ) { int n; int count; char *p; creditsBuffer = NULL; count = FS_LoadFile ("credits", (void *)&creditsBuffer); if (count != -1) { p = creditsBuffer; for (n = 0; n < 255; n++) { creditsIndex[n] = p; while (*p != '\r' && *p != '\n') { p++; if (--count == 0) break; } if (*p == '\r') { *p++ = 0; if (--count == 0) break; } *p++ = 0; if (--count == 0) break; } creditsIndex[++n] = 0; credits = (const char **)creditsIndex; } else { if (modType("xatrix")) // xatrix credits = xatcredits; else if (modType("rogue")) // ROGUE credits = roguecredits; else credits = idcredits; } credits_start_time = cls.realtime; credits_start_line = 0; // Knightmare- allow credits to scroll past top of screen M_PushMenu( M_Credits_MenuDraw, M_Credits_Key); } /* ============================================================================= GAME MENU ============================================================================= */ static int m_game_cursor; static menuframework_s s_game_menu; static menuaction_s s_easy_game_action; static menuaction_s s_medium_game_action; static menuaction_s s_hard_game_action; static menuaction_s s_nitemare_game_action; static menuaction_s s_load_game_action; static menuaction_s s_save_game_action; static menuaction_s s_credits_action; static menuseparator_s s_blankline; static menuaction_s s_game_back_action; static void StartGame( void ) { // disable updates and start the cinematic going cl.servercount = -1; M_ForceMenuOff (); Cvar_SetValue( "deathmatch", 0 ); Cvar_SetValue( "coop", 0 ); Cvar_SetValue( "gamerules", 0 ); //PGM //Cbuf_AddText ("loading ; killserver ; wait ; newgame\n"); if (cls.state != ca_disconnected) // don't force loadscreen if disconnected Cbuf_AddText ("loading ; killserver ; wait\n"); Cbuf_AddText ("newgame\n"); cls.key_dest = key_game; } static void EasyGameFunc( void *data ) { Cvar_ForceSet( "skill", "0" ); StartGame(); } static void MediumGameFunc( void *data ) { Cvar_ForceSet( "skill", "1" ); StartGame(); } static void HardGameFunc( void *data ) { Cvar_ForceSet( "skill", "2" ); StartGame(); } static void NitemareGameFunc( void *data ) { Cvar_ForceSet( "skill", "3" ); StartGame(); } static void LoadGameFunc( void *unused ) { M_Menu_LoadGame_f (); } static void SaveGameFunc( void *unused ) { M_Menu_SaveGame_f(); } static void CreditsFunc( void *unused ) { M_Menu_Credits_f(); } void Game_MenuInit( void ) { /* static const char *difficulty_names[] = { "easy", "medium", "hard", 0 }; */ int y = 0; s_game_menu.x = viddef.width * 0.50 - scaledVideo(3*MENU_FONT_SIZE); s_game_menu.nitems = 0; s_easy_game_action.generic.type = MTYPE_ACTION; s_easy_game_action.generic.flags = QMF_LEFT_JUSTIFY; s_easy_game_action.generic.x = 0; s_easy_game_action.generic.y = y; // 0 s_easy_game_action.generic.name = " easy"; s_easy_game_action.generic.callback = EasyGameFunc; s_medium_game_action.generic.type = MTYPE_ACTION; s_medium_game_action.generic.flags = QMF_LEFT_JUSTIFY; s_medium_game_action.generic.x = 0; s_medium_game_action.generic.y = y += (MENU_FONT_SIZE+2); //10 s_medium_game_action.generic.name = " medium"; s_medium_game_action.generic.callback = MediumGameFunc; s_hard_game_action.generic.type = MTYPE_ACTION; s_hard_game_action.generic.flags = QMF_LEFT_JUSTIFY; s_hard_game_action.generic.x = 0; s_hard_game_action.generic.y = y += (MENU_FONT_SIZE+2); //20 s_hard_game_action.generic.name = " hard"; s_hard_game_action.generic.callback = HardGameFunc; s_nitemare_game_action.generic.type = MTYPE_ACTION; s_nitemare_game_action.generic.flags = QMF_LEFT_JUSTIFY; s_nitemare_game_action.generic.x = 0; s_nitemare_game_action.generic.y = y += (MENU_FONT_SIZE+2); //30 s_nitemare_game_action.generic.name = " nightmare"; s_nitemare_game_action.generic.callback = NitemareGameFunc; s_blankline.generic.type = MTYPE_SEPARATOR; s_load_game_action.generic.type = MTYPE_ACTION; s_load_game_action.generic.flags = QMF_LEFT_JUSTIFY; s_load_game_action.generic.x = 0; s_load_game_action.generic.y = y += 2*(MENU_FONT_SIZE+2); //50 s_load_game_action.generic.name = " load game"; s_load_game_action.generic.callback = LoadGameFunc; s_save_game_action.generic.type = MTYPE_ACTION; s_save_game_action.generic.flags = QMF_LEFT_JUSTIFY; s_save_game_action.generic.x = 0; s_save_game_action.generic.y = y += (MENU_FONT_SIZE+2); //60 s_save_game_action.generic.name = " save game"; s_save_game_action.generic.callback = SaveGameFunc; s_credits_action.generic.type = MTYPE_ACTION; s_credits_action.generic.flags = QMF_LEFT_JUSTIFY; s_credits_action.generic.x = 0; s_credits_action.generic.y = y += (MENU_FONT_SIZE+2); //70 s_credits_action.generic.name = " credits"; s_credits_action.generic.callback = CreditsFunc; s_game_back_action.generic.type = MTYPE_ACTION; s_game_back_action.generic.flags = QMF_LEFT_JUSTIFY; s_game_back_action.generic.x = 0; s_game_back_action.generic.y = y += 2*(MENU_FONT_SIZE+2); //90 s_game_back_action.generic.name = " back to main"; s_game_back_action.generic.callback = M_BackMenu; Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action ); Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action ); Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action ); Menu_AddItem( &s_game_menu, ( void * ) &s_nitemare_game_action ); Menu_AddItem( &s_game_menu, ( void * ) &s_blankline ); Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action ); Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action ); Menu_AddItem( &s_game_menu, ( void * ) &s_blankline ); Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action ); Menu_AddItem( &s_game_menu, ( void * ) &s_game_back_action ); Menu_Center( &s_game_menu ); } void Game_MenuDraw( void ) { M_Banner( "m_banner_game" ); Menu_AdjustCursor( &s_game_menu, 1 ); Menu_Draw( &s_game_menu ); } const char *Game_MenuKey( int key ) { return Default_MenuKey( &s_game_menu, key ); } void M_Menu_Game_f (void) { Game_MenuInit(); M_PushMenu( Game_MenuDraw, Game_MenuKey ); m_game_cursor = 1; } /* ============================================================================= LOADGAME MENU ============================================================================= */ #define MAX_SAVEGAMES 21 // was 15 static menuframework_s s_savegame_menu; static menuframework_s s_loadgame_menu; static menuaction_s s_loadgame_actions[MAX_SAVEGAMES]; static menuaction_s s_loadgame_back_action; static menuframework_s s_savegame_menu; static menuaction_s s_savegame_actions[MAX_SAVEGAMES]; static menuaction_s s_savegame_back_action; char m_savestrings[MAX_SAVEGAMES][32]; qboolean m_savevalid[MAX_SAVEGAMES]; qboolean m_saveshotvalid[MAX_SAVEGAMES+1]; char m_mapname[MAX_QPATH]; qboolean m_mapshotvalid; void Create_Savestrings (void) { int i; fileHandle_t f; char name[MAX_OSPATH]; char mapname[MAX_TOKEN_CHARS]; char *ch; for (i=0 ; i"); m_savevalid[i] = false; } else { FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f); if (i==0) { // grab mapname FS_Read (mapname, sizeof(mapname), f); if (mapname[0] == '*') // skip * marker Com_sprintf (m_mapname, sizeof(m_mapname), mapname+1); else Com_sprintf (m_mapname, sizeof(m_mapname), mapname); if ((ch = strchr (m_mapname, '$'))) *ch = 0; // terminate string at $ marker } FS_FCloseFile(f); m_savevalid[i] = true; } } } void InitSaveshots (qboolean loadmenu) { int i; char shotname [MAX_QPATH]; char mapshotname [MAX_QPATH]; for ( i = 1; i < MAX_SAVEGAMES; i++ ) { // free previously loaded shots Com_sprintf(shotname, sizeof(shotname), "save/save%i/shot.jpg", i); R_FreePic (shotname); Com_sprintf(shotname, sizeof(shotname), "/save/save%i/shot.jpg", i); if (R_DrawFindPic(shotname)) m_saveshotvalid[i] = true; else m_saveshotvalid[i] = false; } if (loadmenu) { // register mapshot for autosave if (m_savevalid[0]) { Com_sprintf(mapshotname, sizeof(mapshotname), "/levelshots/%s.pcx", m_mapname); if (R_DrawFindPic(mapshotname)) m_mapshotvalid = true; else m_mapshotvalid = false; } else m_mapshotvalid = false; } // register null saveshot if (R_DrawFindPic("/gfx/noscreen.pcx")) m_saveshotvalid[MAX_SAVEGAMES] = true; else m_saveshotvalid[MAX_SAVEGAMES] = false; } void DrawSaveshot (qboolean loadmenu) { char shotname [MAX_QPATH]; char mapshotname [MAX_QPATH]; int i; if (loadmenu) i = s_loadgame_actions[s_loadgame_menu.cursor].generic.localdata[0]; else i = s_savegame_actions[s_savegame_menu.cursor].generic.localdata[0]; R_DrawFill ( viddef.width/2 + scaledVideo(44), viddef.height/2 - scaledVideo(60), scaledVideo(244), scaledVideo(184), 3); if ( m_savevalid[i] && m_saveshotvalid[i] ) { Com_sprintf(shotname, sizeof(shotname), "/save/save%i/shot.jpg", i); R_DrawStretchPic ( viddef.width/2 + scaledVideo(46), viddef.height/2 - scaledVideo(58), scaledVideo(240), scaledVideo(180), shotname, 1.0); } else if ( loadmenu && i==0 && m_savevalid[i] && m_mapshotvalid ) // autosave shows mapshot { Com_sprintf(mapshotname, sizeof(mapshotname), "/levelshots/%s.pcx", m_mapname); R_DrawStretchPic ( viddef.width/2 + scaledVideo(46), viddef.height/2 - scaledVideo(58), scaledVideo(240), scaledVideo(180), mapshotname, 1.0); } else if (m_saveshotvalid[MAX_SAVEGAMES]) R_DrawStretchPic ( viddef.width/2 + scaledVideo(46), viddef.height/2 - scaledVideo(58), scaledVideo(240), scaledVideo(180), "/gfx/noscreen.pcx", 1.0); else R_DrawFill ( viddef.width/2 + scaledVideo(46), viddef.height/2 - scaledVideo(58), scaledVideo(240), scaledVideo(180), 0); } extern char *load_saveshot; char loadshotname[MAX_QPATH]; void LoadGameCallback( void *self ) { menuaction_s *a = ( menuaction_s * ) self; // set saveshot name here if ( m_saveshotvalid[ a->generic.localdata[0] ] ) { Com_sprintf(loadshotname, sizeof(loadshotname), "/save/save%i/shot.jpg", a->generic.localdata[0]); load_saveshot = loadshotname; } else load_saveshot = NULL; if ( m_savevalid[ a->generic.localdata[0] ] ) Cbuf_AddText (va("load save%i\n", a->generic.localdata[0] ) ); M_ForceMenuOff (); } void LoadGame_MenuInit ( void ) { int i; s_loadgame_menu.x = viddef.width / 2 - scaledVideo(240); //s_loadgame_menu.x = viddef.width / 2 - scaledVideo(15*MENU_FONT_SIZE); // was 120 s_loadgame_menu.y = viddef.height / 2 - scaledVideo(7.25*MENU_FONT_SIZE); // was 58 s_loadgame_menu.nitems = 0; Create_Savestrings(); for ( i = 0; i < MAX_SAVEGAMES; i++ ) { s_loadgame_actions[i].generic.name = m_savestrings[i]; s_loadgame_actions[i].generic.flags = QMF_LEFT_JUSTIFY; s_loadgame_actions[i].generic.localdata[0] = i; s_loadgame_actions[i].generic.callback = LoadGameCallback; s_loadgame_actions[i].generic.x = 0; s_loadgame_actions[i].generic.y = (i) * (MENU_FONT_SIZE+2); //10 if (i>0) // separate from autosave s_loadgame_actions[i].generic.y += 10; s_loadgame_actions[i].generic.type = MTYPE_ACTION; Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] ); } s_loadgame_back_action.generic.type = MTYPE_ACTION; s_loadgame_back_action.generic.flags = QMF_LEFT_JUSTIFY; s_loadgame_back_action.generic.x = 0; s_loadgame_back_action.generic.y = (MAX_SAVEGAMES+3)*(MENU_FONT_SIZE+2); s_loadgame_back_action.generic.name = " back"; s_loadgame_back_action.generic.callback = M_BackMenu; Menu_AddItem( &s_loadgame_menu, &s_loadgame_back_action ); InitSaveshots (true); // register saveshots } void LoadGame_MenuDraw( void ) { M_Banner( "m_banner_load_game" ); // Menu_AdjustCursor( &s_loadgame_menu, 1 ); Menu_Draw( &s_loadgame_menu ); DrawSaveshot (true); } const char *LoadGame_MenuKey( int key ) { if ( key == K_ESCAPE || key == K_ENTER ) { s_savegame_menu.cursor = s_loadgame_menu.cursor - 1; if ( s_savegame_menu.cursor < 0 ) s_savegame_menu.cursor = 0; } return Default_MenuKey( &s_loadgame_menu, key ); } void M_Menu_LoadGame_f (void) { LoadGame_MenuInit(); M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey ); } /* ============================================================================= SAVEGAME MENU ============================================================================= */ void SaveGameCallback( void *self ) { menuaction_s *a = ( menuaction_s * ) self; Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] )); M_ForceMenuOff (); } void SaveGame_MenuDraw( void ) { M_Banner( "m_banner_save_game" ); Menu_AdjustCursor( &s_savegame_menu, 1 ); Menu_Draw( &s_savegame_menu ); DrawSaveshot (false); } void SaveGame_MenuInit( void ) { int i; s_savegame_menu.x = viddef.width / 2 - scaledVideo(240); //s_savegame_menu.x = viddef.width / 2 - scaledVideo(15*MENU_FONT_SIZE); // was 120 s_savegame_menu.y = viddef.height / 2 - scaledVideo(7.25*MENU_FONT_SIZE);//was 58 s_savegame_menu.nitems = 0; Create_Savestrings(); // don't include the autosave slot for ( i = 0; i < MAX_SAVEGAMES-1; i++ ) { s_savegame_actions[i].generic.name = m_savestrings[i+1]; s_savegame_actions[i].generic.localdata[0] = i+1; s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY; s_savegame_actions[i].generic.callback = SaveGameCallback; s_savegame_actions[i].generic.x = 0; s_savegame_actions[i].generic.y = ( i ) * (MENU_FONT_SIZE+2); //10; s_savegame_actions[i].generic.type = MTYPE_ACTION; Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] ); } s_savegame_back_action.generic.type = MTYPE_ACTION; s_savegame_back_action.generic.flags = QMF_LEFT_JUSTIFY; s_savegame_back_action.generic.x = 0; s_savegame_back_action.generic.y = (MAX_SAVEGAMES+1)*(MENU_FONT_SIZE+2); s_savegame_back_action.generic.name = " back"; s_savegame_back_action.generic.callback = M_BackMenu; Menu_AddItem( &s_savegame_menu, &s_savegame_back_action ); InitSaveshots (false); } const char *SaveGame_MenuKey( int key ) { if ( key == K_ENTER || key == K_ESCAPE ) { s_loadgame_menu.cursor = s_savegame_menu.cursor - 1; if ( s_loadgame_menu.cursor < 0 ) s_loadgame_menu.cursor = 0; } return Default_MenuKey( &s_savegame_menu, key ); } void M_Menu_SaveGame_f (void) { if (!Com_ServerState()) return; // not playing a game SaveGame_MenuInit(); M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey ); Create_Savestrings (); }