1 /*
2 ** menu.cpp
3 ** Menu base class and global interface
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 2010 Christoph Oelckers
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34
35 #include "doomdef.h"
36 #include "doomstat.h"
37 #include "c_dispatch.h"
38 #include "d_gui.h"
39 #include "d_player.h"
40 #include "g_level.h"
41 #include "c_console.h"
42 #include "c_bind.h"
43 #include "s_sound.h"
44 #include "p_tick.h"
45 #include "g_game.h"
46 #include "c_cvars.h"
47 #include "d_event.h"
48 #include "v_video.h"
49 #include "hu_stuff.h"
50 #include "gi.h"
51 #include "v_palette.h"
52 #include "i_input.h"
53 #include "gameconfigfile.h"
54 #include "gstrings.h"
55 #include "r_utility.h"
56 #include "menu/menu.h"
57 #include "textures/textures.h"
58
59 //
60 // Todo: Move these elsewhere
61 //
62 CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
63 CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
64 CVAR (Bool, show_obituaries, true, CVAR_ARCHIVE)
65
66
67 CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE)
68 CVAR(Int, m_use_mouse, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
69 CVAR(Int, m_show_backbutton, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
70
71 DMenu *DMenu::CurrentMenu;
72 int DMenu::MenuTime;
73
74 FGameStartup GameStartupInfo;
75 EMenuState menuactive;
76 bool M_DemoNoPlay;
77 FButtonStatus MenuButtons[NUM_MKEYS];
78 int MenuButtonTickers[NUM_MKEYS];
79 bool MenuButtonOrigin[NUM_MKEYS];
80 int BackbuttonTime;
81 fixed_t BackbuttonAlpha;
82 static bool MenuEnabled = true;
83
84
85 #define KEY_REPEAT_DELAY (TICRATE*5/12)
86 #define KEY_REPEAT_RATE (3)
87
88 //============================================================================
89 //
90 // DMenu base class
91 //
92 //============================================================================
93
94 IMPLEMENT_POINTY_CLASS (DMenu)
DECLARE_POINTER(mParentMenu)95 DECLARE_POINTER(mParentMenu)
96 END_POINTERS
97
98 DMenu::DMenu(DMenu *parent)
99 {
100 mParentMenu = parent;
101 mMouseCapture = false;
102 mBackbuttonSelected = false;
103 GC::WriteBarrier(this, parent);
104 }
105
Responder(event_t * ev)106 bool DMenu::Responder (event_t *ev)
107 {
108 bool res = false;
109 if (ev->type == EV_GUI_Event)
110 {
111 if (ev->subtype == EV_GUI_LButtonDown)
112 {
113 res = MouseEventBack(MOUSE_Click, ev->data1, ev->data2);
114 // make the menu's mouse handler believe that the current coordinate is outside the valid range
115 if (res) ev->data2 = -1;
116 res |= MouseEvent(MOUSE_Click, ev->data1, ev->data2);
117 if (res)
118 {
119 SetCapture();
120 }
121
122 }
123 else if (ev->subtype == EV_GUI_MouseMove)
124 {
125 BackbuttonTime = BACKBUTTON_TIME;
126 if (mMouseCapture || m_use_mouse == 1)
127 {
128 res = MouseEventBack(MOUSE_Move, ev->data1, ev->data2);
129 if (res) ev->data2 = -1;
130 res |= MouseEvent(MOUSE_Move, ev->data1, ev->data2);
131 }
132 }
133 else if (ev->subtype == EV_GUI_LButtonUp)
134 {
135 if (mMouseCapture)
136 {
137 ReleaseCapture();
138 res = MouseEventBack(MOUSE_Release, ev->data1, ev->data2);
139 if (res) ev->data2 = -1;
140 res |= MouseEvent(MOUSE_Release, ev->data1, ev->data2);
141 }
142 }
143 }
144 return false;
145 }
146
147 //=============================================================================
148 //
149 //
150 //
151 //=============================================================================
152
MenuEvent(int mkey,bool fromcontroller)153 bool DMenu::MenuEvent (int mkey, bool fromcontroller)
154 {
155 switch (mkey)
156 {
157 case MKEY_Back:
158 {
159 Close();
160 S_Sound (CHAN_VOICE | CHAN_UI,
161 DMenu::CurrentMenu != NULL? "menu/backup" : "menu/clear", snd_menuvolume, ATTN_NONE);
162 return true;
163 }
164 }
165 return false;
166 }
167
168 //=============================================================================
169 //
170 //
171 //
172 //=============================================================================
173
Close()174 void DMenu::Close ()
175 {
176 assert(DMenu::CurrentMenu == this);
177 DMenu::CurrentMenu = mParentMenu;
178 Destroy();
179 if (DMenu::CurrentMenu != NULL)
180 {
181 GC::WriteBarrier(DMenu::CurrentMenu);
182 }
183 else
184 {
185 M_ClearMenus ();
186 }
187 }
188
189 //=============================================================================
190 //
191 //
192 //
193 //=============================================================================
194
MouseEvent(int type,int x,int y)195 bool DMenu::MouseEvent(int type, int x, int y)
196 {
197 return true;
198 }
199
200 //=============================================================================
201 //
202 //
203 //
204 //=============================================================================
205
MouseEventBack(int type,int x,int y)206 bool DMenu::MouseEventBack(int type, int x, int y)
207 {
208 if (m_show_backbutton >= 0)
209 {
210 FTexture *tex = TexMan(gameinfo.mBackButton);
211 if (tex != NULL)
212 {
213 if (m_show_backbutton&1) x -= screen->GetWidth() - tex->GetScaledWidth() * CleanXfac;
214 if (m_show_backbutton&2) y -= screen->GetHeight() - tex->GetScaledHeight() * CleanYfac;
215 mBackbuttonSelected = ( x >= 0 && x < tex->GetScaledWidth() * CleanXfac &&
216 y >= 0 && y < tex->GetScaledHeight() * CleanYfac);
217 if (mBackbuttonSelected && type == MOUSE_Release)
218 {
219 if (m_use_mouse == 2) mBackbuttonSelected = false;
220 MenuEvent(MKEY_Back, true);
221 }
222 return mBackbuttonSelected;
223 }
224 }
225 return false;
226 }
227
228 //=============================================================================
229 //
230 //
231 //
232 //=============================================================================
233
SetCapture()234 void DMenu::SetCapture()
235 {
236 if (!mMouseCapture)
237 {
238 mMouseCapture = true;
239 I_SetMouseCapture();
240 }
241 }
242
ReleaseCapture()243 void DMenu::ReleaseCapture()
244 {
245 if (mMouseCapture)
246 {
247 mMouseCapture = false;
248 I_ReleaseMouseCapture();
249 }
250 }
251
252 //=============================================================================
253 //
254 //
255 //
256 //=============================================================================
257
Ticker()258 void DMenu::Ticker ()
259 {
260 }
261
Drawer()262 void DMenu::Drawer ()
263 {
264 if (this == DMenu::CurrentMenu && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse)
265 {
266 FTexture *tex = TexMan(gameinfo.mBackButton);
267 int w = tex->GetScaledWidth() * CleanXfac;
268 int h = tex->GetScaledHeight() * CleanYfac;
269 int x = (!(m_show_backbutton&1))? 0:screen->GetWidth() - w;
270 int y = (!(m_show_backbutton&2))? 0:screen->GetHeight() - h;
271 if (mBackbuttonSelected && (mMouseCapture || m_use_mouse == 1))
272 {
273 screen->DrawTexture(tex, x, y, DTA_CleanNoMove, true, DTA_ColorOverlay, MAKEARGB(40, 255,255,255), TAG_DONE);
274 }
275 else
276 {
277 screen->DrawTexture(tex, x, y, DTA_CleanNoMove, true, DTA_Alpha, BackbuttonAlpha, TAG_DONE);
278 }
279 }
280 }
281
DimAllowed()282 bool DMenu::DimAllowed()
283 {
284 return true;
285 }
286
TranslateKeyboardEvents()287 bool DMenu::TranslateKeyboardEvents()
288 {
289 return true;
290 }
291
292 //=============================================================================
293 //
294 //
295 //
296 //=============================================================================
297
M_StartControlPanel(bool makeSound)298 void M_StartControlPanel (bool makeSound)
299 {
300 // intro might call this repeatedly
301 if (DMenu::CurrentMenu != NULL)
302 return;
303
304 ResetButtonStates ();
305 for (int i = 0; i < NUM_MKEYS; ++i)
306 {
307 MenuButtons[i].ReleaseKey(0);
308 }
309
310 C_HideConsole (); // [RH] Make sure console goes bye bye.
311 menuactive = MENU_On;
312 // Pause sound effects before we play the menu switch sound.
313 // That way, it won't be paused.
314 P_CheckTickerPaused ();
315
316 if (makeSound)
317 {
318 S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
319 }
320 BackbuttonTime = 0;
321 BackbuttonAlpha = 0;
322 }
323
324 //=============================================================================
325 //
326 //
327 //
328 //=============================================================================
329
M_ActivateMenu(DMenu * menu)330 void M_ActivateMenu(DMenu *menu)
331 {
332 if (menuactive == MENU_Off) menuactive = MENU_On;
333 if (DMenu::CurrentMenu != NULL) DMenu::CurrentMenu->ReleaseCapture();
334 DMenu::CurrentMenu = menu;
335 GC::WriteBarrier(DMenu::CurrentMenu);
336 }
337
338 //=============================================================================
339 //
340 //
341 //
342 //=============================================================================
343
M_SetMenu(FName menu,int param)344 void M_SetMenu(FName menu, int param)
345 {
346 // some menus need some special treatment
347 switch (menu)
348 {
349 case NAME_Episodemenu:
350 // sent from the player class menu
351 GameStartupInfo.Skill = -1;
352 GameStartupInfo.Episode = -1;
353 GameStartupInfo.PlayerClass =
354 param == -1000? NULL :
355 param == -1? "Random" : GetPrintableDisplayName(PlayerClasses[param].Type);
356 break;
357
358 case NAME_Skillmenu:
359 // sent from the episode menu
360
361 if ((gameinfo.flags & GI_SHAREWARE) && param > 0)
362 {
363 // Only Doom and Heretic have multi-episode shareware versions.
364 M_StartMessage(GStrings("SWSTRING"), 1);
365 return;
366 }
367
368 GameStartupInfo.Episode = param;
369 M_StartupSkillMenu(&GameStartupInfo); // needs player class name from class menu (later)
370 break;
371
372 case NAME_StartgameConfirm:
373 {
374 // sent from the skill menu for a skill that needs to be confirmed
375 GameStartupInfo.Skill = param;
376
377 const char *msg = AllSkills[param].MustConfirmText;
378 if (*msg==0) msg = GStrings("NIGHTMARE");
379 M_StartMessage (msg, 0, NAME_StartgameConfirmed);
380 return;
381 }
382
383 case NAME_Startgame:
384 // sent either from skill menu or confirmation screen. Skill gets only set if sent from skill menu
385 // Now we can finally start the game. Ugh...
386 GameStartupInfo.Skill = param;
387 case NAME_StartgameConfirmed:
388
389 G_DeferedInitNew (&GameStartupInfo);
390 if (gamestate == GS_FULLCONSOLE)
391 {
392 gamestate = GS_HIDECONSOLE;
393 gameaction = ga_newgame;
394 }
395 M_ClearMenus ();
396 return;
397
398 case NAME_Savegamemenu:
399 if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer) || gamestate != GS_LEVEL)
400 {
401 // cannot save outside the game.
402 M_StartMessage (GStrings("SAVEDEAD"), 1);
403 return;
404 }
405 }
406
407 // End of special checks
408
409 FMenuDescriptor **desc = MenuDescriptors.CheckKey(menu);
410 if (desc != NULL)
411 {
412 if ((*desc)->mNetgameMessage.IsNotEmpty() && netgame && !demoplayback)
413 {
414 M_StartMessage((*desc)->mNetgameMessage, 1);
415 return;
416 }
417
418 if ((*desc)->mType == MDESC_ListMenu)
419 {
420 FListMenuDescriptor *ld = static_cast<FListMenuDescriptor*>(*desc);
421 if (ld->mAutoselect >= 0 && ld->mAutoselect < (int)ld->mItems.Size())
422 {
423 // recursively activate the autoselected item without ever creating this menu.
424 ld->mItems[ld->mAutoselect]->Activate();
425 }
426 else
427 {
428 const PClass *cls = ld->mClass == NULL? RUNTIME_CLASS(DListMenu) : ld->mClass;
429
430 DListMenu *newmenu = (DListMenu *)cls->CreateNew();
431 newmenu->Init(DMenu::CurrentMenu, ld);
432 M_ActivateMenu(newmenu);
433 }
434 }
435 else if ((*desc)->mType == MDESC_OptionsMenu)
436 {
437 FOptionMenuDescriptor *ld = static_cast<FOptionMenuDescriptor*>(*desc);
438 const PClass *cls = ld->mClass == NULL? RUNTIME_CLASS(DOptionMenu) : ld->mClass;
439
440 DOptionMenu *newmenu = (DOptionMenu *)cls->CreateNew();
441 newmenu->Init(DMenu::CurrentMenu, ld);
442 M_ActivateMenu(newmenu);
443 }
444 return;
445 }
446 else
447 {
448 const PClass *menuclass = PClass::FindClass(menu);
449 if (menuclass != NULL)
450 {
451 if (menuclass->IsDescendantOf(RUNTIME_CLASS(DMenu)))
452 {
453 DMenu *newmenu = (DMenu*)menuclass->CreateNew();
454 newmenu->mParentMenu = DMenu::CurrentMenu;
455 M_ActivateMenu(newmenu);
456 return;
457 }
458 }
459 }
460 Printf("Attempting to open menu of unknown type '%s'\n", menu.GetChars());
461 }
462
463 //=============================================================================
464 //
465 //
466 //
467 //=============================================================================
468
M_Responder(event_t * ev)469 bool M_Responder (event_t *ev)
470 {
471 int ch = 0;
472 bool keyup = false;
473 int mkey = NUM_MKEYS;
474 bool fromcontroller = true;
475
476 if (chatmodeon)
477 {
478 return false;
479 }
480
481 if (DMenu::CurrentMenu != NULL && menuactive != MENU_Off)
482 {
483 // There are a few input sources we are interested in:
484 //
485 // EV_KeyDown / EV_KeyUp : joysticks/gamepads/controllers
486 // EV_GUI_KeyDown / EV_GUI_KeyUp : the keyboard
487 // EV_GUI_Char : printable characters, which we want in string input mode
488 //
489 // This code previously listened for EV_GUI_KeyRepeat to handle repeating
490 // in the menus, but that doesn't work with gamepads, so now we combine
491 // the multiple inputs into buttons and handle the repetition manually.
492 if (ev->type == EV_GUI_Event)
493 {
494 fromcontroller = false;
495 if (ev->subtype == EV_GUI_KeyRepeat)
496 {
497 // We do our own key repeat handling but still want to eat the
498 // OS's repeated keys.
499 return true;
500 }
501 else if (ev->subtype == EV_GUI_BackButtonDown || ev->subtype == EV_GUI_BackButtonUp)
502 {
503 mkey = MKEY_Back;
504 keyup = ev->subtype == EV_GUI_BackButtonUp;
505 }
506 else if (ev->subtype != EV_GUI_KeyDown && ev->subtype != EV_GUI_KeyUp)
507 {
508 // do we want mouse input?
509 if (ev->subtype >= EV_GUI_FirstMouseEvent && ev->subtype <= EV_GUI_LastMouseEvent)
510 {
511 if (!m_use_mouse)
512 return true;
513 }
514
515 // pass everything else on to the current menu
516 return DMenu::CurrentMenu->Responder(ev);
517 }
518 else if (DMenu::CurrentMenu->TranslateKeyboardEvents())
519 {
520 ch = ev->data1;
521 keyup = ev->subtype == EV_GUI_KeyUp;
522 switch (ch)
523 {
524 case GK_BACK: mkey = MKEY_Back; break;
525 case GK_ESCAPE: mkey = MKEY_Back; break;
526 case GK_RETURN: mkey = MKEY_Enter; break;
527 case GK_UP: mkey = MKEY_Up; break;
528 case GK_DOWN: mkey = MKEY_Down; break;
529 case GK_LEFT: mkey = MKEY_Left; break;
530 case GK_RIGHT: mkey = MKEY_Right; break;
531 case GK_BACKSPACE: mkey = MKEY_Clear; break;
532 case GK_PGUP: mkey = MKEY_PageUp; break;
533 case GK_PGDN: mkey = MKEY_PageDown; break;
534 default:
535 if (!keyup)
536 {
537 return DMenu::CurrentMenu->Responder(ev);
538 }
539 break;
540 }
541 }
542 }
543 else if (menuactive != MENU_WaitKey && (ev->type == EV_KeyDown || ev->type == EV_KeyUp))
544 {
545 keyup = ev->type == EV_KeyUp;
546
547 ch = ev->data1;
548 switch (ch)
549 {
550 case KEY_JOY1:
551 case KEY_PAD_A:
552 mkey = MKEY_Enter;
553 break;
554
555 case KEY_JOY2:
556 case KEY_PAD_B:
557 mkey = MKEY_Back;
558 break;
559
560 case KEY_JOY3:
561 case KEY_PAD_X:
562 mkey = MKEY_Clear;
563 break;
564
565 case KEY_JOY5:
566 case KEY_PAD_LSHOULDER:
567 mkey = MKEY_PageUp;
568 break;
569
570 case KEY_JOY6:
571 case KEY_PAD_RSHOULDER:
572 mkey = MKEY_PageDown;
573 break;
574
575 case KEY_PAD_DPAD_UP:
576 case KEY_PAD_LTHUMB_UP:
577 case KEY_JOYAXIS1MINUS:
578 case KEY_JOYPOV1_UP:
579 mkey = MKEY_Up;
580 break;
581
582 case KEY_PAD_DPAD_DOWN:
583 case KEY_PAD_LTHUMB_DOWN:
584 case KEY_JOYAXIS1PLUS:
585 case KEY_JOYPOV1_DOWN:
586 mkey = MKEY_Down;
587 break;
588
589 case KEY_PAD_DPAD_LEFT:
590 case KEY_PAD_LTHUMB_LEFT:
591 case KEY_JOYAXIS2MINUS:
592 case KEY_JOYPOV1_LEFT:
593 mkey = MKEY_Left;
594 break;
595
596 case KEY_PAD_DPAD_RIGHT:
597 case KEY_PAD_LTHUMB_RIGHT:
598 case KEY_JOYAXIS2PLUS:
599 case KEY_JOYPOV1_RIGHT:
600 mkey = MKEY_Right;
601 break;
602 }
603 }
604
605 if (mkey != NUM_MKEYS)
606 {
607 if (keyup)
608 {
609 MenuButtons[mkey].ReleaseKey(ch);
610 return false;
611 }
612 else
613 {
614 MenuButtons[mkey].PressKey(ch);
615 MenuButtonOrigin[mkey] = fromcontroller;
616 if (mkey <= MKEY_PageDown)
617 {
618 MenuButtonTickers[mkey] = KEY_REPEAT_DELAY;
619 }
620 DMenu::CurrentMenu->MenuEvent(mkey, fromcontroller);
621 return true;
622 }
623 }
624 return DMenu::CurrentMenu->Responder(ev) || !keyup;
625 }
626 else if (MenuEnabled)
627 {
628 if (ev->type == EV_KeyDown)
629 {
630 // Pop-up menu?
631 if (ev->data1 == KEY_ESCAPE)
632 {
633 M_StartControlPanel(true);
634 M_SetMenu(NAME_Mainmenu, -1);
635 return true;
636 }
637 // If devparm is set, pressing F1 always takes a screenshot no matter
638 // what it's bound to. (for those who don't bother to read the docs)
639 if (devparm && ev->data1 == KEY_F1)
640 {
641 G_ScreenShot(NULL);
642 return true;
643 }
644 return false;
645 }
646 else if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_LButtonDown &&
647 ConsoleState != c_down && m_use_mouse)
648 {
649 M_StartControlPanel(true);
650 M_SetMenu(NAME_Mainmenu, -1);
651 return true;
652 }
653 }
654 return false;
655 }
656
657 //=============================================================================
658 //
659 //
660 //
661 //=============================================================================
662
M_Ticker(void)663 void M_Ticker (void)
664 {
665 DMenu::MenuTime++;
666 if (DMenu::CurrentMenu != NULL && menuactive != MENU_Off)
667 {
668 DMenu::CurrentMenu->Ticker();
669
670 for (int i = 0; i < NUM_MKEYS; ++i)
671 {
672 if (MenuButtons[i].bDown)
673 {
674 if (MenuButtonTickers[i] > 0 && --MenuButtonTickers[i] <= 0)
675 {
676 MenuButtonTickers[i] = KEY_REPEAT_RATE;
677 DMenu::CurrentMenu->MenuEvent(i, MenuButtonOrigin[i]);
678 }
679 }
680 }
681 if (BackbuttonTime > 0)
682 {
683 if (BackbuttonAlpha < FRACUNIT) BackbuttonAlpha += FRACUNIT/10;
684 BackbuttonTime--;
685 }
686 else
687 {
688 if (BackbuttonAlpha > 0) BackbuttonAlpha -= FRACUNIT/10;
689 if (BackbuttonAlpha < 0) BackbuttonAlpha = 0;
690 }
691 }
692 }
693
694 //=============================================================================
695 //
696 //
697 //
698 //=============================================================================
699
M_Drawer(void)700 void M_Drawer (void)
701 {
702 player_t *player = &players[consoleplayer];
703 AActor *camera = player->camera;
704 PalEntry fade = 0;
705
706 if (!screen->Accel2D && camera != NULL && (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL))
707 {
708 if (camera->player != NULL)
709 {
710 player = camera->player;
711 }
712 fade = PalEntry (BYTE(player->BlendA*255), BYTE(player->BlendR*255), BYTE(player->BlendG*255), BYTE(player->BlendB*255));
713 }
714
715
716 if (DMenu::CurrentMenu != NULL && menuactive != MENU_Off)
717 {
718 if (DMenu::CurrentMenu->DimAllowed()) screen->Dim(fade);
719 DMenu::CurrentMenu->Drawer();
720 }
721 }
722
723 //=============================================================================
724 //
725 //
726 //
727 //=============================================================================
728
M_ClearMenus()729 void M_ClearMenus ()
730 {
731 M_DemoNoPlay = false;
732 if (DMenu::CurrentMenu != NULL)
733 {
734 DMenu::CurrentMenu->Destroy();
735 DMenu::CurrentMenu = NULL;
736 }
737 V_SetBorderNeedRefresh();
738 menuactive = MENU_Off;
739 }
740
741 //=============================================================================
742 //
743 //
744 //
745 //=============================================================================
746
M_Init(void)747 void M_Init (void)
748 {
749 M_ParseMenuDefs();
750 M_CreateMenus();
751 }
752
753
754 //=============================================================================
755 //
756 //
757 //
758 //=============================================================================
759
M_EnableMenu(bool on)760 void M_EnableMenu (bool on)
761 {
762 MenuEnabled = on;
763 }
764
765
766 //=============================================================================
767 //
768 // [RH] Most menus can now be accessed directly
769 // through console commands.
770 //
771 //=============================================================================
772
CCMD(menu_main)773 CCMD (menu_main)
774 {
775 M_StartControlPanel(true);
776 M_SetMenu(NAME_Mainmenu, -1);
777 }
778
CCMD(menu_load)779 CCMD (menu_load)
780 { // F3
781 M_StartControlPanel (true);
782 M_SetMenu(NAME_Loadgamemenu, -1);
783 }
784
CCMD(menu_save)785 CCMD (menu_save)
786 { // F2
787 M_StartControlPanel (true);
788 M_SetMenu(NAME_Savegamemenu, -1);
789 }
790
CCMD(menu_help)791 CCMD (menu_help)
792 { // F1
793 M_StartControlPanel (true);
794 M_SetMenu(NAME_Readthismenu, -1);
795 }
796
CCMD(menu_game)797 CCMD (menu_game)
798 {
799 M_StartControlPanel (true);
800 M_SetMenu(NAME_Playerclassmenu, -1); // The playerclass menu is the first in the 'start game' chain
801 }
802
CCMD(menu_options)803 CCMD (menu_options)
804 {
805 M_StartControlPanel (true);
806 M_SetMenu(NAME_Optionsmenu, -1);
807 }
808
CCMD(menu_player)809 CCMD (menu_player)
810 {
811 M_StartControlPanel (true);
812 M_SetMenu(NAME_Playermenu, -1);
813 }
814
CCMD(menu_messages)815 CCMD (menu_messages)
816 {
817 M_StartControlPanel (true);
818 M_SetMenu(NAME_MessageOptions, -1);
819 }
820
CCMD(menu_automap)821 CCMD (menu_automap)
822 {
823 M_StartControlPanel (true);
824 M_SetMenu(NAME_AutomapOptions, -1);
825 }
826
CCMD(menu_scoreboard)827 CCMD (menu_scoreboard)
828 {
829 M_StartControlPanel (true);
830 M_SetMenu(NAME_ScoreboardOptions, -1);
831 }
832
CCMD(menu_mapcolors)833 CCMD (menu_mapcolors)
834 {
835 M_StartControlPanel (true);
836 M_SetMenu(NAME_MapColorMenu, -1);
837 }
838
CCMD(menu_keys)839 CCMD (menu_keys)
840 {
841 M_StartControlPanel (true);
842 M_SetMenu(NAME_CustomizeControls, -1);
843 }
844
CCMD(menu_gameplay)845 CCMD (menu_gameplay)
846 {
847 M_StartControlPanel (true);
848 M_SetMenu(NAME_GameplayOptions, -1);
849 }
850
CCMD(menu_compatibility)851 CCMD (menu_compatibility)
852 {
853 M_StartControlPanel (true);
854 M_SetMenu(NAME_CompatibilityOptions, -1);
855 }
856
CCMD(menu_mouse)857 CCMD (menu_mouse)
858 {
859 M_StartControlPanel (true);
860 M_SetMenu(NAME_MouseOptions, -1);
861 }
862
CCMD(menu_joystick)863 CCMD (menu_joystick)
864 {
865 M_StartControlPanel (true);
866 M_SetMenu(NAME_JoystickOptions, -1);
867 }
868
CCMD(menu_sound)869 CCMD (menu_sound)
870 {
871 M_StartControlPanel (true);
872 M_SetMenu(NAME_SoundOptions, -1);
873 }
874
CCMD(menu_advsound)875 CCMD (menu_advsound)
876 {
877 M_StartControlPanel (true);
878 M_SetMenu(NAME_AdvSoundOptions, -1);
879 }
880
CCMD(menu_modreplayer)881 CCMD (menu_modreplayer)
882 {
883 M_StartControlPanel(true);
884 M_SetMenu(NAME_ModReplayerOptions, -1);
885 }
886
CCMD(menu_display)887 CCMD (menu_display)
888 {
889 M_StartControlPanel (true);
890 M_SetMenu(NAME_VideoOptions, -1);
891 }
892
CCMD(menu_video)893 CCMD (menu_video)
894 {
895 M_StartControlPanel (true);
896 M_SetMenu(NAME_VideoModeMenu, -1);
897 }
898
899
900
CCMD(openmenu)901 CCMD (openmenu)
902 {
903 if (argv.argc() < 2)
904 {
905 Printf("Usage: openmenu \"menu_name\"");
906 return;
907 }
908 M_StartControlPanel (true);
909 M_SetMenu(argv[1], -1);
910 }
911
CCMD(closemenu)912 CCMD (closemenu)
913 {
914 M_ClearMenus();
915 }
916
917 //
918 // Toggle messages on/off
919 //
CCMD(togglemessages)920 CCMD (togglemessages)
921 {
922 if (show_messages)
923 {
924 Printf (128, "%s\n", GStrings("MSGOFF"));
925 show_messages = false;
926 }
927 else
928 {
929 Printf (128, "%s\n", GStrings("MSGON"));
930 show_messages = true;
931 }
932 }
933
EXTERN_CVAR(Int,screenblocks)934 EXTERN_CVAR (Int, screenblocks)
935
936 CCMD (sizedown)
937 {
938 screenblocks = screenblocks - 1;
939 S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
940 }
941
CCMD(sizeup)942 CCMD (sizeup)
943 {
944 screenblocks = screenblocks + 1;
945 S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
946 }
947
CCMD(menuconsole)948 CCMD(menuconsole)
949 {
950 M_ClearMenus();
951 C_ToggleConsole();
952 }
953
CCMD(reset2defaults)954 CCMD(reset2defaults)
955 {
956 C_SetDefaultBindings ();
957 C_SetCVarsToDefaults ();
958 R_SetViewSize (screenblocks);
959 }
960
CCMD(reset2saved)961 CCMD(reset2saved)
962 {
963 GameConfig->DoGlobalSetup ();
964 GameConfig->DoGameSetup (gameinfo.ConfigName);
965 GameConfig->DoModSetup (gameinfo.ConfigName);
966 R_SetViewSize (screenblocks);
967 }
968