// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id$ // // Copyright (C) 1993-1996 by 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. // // $Log$ // Revision 1.7 2006/12/13 04:44:17 kkurbjun // Dehacked and BEX support for Doom - currently only supports a DEHACKED file in a WAD (not as a standalone file yet). // // Revision 1.6 2006-04-16 23:14:04 kkurbjun // Fix run so that it stays enabled across level loads. Removed some unused code and added some back in for hopeful future use. // // Revision 1.5 2006-04-04 23:58:37 kkurbjun // Make savegame strings more informative // // Revision 1.4 2006-04-04 23:13:50 kkurbjun // Fix up configurable keys, edit exit string, more work needs to be done on menu keys // // Revision 1.3 2006-04-03 20:03:02 kkurbjun // Updates doom menu w/ new graphics, now requires rockdoom.wad: http://alamode.mines.edu/~kkurbjun/rockdoom.wad // // Revision 1.2 2006-04-03 00:28:13 kkurbjun // Fixes graphic errors in scaling code, note sure about the fix in hu_lib.c though. I havn't seen any corrupted text but it may still need a proper fix. // // Revision 1.1 2006-03-28 15:44:01 dave // Patch #2969 - Doom! Currently only working on the H300. // // // DESCRIPTION: // DOOM selection menu, options, episode etc. // Sliders and icons. Kinda widget stuff. // //----------------------------------------------------------------------------- #include "doomdef.h" #include "dstrings.h" #include "d_main.h" #include "i_system.h" #include "i_video.h" #include "z_zone.h" #include "v_video.h" #include "w_wad.h" #include "r_main.h" #include "d_deh.h" #include "hu_stuff.h" #include "g_game.h" #include "m_argv.h" #include "m_swap.h" #include "s_sound.h" #include "doomstat.h" // Data. #include "sounds.h" #include "m_menu.h" #include "rockmacros.h" extern patchnum_t hu_font[HU_FONTSIZE]; extern boolean message_dontfuckwithme; extern boolean chat_on; // in heads-up code // // defaulted values // int mouseSensitivity; // has default // Show messages has default, 0 = off, 1 = on int showMessages; // Blocky mode, has default, 0 = high, 1 = normal int screenblocks; // has default // temp for screenblocks (0-9) int screenSize; // -1 = no quicksave slot picked! int quickSaveSlot; // 1 = message to be printed int messageToPrint; // ...and here is the message string! const char* messageString; // message x & y int messx; int messy; int messageLastMenuActive; // timed message = no input from user boolean messageNeedsInput; void (*messageRoutine)(int response); #define SAVESTRINGSIZE 24 // we are going to be entering a savegame string int saveStringEnter; int saveSlot; // which slot to save in int saveCharIndex; // which char we're editing // old save description before edit char saveOldString[SAVESTRINGSIZE]; boolean inhelpscreens; boolean menuactive; #define SKULLXOFF -32 #define LINEHEIGHT 16 extern boolean sendpause; char savegamestrings[10][SAVESTRINGSIZE]; char endstring[170]; // // MENU TYPEDEFS // typedef struct { // 0 = no cursor here, 1 = ok, 2 = arrows ok short status; char name[10]; // choice = menu item #. // if status = 2, // choice=0:leftarrow,1:rightarrow void (*routine)(int choice); // hotkey in menu char alphaKey; } menuitem_t; typedef struct menu_s { short numitems; // # of menu items struct menu_s* prevMenu; // previous menu menuitem_t* menuitems; // menu items void (*routine)(void); // draw routine ROCKBOX short x; short y; // x,y of menu short lastOn; // last item user was on in menu } menu_t; short itemOn; // menu item skull is on short skullAnimCounter; // skull animation counter short whichSkull; // which skull to draw int systemvol; // graphic name of skulls // warning: initializer-string for array of chars is too long char skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"}; // current menudef menu_t* currentMenu; // // PROTOTYPES // void M_NewGame(int choice); void M_Episode(int choice); void M_ChooseSkill(int choice); void M_LoadGame(int choice); void M_SaveGame(int choice); void M_Options(int choice); void M_EndGame(int choice); void M_ReadThis(int choice); void M_ReadThis2(int choice); void M_QuitDOOM(int choice); void M_ChangeMessages(int choice); void M_ChangeGamma(int choice); void M_SfxVol(int choice); void M_MusicVol(int choice); void M_SystemVol(int choice); void M_SizeDisplay(int choice); void M_StartGame(int choice); void M_Sound(int choice); void M_FinishReadThis(int choice); void M_LoadSelect(int choice); void M_SaveSelect(int choice); void M_ReadSaveStrings(void); void M_QuickSave(void); void M_QuickLoad(void); void M_DrawMainMenu(void); void M_DrawReadThis1(void); void M_DrawReadThis2(void); void M_DrawNewGame(void); void M_DrawEpisode(void); void M_DrawOptions(void); void M_DrawSound(void); void M_DrawLoad(void); void M_DrawSave(void); void M_DrawSaveLoadBorder(int x,int y); void M_SetupNextMenu(menu_t *menudef); void M_DrawThermo(int x,int y,int thermWidth,int thermDot); void M_DrawEmptyCell(menu_t *menu,int item); void M_DrawSelCell(menu_t *menu,int item); void M_WriteText(int x, int y, char *string); int M_StringWidth(const char* string); int M_StringHeight(const char* string); void M_StartControlPanel(void); void M_StartMessage(const char *string,void *routine,boolean input); void M_StopMessage(void); void M_ClearMenus (void); // // DOOM MENU // enum { newgame = 0, options, loadgame, savegame, readthis, quitdoom, main_end }; unsigned main_e; menuitem_t MainMenu[]= { {1,"M_NGAME",M_NewGame,'n'}, {1,"M_OPTION",M_Options,'o'}, {1,"M_LOADG",M_LoadGame,'l'}, {1,"M_SAVEG",M_SaveGame,'s'}, // Another hickup with Special edition. {1,"M_RDTHIS",M_ReadThis,'r'}, {1,"M_QUITG",M_QuitDOOM,'q'} }; menu_t MainDef = { main_end, NULL, MainMenu, M_DrawMainMenu, 97,64, 0 }; // // EPISODE SELECT // enum { ep1, ep2, ep3, ep4, ep_end }; unsigned episodes_e; menuitem_t EpisodeMenu[]= { {1,"M_EPI1", M_Episode,'k'}, {1,"M_EPI2", M_Episode,'t'}, {1,"M_EPI3", M_Episode,'i'}, {1,"M_EPI4", M_Episode,'t'} }; menu_t EpiDef = { ep_end, // # of menu items &MainDef, // previous menu EpisodeMenu, // menuitem_t -> M_DrawEpisode, // drawing routine -> 48,63, // x,y ep1 // lastOn }; // // NEW GAME // enum { killthings, toorough, hurtme, violence, nightmare, newg_end }; unsigned newgame_e; menuitem_t NewGameMenu[]= { {1,"M_JKILL", M_ChooseSkill, 'i'}, {1,"M_ROUGH", M_ChooseSkill, 'h'}, {1,"M_HURT", M_ChooseSkill, 'h'}, {1,"M_ULTRA", M_ChooseSkill, 'u'}, {1,"M_NMARE", M_ChooseSkill, 'n'} }; menu_t NewDef = { newg_end, // # of menu items &EpiDef, // previous menu NewGameMenu, // menuitem_t -> M_DrawNewGame, // drawing routine -> 48,63, // x,y hurtme // lastOn }; // // OPTIONS MENU // enum { endgame, messages, scrnsize, option_empty1, gamasens, option_empty2, soundvol, opt_end }; unsigned options_e; menuitem_t OptionsMenu[]= { {1,"M_ENDGAM", M_EndGame,'e'}, {1,"M_MESSG", M_ChangeMessages,'m'}, {2,"M_SCRNSZ", M_SizeDisplay,'s'}, {-1,"",0,0}, {2,"M_GAMMA", M_ChangeGamma,'m'}, {-1,"",0,0}, {1,"M_SVOL", M_Sound,'s'} }; menu_t OptionsDef = { opt_end, &MainDef, OptionsMenu, M_DrawOptions, 60,37, 0 }; // // Read This! MENU 1 & 2 // enum { rdthsempty1, read1_end }; unsigned read_e; menuitem_t ReadMenu1[] = { {1,"",M_ReadThis2,0} }; menu_t ReadDef1 = { read1_end, &MainDef, ReadMenu1, M_DrawReadThis1, 280,185, 0 }; enum { rdthsempty2, read2_end }; unsigned read_e2; menuitem_t ReadMenu2[]= { {1,"",M_FinishReadThis,0} }; menu_t ReadDef2 = { read2_end, &ReadDef1, ReadMenu2, M_DrawReadThis2, 330,175, 0 }; // // SOUND VOLUME MENU // enum { sfx_vol, sfx_empty1, music_vol, sfx_empty2, system_vol, sfx_empty3, sound_end }; unsigned sound_e; menuitem_t SoundMenu[]= { {2,"M_SFXVOL",M_SfxVol,'s'}, {-1,"",0,0}, //ROCKBOX {2,"M_MUSVOL",M_MusicVol,'m'}, {-1,"",0,0}, //ROCKBOX {2,"M_SYSVOL",M_SystemVol,'z'}, {-1,"",0,0} //ROCKBOX }; menu_t SoundDef = { sound_end, &OptionsDef, SoundMenu, M_DrawSound, 80,64, 0 }; // // LOAD GAME MENU // enum { load1, load2, load3, load4, load5, load6, load_end }; unsigned load_e; menuitem_t LoadMenu[]= { {1,"", M_LoadSelect,'1'}, {1,"", M_LoadSelect,'2'}, {1,"", M_LoadSelect,'3'}, {1,"", M_LoadSelect,'4'}, {1,"", M_LoadSelect,'5'}, {1,"", M_LoadSelect,'6'} }; menu_t LoadDef = { load_end, &MainDef, LoadMenu, M_DrawLoad, 80,54, 0 }; // // SAVE GAME MENU // menuitem_t SaveMenu[]= { {1,"", M_SaveSelect,'1'}, {1,"", M_SaveSelect,'2'}, {1,"", M_SaveSelect,'3'}, {1,"", M_SaveSelect,'4'}, {1,"", M_SaveSelect,'5'}, {1,"", M_SaveSelect,'6'} }; menu_t SaveDef = { load_end, &MainDef, SaveMenu, M_DrawSave, 80,54, 0 }; // // M_ReadSaveStrings // read the strings from the savegame files // void M_ReadSaveStrings(void) { int handle; int i; char name[256]; for (i = 0;i < load_end;i++) { if (M_CheckParm("-cdrom")) snprintf(name,sizeof(name),"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",i); else snprintf(name,sizeof(name),SAVEGAMENAME"%d.dsg",i); handle = open (name, O_RDONLY | 0); if (handle == -1) { strcpy(&savegamestrings[i][0],EMPTYSTRING); LoadMenu[i].status = 0; continue; } read (handle, &savegamestrings[i], SAVESTRINGSIZE); close (handle); LoadMenu[i].status = 1; } } #define LOADGRAPHIC_Y 8 // // M_LoadGame & Cie. // void M_DrawLoad(void) { int i; V_DrawNamePatch(72 ,LOADGRAPHIC_Y, 0, "M_LOADG", CR_DEFAULT, VPT_STRETCH); for (i = 0;i < load_end; i++) { M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); } } // // Draw border for the savegame description // void M_DrawSaveLoadBorder(int x,int y) { int i; V_DrawNamePatch(x-8, y+7, 0, "M_LSLEFT", CR_DEFAULT, VPT_STRETCH); for (i = 0;i < 24;i++) { V_DrawNamePatch(x, y+7, 0, "M_LSCNTR", CR_DEFAULT, VPT_STRETCH); x += 8; } V_DrawNamePatch(x, y+7, 0, "M_LSRGHT", CR_DEFAULT, VPT_STRETCH); } // // User wants to load this game // void M_LoadSelect(int choice) { char name[256]; if (M_CheckParm("-cdrom")) snprintf(name,sizeof(name),"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",choice); else snprintf(name,sizeof(name),SAVEGAMENAME"%d.dsg",choice); G_LoadGame (choice, false); M_ClearMenus (); } // // Selected from DOOM menu // void M_LoadGame (int choice) { (void)choice; if (netgame) { M_StartMessage(LOADNET,NULL,false); return; } M_SetupNextMenu(&LoadDef); M_ReadSaveStrings(); } // // M_SaveGame & Cie. // void M_DrawSave(void) { int i; V_DrawNamePatch(72, LOADGRAPHIC_Y, 0, "M_SAVEG", CR_DEFAULT, VPT_STRETCH); for (i = 0;i < load_end; i++) { M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); } if (saveStringEnter) { i = M_StringWidth(savegamestrings[saveSlot]); M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_"); } } // // M_Responder calls this when user is finished // void M_DoSave(int slot) { G_SaveGame (slot,savegamestrings[slot]); M_ClearMenus (); // PICK QUICKSAVE SLOT YET? if (quickSaveSlot == -2) quickSaveSlot = slot; } // // User wants to save. Start string input for M_Responder // void M_SaveSelect(int choice) { // we are going to be intercepting all chars saveStringEnter = 1; saveSlot = choice; snprintf(savegamestrings[choice], sizeof(savegamestrings[choice]), (gamemode==shareware||gamemode==registered||gamemode==retail) ? *mapnames[(gameepisode-1)*9+gamemap-1] : (gamemission==doom2) ? *mapnames2[gamemap-1] : (gamemission==pack_plut) ? *mapnamesp[gamemap-1] : (gamemission==pack_tnt) ? *mapnamest[gamemap-1] : "Unknown Location", choice); if (!strcmp(savegamestrings[choice],s_EMPTYSTRING)) savegamestrings[choice][0] = 0; saveCharIndex = strlen(savegamestrings[choice]); } // // Selected from DOOM menu // void M_SaveGame (int choice) { (void)choice; if (!usergame) { M_StartMessage(s_SAVEDEAD,NULL,false); return; } if (gamestate != GS_LEVEL) return; M_SetupNextMenu(&SaveDef); M_ReadSaveStrings(); } // // M_QuickSave // char tempstring[80]; void M_QuickSaveResponse(int ch) { if (ch == 'y') { M_DoSave(quickSaveSlot); S_StartSound(NULL,sfx_swtchx); } } void M_QuickSave(void) { if (!usergame) { S_StartSound(NULL,sfx_oof); return; } if (gamestate != GS_LEVEL) return; if (quickSaveSlot < 0) { M_StartControlPanel(); M_ReadSaveStrings(); M_SetupNextMenu(&SaveDef); quickSaveSlot = -2; // means to pick a slot now return; } snprintf(tempstring,sizeof(tempstring),s_QSPROMPT,savegamestrings[quickSaveSlot]); M_StartMessage(tempstring,M_QuickSaveResponse,true); } // // M_QuickLoad // void M_QuickLoadResponse(int ch) { if (ch == 'y') { M_LoadSelect(quickSaveSlot); S_StartSound(NULL,sfx_swtchx); } } void M_QuickLoad(void) { if (netgame) { M_StartMessage(QLOADNET,NULL,false); return; } if (quickSaveSlot < 0) { M_StartMessage(QSAVESPOT,NULL,false); return; } snprintf(tempstring, sizeof(tempstring), QLPROMPT,savegamestrings[quickSaveSlot]); M_StartMessage(tempstring,M_QuickLoadResponse,true); } // // Read This Menus // Had a "quick hack to fix romero bug" // void M_DrawReadThis1(void) { inhelpscreens = true; switch ( gamemode ) { case commercial: V_DrawNamePatch(0, 0, 0, "HELP", CR_DEFAULT, VPT_STRETCH); break; case shareware: case registered: case retail: V_DrawNamePatch(0, 0, 0, "HELP1", CR_DEFAULT, VPT_STRETCH); break; default: break; } return; } // // Read This Menus - optional second page. // void M_DrawReadThis2(void) { inhelpscreens = true; switch ( gamemode ) { case retail: case commercial: // This hack keeps us from having to change menus. V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH); break; case shareware: case registered: V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH); break; default: break; } return; } // // Change Sfx & Music volumes // void M_DrawSound(void) { int sysmax=(rb->sound_max(SOUND_VOLUME)-rb->sound_min(SOUND_VOLUME)); V_DrawNamePatch(60, 38, 0, "M_SVOL", CR_DEFAULT, VPT_STRETCH); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1), 16,snd_SfxVolume); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1), 16,snd_MusicVolume); M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(system_vol+1), 16,(sysmax+systemvol)/5); } void M_Sound(int choice) { (void) choice; M_SetupNextMenu(&SoundDef); } void M_SfxVol(int choice) { switch(choice) { case 0: if (snd_SfxVolume) snd_SfxVolume--; break; case 1: if (snd_SfxVolume < 15) snd_SfxVolume++; break; } S_SetSfxVolume(snd_SfxVolume /* *8 */); } void M_MusicVol(int choice) { switch(choice) { case 0: if (snd_MusicVolume) snd_MusicVolume--; break; case 1: if (snd_MusicVolume < 15) snd_MusicVolume++; break; } S_SetMusicVolume(snd_MusicVolume /* *8 */); } void M_SystemVol(int choice) { switch(choice) { case 0: if (systemvol-5>rb->sound_min(SOUND_VOLUME)) { systemvol-=5; rb->sound_set(SOUND_VOLUME, systemvol); rb->global_settings->volume = systemvol; } break; case 1: if (systemvol+5sound_max(SOUND_VOLUME)) { systemvol+=5; rb->sound_set(SOUND_VOLUME, systemvol); rb->global_settings->volume = systemvol; } break; } } // // M_DrawMainMenu // void M_DrawMainMenu(void) { V_DrawNamePatch(94, 2, 0, "M_DOOM", CR_DEFAULT, VPT_STRETCH); } // // M_NewGame // void M_DrawNewGame(void) { // CPhipps - patch drawing updated V_DrawNamePatch(96, 14, 0, "M_NEWG", CR_DEFAULT, VPT_STRETCH); V_DrawNamePatch(54, 38, 0, "M_SKILL",CR_DEFAULT, VPT_STRETCH); } void M_NewGame(int choice) { (void) choice; if (netgame && !demoplayback) { M_StartMessage(s_NEWGAME,NULL,false); return; } if ( gamemode == commercial ) M_SetupNextMenu(&NewDef); else M_SetupNextMenu(&EpiDef); } // // M_Episode // int epi; void M_DrawEpisode(void) { // CPhipps - patch drawing updated V_DrawNamePatch(54, 38, 0, "M_EPISOD", CR_DEFAULT, VPT_STRETCH); } void M_VerifyNightmare(int ch) { if (ch != key_menu_enter) return; G_DeferedInitNew(nightmare,epi+1,1); M_ClearMenus (); } void M_ChooseSkill(int choice) { if (choice == nightmare) { M_StartMessage(s_NIGHTMARE,M_VerifyNightmare,true); return; } //jff 3/24/98 remember last skill selected // killough 10/98 moved to here defaultskill = choice+1; G_DeferedInitNew(choice,epi+1,1); M_ClearMenus (); } void M_Episode(int choice) { if ( (gamemode == shareware) && choice) { M_StartMessage(s_SWSTRING,NULL,false); // Ty 03/27/98 - externalized M_SetupNextMenu(&ReadDef1); return; } // Yet another hack... if ( (gamemode == registered) && (choice > 2)) { /* Digita */ // fprintf( stderr, // "M_Episode: 4th episode requires UltimateDOOM\n"); choice = 0; } epi = choice; M_SetupNextMenu(&NewDef); } // // M_Options // char detailNames[2][9] = {"M_GDHIGH","M_GDLOW"}; char msgNames[2][9] = {"M_MSGOFF","M_MSGON"}; void M_DrawOptions(void) { // CPhipps - patch drawing updated V_DrawNamePatch(108, 15, 0, "M_OPTTTL", CR_DEFAULT, VPT_STRETCH); V_DrawNamePatch(OptionsDef.x + 120, OptionsDef.y+LINEHEIGHT*messages, 0, msgNames[showMessages], CR_DEFAULT, VPT_STRETCH); M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(gamasens+1), 4,usegamma); M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1), 9,screenSize); } void M_Options(int choice) { (void)choice; M_SetupNextMenu(&OptionsDef); } // // Toggle messages on/off // void M_ChangeMessages(int choice) { (void)choice; showMessages = 1 - showMessages; if (!showMessages) players[consoleplayer].message = s_MSGOFF; else players[consoleplayer].message = s_MSGON ; message_dontfuckwithme = true; } // // M_EndGame // void M_EndGameResponse(int ch) { if (ch != key_menu_enter) return; // killough 5/26/98: make endgame quit if recording or playing back demo if (demorecording || singledemo) G_CheckDemoStatus(); currentMenu->lastOn = itemOn; M_ClearMenus (); D_StartTitle (); } void M_EndGame(int choice) { (void)choice; if (!usergame) { S_StartSound(NULL,sfx_oof); return; } if (netgame) { M_StartMessage(s_NETEND,NULL,false); return; } M_StartMessage(s_ENDGAME,M_EndGameResponse,true); } // // M_ReadThis // void M_ReadThis(int choice) { (void)choice; M_SetupNextMenu(&ReadDef1); } void M_ReadThis2(int choice) { (void)choice; M_SetupNextMenu(&ReadDef2); } void M_FinishReadThis(int choice) { (void)choice; M_SetupNextMenu(&MainDef); } // // M_QuitDOOM // int quitsounds[8] = { sfx_pldeth, sfx_dmpain, sfx_popain, sfx_slop, sfx_telept, sfx_posit1, sfx_posit3, sfx_sgtatk }; int quitsounds2[8] = { sfx_vilact, sfx_getpow, sfx_boscub, sfx_slop, sfx_skeswg, sfx_kntdth, sfx_bspact, sfx_sgtatk }; void M_QuitResponse(int ch) { if (ch != key_menu_enter) return; if (!netgame) { if (gamemode == commercial) S_StartSound(NULL,quitsounds2[(gametic>>2)&7]); else S_StartSound(NULL,quitsounds[(gametic>>2)&7]); I_WaitVBL(105); } I_Quit (); } void M_QuitDOOM(int choice) { (void)choice; // We pick index 0 which is language sensitive, // or one at random, between 1 and maximum number. if (language != english ) snprintf(endstring,sizeof(endstring),"%s\n\n%s",s_DOSY, endmsg[0] ); else snprintf(endstring,sizeof(endstring),"%s\n\n%s", endmsg[gametic%(NUM_QUITMESSAGES-1)+1], s_DOSY); M_StartMessage(endstring,M_QuitResponse,true); } void M_ChangeGamma(int choice) { switch(choice) { case 0: if (usegamma) usegamma--; break; case 1: if (usegamma < 4) usegamma++; break; } V_SetPalette (0); } void M_SizeDisplay(int choice) { switch(choice) { case 0: if (screenSize > 0) { screenblocks--; screenSize--; } break; case 1: if (screenSize < 8) { screenblocks++; screenSize++; } break; } R_SetViewSize (screenblocks); } // // Menu Functions // void M_DrawThermo ( int x, int y, int thermWidth, int thermDot ) { int xx; int i; xx = x; V_DrawNamePatch(xx, y, 0, "M_THERML", CR_DEFAULT, VPT_STRETCH); xx += 8; for (i=0;ix - 10, menu->y+item*LINEHEIGHT - 1, 0, "M_CELL1", CR_DEFAULT, VPT_STRETCH); } void M_DrawSelCell ( menu_t* menu, int item ) { // CPhipps - patch drawing updated V_DrawNamePatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0, "M_CELL2", CR_DEFAULT, VPT_STRETCH); } void M_StartMessage ( const char* string, void* routine, boolean input ) { messageLastMenuActive = menuactive; messageToPrint = 1; messageString = string; messageRoutine = routine; messageNeedsInput = input; menuactive = true; return; } void M_StopMessage(void) { menuactive = messageLastMenuActive; messageToPrint = 0; } // // Find string width from hu_font chars // int M_StringWidth(const char* string) { int i, c, w = 0; for (i = 0;(size_t)i < strlen(string);i++) w += (c = toupper(string[i]) - HU_FONTSTART) < 0 || c >= HU_FONTSIZE ? 4 : SHORT(hu_font[c].width); return w; } // // Find string height from hu_font chars // int M_StringHeight(const char* string) { int i, h, height = h = SHORT(hu_font[0].height); for (i = 0;string[i];i++) // killough 1/31/98 if (string[i] == '\n') h += height; return h; } // // Write a string using the hu_font // void M_WriteText ( int x, int y, char* string) { int w; char* ch; int c; int cx; int cy; ch = string; cx = x; cy = y; while(1) { c = *ch++; if (!c) break; if (c == '\n') { cx = x; cy += 12; continue; } c = toupper(c) - HU_FONTSTART; if (c < 0 || c>= HU_FONTSIZE) { cx += 4; continue; } w = SHORT (hu_font[c].width); if (cx+w > 320) break; // proff/nicolas 09/20/98 -- changed for hi-res // CPhipps - patch drawing updated V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH); cx+=w; } } // // CONTROL PANEL // // // M_Responder // boolean M_Responder (event_t* ev) { int ch; int i; // static int joywait = 0; // static int mousewait = 0; // static int mousey = 0; // static int lasty = 0; // static int mousex = 0; // static int lastx = 0; ch = -1; // Process joystick input /* if (ev->type == ev_joystick && joywait < I_GetTime()) { if (ev->data3 == -1) { ch = KEY_UPARROW; joywait = I_GetTime() + 5; } else if (ev->data3 == 1) { ch = KEY_DOWNARROW; joywait = I_GetTime() + 5; } if (ev->data2 == -1) { ch = KEY_LEFTARROW; joywait = I_GetTime() + 2; } else if (ev->data2 == 1) { ch = KEY_RIGHTARROW; joywait = I_GetTime() + 2; } if (ev->data1&1) { ch = key_menu_enter; joywait = I_GetTime() + 5; } if (ev->data1&2) { ch = KEY_BACKSPACE; joywait = I_GetTime() + 5; } } else { // Process mouse input if (ev->type == ev_mouse && mousewait < I_GetTime()) { mousey += ev->data3; if (mousey < lasty-30) { ch = KEY_DOWNARROW; mousewait = I_GetTime() + 5; mousey = lasty -= 30; } else if (mousey > lasty+30) { ch = KEY_UPARROW; mousewait = I_GetTime() + 5; mousey = lasty += 30; } mousex += ev->data2; if (mousex < lastx-30) { ch = KEY_LEFTARROW; mousewait = I_GetTime() + 5; mousex = lastx -= 30; } else if (mousex > lastx+30) { ch = KEY_RIGHTARROW; mousewait = I_GetTime() + 5; mousex = lastx += 30; } if (ev->data1&1) { ch = key_menu_enter; mousewait = I_GetTime() + 15; } if (ev->data1&2) { ch = KEY_BACKSPACE; mousewait = I_GetTime() + 15; } } else */if (ev->type == ev_keydown) { ch = ev->data1; } // } if (ch == -1) return false; // Save Game string input if (saveStringEnter) { switch(ch) { case KEY_BACKSPACE: if (saveCharIndex > 0) { saveCharIndex--; savegamestrings[saveSlot][saveCharIndex] = 0; } break; case KEY_ESCAPE: saveStringEnter = 0; strcpy(&savegamestrings[saveSlot][0],saveOldString); break; case KEY_ENTER: saveStringEnter = 0; if (savegamestrings[saveSlot][0]) M_DoSave(saveSlot); break; default: ch = toupper(ch); if (ch != 32) if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE) break; if (ch >= 32 && ch <= 127 && saveCharIndex < SAVESTRINGSIZE-1 && M_StringWidth(savegamestrings[saveSlot]) < (SAVESTRINGSIZE-2)*8) { savegamestrings[saveSlot][saveCharIndex++] = ch; savegamestrings[saveSlot][saveCharIndex] = 0; } break; } return true; } // Take care of any messages that need input if (messageToPrint) { if (messageNeedsInput == true && !(ch == ' ' || ch == 'n' || ch == key_menu_enter || ch == key_menu_escape)) return false; menuactive = messageLastMenuActive; messageToPrint = 0; if (messageRoutine) messageRoutine(ch); menuactive = false; S_StartSound(NULL,sfx_swtchx); return true; } /* if (ch == KEY_F1) // devparm && { G_ScreenShot (); return true; } */ // F-Keys if (!menuactive) { if (ch == key_autorun) // Autorun // V { autorun = !autorun; return true; } switch(ch) { /* case KEY_F1: // Help key M_StartControlPanel (); if ( gamemode == retail ) currentMenu = &ReadDef2; else currentMenu = &ReadDef1; itemOn = 0; S_StartSound(NULL,sfx_swtchn); return true; case KEY_F6: // Quicksave S_StartSound(NULL,sfx_swtchn); M_QuickSave(); return true; case KEY_F9: // Quickload S_StartSound(NULL,sfx_swtchn); M_QuickLoad(); return true; */ } } // Pop-up menu? if (!menuactive) { if (ch == key_menu_escape) { M_StartControlPanel (); S_StartSound(NULL,sfx_swtchn); return true; } return false; } // Keys usable within menu switch (ch) { case KEY_DOWNARROW: do { if (itemOn+1 > currentMenu->numitems-1) itemOn = 0; else itemOn++; S_StartSound(NULL,sfx_pstop); } while(currentMenu->menuitems[itemOn].status==-1); return true; case KEY_UPARROW: do { if (!itemOn) itemOn = currentMenu->numitems-1; else itemOn--; S_StartSound(NULL,sfx_pstop); } while(currentMenu->menuitems[itemOn].status==-1); return true; case KEY_LEFTARROW: if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { S_StartSound(NULL,sfx_stnmov); currentMenu->menuitems[itemOn].routine(0); } return true; case KEY_RIGHTARROW: if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { S_StartSound(NULL,sfx_stnmov); currentMenu->menuitems[itemOn].routine(1); } return true; case KEY_ENTER: if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status) { currentMenu->lastOn = itemOn; if (currentMenu->menuitems[itemOn].status == 2) { currentMenu->menuitems[itemOn].routine(1); // right arrow S_StartSound(NULL,sfx_stnmov); } else { currentMenu->menuitems[itemOn].routine(itemOn); S_StartSound(NULL,sfx_pistol); } } return true; case KEY_ESCAPE: currentMenu->lastOn = itemOn; M_ClearMenus (); S_StartSound(NULL,sfx_swtchx); return true; case KEY_BACKSPACE: currentMenu->lastOn = itemOn; if (currentMenu->prevMenu) { currentMenu = currentMenu->prevMenu; itemOn = currentMenu->lastOn; S_StartSound(NULL,sfx_swtchn); } return true; default: for (i = itemOn+1;i < currentMenu->numitems;i++) if (currentMenu->menuitems[i].alphaKey == ch) { itemOn = i; S_StartSound(NULL,sfx_pstop); return true; } for (i = 0;i <= itemOn;i++) if (currentMenu->menuitems[i].alphaKey == ch) { itemOn = i; S_StartSound(NULL,sfx_pstop); return true; } break; } return false; } // // M_StartControlPanel // void M_StartControlPanel (void) { // intro might call this repeatedly if (menuactive) return; menuactive = 1; currentMenu = &MainDef; // JDC itemOn = currentMenu->lastOn; // JDC } // // M_Drawer // Called after the view has been rendered, // but before it has been blitted. // void M_Drawer (void) { static short x; static short y; unsigned short i; short max; char string[40]; int start; inhelpscreens = false; // Horiz. & Vertically center string and print it. if (messageToPrint) { start = 0; y = 100 - M_StringHeight(messageString)/2; while(*(messageString+start)) { for (i = 0;i < strlen(messageString+start);i++) if (*(messageString+start+i) == '\n') { memset(string,0,40); strncpy(string,messageString+start,i); start += i+1; break; } if (i == strlen(messageString+start)) { strcpy(string,messageString+start); start += i; } x = 160 - M_StringWidth(string)/2; M_WriteText(x,y,string); y += SHORT(hu_font[0].height); } return; } if (!menuactive) return; if (currentMenu->routine) currentMenu->routine(); // call Draw routine // DRAW MENU x = currentMenu->x; y = currentMenu->y; max = currentMenu->numitems; for (i=0;imenuitems[i].name[0]) V_DrawNamePatch(x,y,0,currentMenu->menuitems[i].name, CR_DEFAULT, VPT_STRETCH); y += LINEHEIGHT; } // DRAW SKULL // CPhipps - patch drawing updated V_DrawNamePatch(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,0, skullName[whichSkull], CR_DEFAULT, VPT_STRETCH); } // // M_ClearMenus // void M_ClearMenus (void) { menuactive = 0; // if (!netgame && usergame && paused) // sendpause = true; } // // M_SetupNextMenu // void M_SetupNextMenu(menu_t *menudef) { currentMenu = menudef; itemOn = currentMenu->lastOn; } // // M_Ticker // void M_Ticker (void) { if (--skullAnimCounter <= 0) { whichSkull ^= 1; skullAnimCounter = 8; } } // // M_Init // void M_Init (void) { currentMenu = &MainDef; menuactive = 0; itemOn = currentMenu->lastOn; whichSkull = 0; skullAnimCounter = 10; screenSize = screenblocks - 3; messageToPrint = 0; messageString = NULL; messageLastMenuActive = menuactive; quickSaveSlot = -1; // Here we could catch other version dependencies, // like HELP1/2, and four episodes. switch ( gamemode ) { case commercial: // This is used because DOOM 2 had only one HELP // page. I use CREDIT as second page now, but // kept this hack for educational purposes. MainMenu[readthis] = MainMenu[quitdoom]; MainDef.numitems--; MainDef.y += 8; NewDef.prevMenu = &MainDef; ReadDef1.routine = M_DrawReadThis1; ReadDef1.x = 330; ReadDef1.y = 165; ReadMenu1[0].routine = M_FinishReadThis; break; case shareware: // Episode 2 and 3 are handled, // branching to an ad screen. case registered: // We need to remove the fourth episode. EpiDef.numitems--; break; case retail: // We are fine. default: break; } }