1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
18 // Revision 1.1 2000/02/29 18:21:04 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
23 // DOOM selection menu, options, episode etc.
24 // Sliders and icons. Kinda widget stuff.
26 //-----------------------------------------------------------------------------
32 #include <sys/types.h>
71 extern patch_t
* hu_font
[HU_FONTSIZE
];
72 extern boolean message_dontfuckwithme
;
74 extern boolean chat_on
; // in heads-up code
79 int mouseSensitivity
; // has default
81 // Show messages has default, 0 = off, 1 = on
85 // Blocky mode, has default, 0 = high, 1 = normal
87 int screenblocks
; // has default
89 // temp for screenblocks (0-9)
92 // -1 = no quicksave slot picked!
95 // 1 = message to be printed
97 // ...and here is the message string!
103 int messageLastMenuActive
;
105 // timed message = no input from user
106 boolean messageNeedsInput
;
108 void (*messageRoutine
)(int response
);
110 #define SAVESTRINGSIZE 24
112 char gammamsg
[5][26] =
121 // we are going to be entering a savegame string
123 int saveSlot
; // which slot to save in
124 int saveCharIndex
; // which char we're editing
125 // old save description before edit
126 char saveOldString
[SAVESTRINGSIZE
];
128 boolean inhelpscreens
;
131 #define SKULLXOFF -32
132 #define LINEHEIGHT 16
134 extern boolean sendpause
;
135 char savegamestrings
[10][SAVESTRINGSIZE
];
145 // 0 = no cursor here, 1 = ok, 2 = arrows ok
150 // choice = menu item #.
152 // choice=0:leftarrow,1:rightarrow
153 void (*routine
)(int choice
);
161 typedef struct menu_s
163 short numitems
; // # of menu items
164 struct menu_s
* prevMenu
; // previous menu
165 menuitem_t
* menuitems
; // menu items
166 void (*routine
)(void); // draw routine
168 short y
; // x,y of menu
169 short lastOn
; // last item user was on in menu
172 short itemOn
; // menu item skull is on
173 short skullAnimCounter
; // skull animation counter
174 short whichSkull
; // which skull to draw
176 // graphic name of skulls
177 // warning: initializer-string for array of chars is too long
178 char skullName
[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
186 void M_NewGame(int choice
);
187 void M_Episode(int choice
);
188 void M_ChooseSkill(int choice
);
189 void M_LoadGame(int choice
);
190 void M_SaveGame(int choice
);
191 void M_Options(int choice
);
192 void M_EndGame(int choice
);
193 void M_ReadThis(int choice
);
194 void M_ReadThis2(int choice
);
195 void M_QuitDOOM(int choice
);
197 void M_ChangeMessages(int choice
);
198 void M_ChangeSensitivity(int choice
);
199 void M_SfxVol(int choice
);
200 void M_MusicVol(int choice
);
201 void M_ChangeDetail(int choice
);
202 void M_SizeDisplay(int choice
);
203 void M_StartGame(int choice
);
204 void M_Sound(int choice
);
206 void M_FinishReadThis(int choice
);
207 void M_LoadSelect(int choice
);
208 void M_SaveSelect(int choice
);
209 void M_ReadSaveStrings(void);
210 void M_QuickSave(void);
211 void M_QuickLoad(void);
213 void M_DrawMainMenu(void);
214 void M_DrawReadThis1(void);
215 void M_DrawReadThis2(void);
216 void M_DrawNewGame(void);
217 void M_DrawEpisode(void);
218 void M_DrawOptions(void);
219 void M_DrawSound(void);
220 void M_DrawLoad(void);
221 void M_DrawSave(void);
223 void M_DrawSaveLoadBorder(int x
,int y
);
224 void M_SetupNextMenu(menu_t
*menudef
);
225 void M_DrawThermo(int x
,int y
,int thermWidth
,int thermDot
);
226 void M_DrawEmptyCell(menu_t
*menu
,int item
);
227 void M_DrawSelCell(menu_t
*menu
,int item
);
228 void M_WriteText(int x
, int y
, char *string
);
229 int M_StringWidth(char *string
);
230 int M_StringHeight(char *string
);
231 void M_StartControlPanel(void);
232 void M_StartMessage(char *string
,void (*routine
)(int response
),boolean input
);
233 void M_StopMessage(void);
234 void M_ClearMenus (void);
253 menuitem_t MainMenu
[]=
255 {1,"M_NGAME",M_NewGame
,'n'},
256 {1,"M_OPTION",M_Options
,'o'},
257 {1,"M_LOADG",M_LoadGame
,'l'},
258 {1,"M_SAVEG",M_SaveGame
,'s'},
259 // Another hickup with Special edition.
260 {1,"M_RDTHIS",M_ReadThis
,'r'},
261 {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 ->
318 menuitem_t NewGameMenu
[]=
320 {1,"M_JKILL", M_ChooseSkill
, 'i'},
321 {1,"M_ROUGH", M_ChooseSkill
, 'h'},
322 {1,"M_HURT", M_ChooseSkill
, 'h'},
323 {1,"M_ULTRA", M_ChooseSkill
, 'u'},
324 {1,"M_NMARE", M_ChooseSkill
, 'n'}
329 newg_end
, // # of menu items
330 &EpiDef
, // previous menu
331 NewGameMenu
, // menuitem_t ->
332 M_DrawNewGame
, // drawing routine ->
355 menuitem_t OptionsMenu
[]=
357 {1,"M_ENDGAM", M_EndGame
,'e'},
358 {1,"M_MESSG", M_ChangeMessages
,'m'},
359 {1,"M_DETAIL", M_ChangeDetail
,'g'},
360 {2,"M_SCRNSZ", M_SizeDisplay
,'s'},
362 {2,"M_MSENS", M_ChangeSensitivity
,'m'},
364 {1,"M_SVOL", M_Sound
,'s'}
378 // Read This! MENU 1 & 2
386 menuitem_t ReadMenu1
[] =
407 menuitem_t ReadMenu2
[]=
409 {1,"",M_FinishReadThis
,0}
434 menuitem_t SoundMenu
[]=
436 {2,"M_SFXVOL",M_SfxVol
,'s'},
438 {2,"M_MUSVOL",M_MusicVol
,'m'},
466 menuitem_t LoadMenu
[]=
468 {1,"", M_LoadSelect
,'1'},
469 {1,"", M_LoadSelect
,'2'},
470 {1,"", M_LoadSelect
,'3'},
471 {1,"", M_LoadSelect
,'4'},
472 {1,"", M_LoadSelect
,'5'},
473 {1,"", M_LoadSelect
,'6'}
489 menuitem_t SaveMenu
[]=
491 {1,"", M_SaveSelect
,'1'},
492 {1,"", M_SaveSelect
,'2'},
493 {1,"", M_SaveSelect
,'3'},
494 {1,"", M_SaveSelect
,'4'},
495 {1,"", M_SaveSelect
,'5'},
496 {1,"", M_SaveSelect
,'6'}
512 // read the strings from the savegame files
514 void M_ReadSaveStrings(void)
521 for (i
= 0;i
< load_end
;i
++)
523 if (M_CheckParm("-cdrom"))
524 sprintf(name
,"c:\\doomdata\\"SAVEGAMENAME
"%d.dsg",i
);
526 sprintf(name
,SAVEGAMENAME
"%d.dsg",i
);
528 handle
= open (name
, O_RDONLY
| 0, 0666);
531 strcpy(&savegamestrings
[i
][0],EMPTYSTRING
);
532 LoadMenu
[i
].status
= 0;
535 count
= read (handle
, &savegamestrings
[i
], SAVESTRINGSIZE
);
537 LoadMenu
[i
].status
= 1;
545 void M_DrawLoad(void)
549 V_DrawPatchInDirect (72,28,0,W_CacheLumpName("M_LOADG",PU_CACHE
));
550 for (i
= 0;i
< load_end
; i
++)
552 M_DrawSaveLoadBorder(LoadDef
.x
,LoadDef
.y
+LINEHEIGHT
*i
);
553 M_WriteText(LoadDef
.x
,LoadDef
.y
+LINEHEIGHT
*i
,savegamestrings
[i
]);
560 // Draw border for the savegame description
562 void M_DrawSaveLoadBorder(int x
,int y
)
566 V_DrawPatchInDirect (x
-8,y
+7,0,W_CacheLumpName("M_LSLEFT",PU_CACHE
));
568 for (i
= 0;i
< 24;i
++)
570 V_DrawPatchInDirect (x
,y
+7,0,W_CacheLumpName("M_LSCNTR",PU_CACHE
));
574 V_DrawPatchInDirect (x
,y
+7,0,W_CacheLumpName("M_LSRGHT",PU_CACHE
));
580 // User wants to load this game
582 void M_LoadSelect(int choice
)
586 if (M_CheckParm("-cdrom"))
587 sprintf(name
,"c:\\doomdata\\"SAVEGAMENAME
"%d.dsg",choice
);
589 sprintf(name
,SAVEGAMENAME
"%d.dsg",choice
);
595 // Selected from DOOM menu
597 void M_LoadGame (int choice
)
601 M_StartMessage(LOADNET
,NULL
,false);
605 M_SetupNextMenu(&LoadDef
);
613 void M_DrawSave(void)
617 V_DrawPatchInDirect (72,28,0,W_CacheLumpName("M_SAVEG",PU_CACHE
));
618 for (i
= 0;i
< load_end
; i
++)
620 M_DrawSaveLoadBorder(LoadDef
.x
,LoadDef
.y
+LINEHEIGHT
*i
);
621 M_WriteText(LoadDef
.x
,LoadDef
.y
+LINEHEIGHT
*i
,savegamestrings
[i
]);
626 i
= M_StringWidth(savegamestrings
[saveSlot
]);
627 M_WriteText(LoadDef
.x
+ i
,LoadDef
.y
+LINEHEIGHT
*saveSlot
,"_");
632 // M_Responder calls this when user is finished
634 void M_DoSave(int slot
)
636 G_SaveGame (slot
,savegamestrings
[slot
]);
639 // PICK QUICKSAVE SLOT YET?
640 if (quickSaveSlot
== -2)
641 quickSaveSlot
= slot
;
645 // User wants to save. Start string input for M_Responder
647 void M_SaveSelect(int choice
)
649 // we are going to be intercepting all chars
653 strcpy(saveOldString
,savegamestrings
[choice
]);
654 if (!strcmp(savegamestrings
[choice
],EMPTYSTRING
))
655 savegamestrings
[choice
][0] = 0;
656 saveCharIndex
= strlen(savegamestrings
[choice
]);
660 // Selected from DOOM menu
662 void M_SaveGame (int choice
)
666 M_StartMessage(SAVEDEAD
,NULL
,false);
670 if (gamestate
!= GS_LEVEL
)
673 M_SetupNextMenu(&SaveDef
);
684 void M_QuickSaveResponse(int ch
)
688 M_DoSave(quickSaveSlot
);
689 S_StartSound(NULL
,sfx_swtchx
);
693 void M_QuickSave(void)
697 S_StartSound(NULL
,sfx_oof
);
701 if (gamestate
!= GS_LEVEL
)
704 if (quickSaveSlot
< 0)
706 M_StartControlPanel();
708 M_SetupNextMenu(&SaveDef
);
709 quickSaveSlot
= -2; // means to pick a slot now
712 sprintf(tempstring
,QSPROMPT
,savegamestrings
[quickSaveSlot
]);
713 M_StartMessage(tempstring
,M_QuickSaveResponse
,true);
721 void M_QuickLoadResponse(int ch
)
725 M_LoadSelect(quickSaveSlot
);
726 S_StartSound(NULL
,sfx_swtchx
);
731 void M_QuickLoad(void)
735 M_StartMessage(QLOADNET
,NULL
,false);
739 if (quickSaveSlot
< 0)
741 M_StartMessage(QSAVESPOT
,NULL
,false);
744 sprintf(tempstring
,QLPROMPT
,savegamestrings
[quickSaveSlot
]);
745 M_StartMessage(tempstring
,M_QuickLoadResponse
,true);
753 // Had a "quick hack to fix romero bug"
755 void M_DrawReadThis1(void)
757 inhelpscreens
= true;
761 V_DrawPatchInDirect (0,0,0,W_CacheLumpName("HELP",PU_CACHE
));
766 V_DrawPatchInDirect (0,0,0,W_CacheLumpName("HELP1",PU_CACHE
));
777 // Read This Menus - optional second page.
779 void M_DrawReadThis2(void)
781 inhelpscreens
= true;
786 // This hack keeps us from having to change menus.
787 V_DrawPatchInDirect (0,0,0,W_CacheLumpName("CREDIT",PU_CACHE
));
791 V_DrawPatchInDirect (0,0,0,W_CacheLumpName("HELP2",PU_CACHE
));
801 // Change Sfx & Music volumes
803 void M_DrawSound(void)
805 V_DrawPatchInDirect (60,38,0,W_CacheLumpName("M_SVOL",PU_CACHE
));
807 M_DrawThermo(SoundDef
.x
,SoundDef
.y
+LINEHEIGHT
*(sfx_vol
+1),
810 M_DrawThermo(SoundDef
.x
,SoundDef
.y
+LINEHEIGHT
*(music_vol
+1),
814 void M_Sound(int choice
)
816 M_SetupNextMenu(&SoundDef
);
819 void M_SfxVol(int choice
)
828 if (snd_SfxVolume
< 15)
833 S_SetSfxVolume(snd_SfxVolume
/* *8 */);
836 void M_MusicVol(int choice
)
845 if (snd_MusicVolume
< 15)
850 S_SetMusicVolume(snd_MusicVolume
/* *8 */);
859 void M_DrawMainMenu(void)
861 V_DrawPatchInDirect (94,2,0,W_CacheLumpName("M_DOOM",PU_CACHE
));
870 void M_DrawNewGame(void)
872 V_DrawPatchInDirect (96,14,0,W_CacheLumpName("M_NEWG",PU_CACHE
));
873 V_DrawPatchInDirect (54,38,0,W_CacheLumpName("M_SKILL",PU_CACHE
));
876 void M_NewGame(int choice
)
878 if (netgame
&& !demoplayback
)
880 M_StartMessage(NEWGAME
,NULL
,false);
884 if ( gamemode
== commercial
)
885 M_SetupNextMenu(&NewDef
);
887 M_SetupNextMenu(&EpiDef
);
896 void M_DrawEpisode(void)
898 V_DrawPatchInDirect (54,38,0,W_CacheLumpName("M_EPISOD",PU_CACHE
));
901 void M_VerifyNightmare(int ch
)
906 G_DeferedInitNew(nightmare
,epi
+1,1);
910 void M_ChooseSkill(int choice
)
912 if (choice
== nightmare
)
914 M_StartMessage(NIGHTMARE
,M_VerifyNightmare
,true);
918 G_DeferedInitNew(choice
,epi
+1,1);
922 void M_Episode(int choice
)
924 if ( (gamemode
== shareware
)
927 M_StartMessage(SWSTRING
,NULL
,false);
928 M_SetupNextMenu(&ReadDef1
);
932 // Yet another hack...
933 if ( (gamemode
== registered
)
937 "M_Episode: 4th episode requires UltimateDOOM\n");
942 M_SetupNextMenu(&NewDef
);
950 char detailNames
[2][9] = {"M_GDHIGH","M_GDLOW"};
951 char msgNames
[2][9] = {"M_MSGOFF","M_MSGON"};
954 void M_DrawOptions(void)
956 V_DrawPatchInDirect (108,15,0,W_CacheLumpName("M_OPTTTL",PU_CACHE
));
958 V_DrawPatchInDirect (OptionsDef
.x
+ 175,OptionsDef
.y
+LINEHEIGHT
*detail
,0,
959 W_CacheLumpName(detailNames
[detailLevel
],PU_CACHE
));
961 V_DrawPatchInDirect (OptionsDef
.x
+ 120,OptionsDef
.y
+LINEHEIGHT
*messages
,0,
962 W_CacheLumpName(msgNames
[showMessages
],PU_CACHE
));
964 M_DrawThermo(OptionsDef
.x
,OptionsDef
.y
+LINEHEIGHT
*(mousesens
+1),
965 10,mouseSensitivity
);
967 M_DrawThermo(OptionsDef
.x
,OptionsDef
.y
+LINEHEIGHT
*(scrnsize
+1),
971 void M_Options(int choice
)
973 M_SetupNextMenu(&OptionsDef
);
979 // Toggle messages on/off
981 void M_ChangeMessages(int choice
)
983 // warning: unused parameter `int choice'
985 showMessages
= 1 - showMessages
;
988 players
[consoleplayer
].message
= MSGOFF
;
990 players
[consoleplayer
].message
= MSGON
;
992 message_dontfuckwithme
= true;
999 void M_EndGameResponse(int ch
)
1004 currentMenu
->lastOn
= itemOn
;
1009 void M_EndGame(int choice
)
1014 S_StartSound(NULL
,sfx_oof
);
1020 M_StartMessage(NETEND
,NULL
,false);
1024 M_StartMessage(ENDGAME
,M_EndGameResponse
,true);
1033 void M_ReadThis(int choice
)
1036 M_SetupNextMenu(&ReadDef1
);
1039 void M_ReadThis2(int choice
)
1042 M_SetupNextMenu(&ReadDef2
);
1045 void M_FinishReadThis(int choice
)
1048 M_SetupNextMenu(&MainDef
);
1069 int quitsounds2
[8] =
1083 void M_QuitResponse(int ch
)
1089 if (gamemode
== commercial
)
1090 S_StartSound(NULL
,quitsounds2
[(gametic
>>2)&7]);
1092 S_StartSound(NULL
,quitsounds
[(gametic
>>2)&7]);
1101 void M_QuitDOOM(int choice
)
1103 // We pick index 0 which is language sensitive,
1104 // or one at random, between 1 and maximum number.
1105 if (language
!= english
)
1106 sprintf(endstring
,"%s\n\n"DOSY
, endmsg
[0] );
1108 sprintf(endstring
,"%s\n\n"DOSY
, endmsg
[ (gametic
%(NUM_QUITMESSAGES
-2))+1 ]);
1110 M_StartMessage(endstring
,M_QuitResponse
,true);
1116 void M_ChangeSensitivity(int choice
)
1121 if (mouseSensitivity
)
1125 if (mouseSensitivity
< 9)
1134 void M_ChangeDetail(int choice
)
1137 detailLevel
= 1 - detailLevel
;
1139 // FIXME - does not work. Remove anyway?
1140 // fprintf( stderr, "M_ChangeDetail: low detail mode n.a.\n");
1144 R_SetViewSize (screenblocks
, detailLevel
);
1147 players
[consoleplayer
].message
= DETAILHI
;
1149 players
[consoleplayer
].message
= DETAILLO
;
1155 void M_SizeDisplay(int choice
)
1176 R_SetViewSize (screenblocks
, detailLevel
);
1196 V_DrawPatchInDirect (xx
,y
,0,W_CacheLumpName("M_THERML",PU_CACHE
));
1198 for (i
=0;i
<thermWidth
;i
++)
1200 V_DrawPatchInDirect (xx
,y
,0,W_CacheLumpName("M_THERMM",PU_CACHE
));
1203 V_DrawPatchInDirect (xx
,y
,0,W_CacheLumpName("M_THERMR",PU_CACHE
));
1205 V_DrawPatchInDirect ((x
+8) + thermDot
*8,y
,
1206 0,W_CacheLumpName("M_THERMO",PU_CACHE
));
1216 V_DrawPatchInDirect (menu
->x
- 10, menu
->y
+item
*LINEHEIGHT
- 1, 0,
1217 W_CacheLumpName("M_CELL1",PU_CACHE
));
1225 V_DrawPatchInDirect (menu
->x
- 10, menu
->y
+item
*LINEHEIGHT
- 1, 0,
1226 W_CacheLumpName("M_CELL2",PU_CACHE
));
1233 void (*routine
)(int response
),
1234 /* void* routine, */
1237 messageLastMenuActive
= menuactive
;
1239 messageString
= string
;
1240 messageRoutine
= routine
;
1241 messageNeedsInput
= input
;
1248 void M_StopMessage(void)
1250 menuactive
= messageLastMenuActive
;
1257 // Find string width from hu_font chars
1259 int M_StringWidth(char* string
)
1265 for (i
= 0;i
< strlen(string
);i
++)
1267 c
= toupper(string
[i
]) - HU_FONTSTART
;
1268 if (c
< 0 || c
>= HU_FONTSIZE
)
1271 w
+= SWAPSHORT(hu_font
[c
]->width
);
1280 // Find string height from hu_font chars
1282 int M_StringHeight(char* string
)
1286 int height
= SWAPSHORT(hu_font
[0]->height
);
1289 for (i
= 0;i
< strlen(string
);i
++)
1290 if (string
[i
] == '\n')
1298 // Write a string using the hu_font
1329 c
= toupper(c
) - HU_FONTSTART
;
1330 if (c
< 0 || c
>= HU_FONTSIZE
)
1336 w
= SWAPSHORT(hu_font
[c
]->width
);
1337 if (cx
+w
> SCREENWIDTH
)
1339 V_DrawPatchInDirect(cx
, cy
, 0, hu_font
[c
]);
1353 boolean
M_Responder (event_t
* ev
)
1357 static int joywait
= 0;
1358 static int mousewait
= 0;
1359 static int mousey
= 0;
1360 static int lasty
= 0;
1361 static int mousex
= 0;
1362 static int lastx
= 0;
1366 if (ev
->type
== ev_joystick
&& joywait
< I_GetTime())
1368 if (ev
->data3
== -1)
1371 joywait
= I_GetTime() + 5;
1373 else if (ev
->data3
== 1)
1376 joywait
= I_GetTime() + 5;
1379 if (ev
->data2
== -1)
1382 joywait
= I_GetTime() + 2;
1384 else if (ev
->data2
== 1)
1386 ch
= KEY_RIGHTARROW
;
1387 joywait
= I_GetTime() + 2;
1393 joywait
= I_GetTime() + 5;
1398 joywait
= I_GetTime() + 5;
1403 if (ev
->type
== ev_mouse
&& mousewait
< I_GetTime())
1405 mousey
+= ev
->data3
;
1406 if (mousey
< lasty
-30)
1409 mousewait
= I_GetTime() + 5;
1410 mousey
= lasty
-= 30;
1412 else if (mousey
> lasty
+30)
1415 mousewait
= I_GetTime() + 5;
1416 mousey
= lasty
+= 30;
1419 mousex
+= ev
->data2
;
1420 if (mousex
< lastx
-30)
1423 mousewait
= I_GetTime() + 5;
1424 mousex
= lastx
-= 30;
1426 else if (mousex
> lastx
+30)
1428 ch
= KEY_RIGHTARROW
;
1429 mousewait
= I_GetTime() + 5;
1430 mousex
= lastx
+= 30;
1436 mousewait
= I_GetTime() + 15;
1442 mousewait
= I_GetTime() + 15;
1446 if (ev
->type
== ev_keydown
)
1456 // Save Game string input
1457 if (saveStringEnter
)
1462 if (saveCharIndex
> 0)
1465 savegamestrings
[saveSlot
][saveCharIndex
] = 0;
1470 saveStringEnter
= 0;
1471 strcpy(&savegamestrings
[saveSlot
][0],saveOldString
);
1475 saveStringEnter
= 0;
1476 if (savegamestrings
[saveSlot
][0])
1483 if (ch
-HU_FONTSTART
< 0 || ch
-HU_FONTSTART
>= HU_FONTSIZE
)
1485 if (ch
>= 32 && ch
<= 127 &&
1486 saveCharIndex
< SAVESTRINGSIZE
-1 &&
1487 M_StringWidth(savegamestrings
[saveSlot
]) <
1488 (SAVESTRINGSIZE
-2)*8)
1490 savegamestrings
[saveSlot
][saveCharIndex
++] = ch
;
1491 savegamestrings
[saveSlot
][saveCharIndex
] = 0;
1498 // Take care of any messages that need input
1501 if (messageNeedsInput
== true &&
1502 !(ch
== ' ' || ch
== 'n' || ch
== 'y' || ch
== KEY_ESCAPE
))
1505 menuactive
= messageLastMenuActive
;
1511 S_StartSound(NULL
,sfx_swtchx
);
1515 if (devparm
&& ch
== KEY_F1
)
1526 case KEY_MINUS
: // Screen size down
1527 if (automapactive
|| chat_on
)
1530 S_StartSound(NULL
,sfx_stnmov
);
1533 case KEY_EQUALS
: // Screen size up
1534 if (automapactive
|| chat_on
)
1537 S_StartSound(NULL
,sfx_stnmov
);
1540 case KEY_F1
: // Help key
1541 M_StartControlPanel ();
1543 if ( gamemode
== retail
)
1544 currentMenu
= &ReadDef2
;
1546 currentMenu
= &ReadDef1
;
1549 S_StartSound(NULL
,sfx_swtchn
);
1552 case KEY_F2
: // Save
1553 M_StartControlPanel();
1554 S_StartSound(NULL
,sfx_swtchn
);
1558 case KEY_F3
: // Load
1559 M_StartControlPanel();
1560 S_StartSound(NULL
,sfx_swtchn
);
1564 case KEY_F4
: // Sound Volume
1565 M_StartControlPanel ();
1566 currentMenu
= &SoundDef
;
1568 S_StartSound(NULL
,sfx_swtchn
);
1571 case KEY_F5
: // Detail toggle
1573 S_StartSound(NULL
,sfx_swtchn
);
1576 case KEY_F6
: // Quicksave
1577 S_StartSound(NULL
,sfx_swtchn
);
1581 case KEY_F7
: // End game
1582 S_StartSound(NULL
,sfx_swtchn
);
1586 case KEY_F8
: // Toggle messages
1587 M_ChangeMessages(0);
1588 S_StartSound(NULL
,sfx_swtchn
);
1591 case KEY_F9
: // Quickload
1592 S_StartSound(NULL
,sfx_swtchn
);
1596 case KEY_F10
: // Quit DOOM
1597 S_StartSound(NULL
,sfx_swtchn
);
1601 case KEY_F11
: // gamma toggle
1605 players
[consoleplayer
].message
= gammamsg
[usegamma
];
1606 I_RecalcPalettes ();
1607 I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE
), 0);
1616 if (ch
== KEY_ESCAPE
)
1618 M_StartControlPanel ();
1619 S_StartSound(NULL
,sfx_swtchn
);
1626 // Keys usable within menu
1632 if (itemOn
+1 > currentMenu
->numitems
-1)
1635 S_StartSound(NULL
,sfx_pstop
);
1636 } while(currentMenu
->menuitems
[itemOn
].status
==-1);
1643 itemOn
= currentMenu
->numitems
-1;
1645 S_StartSound(NULL
,sfx_pstop
);
1646 } while(currentMenu
->menuitems
[itemOn
].status
==-1);
1650 if (currentMenu
->menuitems
[itemOn
].routine
&&
1651 currentMenu
->menuitems
[itemOn
].status
== 2)
1653 S_StartSound(NULL
,sfx_stnmov
);
1654 currentMenu
->menuitems
[itemOn
].routine(0);
1658 case KEY_RIGHTARROW
:
1659 if (currentMenu
->menuitems
[itemOn
].routine
&&
1660 currentMenu
->menuitems
[itemOn
].status
== 2)
1662 S_StartSound(NULL
,sfx_stnmov
);
1663 currentMenu
->menuitems
[itemOn
].routine(1);
1668 if (currentMenu
->menuitems
[itemOn
].routine
&&
1669 currentMenu
->menuitems
[itemOn
].status
)
1671 currentMenu
->lastOn
= itemOn
;
1672 if (currentMenu
->menuitems
[itemOn
].status
== 2)
1674 currentMenu
->menuitems
[itemOn
].routine(1); // right arrow
1675 S_StartSound(NULL
,sfx_stnmov
);
1679 currentMenu
->menuitems
[itemOn
].routine(itemOn
);
1680 S_StartSound(NULL
,sfx_pistol
);
1686 currentMenu
->lastOn
= itemOn
;
1688 S_StartSound(NULL
,sfx_swtchx
);
1692 currentMenu
->lastOn
= itemOn
;
1693 if (currentMenu
->prevMenu
)
1695 currentMenu
= currentMenu
->prevMenu
;
1696 itemOn
= currentMenu
->lastOn
;
1697 S_StartSound(NULL
,sfx_swtchn
);
1702 for (i
= itemOn
+1;i
< currentMenu
->numitems
;i
++)
1703 if (currentMenu
->menuitems
[i
].alphaKey
== ch
)
1706 S_StartSound(NULL
,sfx_pstop
);
1709 for (i
= 0;i
<= itemOn
;i
++)
1710 if (currentMenu
->menuitems
[i
].alphaKey
== ch
)
1713 S_StartSound(NULL
,sfx_pstop
);
1726 // M_StartControlPanel
1728 void M_StartControlPanel (void)
1730 // intro might call this repeatedly
1735 currentMenu
= &MainDef
; // JDC
1736 itemOn
= currentMenu
->lastOn
; // JDC
1742 // Called after the view has been rendered,
1743 // but before it has been blitted.
1745 void M_Drawer (void)
1754 inhelpscreens
= false;
1757 // Horiz. & Vertically center string and print it.
1761 y
= 100 - M_StringHeight(messageString
)/2;
1762 while(*(messageString
+start
))
1764 for (i
= 0;i
< strlen(messageString
+start
);i
++)
1765 if (*(messageString
+start
+i
) == '\n')
1767 memset(string
,0,40);
1768 strncpy(string
,messageString
+start
,i
);
1773 if (i
== strlen(messageString
+start
))
1775 strcpy(string
,messageString
+start
);
1779 x
= 160 - M_StringWidth(string
)/2;
1780 M_WriteText(x
,y
,string
);
1781 y
+= SWAPSHORT(hu_font
[0]->height
);
1789 if (currentMenu
->routine
)
1790 currentMenu
->routine(); // call Draw routine
1795 max
= currentMenu
->numitems
;
1799 if (currentMenu
->menuitems
[i
].name
[0])
1800 V_DrawPatchInDirect (x
,y
,0,
1801 W_CacheLumpName(currentMenu
->menuitems
[i
].name
,PU_CACHE
));
1807 V_DrawPatchInDirect(x
+ SKULLXOFF
,currentMenu
->y
- 5 + itemOn
*LINEHEIGHT
, 0,
1808 W_CacheLumpName(skullName
[whichSkull
],PU_CACHE
));
1816 void M_ClearMenus (void)
1819 // if (!netgame && usergame && paused)
1820 // sendpause = true;
1829 void M_SetupNextMenu(menu_t
*menudef
)
1831 currentMenu
= menudef
;
1832 itemOn
= currentMenu
->lastOn
;
1839 void M_Ticker (void)
1841 if (--skullAnimCounter
<= 0)
1844 skullAnimCounter
= 8;
1854 currentMenu
= &MainDef
;
1856 itemOn
= currentMenu
->lastOn
;
1858 skullAnimCounter
= 10;
1859 screenSize
= screenblocks
- 3;
1861 messageString
= NULL
;
1862 messageLastMenuActive
= menuactive
;
1865 // Here we could catch other version dependencies,
1866 // like HELP1/2, and four episodes.
1872 // This is used because DOOM 2 had only one HELP
1873 // page. I use CREDIT as second page now, but
1874 // kept this hack for educational purposes.
1875 MainMenu
[readthis
] = MainMenu
[quitdoom
];
1878 NewDef
.prevMenu
= &MainDef
;
1879 ReadDef1
.routine
= M_DrawReadThis1
;
1882 ReadMenu1
[0].routine
= M_FinishReadThis
;
1885 // Episode 2 and 3 are handled,
1886 // branching to an ad screen.
1888 // We need to remove the fourth episode.