1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
19 // Revision 1.7 2006/12/13 04:44:17 kkurbjun
20 // Dehacked and BEX support for Doom - currently only supports a DEHACKED file in a WAD (not as a standalone file yet).
22 // Revision 1.6 2006-04-16 23:14:04 kkurbjun
23 // Fix run so that it stays enabled across level loads. Removed some unused code and added some back in for hopeful future use.
25 // Revision 1.5 2006-04-04 23:58:37 kkurbjun
26 // Make savegame strings more informative
28 // Revision 1.4 2006-04-04 23:13:50 kkurbjun
29 // Fix up configurable keys, edit exit string, more work needs to be done on menu keys
31 // Revision 1.3 2006-04-03 20:03:02 kkurbjun
32 // Updates doom menu w/ new graphics, now requires rockdoom.wad: http://alamode.mines.edu/~kkurbjun/rockdoom.wad
34 // Revision 1.2 2006-04-03 00:28:13 kkurbjun
35 // 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.
37 // Revision 1.1 2006-03-28 15:44:01 dave
38 // Patch #2969 - Doom! Currently only working on the H300.
42 // DOOM selection menu, options, episode etc.
43 // Sliders and icons. Kinda widget stuff.
45 //-----------------------------------------------------------------------------
74 #include "rockmacros.h"
77 extern patchnum_t hu_font
[HU_FONTSIZE
];
78 extern boolean message_dontfuckwithme
;
80 extern boolean chat_on
; // in heads-up code
85 int mouseSensitivity
; // has default
87 // Show messages has default, 0 = off, 1 = on
90 // Blocky mode, has default, 0 = high, 1 = normal
91 int screenblocks
; // has default
93 // temp for screenblocks (0-9)
96 // -1 = no quicksave slot picked!
99 // 1 = message to be printed
101 // ...and here is the message string!
102 const char* messageString
;
107 int messageLastMenuActive
;
109 // timed message = no input from user
110 boolean messageNeedsInput
;
112 void (*messageRoutine
)(int response
);
114 #define SAVESTRINGSIZE 24
116 // we are going to be entering a savegame string
118 int saveSlot
; // which slot to save in
119 int saveCharIndex
; // which char we're editing
120 // old save description before edit
121 char saveOldString
[SAVESTRINGSIZE
];
123 boolean inhelpscreens
;
126 #define SKULLXOFF -32
127 #define LINEHEIGHT 16
129 extern boolean sendpause
;
130 char savegamestrings
[10][SAVESTRINGSIZE
];
140 // 0 = no cursor here, 1 = ok, 2 = arrows ok
145 // choice = menu item #.
147 // choice=0:leftarrow,1:rightarrow
148 void (*routine
)(int choice
);
157 typedef struct menu_s
159 short numitems
; // # of menu items
160 struct menu_s
* prevMenu
; // previous menu
161 menuitem_t
* menuitems
; // menu items
162 void (*routine
)(void); // draw routine ROCKBOX
164 short y
; // x,y of menu
165 short lastOn
; // last item user was on in menu
169 short itemOn
; // menu item skull is on
170 short skullAnimCounter
; // skull animation counter
171 short whichSkull
; // which skull to draw
174 // graphic name of skulls
175 // warning: initializer-string for array of chars is too long
176 char skullName
[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
184 void M_NewGame(int choice
);
185 void M_Episode(int choice
);
186 void M_ChooseSkill(int choice
);
187 void M_LoadGame(int choice
);
188 void M_SaveGame(int choice
);
189 void M_Options(int choice
);
190 void M_EndGame(int choice
);
191 void M_ReadThis(int choice
);
192 void M_ReadThis2(int choice
);
193 void M_QuitDOOM(int choice
);
195 void M_ChangeMessages(int choice
);
196 void M_ChangeGamma(int choice
);
197 void M_SfxVol(int choice
);
198 void M_MusicVol(int choice
);
199 void M_SystemVol(int choice
);
200 void M_SizeDisplay(int choice
);
201 void M_StartGame(int choice
);
202 void M_Sound(int choice
);
204 void M_FinishReadThis(int choice
);
205 void M_LoadSelect(int choice
);
206 void M_SaveSelect(int choice
);
207 void M_ReadSaveStrings(void);
208 void M_QuickSave(void);
209 void M_QuickLoad(void);
211 void M_DrawMainMenu(void);
212 void M_DrawReadThis1(void);
213 void M_DrawReadThis2(void);
214 void M_DrawNewGame(void);
215 void M_DrawEpisode(void);
216 void M_DrawOptions(void);
217 void M_DrawSound(void);
218 void M_DrawLoad(void);
219 void M_DrawSave(void);
221 void M_DrawSaveLoadBorder(int x
,int y
);
222 void M_SetupNextMenu(menu_t
*menudef
);
223 void M_DrawThermo(int x
,int y
,int thermWidth
,int thermDot
);
224 void M_DrawEmptyCell(menu_t
*menu
,int item
);
225 void M_DrawSelCell(menu_t
*menu
,int item
);
226 void M_WriteText(int x
, int y
, char *string
);
227 int M_StringWidth(const char* string
);
228 int M_StringHeight(const char* string
);
229 void M_StartControlPanel(void);
230 void M_StartMessage(const char *string
,void *routine
,boolean input
);
231 void M_StopMessage(void);
232 void M_ClearMenus (void);
252 menuitem_t MainMenu
[]=
254 {1,"M_NGAME",M_NewGame
,'n'},
255 {1,"M_OPTION",M_Options
,'o'},
256 {1,"M_LOADG",M_LoadGame
,'l'},
257 {1,"M_SAVEG",M_SaveGame
,'s'},
258 // Another hickup with Special edition.
259 {1,"M_RDTHIS",M_ReadThis
,'r'},
260 {1,"M_QUITG",M_QuitDOOM
,'q'}
287 menuitem_t EpisodeMenu
[]=
289 {1,"M_EPI1", M_Episode
,'k'},
290 {1,"M_EPI2", M_Episode
,'t'},
291 {1,"M_EPI3", M_Episode
,'i'},
292 {1,"M_EPI4", M_Episode
,'t'}
297 ep_end
, // # of menu items
298 &MainDef
, // previous menu
299 EpisodeMenu
, // menuitem_t ->
300 M_DrawEpisode
, // drawing routine ->
319 menuitem_t NewGameMenu
[]=
321 {1,"M_JKILL", M_ChooseSkill
, 'i'},
322 {1,"M_ROUGH", M_ChooseSkill
, 'h'},
323 {1,"M_HURT", M_ChooseSkill
, 'h'},
324 {1,"M_ULTRA", M_ChooseSkill
, 'u'},
325 {1,"M_NMARE", M_ChooseSkill
, 'n'}
330 newg_end
, // # of menu items
331 &EpiDef
, // previous menu
332 NewGameMenu
, // menuitem_t ->
333 M_DrawNewGame
, // drawing routine ->
356 menuitem_t OptionsMenu
[]=
358 {1,"M_ENDGAM", M_EndGame
,'e'},
359 {1,"M_MESSG", M_ChangeMessages
,'m'},
360 {2,"M_SCRNSZ", M_SizeDisplay
,'s'},
362 {2,"M_GAMMA", M_ChangeGamma
,'m'},
364 {1,"M_SVOL", M_Sound
,'s'}
378 // Read This! MENU 1 & 2
387 menuitem_t ReadMenu1
[] =
409 menuitem_t ReadMenu2
[]=
411 {1,"",M_FinishReadThis
,0}
439 menuitem_t SoundMenu
[]=
441 {2,"M_SFXVOL",M_SfxVol
,'s'},
442 {-1,"",0,0}, //ROCKBOX
443 {2,"M_MUSVOL",M_MusicVol
,'m'},
444 {-1,"",0,0}, //ROCKBOX
445 {2,"M_SYSVOL",M_SystemVol
,'z'},
446 {-1,"",0,0} //ROCKBOX
474 menuitem_t LoadMenu
[]=
476 {1,"", M_LoadSelect
,'1'},
477 {1,"", M_LoadSelect
,'2'},
478 {1,"", M_LoadSelect
,'3'},
479 {1,"", M_LoadSelect
,'4'},
480 {1,"", M_LoadSelect
,'5'},
481 {1,"", M_LoadSelect
,'6'}
497 menuitem_t SaveMenu
[]=
499 {1,"", M_SaveSelect
,'1'},
500 {1,"", M_SaveSelect
,'2'},
501 {1,"", M_SaveSelect
,'3'},
502 {1,"", M_SaveSelect
,'4'},
503 {1,"", M_SaveSelect
,'5'},
504 {1,"", M_SaveSelect
,'6'}
520 // read the strings from the savegame files
522 void M_ReadSaveStrings(void)
528 for (i
= 0;i
< load_end
;i
++)
530 if (M_CheckParm("-cdrom"))
531 snprintf(name
,sizeof(name
),"c:\\doomdata\\"SAVEGAMENAME
"%d.dsg",i
);
533 snprintf(name
,sizeof(name
),SAVEGAMENAME
"%d.dsg",i
);
535 handle
= open (name
, O_RDONLY
| 0);
538 strcpy(&savegamestrings
[i
][0],EMPTYSTRING
);
539 LoadMenu
[i
].status
= 0;
542 read (handle
, &savegamestrings
[i
], SAVESTRINGSIZE
);
544 LoadMenu
[i
].status
= 1;
548 #define LOADGRAPHIC_Y 8
552 void M_DrawLoad(void)
556 V_DrawNamePatch(72 ,LOADGRAPHIC_Y
, 0, "M_LOADG", CR_DEFAULT
, VPT_STRETCH
);
557 for (i
= 0;i
< load_end
; i
++)
559 M_DrawSaveLoadBorder(LoadDef
.x
,LoadDef
.y
+LINEHEIGHT
*i
);
560 M_WriteText(LoadDef
.x
,LoadDef
.y
+LINEHEIGHT
*i
,savegamestrings
[i
]);
567 // Draw border for the savegame description
569 void M_DrawSaveLoadBorder(int x
,int y
)
573 V_DrawNamePatch(x
-8, y
+7, 0, "M_LSLEFT", CR_DEFAULT
, VPT_STRETCH
);
574 for (i
= 0;i
< 24;i
++)
576 V_DrawNamePatch(x
, y
+7, 0, "M_LSCNTR", CR_DEFAULT
, VPT_STRETCH
);
579 V_DrawNamePatch(x
, y
+7, 0, "M_LSRGHT", CR_DEFAULT
, VPT_STRETCH
);
585 // User wants to load this game
587 void M_LoadSelect(int choice
)
591 if (M_CheckParm("-cdrom"))
592 snprintf(name
,sizeof(name
),"c:\\doomdata\\"SAVEGAMENAME
"%d.dsg",choice
);
594 snprintf(name
,sizeof(name
),SAVEGAMENAME
"%d.dsg",choice
);
595 G_LoadGame (choice
, false);
600 // Selected from DOOM menu
602 void M_LoadGame (int choice
)
607 M_StartMessage(LOADNET
,NULL
,false);
611 M_SetupNextMenu(&LoadDef
);
619 void M_DrawSave(void)
623 V_DrawNamePatch(72, LOADGRAPHIC_Y
, 0, "M_SAVEG", CR_DEFAULT
, VPT_STRETCH
);
624 for (i
= 0;i
< load_end
; i
++)
626 M_DrawSaveLoadBorder(LoadDef
.x
,LoadDef
.y
+LINEHEIGHT
*i
);
627 M_WriteText(LoadDef
.x
,LoadDef
.y
+LINEHEIGHT
*i
,savegamestrings
[i
]);
632 i
= M_StringWidth(savegamestrings
[saveSlot
]);
633 M_WriteText(LoadDef
.x
+ i
,LoadDef
.y
+LINEHEIGHT
*saveSlot
,"_");
638 // M_Responder calls this when user is finished
640 void M_DoSave(int slot
)
642 G_SaveGame (slot
,savegamestrings
[slot
]);
645 // PICK QUICKSAVE SLOT YET?
646 if (quickSaveSlot
== -2)
647 quickSaveSlot
= slot
;
651 // User wants to save. Start string input for M_Responder
653 void M_SaveSelect(int choice
)
655 // we are going to be intercepting all chars
659 snprintf(savegamestrings
[choice
], sizeof(savegamestrings
[choice
]),
660 (gamemode
==shareware
||gamemode
==registered
||gamemode
==retail
) ?
661 *mapnames
[(gameepisode
-1)*9+gamemap
-1] : (gamemission
==doom2
) ?
662 *mapnames2
[gamemap
-1] : (gamemission
==pack_plut
) ?
663 *mapnamesp
[gamemap
-1] : (gamemission
==pack_tnt
) ?
664 *mapnamest
[gamemap
-1] : "Unknown Location", choice
);
665 if (!strcmp(savegamestrings
[choice
],s_EMPTYSTRING
))
666 savegamestrings
[choice
][0] = 0;
667 saveCharIndex
= strlen(savegamestrings
[choice
]);
671 // Selected from DOOM menu
673 void M_SaveGame (int choice
)
678 M_StartMessage(s_SAVEDEAD
,NULL
,false);
682 if (gamestate
!= GS_LEVEL
)
685 M_SetupNextMenu(&SaveDef
);
696 void M_QuickSaveResponse(int ch
)
700 M_DoSave(quickSaveSlot
);
702 S_StartSound(NULL
,sfx_swtchx
);
707 void M_QuickSave(void)
711 S_StartSound(NULL
,sfx_oof
);
715 if (gamestate
!= GS_LEVEL
)
718 if (quickSaveSlot
< 0)
720 M_StartControlPanel();
722 M_SetupNextMenu(&SaveDef
);
723 quickSaveSlot
= -2; // means to pick a slot now
726 snprintf(tempstring
,sizeof(tempstring
),s_QSPROMPT
,savegamestrings
[quickSaveSlot
]);
727 M_StartMessage(tempstring
,M_QuickSaveResponse
,true);
735 void M_QuickLoadResponse(int ch
)
739 M_LoadSelect(quickSaveSlot
);
740 S_StartSound(NULL
,sfx_swtchx
);
745 void M_QuickLoad(void)
749 M_StartMessage(QLOADNET
,NULL
,false);
753 if (quickSaveSlot
< 0)
755 M_StartMessage(QSAVESPOT
,NULL
,false);
758 snprintf(tempstring
, sizeof(tempstring
), QLPROMPT
,savegamestrings
[quickSaveSlot
]);
759 M_StartMessage(tempstring
,M_QuickLoadResponse
,true);
767 // Had a "quick hack to fix romero bug"
769 void M_DrawReadThis1(void)
771 inhelpscreens
= true;
775 V_DrawNamePatch(0, 0, 0, "HELP", CR_DEFAULT
, VPT_STRETCH
);
780 V_DrawNamePatch(0, 0, 0, "HELP1", CR_DEFAULT
, VPT_STRETCH
);
791 // Read This Menus - optional second page.
793 void M_DrawReadThis2(void)
795 inhelpscreens
= true;
800 // This hack keeps us from having to change menus.
801 V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT
, VPT_STRETCH
);
805 V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT
, VPT_STRETCH
);
815 // Change Sfx & Music volumes
817 void M_DrawSound(void)
819 int sysmax
=(rb
->sound_max(SOUND_VOLUME
)-rb
->sound_min(SOUND_VOLUME
));
820 V_DrawNamePatch(60, 38, 0, "M_SVOL", CR_DEFAULT
, VPT_STRETCH
);
822 M_DrawThermo(SoundDef
.x
,SoundDef
.y
+LINEHEIGHT
*(sfx_vol
+1),
825 M_DrawThermo(SoundDef
.x
,SoundDef
.y
+LINEHEIGHT
*(music_vol
+1),
828 M_DrawThermo(SoundDef
.x
,SoundDef
.y
+LINEHEIGHT
*(system_vol
+1),
829 16,(sysmax
+systemvol
)/5);
832 void M_Sound(int choice
)
835 M_SetupNextMenu(&SoundDef
);
838 void M_SfxVol(int choice
)
847 if (snd_SfxVolume
< 15)
852 S_SetSfxVolume(snd_SfxVolume
/* *8 */);
855 void M_MusicVol(int choice
)
864 if (snd_MusicVolume
< 15)
869 S_SetMusicVolume(snd_MusicVolume
/* *8 */);
872 void M_SystemVol(int choice
)
877 if (systemvol
-5>rb
->sound_min(SOUND_VOLUME
))
880 rb
->sound_set(SOUND_VOLUME
, systemvol
);
881 rb
->global_settings
->volume
= systemvol
;
885 if (systemvol
+5<rb
->sound_max(SOUND_VOLUME
))
888 rb
->sound_set(SOUND_VOLUME
, systemvol
);
889 rb
->global_settings
->volume
= systemvol
;
898 void M_DrawMainMenu(void)
900 V_DrawNamePatch(94, 2, 0, "M_DOOM", CR_DEFAULT
, VPT_STRETCH
);
909 void M_DrawNewGame(void)
911 // CPhipps - patch drawing updated
912 V_DrawNamePatch(96, 14, 0, "M_NEWG", CR_DEFAULT
, VPT_STRETCH
);
913 V_DrawNamePatch(54, 38, 0, "M_SKILL",CR_DEFAULT
, VPT_STRETCH
);
916 void M_NewGame(int choice
)
919 if (netgame
&& !demoplayback
)
921 M_StartMessage(s_NEWGAME
,NULL
,false);
925 if ( gamemode
== commercial
)
926 M_SetupNextMenu(&NewDef
);
928 M_SetupNextMenu(&EpiDef
);
937 void M_DrawEpisode(void)
939 // CPhipps - patch drawing updated
940 V_DrawNamePatch(54, 38, 0, "M_EPISOD", CR_DEFAULT
, VPT_STRETCH
);
943 void M_VerifyNightmare(int ch
)
945 if (ch
!= key_menu_enter
)
948 G_DeferedInitNew(nightmare
,epi
+1,1);
952 void M_ChooseSkill(int choice
)
954 if (choice
== nightmare
)
956 M_StartMessage(s_NIGHTMARE
,M_VerifyNightmare
,true);
960 //jff 3/24/98 remember last skill selected
961 // killough 10/98 moved to here
962 defaultskill
= choice
+1;
964 G_DeferedInitNew(choice
,epi
+1,1);
968 void M_Episode(int choice
)
970 if ( (gamemode
== shareware
)
973 M_StartMessage(s_SWSTRING
,NULL
,false); // Ty 03/27/98 - externalized
974 M_SetupNextMenu(&ReadDef1
);
978 // Yet another hack...
979 if ( (gamemode
== registered
)
984 // "M_Episode: 4th episode requires UltimateDOOM\n");
989 M_SetupNextMenu(&NewDef
);
997 char detailNames
[2][9] = {"M_GDHIGH","M_GDLOW"};
998 char msgNames
[2][9] = {"M_MSGOFF","M_MSGON"};
1001 void M_DrawOptions(void)
1003 // CPhipps - patch drawing updated
1004 V_DrawNamePatch(108, 15, 0, "M_OPTTTL", CR_DEFAULT
, VPT_STRETCH
);
1006 V_DrawNamePatch(OptionsDef
.x
+ 120, OptionsDef
.y
+LINEHEIGHT
*messages
, 0,
1007 msgNames
[showMessages
], CR_DEFAULT
, VPT_STRETCH
);
1009 M_DrawThermo(OptionsDef
.x
,OptionsDef
.y
+LINEHEIGHT
*(gamasens
+1),
1012 M_DrawThermo(OptionsDef
.x
,OptionsDef
.y
+LINEHEIGHT
*(scrnsize
+1),
1016 void M_Options(int choice
)
1019 M_SetupNextMenu(&OptionsDef
);
1025 // Toggle messages on/off
1027 void M_ChangeMessages(int choice
)
1030 showMessages
= 1 - showMessages
;
1033 players
[consoleplayer
].message
= s_MSGOFF
;
1035 players
[consoleplayer
].message
= s_MSGON
;
1037 message_dontfuckwithme
= true;
1044 void M_EndGameResponse(int ch
)
1046 if (ch
!= key_menu_enter
)
1049 // killough 5/26/98: make endgame quit if recording or playing back demo
1050 if (demorecording
|| singledemo
)
1051 G_CheckDemoStatus();
1053 currentMenu
->lastOn
= itemOn
;
1058 void M_EndGame(int choice
)
1063 S_StartSound(NULL
,sfx_oof
);
1069 M_StartMessage(s_NETEND
,NULL
,false);
1073 M_StartMessage(s_ENDGAME
,M_EndGameResponse
,true);
1082 void M_ReadThis(int choice
)
1085 M_SetupNextMenu(&ReadDef1
);
1088 void M_ReadThis2(int choice
)
1091 M_SetupNextMenu(&ReadDef2
);
1094 void M_FinishReadThis(int choice
)
1097 M_SetupNextMenu(&MainDef
);
1118 int quitsounds2
[8] =
1132 void M_QuitResponse(int ch
)
1134 if (ch
!= key_menu_enter
)
1138 if (gamemode
== commercial
)
1139 S_StartSound(NULL
,quitsounds2
[(gametic
>>2)&7]);
1141 S_StartSound(NULL
,quitsounds
[(gametic
>>2)&7]);
1150 void M_QuitDOOM(int choice
)
1153 // We pick index 0 which is language sensitive,
1154 // or one at random, between 1 and maximum number.
1155 if (language
!= english
)
1156 snprintf(endstring
,sizeof(endstring
),"%s\n\n%s",s_DOSY
, endmsg
[0] );
1158 snprintf(endstring
,sizeof(endstring
),"%s\n\n%s", endmsg
[gametic
%(NUM_QUITMESSAGES
-1)+1], s_DOSY
);
1160 M_StartMessage(endstring
,M_QuitResponse
,true);
1166 void M_ChangeGamma(int choice
)
1182 void M_SizeDisplay(int choice
)
1203 R_SetViewSize (screenblocks
);
1223 V_DrawNamePatch(xx
, y
, 0, "M_THERML", CR_DEFAULT
, VPT_STRETCH
);
1225 for (i
=0;i
<thermWidth
;i
++)
1227 V_DrawNamePatch(xx
, y
, 0, "M_THERMM", CR_DEFAULT
, VPT_STRETCH
);
1230 V_DrawNamePatch(xx
, y
, 0, "M_THERMR", CR_DEFAULT
, VPT_STRETCH
);
1231 V_DrawNamePatch((x
+8)+thermDot
*8,y
,0,"M_THERMO",CR_DEFAULT
,VPT_STRETCH
);
1241 // CPhipps - patch drawing updated
1242 V_DrawNamePatch(menu
->x
- 10, menu
->y
+item
*LINEHEIGHT
- 1, 0,
1243 "M_CELL1", CR_DEFAULT
, VPT_STRETCH
);
1251 // CPhipps - patch drawing updated
1252 V_DrawNamePatch(menu
->x
- 10, menu
->y
+item
*LINEHEIGHT
- 1, 0,
1253 "M_CELL2", CR_DEFAULT
, VPT_STRETCH
);
1259 ( const char* string
,
1263 messageLastMenuActive
= menuactive
;
1265 messageString
= string
;
1266 messageRoutine
= routine
;
1267 messageNeedsInput
= input
;
1274 void M_StopMessage(void)
1276 menuactive
= messageLastMenuActive
;
1283 // Find string width from hu_font chars
1285 int M_StringWidth(const char* string
)
1288 for (i
= 0;(size_t)i
< strlen(string
);i
++)
1289 w
+= (c
= toupper(string
[i
]) - HU_FONTSTART
) < 0 || c
>= HU_FONTSIZE
?
1290 4 : SHORT(hu_font
[c
].width
);
1295 // Find string height from hu_font chars
1298 int M_StringHeight(const char* string
)
1300 int i
, h
, height
= h
= SHORT(hu_font
[0].height
);
1301 for (i
= 0;string
[i
];i
++) // killough 1/31/98
1302 if (string
[i
] == '\n')
1309 // Write a string using the hu_font
1340 c
= toupper(c
) - HU_FONTSTART
;
1341 if (c
< 0 || c
>= HU_FONTSIZE
)
1347 w
= SHORT (hu_font
[c
].width
);
1350 // proff/nicolas 09/20/98 -- changed for hi-res
1351 // CPhipps - patch drawing updated
1352 V_DrawNumPatch(cx
, cy
, 0, hu_font
[c
].lumpnum
, CR_DEFAULT
, VPT_STRETCH
);
1366 boolean
M_Responder (event_t
* ev
)
1370 // static int joywait = 0;
1371 // static int mousewait = 0;
1372 // static int mousey = 0;
1373 // static int lasty = 0;
1374 // static int mousex = 0;
1375 // static int lastx = 0;
1379 // Process joystick input
1381 /* if (ev->type == ev_joystick && joywait < I_GetTime())
1383 if (ev->data3 == -1)
1386 joywait = I_GetTime() + 5;
1388 else if (ev->data3 == 1)
1391 joywait = I_GetTime() + 5;
1394 if (ev->data2 == -1)
1397 joywait = I_GetTime() + 2;
1399 else if (ev->data2 == 1)
1401 ch = KEY_RIGHTARROW;
1402 joywait = I_GetTime() + 2;
1407 ch = key_menu_enter;
1408 joywait = I_GetTime() + 5;
1413 joywait = I_GetTime() + 5;
1418 // Process mouse input
1419 if (ev->type == ev_mouse && mousewait < I_GetTime())
1421 mousey += ev->data3;
1422 if (mousey < lasty-30)
1425 mousewait = I_GetTime() + 5;
1426 mousey = lasty -= 30;
1428 else if (mousey > lasty+30)
1431 mousewait = I_GetTime() + 5;
1432 mousey = lasty += 30;
1435 mousex += ev->data2;
1436 if (mousex < lastx-30)
1439 mousewait = I_GetTime() + 5;
1440 mousex = lastx -= 30;
1442 else if (mousex > lastx+30)
1444 ch = KEY_RIGHTARROW;
1445 mousewait = I_GetTime() + 5;
1446 mousex = lastx += 30;
1451 ch = key_menu_enter;
1452 mousewait = I_GetTime() + 15;
1458 mousewait = I_GetTime() + 15;
1461 else */if (ev
->type
== ev_keydown
)
1471 // Save Game string input
1472 if (saveStringEnter
)
1477 if (saveCharIndex
> 0)
1480 savegamestrings
[saveSlot
][saveCharIndex
] = 0;
1485 saveStringEnter
= 0;
1486 strcpy(&savegamestrings
[saveSlot
][0],saveOldString
);
1490 saveStringEnter
= 0;
1491 if (savegamestrings
[saveSlot
][0])
1498 if (ch
-HU_FONTSTART
< 0 || ch
-HU_FONTSTART
>= HU_FONTSIZE
)
1500 if (ch
>= 32 && ch
<= 127 &&
1501 saveCharIndex
< SAVESTRINGSIZE
-1 &&
1502 M_StringWidth(savegamestrings
[saveSlot
]) <
1503 (SAVESTRINGSIZE
-2)*8)
1505 savegamestrings
[saveSlot
][saveCharIndex
++] = ch
;
1506 savegamestrings
[saveSlot
][saveCharIndex
] = 0;
1513 // Take care of any messages that need input
1516 if (messageNeedsInput
== true &&
1517 !(ch
== ' ' || ch
== 'n' || ch
== key_menu_enter
|| ch
== key_menu_escape
))
1520 menuactive
= messageLastMenuActive
;
1526 S_StartSound(NULL
,sfx_swtchx
);
1530 if (ch == KEY_F1) // devparm &&
1539 if (ch
== key_autorun
) // Autorun // V
1548 case KEY_F1: // Help key
1549 M_StartControlPanel ();
1551 if ( gamemode == retail )
1552 currentMenu = &ReadDef2;
1554 currentMenu = &ReadDef1;
1557 S_StartSound(NULL,sfx_swtchn);
1560 case KEY_F6: // Quicksave
1561 S_StartSound(NULL,sfx_swtchn);
1565 case KEY_F9: // Quickload
1566 S_StartSound(NULL,sfx_swtchn);
1577 if (ch
== key_menu_escape
)
1579 M_StartControlPanel ();
1580 S_StartSound(NULL
,sfx_swtchn
);
1587 // Keys usable within menu
1593 if (itemOn
+1 > currentMenu
->numitems
-1)
1597 S_StartSound(NULL
,sfx_pstop
);
1599 while(currentMenu
->menuitems
[itemOn
].status
==-1);
1606 itemOn
= currentMenu
->numitems
-1;
1609 S_StartSound(NULL
,sfx_pstop
);
1611 while(currentMenu
->menuitems
[itemOn
].status
==-1);
1615 if (currentMenu
->menuitems
[itemOn
].routine
&&
1616 currentMenu
->menuitems
[itemOn
].status
== 2)
1618 S_StartSound(NULL
,sfx_stnmov
);
1619 currentMenu
->menuitems
[itemOn
].routine(0);
1623 case KEY_RIGHTARROW
:
1624 if (currentMenu
->menuitems
[itemOn
].routine
&&
1625 currentMenu
->menuitems
[itemOn
].status
== 2)
1627 S_StartSound(NULL
,sfx_stnmov
);
1628 currentMenu
->menuitems
[itemOn
].routine(1);
1633 if (currentMenu
->menuitems
[itemOn
].routine
&&
1634 currentMenu
->menuitems
[itemOn
].status
)
1636 currentMenu
->lastOn
= itemOn
;
1637 if (currentMenu
->menuitems
[itemOn
].status
== 2)
1639 currentMenu
->menuitems
[itemOn
].routine(1); // right arrow
1640 S_StartSound(NULL
,sfx_stnmov
);
1644 currentMenu
->menuitems
[itemOn
].routine(itemOn
);
1645 S_StartSound(NULL
,sfx_pistol
);
1651 currentMenu
->lastOn
= itemOn
;
1653 S_StartSound(NULL
,sfx_swtchx
);
1657 currentMenu
->lastOn
= itemOn
;
1658 if (currentMenu
->prevMenu
)
1660 currentMenu
= currentMenu
->prevMenu
;
1661 itemOn
= currentMenu
->lastOn
;
1662 S_StartSound(NULL
,sfx_swtchn
);
1667 for (i
= itemOn
+1;i
< currentMenu
->numitems
;i
++)
1668 if (currentMenu
->menuitems
[i
].alphaKey
== ch
)
1671 S_StartSound(NULL
,sfx_pstop
);
1674 for (i
= 0;i
<= itemOn
;i
++)
1675 if (currentMenu
->menuitems
[i
].alphaKey
== ch
)
1678 S_StartSound(NULL
,sfx_pstop
);
1691 // M_StartControlPanel
1693 void M_StartControlPanel (void)
1695 // intro might call this repeatedly
1700 currentMenu
= &MainDef
; // JDC
1701 itemOn
= currentMenu
->lastOn
; // JDC
1707 // Called after the view has been rendered,
1708 // but before it has been blitted.
1710 void M_Drawer (void)
1719 inhelpscreens
= false;
1722 // Horiz. & Vertically center string and print it.
1726 y
= 100 - M_StringHeight(messageString
)/2;
1727 while(*(messageString
+start
))
1729 for (i
= 0;i
< strlen(messageString
+start
);i
++)
1730 if (*(messageString
+start
+i
) == '\n')
1732 memset(string
,0,40);
1733 strncpy(string
,messageString
+start
,i
);
1737 if (i
== strlen(messageString
+start
))
1739 strcpy(string
,messageString
+start
);
1743 x
= 160 - M_StringWidth(string
)/2;
1744 M_WriteText(x
,y
,string
);
1745 y
+= SHORT(hu_font
[0].height
);
1753 if (currentMenu
->routine
)
1754 currentMenu
->routine(); // call Draw routine
1759 max
= currentMenu
->numitems
;
1763 if (currentMenu
->menuitems
[i
].name
[0])
1764 V_DrawNamePatch(x
,y
,0,currentMenu
->menuitems
[i
].name
,
1765 CR_DEFAULT
, VPT_STRETCH
);
1770 // CPhipps - patch drawing updated
1771 V_DrawNamePatch(x
+ SKULLXOFF
, currentMenu
->y
- 5 + itemOn
*LINEHEIGHT
,0,
1772 skullName
[whichSkull
], CR_DEFAULT
, VPT_STRETCH
);
1780 void M_ClearMenus (void)
1783 // if (!netgame && usergame && paused)
1784 // sendpause = true;
1793 void M_SetupNextMenu(menu_t
*menudef
)
1795 currentMenu
= menudef
;
1796 itemOn
= currentMenu
->lastOn
;
1803 void M_Ticker (void)
1805 if (--skullAnimCounter
<= 0)
1808 skullAnimCounter
= 8;
1818 currentMenu
= &MainDef
;
1820 itemOn
= currentMenu
->lastOn
;
1822 skullAnimCounter
= 10;
1823 screenSize
= screenblocks
- 3;
1825 messageString
= NULL
;
1826 messageLastMenuActive
= menuactive
;
1829 // Here we could catch other version dependencies,
1830 // like HELP1/2, and four episodes.
1836 // This is used because DOOM 2 had only one HELP
1837 // page. I use CREDIT as second page now, but
1838 // kept this hack for educational purposes.
1839 MainMenu
[readthis
] = MainMenu
[quitdoom
];
1842 NewDef
.prevMenu
= &MainDef
;
1843 ReadDef1
.routine
= M_DrawReadThis1
;
1846 ReadMenu1
[0].routine
= M_FinishReadThis
;
1849 // Episode 2 and 3 are handled,
1850 // branching to an ad screen.
1852 // We need to remove the fourth episode.