m_menu.c (24509B)
1 #include <unistd.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <fcntl.h> 5 #include <stdlib.h> 6 #include <ctype.h> 7 8 #include "m_swap.h" 9 #include "doomdef.h" 10 #include "d_main.h" 11 #include "i_system.h" 12 #include "i_video.h" 13 #include "z_zone.h" 14 #include "v_video.h" 15 #include "w_wad.h" 16 #include "r_local.h" 17 #include "hu_stuff.h" 18 #include "g_game.h" 19 #include "m_argv.h" 20 #include "s_sound.h" 21 #include "doomstat.h" 22 #include "sounds.h" 23 #include "m_menu.h" 24 25 #define SAVESTRINGSIZE 24 26 #define SKULLXOFF -32 27 #define LINEHEIGHT 16 28 29 typedef struct { 30 short status; 31 char name[10]; 32 void (*routine)(int choice); 33 char alphaKey; 34 } menuitem_t; 35 36 typedef struct menu_s { 37 short numitems; 38 struct menu_s* prevMenu; 39 menuitem_t* menuitems; 40 void (*routine)(); 41 short x; 42 short y; 43 short lastOn; 44 } menu_t; 45 46 extern patch_t* hu_font[HU_FONTSIZE]; 47 extern boolean message_dontfuckwithme; 48 extern boolean chat_on; 49 int mouseSensitivity; 50 int showMessages; 51 int detailLevel; 52 int screenblocks; 53 int screenSize; 54 int quickSaveSlot; 55 int messageToPrint; 56 char* messageString; 57 int messx; 58 int messy; 59 int messageLastMenuActive; 60 boolean messageNeedsInput; 61 void (*messageRoutine)(int response); 62 int saveStringEnter; 63 int saveSlot; 64 int saveCharIndex; 65 char saveOldString[SAVESTRINGSIZE]; 66 boolean inhelpscreens; 67 boolean menuactive; 68 extern boolean sendpause; 69 char savegamestrings[10][SAVESTRINGSIZE]; 70 char tempstring[160]; 71 char endstring[160]; 72 short itemOn; 73 short skullAnimCounter; 74 short whichSkull; 75 menu_t* currentMenu; 76 int epi; 77 78 int gammamsg[] = { 79 GAMMALVL0, 80 GAMMALVL1, 81 GAMMALVL2, 82 GAMMALVL3, 83 GAMMALVL4 84 }; 85 86 char skullName[2][/*8*/9] = {"M_SKULL1", "M_SKULL2"}; 87 char detailNames[2][9] = {"M_GDHIGH", "M_GDLOW"}; 88 char msgNames[2][9] = {"M_MSGOFF", "M_MSGON"}; 89 int quitsounds[8] = { 90 sfx_pldeth, 91 sfx_dmpain, 92 sfx_popain, 93 sfx_slop, 94 sfx_telept, 95 sfx_posit1, 96 sfx_posit3, 97 sfx_sgtatk 98 }; 99 100 int quitsounds2[8] = { 101 sfx_vilact, 102 sfx_getpow, 103 sfx_boscub, 104 sfx_slop, 105 sfx_skeswg, 106 sfx_kntdth, 107 sfx_bspact, 108 sfx_sgtatk 109 }; 110 111 112 void M_NewGame(int choice); 113 void M_Episode(int choice); 114 void M_ChooseSkill(int choice); 115 void M_LoadGame(int choice); 116 void M_SaveGame(int choice); 117 void M_Options(int choice); 118 void M_EndGame(int choice); 119 void M_ReadThis(int choice); 120 void M_ReadThis2(int choice); 121 void M_QuitDOOM(int choice); 122 void M_ChangeMessages(int choice); 123 void M_ChangeSensitivity(int choice); 124 void M_SfxVol(int choice); 125 void M_MusicVol(int choice); 126 void M_ChangeDetail(int choice); 127 void M_SizeDisplay(int choice); 128 void M_StartGame(int choice); 129 void M_Sound(int choice); 130 void M_FinishReadThis(int choice); 131 void M_LoadSelect(int choice); 132 void M_SaveSelect(int choice); 133 void M_ReadSaveStrings(); 134 void M_QuickSave(); 135 void M_QuickLoad(); 136 void M_DrawMainMenu(); 137 void M_DrawReadThis1(); 138 void M_DrawReadThis2(); 139 void M_DrawNewGame(); 140 void M_DrawEpisode(); 141 void M_DrawOptions(); 142 void M_DrawSound(); 143 void M_DrawLoad(); 144 void M_DrawSave(); 145 void M_DrawSaveLoadBorder(int x, int y); 146 void M_SetupNextMenu(menu_t* menudef); 147 void M_DrawThermo(int x, int y, int thermWidth, int thermDot); 148 void M_DrawEmptyCell(menu_t* menu, int item); 149 void M_DrawSelCell(menu_t* menu, int item); 150 void M_WriteText(int x, int y, char* string); 151 int M_StringWidth(char* string); 152 int M_StringHeight(char* string); 153 void M_StartControlPanel(); 154 void M_StartMessage(char* string, void (*routine)(int), boolean input); 155 void M_StopMessage(); 156 void M_ClearMenus(); 157 158 enum { 159 newgame = 0, 160 options, 161 loadgame, 162 savegame, 163 readthis, 164 quitdoom, 165 main_end 166 } main_e; 167 168 menuitem_t MainMenu[] = { 169 {1, "M_NGAME", M_NewGame, 'n'}, 170 {1, "M_OPTION", M_Options, 'o'}, 171 {1, "M_LOADG", M_LoadGame, 'l'}, 172 {1, "M_SAVEG", M_SaveGame, 's'}, 173 174 {1, "M_RDTHIS", M_ReadThis, 'r'}, 175 {1, "M_QUITG", M_QuitDOOM, 'q'} 176 }; 177 178 menu_t MainDef = { 179 main_end, 180 NULL, 181 MainMenu, 182 M_DrawMainMenu, 183 97, 64, 184 0 185 }; 186 187 enum { 188 ep1, 189 ep2, 190 ep3, 191 ep4, 192 ep_end 193 } episodes_e; 194 195 menuitem_t EpisodeMenu[] = { 196 {1, "M_EPI1", M_Episode, 'k'}, 197 {1, "M_EPI2", M_Episode, 't'}, 198 {1, "M_EPI3", M_Episode, 'i'}, 199 {1, "M_EPI4", M_Episode, 't'} 200 }; 201 202 menu_t EpiDef = { 203 ep_end, 204 &MainDef, 205 EpisodeMenu, 206 M_DrawEpisode, 207 48, 63, 208 ep1 209 }; 210 211 enum { 212 killthings, 213 toorough, 214 hurtme, 215 violence, 216 nightmare, 217 newg_end 218 } newgame_e; 219 220 menuitem_t NewGameMenu[] = { 221 {1, "M_JKILL", M_ChooseSkill, 'i'}, 222 {1, "M_ROUGH", M_ChooseSkill, 'h'}, 223 {1, "M_HURT", M_ChooseSkill, 'h'}, 224 {1, "M_ULTRA", M_ChooseSkill, 'u'}, 225 {1, "M_NMARE", M_ChooseSkill, 'n'} 226 }; 227 228 menu_t NewDef = { 229 newg_end, 230 &EpiDef, 231 NewGameMenu, 232 M_DrawNewGame, 233 48, 63, 234 hurtme 235 }; 236 237 enum { 238 endgame, 239 messages, 240 detail, 241 scrnsize, 242 option_empty1, 243 mousesens, 244 option_empty2, 245 soundvol, 246 opt_end 247 } options_e; 248 249 menuitem_t OptionsMenu[] = { 250 {1, "M_ENDGAM", M_EndGame, 'e'}, 251 {1, "M_MESSG", M_ChangeMessages, 'm'}, 252 {1, "M_DETAIL", M_ChangeDetail, 'g'}, 253 {2, "M_SCRNSZ", M_SizeDisplay, 's'}, 254 {-1, "", 0}, 255 {2, "M_MSENS", M_ChangeSensitivity, 'm'}, 256 {-1, "", 0}, 257 {1, "M_SVOL", M_Sound, 's'} 258 }; 259 260 menu_t OptionsDef = { 261 opt_end, 262 &MainDef, 263 OptionsMenu, 264 M_DrawOptions, 265 60, 37, 266 0 267 }; 268 269 enum { 270 rdthsempty1, 271 read1_end 272 } read_e; 273 274 menuitem_t ReadMenu1[] = { 275 {1, "", M_ReadThis2, 0} 276 }; 277 278 menu_t ReadDef1 = { 279 read1_end, 280 &MainDef, 281 ReadMenu1, 282 M_DrawReadThis1, 283 280, 185, 284 0 285 }; 286 287 enum { 288 rdthsempty2, 289 read2_end 290 } read_e2; 291 292 menuitem_t ReadMenu2[] = { 293 {1, "", M_FinishReadThis, 0} 294 }; 295 296 menu_t ReadDef2 = { 297 read2_end, 298 &ReadDef1, 299 ReadMenu2, 300 M_DrawReadThis2, 301 330, 175, 302 0 303 }; 304 305 enum { 306 sfx_vol, 307 sfx_empty1, 308 music_vol, 309 sfx_empty2, 310 sound_end 311 } sound_e; 312 313 menuitem_t SoundMenu[] = { 314 {2, "M_SFXVOL", M_SfxVol, 's'}, 315 {-1, "", 0}, 316 {2, "M_MUSVOL", M_MusicVol, 'm'}, 317 {-1, "", 0} 318 }; 319 320 menu_t SoundDef = { 321 sound_end, 322 &OptionsDef, 323 SoundMenu, 324 M_DrawSound, 325 80, 64, 326 0 327 }; 328 329 enum { 330 load1, 331 load2, 332 load3, 333 load4, 334 load5, 335 load6, 336 load_end 337 } load_e; 338 339 menuitem_t LoadMenu[] = { 340 {1, "", M_LoadSelect, '1'}, 341 {1, "", M_LoadSelect, '2'}, 342 {1, "", M_LoadSelect, '3'}, 343 {1, "", M_LoadSelect, '4'}, 344 {1, "", M_LoadSelect, '5'}, 345 {1, "", M_LoadSelect, '6'} 346 }; 347 348 menu_t LoadDef = { 349 load_end, 350 &MainDef, 351 LoadMenu, 352 M_DrawLoad, 353 80, 54, 354 0 355 }; 356 357 menuitem_t SaveMenu[] = { 358 {1, "", M_SaveSelect, '1'}, 359 {1, "", M_SaveSelect, '2'}, 360 {1, "", M_SaveSelect, '3'}, 361 {1, "", M_SaveSelect, '4'}, 362 {1, "", M_SaveSelect, '5'}, 363 {1, "", M_SaveSelect, '6'} 364 }; 365 366 menu_t SaveDef = { 367 load_end, 368 &MainDef, 369 SaveMenu, 370 M_DrawSave, 371 80, 54, 372 0 373 }; 374 375 void 376 M_ReadSaveStrings() 377 { 378 int i, handle; 379 char name[256]; 380 381 for (i = 0;i < load_end;i++) { 382 if (M_CheckParm("-cdrom")) 383 sprintf(name, "c:\\doomdata\\%s%d.dsg", lang[SAVEGAMENAME], i); 384 else 385 sprintf(name, "%s%d.dsg", lang[SAVEGAMENAME], i); 386 handle = open(name, O_RDONLY | 0, 0666); 387 if (handle == -1) { 388 strcpy(&savegamestrings[i][0], lang[EMPTYSTRING]); 389 LoadMenu[i].status = 0; 390 continue; 391 } 392 read(handle, &savegamestrings[i], SAVESTRINGSIZE); 393 close(handle); 394 LoadMenu[i].status = 1; 395 } 396 } 397 398 void 399 M_DrawLoad() 400 { 401 int i; 402 403 V_DrawPatch(72, 28, 0, W_CacheLumpName("M_LOADG", PU_CACHE)); 404 for (i = 0; i < load_end; ++i) { 405 M_DrawSaveLoadBorder(LoadDef.x, LoadDef.y+LINEHEIGHT*i); 406 M_WriteText(LoadDef.x, LoadDef.y+LINEHEIGHT*i, savegamestrings[i]); 407 } 408 } 409 410 void 411 M_DrawSaveLoadBorder(int x, int y) 412 { 413 int i; 414 415 V_DrawPatch(x - 8, y + 7, 0, W_CacheLumpName("M_LSLEFT", PU_CACHE)); 416 for (i = 0; i < 24; ++i) { 417 V_DrawPatch(x, y+7, 0, W_CacheLumpName("M_LSCNTR", PU_CACHE)); 418 x += 8; 419 } 420 V_DrawPatch(x, y + 7, 0, W_CacheLumpName("M_LSRGHT", PU_CACHE)); 421 } 422 423 void 424 M_LoadSelect(int choice) 425 { 426 char name[256]; 427 428 if (M_CheckParm("-cdrom")) 429 sprintf(name, "c:\\doomdata\\%s%d.dsg", lang[SAVEGAMENAME], choice); 430 else 431 sprintf(name, "%s%d.dsg", lang[SAVEGAMENAME], choice); 432 G_LoadGame(name); 433 M_ClearMenus(); 434 } 435 436 void 437 M_LoadGame(int choice) 438 { 439 if (netgame) { 440 M_StartMessage(lang[LOADNET], NULL, false); 441 return; 442 } 443 M_SetupNextMenu(&LoadDef); 444 M_ReadSaveStrings(); 445 } 446 447 void 448 M_DrawSave() 449 { 450 int i; 451 452 V_DrawPatch(72, 28, 0, W_CacheLumpName("M_SAVEG", PU_CACHE)); 453 for (i = 0; i < load_end; ++i) { 454 M_DrawSaveLoadBorder(LoadDef.x, LoadDef.y+LINEHEIGHT*i); 455 M_WriteText(LoadDef.x, LoadDef.y+LINEHEIGHT*i, savegamestrings[i]); 456 } 457 if (saveStringEnter) { 458 i = M_StringWidth(savegamestrings[saveSlot]); 459 M_WriteText(LoadDef.x + i, LoadDef.y+LINEHEIGHT*saveSlot, "_"); 460 } 461 } 462 463 void 464 M_DoSave(int slot) 465 { 466 G_SaveGame(slot, savegamestrings[slot]); 467 M_ClearMenus(); 468 if (quickSaveSlot == -2) quickSaveSlot = slot; 469 } 470 471 void 472 M_SaveSelect(int choice) 473 { 474 saveStringEnter = 1; 475 saveSlot = choice; 476 strcpy(saveOldString, savegamestrings[choice]); 477 if (!strcmp(savegamestrings[choice], lang[EMPTYSTRING])) 478 savegamestrings[choice][0] = 0; 479 saveCharIndex = strlen(savegamestrings[choice]); 480 } 481 482 void 483 M_SaveGame(int choice) 484 { 485 if (!usergame) { 486 M_StartMessage(lang[SAVEDEAD], NULL, false); 487 return; 488 } 489 if (gamestate != GS_LEVEL) 490 return; 491 M_SetupNextMenu(&SaveDef); 492 M_ReadSaveStrings(); 493 } 494 495 void 496 M_QuickSaveResponse(int ch) 497 { 498 if (ch == 'y') { 499 M_DoSave(quickSaveSlot); 500 S_StartSound(NULL, sfx_swtchx); 501 } 502 } 503 504 void 505 M_QuickSave() 506 { 507 if (!usergame) { 508 S_StartSound(NULL, sfx_oof); 509 return; 510 } 511 if (gamestate != GS_LEVEL) return; 512 if (quickSaveSlot < 0) { 513 M_StartControlPanel(); 514 M_ReadSaveStrings(); 515 M_SetupNextMenu(&SaveDef); 516 quickSaveSlot = -2; 517 return; 518 } 519 sprintf(tempstring, lang[QSPROMPT], savegamestrings[quickSaveSlot]); 520 M_StartMessage(tempstring, M_QuickSaveResponse, true); 521 } 522 523 void 524 M_QuickLoadResponse(int ch) 525 { 526 if (ch == 'y') { 527 M_LoadSelect(quickSaveSlot); 528 S_StartSound(NULL, sfx_swtchx); 529 } 530 } 531 532 void 533 M_QuickLoad() 534 { 535 if (netgame) { 536 M_StartMessage(lang[QLOADNET], NULL, false); 537 return; 538 } 539 if (quickSaveSlot < 0) { 540 M_StartMessage(lang[QSAVESPOT], NULL, false); 541 return; 542 } 543 sprintf(tempstring, lang[QLPROMPT], savegamestrings[quickSaveSlot]); 544 M_StartMessage(tempstring, M_QuickLoadResponse, true); 545 } 546 547 void 548 M_DrawReadThis1() 549 { 550 inhelpscreens = true; 551 V_DrawPatch(0, 0, 0, W_CacheLumpName("HELP1", PU_CACHE)); 552 return; 553 } 554 555 void 556 M_DrawReadThis2() 557 { 558 inhelpscreens = true; 559 V_DrawPatch(0, 0, 0, W_CacheLumpName("HELP2", PU_CACHE)); 560 return; 561 } 562 563 void 564 M_DrawSound() 565 { 566 V_DrawPatch(60, 38, 0, W_CacheLumpName("M_SVOL", PU_CACHE)); 567 M_DrawThermo(SoundDef.x, SoundDef.y+LINEHEIGHT*(sfx_vol+1), 16, snd_SfxVolume); 568 M_DrawThermo(SoundDef.x, SoundDef.y+LINEHEIGHT*(music_vol+1), 16, snd_MusicVolume); 569 } 570 571 void 572 M_Sound(int choice) 573 { 574 M_SetupNextMenu(&SoundDef); 575 } 576 577 void 578 M_SfxVol(int choice) 579 { 580 switch (choice) { 581 case 0: 582 if (snd_SfxVolume) 583 snd_SfxVolume--; 584 break; 585 case 1: 586 if (snd_SfxVolume < 15) 587 snd_SfxVolume++; 588 break; 589 } 590 S_SetSfxVolume(snd_SfxVolume /* *8 */); 591 } 592 593 void 594 M_MusicVol(int choice) 595 { 596 switch (choice) { 597 case 0: 598 if (snd_MusicVolume) snd_MusicVolume--; 599 break; 600 case 1: 601 if (snd_MusicVolume < 15) snd_MusicVolume++; 602 break; 603 } 604 S_SetMusicVolume(snd_MusicVolume /* *8 */); 605 } 606 607 void 608 M_DrawMainMenu() 609 { 610 V_DrawPatch(94, 2, 0, W_CacheLumpName("M_DOOM", PU_CACHE)); 611 } 612 613 void 614 M_DrawNewGame() 615 { 616 V_DrawPatch(96, 14, 0, W_CacheLumpName("M_NEWG", PU_CACHE)); 617 V_DrawPatch(54, 38, 0, W_CacheLumpName("M_SKILL", PU_CACHE)); 618 } 619 620 void 621 M_NewGame(int choice) 622 { 623 if (netgame && !demoplayback) { 624 M_StartMessage(lang[NEWGAME], NULL, false); 625 return; 626 } 627 M_SetupNextMenu(&EpiDef); 628 } 629 630 631 void M_DrawEpisode() 632 { 633 V_DrawPatch(54, 38, 0, W_CacheLumpName("M_EPISOD", PU_CACHE)); 634 } 635 636 void 637 M_VerifyNightmare(int ch) 638 { 639 if (ch != 'y') return; 640 G_DeferedInitNew(nightmare, epi+1, 1); 641 M_ClearMenus(); 642 } 643 644 void 645 M_ChooseSkill(int choice) 646 { 647 if (choice == nightmare) { 648 M_StartMessage(lang[NIGHTMARE], M_VerifyNightmare, true); 649 return; 650 } 651 G_DeferedInitNew(choice, epi+1, 1); 652 M_ClearMenus(); 653 } 654 655 void 656 M_Episode(int choice) 657 { 658 if (choice) { 659 M_StartMessage(lang[SWSTRING], NULL, false); 660 M_SetupNextMenu(&ReadDef1); 661 return; 662 } 663 epi = choice; 664 M_SetupNextMenu(&NewDef); 665 } 666 667 668 void 669 M_DrawOptions() 670 { 671 V_DrawPatch(108, 15, 0, W_CacheLumpName("M_OPTTTL", PU_CACHE)); 672 V_DrawPatch(OptionsDef.x + 175, OptionsDef.y+LINEHEIGHT*detail, 0, W_CacheLumpName(detailNames[detailLevel], PU_CACHE)); 673 V_DrawPatch(OptionsDef.x + 120, OptionsDef.y+LINEHEIGHT*messages, 0, W_CacheLumpName(msgNames[showMessages], PU_CACHE)); 674 M_DrawThermo(OptionsDef.x, OptionsDef.y+LINEHEIGHT*(mousesens+1), 10, mouseSensitivity); 675 M_DrawThermo(OptionsDef.x, OptionsDef.y+LINEHEIGHT*(scrnsize+1), 9, screenSize); 676 } 677 678 void 679 M_Options(int choice) 680 { 681 M_SetupNextMenu(&OptionsDef); 682 } 683 684 void 685 M_ChangeMessages(int choice) 686 { 687 choice = 0; 688 showMessages = 1 - showMessages; 689 if (!showMessages) 690 players[consoleplayer].message = lang[MSGOFF]; 691 else 692 players[consoleplayer].message = lang[MSGON]; 693 message_dontfuckwithme = true; 694 } 695 696 void 697 M_EndGameResponse(int ch) 698 { 699 if (ch != 'y') return; 700 currentMenu->lastOn = itemOn; 701 M_ClearMenus(); 702 D_StartTitle(); 703 } 704 705 void 706 M_EndGame(int choice) 707 { 708 choice = 0; 709 if (!usergame) { 710 S_StartSound(NULL, sfx_oof); 711 return; 712 } 713 if (netgame) { 714 M_StartMessage(lang[NETEND], NULL, false); 715 return; 716 } 717 M_StartMessage(lang[ENDGAME], M_EndGameResponse, true); 718 } 719 720 void 721 M_ReadThis(int choice) 722 { 723 choice = 0; 724 M_SetupNextMenu(&ReadDef1); 725 } 726 727 void 728 M_ReadThis2(int choice) 729 { 730 choice = 0; 731 M_SetupNextMenu(&ReadDef2); 732 } 733 734 void 735 M_FinishReadThis(int choice) 736 { 737 choice = 0; 738 M_SetupNextMenu(&MainDef); 739 } 740 741 742 743 void 744 M_QuitResponse(int ch) 745 { 746 if (ch != 'y') return; 747 if (!netgame) { 748 S_StartSound(NULL, quitsounds[(gametic>>2)&7]); 749 I_WaitVBL(105); 750 } 751 I_Quit(); 752 } 753 754 void 755 M_QuitDOOM(int choice) 756 { 757 sprintf(endstring, "%s\n\n%s", lang[DOSY], lang[QUITMSG0 + (gametic % (QUITMSG21 - QUITMSG0 + 2))]); 758 M_StartMessage(endstring, M_QuitResponse, true); 759 } 760 761 void 762 M_ChangeSensitivity(int choice) 763 { 764 switch (choice) { 765 case 0: 766 if (mouseSensitivity) mouseSensitivity--; 767 break; 768 case 1: 769 if (mouseSensitivity < 9) mouseSensitivity++; 770 break; 771 } 772 } 773 774 void 775 M_ChangeDetail(int choice) 776 { 777 choice = 0; 778 detailLevel = 1 - detailLevel; 779 fprintf(stderr, "M_ChangeDetail: low detail mode n.a.\n"); 780 return; 781 } 782 783 void 784 M_SizeDisplay(int choice) 785 { 786 if (!choice && screenSize > 0) { 787 --screenblocks; 788 --screenSize; 789 } 790 if (choice == 1 && screenSize < 8) { 791 ++screenblocks; 792 ++screenSize; 793 } 794 R_SetViewSize(screenblocks, detailLevel); 795 } 796 797 void 798 M_DrawThermo(int x, int y, int thermWidth, int thermDot) 799 { 800 int xx; 801 int i; 802 803 xx = x; 804 V_DrawPatch(xx, y, 0, W_CacheLumpName("M_THERML", PU_CACHE)); 805 xx += 8; 806 for (i = 0; i < thermWidth; ++i) { 807 V_DrawPatch(xx, y, 0, W_CacheLumpName("M_THERMM", PU_CACHE)); 808 xx += 8; 809 } 810 V_DrawPatch(xx, y, 0, W_CacheLumpName("M_THERMR", PU_CACHE)); 811 V_DrawPatch((x+8) + thermDot*8, y, 0, W_CacheLumpName("M_THERMO", PU_CACHE)); 812 } 813 814 void 815 M_DrawEmptyCell(menu_t* menu, int item) 816 { 817 V_DrawPatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0, W_CacheLumpName("M_CELL1", PU_CACHE)); 818 } 819 820 void 821 M_DrawSelCell(menu_t* menu, int item) 822 { 823 V_DrawPatch(menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0, W_CacheLumpName("M_CELL2", PU_CACHE)); 824 } 825 826 void 827 M_StartMessage(char* string, void (*routine)(int), boolean input) 828 { 829 messageLastMenuActive = menuactive; 830 messageToPrint = 1; 831 messageString = string; 832 messageRoutine = routine; 833 messageNeedsInput = input; 834 menuactive = true; 835 return; 836 } 837 838 void 839 M_StopMessage() 840 { 841 menuactive = messageLastMenuActive; 842 messageToPrint = 0; 843 } 844 845 int 846 M_StringWidth(char* string) 847 { 848 int i, w, c; 849 850 w = 0; 851 for (i = 0;i < strlen(string);i++) { 852 c = toupper(string[i]) - HU_FONTSTART; 853 if (c < 0 || c >= HU_FONTSIZE) w += 4; 854 else w += SHORT(hu_font[c]->width); 855 } 856 return w; 857 } 858 859 int 860 M_StringHeight(char* string) 861 { 862 int i, h, height; 863 864 height = SHORT(hu_font[0]->height); 865 h = height; 866 for (i = 0;i < strlen(string);i++) 867 if (string[i] == '\n') h += height; 868 return h; 869 } 870 871 void 872 M_WriteText(int x, int y, char* string) 873 { 874 char* ch; 875 int c, cx, cy, w; 876 877 ch = string; 878 cx = x; 879 cy = y; 880 while (1) { 881 c = *ch++; 882 if (!c) break; 883 if (c == '\n') { 884 cx = x; 885 cy += 12; 886 continue; 887 } 888 c = toupper(c) - HU_FONTSTART; 889 if (c < 0 || c>= HU_FONTSIZE) { 890 cx += 4; 891 continue; 892 } 893 w = SHORT(hu_font[c]->width); 894 if (cx+w > SCREENWIDTH) break; 895 V_DrawPatch(cx, cy, 0, hu_font[c]); 896 cx+=w; 897 } 898 } 899 900 boolean 901 M_Responder(event_t* ev) 902 { 903 int i, ch; 904 static int joywait, mousewait, mousey, mousex, lasty, lastx; 905 906 joywait = mousewait = mousey = mousex = lasty = lastx = 0; 907 ch = -1; 908 if (ev->type == ev_joystick && joywait < I_GetTime()) { 909 if (ev->data3 == -1) { 910 ch = KEY_UPARROW; 911 joywait = I_GetTime() + 5; 912 } 913 else if (ev->data3 == 1) { 914 ch = KEY_DOWNARROW; 915 joywait = I_GetTime() + 5; 916 } 917 if (ev->data2 == -1) { 918 ch = KEY_LEFTARROW; 919 joywait = I_GetTime() + 2; 920 } 921 else if (ev->data2 == 1) { 922 ch = KEY_RIGHTARROW; 923 joywait = I_GetTime() + 2; 924 } 925 if (ev->data1&1) { 926 ch = KEY_ENTER; 927 joywait = I_GetTime() + 5; 928 } 929 if (ev->data1&2) { 930 ch = KEY_BACKSPACE; 931 joywait = I_GetTime() + 5; 932 } 933 } else { 934 if (ev->type == ev_mouse && mousewait < I_GetTime()) { 935 mousey += ev->data3; 936 if (mousey < lasty-30) { 937 ch = KEY_DOWNARROW; 938 mousewait = I_GetTime() + 5; 939 mousey = lasty -= 30; 940 } else if (mousey > lasty+30) { 941 ch = KEY_UPARROW; 942 mousewait = I_GetTime() + 5; 943 mousey = lasty += 30; 944 } 945 mousex += ev->data2; 946 if (mousex < lastx-30) { 947 ch = KEY_LEFTARROW; 948 mousewait = I_GetTime() + 5; 949 mousex = lastx -= 30; 950 } 951 else if (mousex > lastx+30) { 952 ch = KEY_RIGHTARROW; 953 mousewait = I_GetTime() + 5; 954 mousex = lastx += 30; 955 } 956 if (ev->data1&1) { 957 ch = KEY_ENTER; 958 mousewait = I_GetTime() + 15; 959 } 960 if (ev->data1&2) { 961 ch = KEY_BACKSPACE; 962 mousewait = I_GetTime() + 15; 963 } 964 } else { 965 if (ev->type == ev_keydown) ch = ev->data1; 966 } 967 } 968 if (ch == -1) return false; 969 if (saveStringEnter) { 970 switch (ch) { 971 case KEY_BACKSPACE: 972 if (saveCharIndex > 0) { 973 saveCharIndex--; 974 savegamestrings[saveSlot][saveCharIndex] = 0; 975 } 976 break; 977 case KEY_ESCAPE: 978 saveStringEnter = 0; 979 strcpy(&savegamestrings[saveSlot][0], saveOldString); 980 break; 981 case KEY_ENTER: 982 saveStringEnter = 0; 983 if (savegamestrings[saveSlot][0]) M_DoSave(saveSlot); 984 break; 985 default: 986 ch = toupper(ch); 987 if (ch != 32) 988 if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE) 989 break; 990 if (ch >= 32 && ch <= 127 && saveCharIndex < SAVESTRINGSIZE-1 && M_StringWidth(savegamestrings[saveSlot]) < (SAVESTRINGSIZE-2)*8) { 991 savegamestrings[saveSlot][saveCharIndex++] = ch; 992 savegamestrings[saveSlot][saveCharIndex] = 0; 993 } 994 break; 995 } 996 return true; 997 } 998 if (messageToPrint) { 999 if (messageNeedsInput && !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE)) return false; 1000 menuactive = messageLastMenuActive; 1001 messageToPrint = 0; 1002 if (messageRoutine) messageRoutine(ch); 1003 menuactive = false; 1004 S_StartSound(NULL, sfx_swtchx); 1005 return true; 1006 } 1007 if (!menuactive) { 1008 switch (ch) { 1009 case KEY_MINUS: 1010 if (automapactive || chat_on) return false; 1011 M_SizeDisplay(0); 1012 S_StartSound(NULL, sfx_stnmov); 1013 return true; 1014 case KEY_EQUALS: 1015 if (automapactive || chat_on) return false; 1016 M_SizeDisplay(1); 1017 S_StartSound(NULL, sfx_stnmov); 1018 return true; 1019 case KEY_F1: 1020 M_StartControlPanel(); 1021 currentMenu = &ReadDef1; 1022 itemOn = 0; 1023 S_StartSound(NULL, sfx_swtchn); 1024 return true; 1025 case KEY_F2: 1026 M_StartControlPanel(); 1027 S_StartSound(NULL, sfx_swtchn); 1028 M_SaveGame(0); 1029 return true; 1030 case KEY_F3: 1031 M_StartControlPanel(); 1032 S_StartSound(NULL, sfx_swtchn); 1033 M_LoadGame(0); 1034 return true; 1035 case KEY_F4: 1036 M_StartControlPanel(); 1037 currentMenu = &SoundDef; 1038 itemOn = sfx_vol; 1039 S_StartSound(NULL, sfx_swtchn); 1040 return true; 1041 case KEY_F5: 1042 M_ChangeDetail(0); 1043 S_StartSound(NULL, sfx_swtchn); 1044 return true; 1045 case KEY_F6: 1046 S_StartSound(NULL, sfx_swtchn); 1047 M_QuickSave(); 1048 return true; 1049 case KEY_F7: 1050 S_StartSound(NULL, sfx_swtchn); 1051 M_EndGame(0); 1052 return true; 1053 case KEY_F8: 1054 M_ChangeMessages(0); 1055 S_StartSound(NULL, sfx_swtchn); 1056 return true; 1057 case KEY_F9: 1058 S_StartSound(NULL, sfx_swtchn); 1059 M_QuickLoad(); 1060 return true; 1061 case KEY_F10: 1062 S_StartSound(NULL, sfx_swtchn); 1063 M_QuitDOOM(0); 1064 return true; 1065 case KEY_F11: 1066 usegamma++; 1067 if (usegamma > 4) usegamma = 0; 1068 players[consoleplayer].message = lang[gammamsg[usegamma]]; 1069 I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); 1070 return true; 1071 } 1072 } 1073 if (!menuactive) { 1074 if (ch == KEY_ESCAPE) { 1075 M_StartControlPanel(); 1076 S_StartSound(NULL, sfx_swtchn); 1077 return true; 1078 } 1079 return false; 1080 } 1081 switch (ch) { 1082 case KEY_DOWNARROW: 1083 do { 1084 if (itemOn+1 > currentMenu->numitems-1) itemOn = 0; 1085 else itemOn++; 1086 S_StartSound(NULL, sfx_pstop); 1087 } while (currentMenu->menuitems[itemOn].status==-1); 1088 return true; 1089 case KEY_UPARROW: 1090 do { 1091 if (!itemOn) itemOn = currentMenu->numitems-1; 1092 else itemOn--; 1093 S_StartSound(NULL, sfx_pstop); 1094 } while (currentMenu->menuitems[itemOn].status==-1); 1095 return true; 1096 case KEY_LEFTARROW: 1097 if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { 1098 S_StartSound(NULL, sfx_stnmov); 1099 currentMenu->menuitems[itemOn].routine(0); 1100 } 1101 return true; 1102 case KEY_RIGHTARROW: 1103 if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { 1104 S_StartSound(NULL, sfx_stnmov); 1105 currentMenu->menuitems[itemOn].routine(1); 1106 } 1107 return true; 1108 case KEY_ENTER: 1109 if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status) { 1110 currentMenu->lastOn = itemOn; 1111 if (currentMenu->menuitems[itemOn].status == 2) { 1112 currentMenu->menuitems[itemOn].routine(1); 1113 S_StartSound(NULL, sfx_stnmov); 1114 } else { 1115 currentMenu->menuitems[itemOn].routine(itemOn); 1116 S_StartSound(NULL, sfx_pistol); 1117 } 1118 } 1119 return true; 1120 case KEY_ESCAPE: 1121 currentMenu->lastOn = itemOn; 1122 M_ClearMenus(); 1123 S_StartSound(NULL, sfx_swtchx); 1124 return true; 1125 case KEY_BACKSPACE: 1126 currentMenu->lastOn = itemOn; 1127 if (currentMenu->prevMenu) { 1128 currentMenu = currentMenu->prevMenu; 1129 itemOn = currentMenu->lastOn; 1130 S_StartSound(NULL, sfx_swtchn); 1131 } 1132 return true; 1133 default: 1134 for (i = itemOn+1;i < currentMenu->numitems;i++) 1135 if (currentMenu->menuitems[i].alphaKey == ch) { 1136 itemOn = i; 1137 S_StartSound(NULL, sfx_pstop); 1138 return true; 1139 } 1140 for (i = 0;i <= itemOn;i++) 1141 if (currentMenu->menuitems[i].alphaKey == ch) { 1142 itemOn = i; 1143 S_StartSound(NULL, sfx_pstop); 1144 return true; 1145 } 1146 break; 1147 } 1148 return false; 1149 } 1150 1151 void 1152 M_StartControlPanel() 1153 { 1154 if (menuactive) return; 1155 menuactive = 1; 1156 currentMenu = &MainDef; 1157 itemOn = currentMenu->lastOn; 1158 } 1159 1160 void 1161 M_Drawer() 1162 { 1163 static short x, y; 1164 char string[40]; 1165 int start; 1166 short i, max; 1167 1168 inhelpscreens = false; 1169 if (messageToPrint) { 1170 start = 0; 1171 y = 100 - M_StringHeight(messageString)/2; 1172 while (messageString[start]) { 1173 for (i = 0; i < strlen(messageString+start); ++i) 1174 if ((messageString[start+i]) == '\n') { 1175 memset(string, 0, 40); 1176 strncpy(string, messageString+start, i); 1177 start += i + 1; 1178 break; 1179 } 1180 if (i == strlen(messageString+start)) { 1181 strcpy(string, messageString+start); 1182 start += i; 1183 } 1184 x = 160 - M_StringWidth(string)/2; 1185 M_WriteText(x, y, string); 1186 y += SHORT(hu_font[0]->height); 1187 } 1188 return; 1189 } 1190 if (!menuactive) return; 1191 if (currentMenu->routine) currentMenu->routine(); 1192 x = currentMenu->x; 1193 y = currentMenu->y; 1194 max = currentMenu->numitems; 1195 for (i = 0; i < max; ++i) { 1196 if (currentMenu->menuitems[i].name[0]) V_DrawPatch(x, y, 0, W_CacheLumpName(currentMenu->menuitems[i].name, PU_CACHE)); 1197 y += LINEHEIGHT; 1198 } 1199 V_DrawPatch(x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT, 0, W_CacheLumpName(skullName[whichSkull], PU_CACHE)); 1200 } 1201 1202 void 1203 M_ClearMenus() 1204 { 1205 menuactive = 0; 1206 } 1207 1208 void 1209 M_SetupNextMenu(menu_t* menudef) 1210 { 1211 currentMenu = menudef; 1212 itemOn = currentMenu->lastOn; 1213 } 1214 1215 void 1216 M_Ticker() 1217 { 1218 if (--skullAnimCounter <= 0) { 1219 whichSkull ^= 1; 1220 skullAnimCounter = 8; 1221 } 1222 } 1223 1224 void 1225 M_Init() 1226 { 1227 currentMenu = &MainDef; 1228 menuactive = 0; 1229 itemOn = currentMenu->lastOn; 1230 whichSkull = 0; 1231 skullAnimCounter = 10; 1232 screenSize = screenblocks - 3; 1233 messageToPrint = 0; 1234 messageString = NULL; 1235 messageLastMenuActive = menuactive; 1236 quickSaveSlot = -1; 1237 EpiDef.numitems--; 1238 }