m_menu.cpp 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "Precompiled.h"
  21. #include "globaldata.h"
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <fcntl.h>
  25. #include <stdlib.h>
  26. #include <ctype.h>
  27. #include "doomdef.h"
  28. #include "dstrings.h"
  29. #include "d_main.h"
  30. #include "i_system.h"
  31. #include "i_video.h"
  32. #include "z_zone.h"
  33. #include "v_video.h"
  34. #include "w_wad.h"
  35. #include "m_misc.h"
  36. #include "r_local.h"
  37. #include "hu_stuff.h"
  38. #include "g_game.h"
  39. #include "m_argv.h"
  40. #include "m_swap.h"
  41. #include "s_sound.h"
  42. #include "doomstat.h"
  43. // Data.
  44. #include "sounds.h"
  45. #include "m_menu.h"
  46. #include "Main.h"
  47. //#include "../game/player/PlayerProfileDoom.h"
  48. #include "sys/sys_session.h"
  49. #include "sys/sys_signin.h"
  50. #include "d3xp/Game_local.h"
  51. extern idCVar in_useJoystick;
  52. //
  53. // defaulted values
  54. //
  55. // Show messages has default, 0 = off, 1 = on
  56. // Blocky mode, has default, 0 = high, 1 = normal
  57. // temp for ::g->screenblocks (0-9)
  58. // -1 = no quicksave slot picked!
  59. // 1 = message to be printed
  60. // ...and here is the message string!
  61. // message x & y
  62. // timed message = no input from user
  63. const char gammamsg[5][26] =
  64. {
  65. GAMMALVL0,
  66. GAMMALVL1,
  67. GAMMALVL2,
  68. GAMMALVL3,
  69. GAMMALVL4
  70. };
  71. // we are going to be entering a savegame string
  72. // old save description before edit
  73. //
  74. // MENU TYPEDEFS
  75. //
  76. // graphic name of skulls
  77. // warning: initializer-string for array of chars is too long
  78. char skullName[2][/*8*/9] =
  79. {
  80. "M_SKULL1","M_SKULL2"
  81. };
  82. // current menudef
  83. //
  84. // PROTOTYPES
  85. //
  86. void M_NewGame(int choice);
  87. void M_Episode(int choice);
  88. void M_Expansion(int choice);
  89. void M_ChooseSkill(int choice);
  90. void M_LoadGame(int choice);
  91. void M_LoadExpansion(int choice);
  92. void M_SaveGame(int choice);
  93. void M_Options(int choice);
  94. void M_EndGame(int choice);
  95. void M_ReadThis(int choice);
  96. void M_ReadThis2(int choice);
  97. void M_QuitDOOM(int choice);
  98. void M_ExitGame(int choice);
  99. void M_GameSelection(int choice);
  100. void M_CancelExit(int choice);
  101. void M_ChangeMessages(int choice);
  102. void M_ChangeGPad(int choice);
  103. void M_FullScreen(int choice);
  104. void M_ChangeSensitivity(int choice);
  105. void M_SfxVol(int choice);
  106. void M_MusicVol(int choice);
  107. void M_ChangeDetail(int choice);
  108. void M_SizeDisplay(int choice);
  109. void M_StartGame(int choice);
  110. void M_Sound(int choice);
  111. void M_FinishReadThis(int choice);
  112. void M_LoadSelect(int choice);
  113. void M_SaveSelect(int choice);
  114. void M_ReadSaveStrings(void);
  115. void M_QuickSave(void);
  116. void M_QuickLoad(void);
  117. void M_DrawMainMenu(void);
  118. void M_DrawQuit(void);
  119. void M_DrawReadThis1(void);
  120. void M_DrawReadThis2(void);
  121. void M_DrawNewGame(void);
  122. void M_DrawEpisode(void);
  123. void M_DrawOptions(void);
  124. void M_DrawSound(void);
  125. void M_DrawLoad(void);
  126. void M_DrawSave(void);
  127. void M_DrawSaveLoadBorder(int x,int y);
  128. void M_SetupNextMenu(menu_t *menudef);
  129. void M_DrawThermo(int x,int y,int thermWidth,int thermDot);
  130. void M_DrawEmptyCell(menu_t *menu,int item);
  131. void M_DrawSelCell(menu_t *menu,int item);
  132. void M_WriteText(int x, int y, char *string);
  133. int M_StringWidth(char *string);
  134. int M_StringHeight(char *string);
  135. void M_StartControlPanel(void);
  136. void M_StartMessage(char *string,messageRoutine_t routine,qboolean input);
  137. void M_StopMessage(void);
  138. void M_ClearMenus (void);
  139. //
  140. // DOOM MENU
  141. //
  142. //
  143. // EPISODE SELECT
  144. //
  145. //
  146. // NEW GAME
  147. //
  148. //
  149. // OPTIONS MENU
  150. //
  151. //
  152. // Read This! MENU 1 & 2
  153. //
  154. //
  155. // SOUND VOLUME MENU
  156. //
  157. //
  158. // LOAD GAME MENU
  159. //
  160. //
  161. // SAVE GAME MENU
  162. //
  163. //
  164. // M_ReadSaveStrings
  165. // read the strings from the savegame files
  166. //
  167. void M_ReadSaveStrings(void)
  168. {
  169. idFile* handle;
  170. int count;
  171. int i;
  172. char name[256];
  173. for (i = 0;i < load_end;i++)
  174. {
  175. if( common->GetCurrentGame() == DOOM_CLASSIC ) {
  176. sprintf(name,"DOOM\\%s%d.dsg", SAVEGAMENAME,i );
  177. } else {
  178. if( DoomLib::idealExpansion == doom2 ) {
  179. sprintf(name,"DOOM2\\%s%d.dsg", SAVEGAMENAME,i );
  180. } else {
  181. sprintf(name,"DOOM2_NRFTL\\%s%d.dsg", SAVEGAMENAME,i );
  182. }
  183. }
  184. handle = fileSystem->OpenFileRead ( name, false );
  185. if (handle == NULL)
  186. {
  187. strcpy(&::g->savegamestrings[i][0],EMPTYSTRING);
  188. ::g->LoadMenu[i].status = 0;
  189. continue;
  190. }
  191. count = handle->Read( &::g->savegamestrings[i], SAVESTRINGSIZE );
  192. fileSystem->CloseFile( handle );
  193. strcpy( ::g->savegamepaths[i], name );
  194. ::g->LoadMenu[i].status = 1;
  195. }
  196. }
  197. //
  198. // M_LoadGame & Cie.
  199. //
  200. void M_DrawLoad(void)
  201. {
  202. int i;
  203. V_DrawPatchDirect (72,28,0,(patch_t*)W_CacheLumpName("M_LOADG",PU_CACHE_SHARED));
  204. for (i = 0;i < load_end; i++)
  205. {
  206. M_DrawSaveLoadBorder(::g->LoadDef.x,::g->LoadDef.y+LINEHEIGHT*i);
  207. M_WriteText(::g->LoadDef.x,::g->LoadDef.y+LINEHEIGHT*i,::g->savegamestrings[i]);
  208. }
  209. }
  210. //
  211. // Draw border for the savegame description
  212. //
  213. void M_DrawSaveLoadBorder(int x,int y)
  214. {
  215. int i;
  216. V_DrawPatchDirect (x-8,y+7,0,(patch_t*)W_CacheLumpName("M_LSLEFT",PU_CACHE_SHARED));
  217. for (i = 0;i < 28;i++)
  218. {
  219. V_DrawPatchDirect (x,y+7,0,(patch_t*)W_CacheLumpName("M_LSCNTR",PU_CACHE_SHARED));
  220. x += 8;
  221. }
  222. V_DrawPatchDirect (x,y+7,0,(patch_t*)W_CacheLumpName("M_LSRGHT",PU_CACHE_SHARED));
  223. }
  224. //
  225. // User wants to load this game
  226. //
  227. void M_LoadSelect(int choice)
  228. {
  229. if( ::g->gamemode != commercial ) {
  230. G_LoadGame ( ::g->savegamepaths[ choice ] );
  231. } else {
  232. strcpy( DoomLib::loadGamePath, ::g->savegamepaths[ choice ] );
  233. DoomLib::SetCurrentExpansion( DoomLib::idealExpansion );
  234. DoomLib::skipToLoad = true;
  235. }
  236. M_ClearMenus ();
  237. }
  238. void M_LoadExpansion(int choice)
  239. {
  240. ::g->exp = choice;
  241. if( choice == 0 ) {
  242. DoomLib::SetIdealExpansion( doom2 );
  243. }else {
  244. DoomLib::SetIdealExpansion( pack_nerve );
  245. }
  246. M_SetupNextMenu(&::g->LoadDef);
  247. M_ReadSaveStrings();
  248. }
  249. //
  250. // Selected from DOOM menu
  251. //
  252. void M_LoadGame (int choice)
  253. {
  254. if (::g->netgame)
  255. {
  256. M_StartMessage(LOADNET,NULL,false);
  257. return;
  258. }
  259. if (::g->gamemode == commercial) {
  260. M_SetupNextMenu(&::g->LoadExpDef);
  261. } else{
  262. M_SetupNextMenu(&::g->LoadDef);
  263. M_ReadSaveStrings();
  264. }
  265. }
  266. //
  267. // M_SaveGame & Cie.
  268. //
  269. void M_DrawSave(void)
  270. {
  271. int i;
  272. V_DrawPatchDirect (72,28,0,(patch_t*)W_CacheLumpName("M_SAVEG",PU_CACHE_SHARED));
  273. for (i = 0;i < load_end; i++)
  274. {
  275. M_DrawSaveLoadBorder(::g->LoadDef.x,::g->LoadDef.y+LINEHEIGHT*i);
  276. M_WriteText(::g->LoadDef.x,::g->LoadDef.y+LINEHEIGHT*i,::g->savegamestrings[i]);
  277. }
  278. if (::g->saveStringEnter)
  279. {
  280. i = M_StringWidth(::g->savegamestrings[::g->saveSlot]);
  281. M_WriteText(::g->LoadDef.x + i,::g->LoadDef.y+LINEHEIGHT*::g->saveSlot,"_");
  282. }
  283. }
  284. //
  285. // M_Responder calls this when user is finished
  286. //
  287. void M_DoSave(int slot)
  288. {
  289. G_SaveGame (slot,::g->savegamestrings[slot]);
  290. M_ClearMenus ();
  291. // PICK QUICKSAVE SLOT YET?
  292. if (::g->quickSaveSlot == -2)
  293. ::g->quickSaveSlot = slot;
  294. }
  295. //
  296. // User wants to save. Start string input for M_Responder
  297. //
  298. //
  299. // Locally used constants, shortcuts.
  300. //
  301. extern const char* mapnames[];
  302. extern const char* mapnames2[];
  303. void M_SaveSelect(int choice)
  304. {
  305. const char* s;
  306. const ExpansionData* exp = DoomLib::GetCurrentExpansion();
  307. switch ( ::g->gamemode )
  308. {
  309. case shareware:
  310. case registered:
  311. case retail:
  312. s = (exp->mapNames[(::g->gameepisode-1)*9+::g->gamemap-1]);
  313. break;
  314. case commercial:
  315. default:
  316. s = (exp->mapNames[::g->gamemap-1]);
  317. break;
  318. }
  319. ::g->saveSlot = choice;
  320. strcpy(::g->savegamestrings[::g->saveSlot], s);
  321. M_DoSave(::g->saveSlot);
  322. }
  323. //
  324. // Selected from DOOM menu
  325. //
  326. void M_SaveGame (int choice)
  327. {
  328. if (!::g->usergame)
  329. {
  330. M_StartMessage(SAVEDEAD,NULL,false);
  331. return;
  332. }
  333. else if( ::g->plyr && ::g->plyr->mo && ::g->plyr->mo->health <= 0 ) {
  334. M_StartMessage("you can't save if you're dead!\n\npress any button",NULL,false);
  335. return;
  336. }
  337. if (::g->gamestate != GS_LEVEL)
  338. return;
  339. // Reset back to what expansion we are currently playing.
  340. DoomLib::SetIdealExpansion( DoomLib::expansionSelected );
  341. M_SetupNextMenu(&::g->SaveDef);
  342. M_ReadSaveStrings();
  343. }
  344. //
  345. // M_QuickSave
  346. //
  347. void M_QuickSaveResponse(int ch)
  348. {
  349. if (ch == KEY_ENTER)
  350. {
  351. M_DoSave(::g->quickSaveSlot);
  352. S_StartSound(NULL,sfx_swtchx);
  353. }
  354. }
  355. void M_QuickSave(void)
  356. {
  357. if (!::g->usergame)
  358. {
  359. S_StartSound(NULL,sfx_oof);
  360. return;
  361. }
  362. if (::g->gamestate != GS_LEVEL)
  363. return;
  364. if (::g->quickSaveSlot < 0)
  365. {
  366. M_StartControlPanel();
  367. M_ReadSaveStrings();
  368. M_SetupNextMenu(&::g->SaveDef);
  369. ::g->quickSaveSlot = -2; // means to pick a slot now
  370. return;
  371. }
  372. sprintf(::g->tempstring,QSPROMPT,::g->savegamestrings[::g->quickSaveSlot]);
  373. M_StartMessage(::g->tempstring,M_QuickSaveResponse,true);
  374. }
  375. //
  376. // M_QuickLoad
  377. //
  378. void M_QuickLoadResponse(int ch)
  379. {
  380. if (ch == KEY_ENTER)
  381. {
  382. M_LoadSelect(::g->quickSaveSlot);
  383. S_StartSound(NULL,sfx_swtchx);
  384. }
  385. }
  386. void M_QuickLoad(void)
  387. {
  388. if (::g->netgame)
  389. {
  390. M_StartMessage(QLOADNET,NULL,false);
  391. return;
  392. }
  393. if (::g->quickSaveSlot < 0)
  394. {
  395. M_StartMessage(QSAVESPOT,NULL,false);
  396. return;
  397. }
  398. sprintf(::g->tempstring,QLPROMPT,::g->savegamestrings[::g->quickSaveSlot]);
  399. M_StartMessage(::g->tempstring,M_QuickLoadResponse,true);
  400. }
  401. //
  402. // Read This Menus
  403. // Had a "quick hack to fix romero bug"
  404. //
  405. void M_DrawReadThis1(void)
  406. {
  407. ::g->inhelpscreens = true;
  408. switch ( ::g->gamemode )
  409. {
  410. case commercial:
  411. V_DrawPatchDirect (0,0,0,(patch_t*)W_CacheLumpName("HELP",PU_CACHE_SHARED));
  412. break;
  413. case shareware:
  414. case registered:
  415. case retail:
  416. V_DrawPatchDirect (0,0,0,(patch_t*)W_CacheLumpName("HELP1",PU_CACHE_SHARED));
  417. break;
  418. default:
  419. break;
  420. }
  421. return;
  422. }
  423. //
  424. // Read This Menus - optional second page.
  425. //
  426. void M_DrawReadThis2(void)
  427. {
  428. ::g->inhelpscreens = true;
  429. switch ( ::g->gamemode )
  430. {
  431. case retail:
  432. case commercial:
  433. // This hack keeps us from having to change menus.
  434. V_DrawPatchDirect (0,0,0,(patch_t*)W_CacheLumpName("CREDIT",PU_CACHE_SHARED));
  435. break;
  436. case shareware:
  437. case registered:
  438. V_DrawPatchDirect (0,0,0,(patch_t*)W_CacheLumpName("HELP2",PU_CACHE_SHARED));
  439. break;
  440. default:
  441. break;
  442. }
  443. return;
  444. }
  445. //
  446. // Change Sfx & Music volumes
  447. //
  448. void M_DrawSound(void)
  449. {
  450. V_DrawPatchDirect (60,38,0,(patch_t*)W_CacheLumpName("M_SVOL",PU_CACHE_SHARED));
  451. M_DrawThermo( ::g->SoundDef.x,::g->SoundDef.y+LINEHEIGHT*(sfx_vol+1),
  452. 16, s_volume_sound.GetInteger() );
  453. M_DrawThermo(::g->SoundDef.x,::g->SoundDef.y+LINEHEIGHT*(music_vol+1),
  454. 16, s_volume_midi.GetInteger() );
  455. }
  456. void M_Sound(int choice)
  457. {
  458. M_SetupNextMenu(&::g->SoundDef);
  459. }
  460. void M_SfxVol(int choice)
  461. {
  462. switch(choice)
  463. {
  464. case 0:
  465. s_volume_sound.SetInteger( s_volume_sound.GetInteger() - 1 );
  466. break;
  467. case 1:
  468. s_volume_sound.SetInteger( s_volume_sound.GetInteger() + 1 );
  469. break;
  470. }
  471. S_SetSfxVolume( s_volume_sound.GetInteger() );
  472. }
  473. void M_MusicVol(int choice)
  474. {
  475. switch(choice)
  476. {
  477. case 0:
  478. s_volume_midi.SetInteger( s_volume_midi.GetInteger() - 1 );
  479. break;
  480. case 1:
  481. s_volume_midi.SetInteger( s_volume_midi.GetInteger() + 1 );
  482. break;
  483. }
  484. S_SetMusicVolume( s_volume_midi.GetInteger() );
  485. }
  486. //
  487. // M_DrawMainMenu
  488. //
  489. void M_DrawMainMenu(void)
  490. {
  491. V_DrawPatchDirect (94,2,0,(patch_t*)W_CacheLumpName("M_DOOM",PU_CACHE_SHARED));
  492. }
  493. //
  494. // M_DrawQuit
  495. //
  496. void M_DrawQuit(void) {
  497. V_DrawPatchDirect (54,38,0,(patch_t*)W_CacheLumpName("M_EXITO",PU_CACHE_SHARED));
  498. }
  499. //
  500. // M_NewGame
  501. //
  502. void M_DrawNewGame(void)
  503. {
  504. V_DrawPatchDirect (96,14,0,(patch_t*)W_CacheLumpName("M_NEWG",PU_CACHE_SHARED));
  505. V_DrawPatchDirect (54,38,0,(patch_t*)W_CacheLumpName("M_SKILL",PU_CACHE_SHARED));
  506. }
  507. void M_NewGame(int choice)
  508. {
  509. if (::g->netgame && !::g->demoplayback)
  510. {
  511. M_StartMessage(NEWGAME,NULL,false);
  512. return;
  513. }
  514. if ( ::g->gamemode == commercial )
  515. M_SetupNextMenu(&::g->ExpDef);
  516. else
  517. M_SetupNextMenu(&::g->EpiDef);
  518. }
  519. //
  520. // M_Episode
  521. //
  522. void M_DrawEpisode(void)
  523. {
  524. V_DrawPatchDirect (54,38,0,(patch_t*)W_CacheLumpName("M_EPISOD",PU_CACHE_SHARED));
  525. }
  526. void M_VerifyNightmare(int ch)
  527. {
  528. if (ch != KEY_ENTER)
  529. return;
  530. G_DeferedInitNew((skill_t)nightmare,::g->epi+1, 1);
  531. M_ClearMenus ();
  532. }
  533. void M_ChooseSkill(int choice)
  534. {
  535. /*
  536. if (choice == nightmare)
  537. {
  538. M_StartMessage(NIGHTMARE,M_VerifyNightmare,true);
  539. return;
  540. }
  541. */
  542. if ( ::g->gamemode != commercial ) {
  543. static int startLevel = 1;
  544. G_DeferedInitNew((skill_t)choice,::g->epi+1, startLevel);
  545. M_ClearMenus ();
  546. } else {
  547. DoomLib::SetCurrentExpansion( DoomLib::idealExpansion );
  548. DoomLib::skipToNew = true;
  549. DoomLib::chosenSkill = choice;
  550. DoomLib::chosenEpisode = ::g->epi+1;
  551. }
  552. }
  553. void M_Episode(int choice)
  554. {
  555. // Yet another hack...
  556. if ( (::g->gamemode == registered)
  557. && (choice > 2))
  558. {
  559. I_PrintfE("M_Episode: 4th episode requires UltimateDOOM\n");
  560. choice = 0;
  561. }
  562. ::g->epi = choice;
  563. M_SetupNextMenu(&::g->NewDef);
  564. }
  565. void M_Expansion(int choice)
  566. {
  567. ::g->exp = choice;
  568. if( choice == 0 ) {
  569. DoomLib::SetIdealExpansion( doom2 );
  570. }else {
  571. DoomLib::SetIdealExpansion( pack_nerve );
  572. }
  573. M_SetupNextMenu(&::g->NewDef);
  574. }
  575. //
  576. // M_Options
  577. //
  578. char detailNames[2][9] =
  579. {
  580. "M_GDHIGH","M_GDLOW"
  581. };
  582. char msgNames[2][9] =
  583. {
  584. "M_MSGOFF","M_MSGON"
  585. };
  586. int M_GetMouseSpeedForMenu( float cvarValue ) {
  587. const float shiftedMouseSpeed = cvarValue - 0.25f;
  588. const float normalizedMouseSpeed = shiftedMouseSpeed / ( 4.0f - 0.25 );
  589. const float scaledMouseSpeed = normalizedMouseSpeed * 15.0f;
  590. const int roundedMouseSpeed = static_cast< int >( scaledMouseSpeed + 0.5f );
  591. return roundedMouseSpeed;
  592. }
  593. void M_DrawOptions(void)
  594. {
  595. V_DrawPatchDirect (108,15,0,(patch_t*)W_CacheLumpName("M_OPTTTL",PU_CACHE_SHARED));
  596. //V_DrawPatchDirect (::g->OptionsDef.x + 175,::g->OptionsDef.y+LINEHEIGHT*detail,0,
  597. // (patch_t*)W_CacheLumpName(detailNames[::g->detailLevel],PU_CACHE_SHARED));
  598. int fullscreenOnOff = r_fullscreen.GetInteger() >= 1 ? 1 : 0;
  599. V_DrawPatchDirect (::g->OptionsDef.x + 150,::g->OptionsDef.y+LINEHEIGHT*endgame,0,
  600. (patch_t*)W_CacheLumpName(msgNames[fullscreenOnOff],PU_CACHE_SHARED));
  601. V_DrawPatchDirect (::g->OptionsDef.x + 120,::g->OptionsDef.y+LINEHEIGHT*scrnsize,0,
  602. (patch_t*)W_CacheLumpName(msgNames[in_useJoystick.GetInteger()],PU_CACHE_SHARED));
  603. V_DrawPatchDirect (::g->OptionsDef.x + 120,::g->OptionsDef.y+LINEHEIGHT*messages,0,
  604. (patch_t*)W_CacheLumpName(msgNames[m_show_messages.GetInteger()],PU_CACHE_SHARED));
  605. extern idCVar in_mouseSpeed;
  606. const int roundedMouseSpeed = M_GetMouseSpeedForMenu( in_mouseSpeed.GetFloat() );
  607. M_DrawThermo( ::g->OptionsDef.x, ::g->OptionsDef.y + LINEHEIGHT * ( mousesens + 1 ), 16, roundedMouseSpeed );
  608. //M_DrawThermo(::g->OptionsDef.x,::g->OptionsDef.y+LINEHEIGHT*(scrnsize+1),
  609. // 9,::g->screenSize);
  610. }
  611. void M_Options(int choice)
  612. {
  613. M_SetupNextMenu(&::g->OptionsDef);
  614. }
  615. //
  616. // Toggle messages on/off
  617. //
  618. void M_ChangeMessages(int choice)
  619. {
  620. // warning: unused parameter `int choice'
  621. choice = 0;
  622. m_show_messages.SetBool( !m_show_messages.GetBool() );
  623. if (!m_show_messages.GetBool())
  624. ::g->players[::g->consoleplayer].message = MSGOFF;
  625. else
  626. ::g->players[::g->consoleplayer].message = MSGON ;
  627. ::g->message_dontfuckwithme = true;
  628. }
  629. //
  630. // Toggle messages on/off
  631. //
  632. void M_ChangeGPad(int choice)
  633. {
  634. // warning: unused parameter `int choice'
  635. choice = 0;
  636. in_useJoystick.SetBool( !in_useJoystick.GetBool() );
  637. ::g->message_dontfuckwithme = true;
  638. }
  639. //
  640. // Toggle Fullscreen
  641. //
  642. void M_FullScreen( int choice ) {
  643. r_fullscreen.SetInteger( r_fullscreen.GetInteger() ? 0: 1 );
  644. cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" );
  645. }
  646. //
  647. // M_EndGame
  648. //
  649. void M_EndGameResponse(int ch)
  650. {
  651. if (ch != KEY_ENTER)
  652. return;
  653. ::g->currentMenu->lastOn = ::g->itemOn;
  654. M_ClearMenus ();
  655. D_StartTitle ();
  656. }
  657. void M_EndGame(int choice)
  658. {
  659. choice = 0;
  660. if (!::g->usergame)
  661. {
  662. S_StartSound(NULL,sfx_oof);
  663. return;
  664. }
  665. if (::g->netgame)
  666. {
  667. M_StartMessage(NETEND,NULL,false);
  668. return;
  669. }
  670. M_StartMessage(ENDGAME,M_EndGameResponse,true);
  671. }
  672. //
  673. // M_ReadThis
  674. //
  675. void M_ReadThis(int choice)
  676. {
  677. }
  678. void M_ReadThis2(int choice)
  679. {
  680. }
  681. void M_FinishReadThis(int choice)
  682. {
  683. choice = 0;
  684. M_SetupNextMenu(&::g->MainDef);
  685. }
  686. //
  687. // M_QuitDOOM
  688. //
  689. void M_QuitResponse(int ch)
  690. {
  691. // Exceptions disabled by default on PS3
  692. //throw "";
  693. }
  694. void M_QuitDOOM(int choice)
  695. {
  696. M_SetupNextMenu(&::g->QuitDef);
  697. //M_StartMessage("are you sure?\npress A to quit, or B to cancel",M_QuitResponse,true);
  698. //common->SwitchToGame( DOOM3_BFG );
  699. }
  700. void M_ExitGame(int choice)
  701. {
  702. common->Quit();
  703. }
  704. void M_CancelExit(int choice) {
  705. M_SetupNextMenu(&::g->MainDef);
  706. }
  707. void M_GameSelection(int choice)
  708. {
  709. common->SwitchToGame( DOOM3_BFG );
  710. }
  711. void M_ChangeSensitivity(int choice)
  712. {
  713. extern idCVar in_mouseSpeed;
  714. int roundedMouseSpeed = M_GetMouseSpeedForMenu( in_mouseSpeed.GetFloat() );
  715. switch(choice)
  716. {
  717. case 0:
  718. if ( roundedMouseSpeed > 0 ) {
  719. roundedMouseSpeed--;
  720. }
  721. break;
  722. case 1:
  723. if ( roundedMouseSpeed < 15 ) {
  724. roundedMouseSpeed++;
  725. }
  726. break;
  727. }
  728. const float normalizedNewMouseSpeed = roundedMouseSpeed / 15.0f;
  729. const float rescaledNewMouseSpeed = 0.25f + ( ( 4.0f - 0.25 ) * normalizedNewMouseSpeed );
  730. in_mouseSpeed.SetFloat( rescaledNewMouseSpeed );
  731. }
  732. void M_ChangeDetail(int choice)
  733. {
  734. choice = 0;
  735. ::g->detailLevel = 1 - ::g->detailLevel;
  736. // FIXME - does not work. Remove anyway?
  737. I_PrintfE("M_ChangeDetail: low detail mode n.a.\n");
  738. return;
  739. /*R_SetViewSize (::g->screenblocks, ::g->detailLevel);
  740. if (!::g->detailLevel)
  741. ::g->players[::g->consoleplayer].message = DETAILHI;
  742. else
  743. ::g->players[::g->consoleplayer].message = DETAILLO;*/
  744. }
  745. void M_SizeDisplay(int choice)
  746. {
  747. switch(choice)
  748. {
  749. case 0:
  750. if (::g->screenSize > 7)
  751. {
  752. ::g->screenblocks--;
  753. ::g->screenSize--;
  754. }
  755. break;
  756. case 1:
  757. if (::g->screenSize < 8)
  758. {
  759. ::g->screenblocks++;
  760. ::g->screenSize++;
  761. }
  762. break;
  763. }
  764. R_SetViewSize (::g->screenblocks, ::g->detailLevel);
  765. }
  766. //
  767. // Menu Functions
  768. //
  769. void
  770. M_DrawThermo
  771. ( int x,
  772. int y,
  773. int thermWidth,
  774. int thermDot )
  775. {
  776. int xx;
  777. int i;
  778. xx = x;
  779. V_DrawPatchDirect (xx,y,0,(patch_t*)W_CacheLumpName("M_THERML",PU_CACHE_SHARED));
  780. xx += 8;
  781. for (i=0;i<thermWidth;i++)
  782. {
  783. V_DrawPatchDirect (xx,y,0,(patch_t*)W_CacheLumpName("M_THERMM",PU_CACHE_SHARED));
  784. xx += 8;
  785. }
  786. V_DrawPatchDirect (xx,y,0,(patch_t*)W_CacheLumpName("M_THERMR",PU_CACHE_SHARED));
  787. V_DrawPatchDirect ((x+8) + thermDot*8,y,
  788. 0,(patch_t*)W_CacheLumpName("M_THERMO",PU_CACHE_SHARED));
  789. }
  790. void
  791. M_DrawEmptyCell
  792. ( menu_t* menu,
  793. int item )
  794. {
  795. V_DrawPatchDirect (menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
  796. (patch_t*)W_CacheLumpName("M_CELL1",PU_CACHE_SHARED));
  797. }
  798. void
  799. M_DrawSelCell
  800. ( menu_t* menu,
  801. int item )
  802. {
  803. V_DrawPatchDirect (menu->x - 10, menu->y+item*LINEHEIGHT - 1, 0,
  804. (patch_t*)W_CacheLumpName("M_CELL2",PU_CACHE_SHARED));
  805. }
  806. void
  807. M_StartMessage
  808. ( char* string,
  809. messageRoutine_t routine,
  810. qboolean input )
  811. {
  812. ::g->messageLastMenuActive = ::g->menuactive;
  813. ::g->messageToPrint = 1;
  814. ::g->messageString = string;
  815. ::g->messageRoutine = (messageRoutine_t)routine;
  816. ::g->messageNeedsInput = input;
  817. ::g->menuactive = true;
  818. return;
  819. }
  820. void M_StopMessage(void)
  821. {
  822. ::g->menuactive = ::g->messageLastMenuActive;
  823. ::g->messageToPrint = 0;
  824. }
  825. //
  826. // Find string width from ::g->hu_font chars
  827. //
  828. int M_StringWidth(char* string)
  829. {
  830. unsigned int i;
  831. int w = 0;
  832. int c;
  833. for (i = 0;i < strlen(string);i++)
  834. {
  835. c = toupper(string[i]) - HU_FONTSTART;
  836. if (c < 0 || c >= HU_FONTSIZE)
  837. w += 4;
  838. else
  839. w += SHORT (::g->hu_font[c]->width);
  840. }
  841. return w;
  842. }
  843. //
  844. // Find string height from ::g->hu_font chars
  845. //
  846. int M_StringHeight(char* string)
  847. {
  848. unsigned int i;
  849. int h;
  850. int height = SHORT(::g->hu_font[0]->height);
  851. h = height;
  852. for (i = 0;i < strlen(string);i++)
  853. if (string[i] == '\n')
  854. h += height;
  855. return h;
  856. }
  857. //
  858. // Write a string using the ::g->hu_font
  859. //
  860. void
  861. M_WriteText
  862. ( int x,
  863. int y,
  864. char* string)
  865. {
  866. int w;
  867. char* ch;
  868. int c;
  869. int cx;
  870. int cy;
  871. ch = string;
  872. cx = x;
  873. cy = y;
  874. while(1)
  875. {
  876. c = *ch++;
  877. if (!c)
  878. break;
  879. if (c == '\n')
  880. {
  881. cx = x;
  882. cy += 12;
  883. continue;
  884. }
  885. c = toupper(c) - HU_FONTSTART;
  886. if (c < 0 || c>= HU_FONTSIZE)
  887. {
  888. cx += 4;
  889. continue;
  890. }
  891. w = SHORT (::g->hu_font[c]->width);
  892. if (cx+w > SCREENWIDTH)
  893. break;
  894. V_DrawPatchDirect(cx, cy, 0, ::g->hu_font[c]);
  895. cx+=w;
  896. }
  897. }
  898. //
  899. // CONTROL PANEL
  900. //
  901. //
  902. // M_Responder
  903. //
  904. qboolean M_Responder (event_t* ev)
  905. {
  906. int ch;
  907. int i;
  908. ch = -1;
  909. if (ev->type == ev_joystick && ::g->joywait < I_GetTime())
  910. {
  911. if (ev->data3 == -1)
  912. {
  913. ch = KEY_UPARROW;
  914. ::g->joywait = I_GetTime() + 5;
  915. }
  916. else if (ev->data3 == 1)
  917. {
  918. ch = KEY_DOWNARROW;
  919. ::g->joywait = I_GetTime() + 5;
  920. }
  921. if (ev->data2 == -1)
  922. {
  923. ch = KEY_LEFTARROW;
  924. ::g->joywait = I_GetTime() + 2;
  925. }
  926. else if (ev->data2 == 1)
  927. {
  928. ch = KEY_RIGHTARROW;
  929. ::g->joywait = I_GetTime() + 2;
  930. }
  931. if (ev->data1&1)
  932. {
  933. ch = KEY_ENTER;
  934. ::g->joywait = I_GetTime() + 5;
  935. }
  936. if (ev->data1&2)
  937. {
  938. ch = KEY_BACKSPACE;
  939. ::g->joywait = I_GetTime() + 5;
  940. }
  941. }
  942. else
  943. {
  944. if (ev->type == ev_mouse && ::g->mousewait < I_GetTime())
  945. {
  946. ::g->mmenu_mousey += ev->data3;
  947. if (::g->mmenu_mousey < ::g->lasty-30)
  948. {
  949. ch = KEY_DOWNARROW;
  950. ::g->mousewait = I_GetTime() + 5;
  951. ::g->mmenu_mousey = ::g->lasty -= 30;
  952. }
  953. else if (::g->mmenu_mousey > ::g->lasty+30)
  954. {
  955. ch = KEY_UPARROW;
  956. ::g->mousewait = I_GetTime() + 5;
  957. ::g->mmenu_mousey = ::g->lasty += 30;
  958. }
  959. ::g->mmenu_mousex += ev->data2;
  960. if (::g->mmenu_mousex < ::g->lastx-30)
  961. {
  962. ch = KEY_LEFTARROW;
  963. ::g->mousewait = I_GetTime() + 5;
  964. ::g->mmenu_mousex = ::g->lastx -= 30;
  965. }
  966. else if (::g->mmenu_mousex > ::g->lastx+30)
  967. {
  968. ch = KEY_RIGHTARROW;
  969. ::g->mousewait = I_GetTime() + 5;
  970. ::g->mmenu_mousex = ::g->lastx += 30;
  971. }
  972. if (ev->data1&1)
  973. {
  974. ch = KEY_ENTER;
  975. ::g->mousewait = I_GetTime() + 15;
  976. }
  977. if (ev->data1&2)
  978. {
  979. ch = KEY_BACKSPACE;
  980. ::g->mousewait = I_GetTime() + 15;
  981. }
  982. } else
  983. if (ev->type == ev_keydown)
  984. {
  985. ch = ev->data1;
  986. }
  987. }
  988. if (ch == -1)
  989. return false;
  990. // Save Game string input
  991. if (::g->saveStringEnter)
  992. {
  993. switch(ch)
  994. {
  995. case KEY_BACKSPACE:
  996. if (::g->saveCharIndex > 0)
  997. {
  998. ::g->saveCharIndex--;
  999. ::g->savegamestrings[::g->saveSlot][::g->saveCharIndex] = 0;
  1000. }
  1001. break;
  1002. case KEY_ESCAPE:
  1003. ::g->saveStringEnter = 0;
  1004. strcpy(&::g->savegamestrings[::g->saveSlot][0],::g->saveOldString);
  1005. break;
  1006. case KEY_ENTER:
  1007. ::g->saveStringEnter = 0;
  1008. if (::g->savegamestrings[::g->saveSlot][0])
  1009. M_DoSave(::g->saveSlot);
  1010. break;
  1011. default:
  1012. ch = toupper(ch);
  1013. if (ch != 32)
  1014. if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE)
  1015. break;
  1016. if (ch >= 32 && ch <= 127 &&
  1017. ::g->saveCharIndex < SAVESTRINGSIZE-1 &&
  1018. M_StringWidth(::g->savegamestrings[::g->saveSlot]) <
  1019. (SAVESTRINGSIZE-2)*8)
  1020. {
  1021. ::g->savegamestrings[::g->saveSlot][::g->saveCharIndex++] = ch;
  1022. ::g->savegamestrings[::g->saveSlot][::g->saveCharIndex] = 0;
  1023. }
  1024. break;
  1025. }
  1026. return true;
  1027. }
  1028. // Take care of any messages that need input
  1029. if (::g->messageToPrint)
  1030. {
  1031. if (::g->messageNeedsInput == true &&
  1032. !(ch == KEY_ENTER || ch == KEY_BACKSPACE || ch == KEY_ESCAPE))
  1033. return false;
  1034. ::g->menuactive = ::g->messageLastMenuActive;
  1035. ::g->messageToPrint = 0;
  1036. if (::g->messageRoutine)
  1037. ::g->messageRoutine(ch);
  1038. S_StartSound(NULL,sfx_swtchx);
  1039. return true;
  1040. }
  1041. /*
  1042. if (::g->devparm && ch == KEY_F1)
  1043. {
  1044. G_ScreenShot ();
  1045. return true;
  1046. }
  1047. // F-Keys
  1048. if (!::g->menuactive)
  1049. switch(ch)
  1050. {
  1051. case KEY_MINUS: // Screen size down
  1052. if (::g->automapactive || ::g->chat_on)
  1053. return false;
  1054. //M_SizeDisplay(0);
  1055. S_StartSound(NULL,sfx_stnmov);
  1056. return true;
  1057. case KEY_EQUALS: // Screen size up
  1058. if (::g->automapactive || ::g->chat_on)
  1059. return false;
  1060. //M_SizeDisplay(1);
  1061. S_StartSound(NULL,sfx_stnmov);
  1062. return true;
  1063. case KEY_F1: // Help key
  1064. M_StartControlPanel ();
  1065. if ( ::g->gamemode == retail )
  1066. ::g->currentMenu = &::g->ReadDef2;
  1067. else
  1068. ::g->currentMenu = &::g->ReadDef1;
  1069. ::g->itemOn = 0;
  1070. S_StartSound(NULL,sfx_swtchn);
  1071. return true;
  1072. case KEY_F2: // Save
  1073. M_StartControlPanel();
  1074. S_StartSound(NULL,sfx_swtchn);
  1075. M_SaveGame(0);
  1076. return true;
  1077. case KEY_F3: // Load
  1078. M_StartControlPanel();
  1079. S_StartSound(NULL,sfx_swtchn);
  1080. M_LoadGame(0);
  1081. return true;
  1082. case KEY_F4: // Sound Volume
  1083. M_StartControlPanel ();
  1084. ::g->currentMenu = &::g->SoundDef;
  1085. ::g->itemOn = sfx_vol;
  1086. S_StartSound(NULL,sfx_swtchn);
  1087. return true;
  1088. case KEY_F5: // Detail toggle
  1089. M_ChangeDetail(0);
  1090. S_StartSound(NULL,sfx_swtchn);
  1091. return true;
  1092. case KEY_F6: // Quicksave
  1093. S_StartSound(NULL,sfx_swtchn);
  1094. M_QuickSave();
  1095. return true;
  1096. case KEY_F7: // End game
  1097. S_StartSound(NULL,sfx_swtchn);
  1098. M_EndGame(0);
  1099. return true;
  1100. case KEY_F8: // Toggle messages
  1101. M_ChangeMessages(0);
  1102. S_StartSound(NULL,sfx_swtchn);
  1103. return true;
  1104. case KEY_F9: // Quickload
  1105. S_StartSound(NULL,sfx_swtchn);
  1106. M_QuickLoad();
  1107. return true;
  1108. case KEY_F10: // Quit DOOM
  1109. S_StartSound(NULL,sfx_swtchn);
  1110. M_QuitDOOM(0);
  1111. return true;
  1112. case KEY_F11: // gamma toggle
  1113. ::g->usegamma++;
  1114. if (::g->usegamma > 4)
  1115. ::g->usegamma = 0;
  1116. ::g->players[::g->consoleplayer].message = gammamsg[::g->usegamma];
  1117. I_SetPalette ((byte*)W_CacheLumpName ("PLAYPAL",PU_CACHE_SHARED));
  1118. return true;
  1119. }
  1120. */
  1121. // Pop-up menu?
  1122. if (!::g->menuactive)
  1123. {
  1124. if (ch == KEY_ESCAPE && ( ::g->gamestate == GS_LEVEL || ::g->gamestate == GS_INTERMISSION || ::g->gamestate == GS_FINALE ) )
  1125. {
  1126. M_StartControlPanel ();
  1127. S_StartSound(NULL,sfx_swtchn);
  1128. return true;
  1129. }
  1130. return false;
  1131. }
  1132. // Keys usable within menu
  1133. switch (ch)
  1134. {
  1135. case KEY_DOWNARROW:
  1136. do
  1137. {
  1138. if (::g->itemOn+1 > ::g->currentMenu->numitems-1)
  1139. ::g->itemOn = 0;
  1140. else ::g->itemOn++;
  1141. S_StartSound(NULL,sfx_pstop);
  1142. } while(::g->currentMenu->menuitems[::g->itemOn].status==-1);
  1143. return true;
  1144. case KEY_UPARROW:
  1145. do
  1146. {
  1147. if (!::g->itemOn)
  1148. ::g->itemOn = ::g->currentMenu->numitems-1;
  1149. else ::g->itemOn--;
  1150. S_StartSound(NULL,sfx_pstop);
  1151. } while(::g->currentMenu->menuitems[::g->itemOn].status==-1);
  1152. return true;
  1153. case KEY_LEFTARROW:
  1154. if (::g->currentMenu->menuitems[::g->itemOn].routine &&
  1155. ::g->currentMenu->menuitems[::g->itemOn].status == 2)
  1156. {
  1157. S_StartSound(NULL,sfx_stnmov);
  1158. ::g->currentMenu->menuitems[::g->itemOn].routine(0);
  1159. }
  1160. return true;
  1161. case KEY_RIGHTARROW:
  1162. if (::g->currentMenu->menuitems[::g->itemOn].routine &&
  1163. ::g->currentMenu->menuitems[::g->itemOn].status == 2)
  1164. {
  1165. S_StartSound(NULL,sfx_stnmov);
  1166. ::g->currentMenu->menuitems[::g->itemOn].routine(1);
  1167. }
  1168. return true;
  1169. case KEY_ENTER:
  1170. if (::g->currentMenu->menuitems[::g->itemOn].routine &&
  1171. ::g->currentMenu->menuitems[::g->itemOn].status)
  1172. {
  1173. ::g->currentMenu->lastOn = ::g->itemOn;
  1174. if (::g->currentMenu->menuitems[::g->itemOn].status == 2)
  1175. {
  1176. ::g->currentMenu->menuitems[::g->itemOn].routine(1); // right arrow
  1177. S_StartSound(NULL,sfx_stnmov);
  1178. }
  1179. else
  1180. {
  1181. ::g->currentMenu->menuitems[::g->itemOn].routine(::g->itemOn);
  1182. S_StartSound(NULL,sfx_pistol);
  1183. }
  1184. }
  1185. return true;
  1186. case KEY_ESCAPE:
  1187. case KEY_BACKSPACE:
  1188. ::g->currentMenu->lastOn = ::g->itemOn;
  1189. if (::g->currentMenu->prevMenu)
  1190. {
  1191. ::g->currentMenu = ::g->currentMenu->prevMenu;
  1192. ::g->itemOn = ::g->currentMenu->lastOn;
  1193. S_StartSound(NULL,sfx_swtchn);
  1194. } else if ( ::g->currentMenu == &::g->MainDef && ( !::g->demoplayback && ::g->gamestate != GS_DEMOSCREEN ) ) {
  1195. M_ClearMenus();
  1196. ::g->paused = false;
  1197. }
  1198. return true;
  1199. default:
  1200. for (i = ::g->itemOn+1;i < ::g->currentMenu->numitems;i++)
  1201. if (::g->currentMenu->menuitems[i].alphaKey == ch)
  1202. {
  1203. ::g->itemOn = i;
  1204. S_StartSound(NULL,sfx_pstop);
  1205. return true;
  1206. }
  1207. for (i = 0;i <= ::g->itemOn;i++)
  1208. if (::g->currentMenu->menuitems[i].alphaKey == ch)
  1209. {
  1210. ::g->itemOn = i;
  1211. S_StartSound(NULL,sfx_pstop);
  1212. return true;
  1213. }
  1214. break;
  1215. }
  1216. return false;
  1217. }
  1218. //
  1219. // M_StartControlPanel
  1220. //
  1221. void M_StartControlPanel (void)
  1222. {
  1223. // intro might call this repeatedly
  1224. if (::g->menuactive)
  1225. return;
  1226. ::g->menuactive = 1;
  1227. ::g->currentMenu = &::g->MainDef;
  1228. ::g->itemOn = ::g->currentMenu->lastOn;
  1229. }
  1230. //
  1231. // M_Drawer
  1232. // Called after the view has been rendered,
  1233. // but before it has been blitted.
  1234. //
  1235. void M_Drawer (void)
  1236. {
  1237. unsigned short i;
  1238. short max;
  1239. char string[40];
  1240. int start;
  1241. ::g->inhelpscreens = false;
  1242. // Horiz. & Vertically center string and print it.
  1243. if (::g->messageToPrint)
  1244. {
  1245. start = 0;
  1246. ::g->md_y = 100 - M_StringHeight(::g->messageString)/2;
  1247. while(*(::g->messageString+start))
  1248. {
  1249. for (i = 0;i < strlen(::g->messageString+start);i++)
  1250. if (*(::g->messageString+start+i) == '\n')
  1251. {
  1252. memset(string,0,40);
  1253. strncpy(string,::g->messageString+start,i);
  1254. start += i+1;
  1255. break;
  1256. }
  1257. if (i == strlen(::g->messageString+start))
  1258. {
  1259. strcpy(string,::g->messageString+start);
  1260. start += i;
  1261. }
  1262. ::g->md_x = 160 - M_StringWidth(string)/2;
  1263. M_WriteText(::g->md_x,::g->md_y,string);
  1264. ::g->md_y += SHORT(::g->hu_font[0]->height);
  1265. }
  1266. return;
  1267. }
  1268. if (!::g->menuactive)
  1269. return;
  1270. if (::g->currentMenu->routine)
  1271. ::g->currentMenu->routine(); // call Draw routine
  1272. // DRAW MENU
  1273. ::g->md_x = ::g->currentMenu->x;
  1274. ::g->md_y = ::g->currentMenu->y;
  1275. max = ::g->currentMenu->numitems;
  1276. for (i=0;i<max;i++)
  1277. {
  1278. if (::g->currentMenu->menuitems[i].name[0])
  1279. V_DrawPatchDirect (::g->md_x,::g->md_y,0,
  1280. (patch_t*)W_CacheLumpName(::g->currentMenu->menuitems[i].name ,PU_CACHE_SHARED));
  1281. ::g->md_y += LINEHEIGHT;
  1282. }
  1283. // DRAW SKULL
  1284. V_DrawPatchDirect(::g->md_x + SKULLXOFF,::g->currentMenu->y - 5 + ::g->itemOn*LINEHEIGHT, 0,
  1285. (patch_t*)W_CacheLumpName(skullName[::g->whichSkull],PU_CACHE_SHARED));
  1286. }
  1287. //
  1288. // M_ClearMenus
  1289. //
  1290. void M_ClearMenus (void)
  1291. {
  1292. ::g->menuactive = 0;
  1293. // if (!::g->netgame && ::g->usergame && ::g->paused)
  1294. // ::g->sendpause = true;
  1295. }
  1296. //
  1297. // M_SetupNextMenu
  1298. //
  1299. void M_SetupNextMenu(menu_t *menudef)
  1300. {
  1301. ::g->currentMenu = menudef;
  1302. ::g->itemOn = ::g->currentMenu->lastOn;
  1303. }
  1304. //
  1305. // M_Ticker
  1306. //
  1307. void M_Ticker (void)
  1308. {
  1309. if (--::g->skullAnimCounter <= 0)
  1310. {
  1311. ::g->whichSkull ^= 1;
  1312. ::g->skullAnimCounter = 8;
  1313. }
  1314. }
  1315. //
  1316. // M_Init
  1317. //
  1318. void M_Init (void)
  1319. {
  1320. ::g->currentMenu = &::g->MainDef;
  1321. ::g->menuactive = 1;
  1322. ::g->itemOn = ::g->currentMenu->lastOn;
  1323. ::g->whichSkull = 0;
  1324. ::g->skullAnimCounter = 10;
  1325. ::g->screenSize = ::g->screenblocks - 3;
  1326. ::g->messageToPrint = 0;
  1327. ::g->messageString = NULL;
  1328. ::g->messageLastMenuActive = ::g->menuactive;
  1329. ::g->quickSaveSlot = -1;
  1330. // Here we could catch other version dependencies,
  1331. // like HELP1/2, and four episodes.
  1332. switch ( ::g->gamemode )
  1333. {
  1334. case commercial:
  1335. // This is used because DOOM 2 had only one HELP
  1336. // page. I use CREDIT as second page now, but
  1337. // kept this hack for educational purposes.
  1338. //::g->MainMenu[readthis] = ::g->MainMenu[quitdoom];
  1339. //::g->MainDef.numitems--;
  1340. ::g->MainDef.y += 8;
  1341. ::g->NewDef.prevMenu = &::g->MainDef;
  1342. //::g->ReadDef1.routine = M_DrawReadThis1;
  1343. //::g->ReadDef1.x = 330;
  1344. //::g->ReadDef1.y = 165;
  1345. //::g->ReadMenu1[0].routine = M_FinishReadThis;
  1346. break;
  1347. case shareware:
  1348. // Episode 2 and 3 are handled,
  1349. // branching to an ad screen.
  1350. case registered:
  1351. // We need to remove the fourth episode.
  1352. ::g->EpiDef.numitems--;
  1353. break;
  1354. case retail:
  1355. // We are fine.
  1356. default:
  1357. break;
  1358. }
  1359. }