GOPTIONS.CPP 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /* $Header: /counterstrike/GOPTIONS.CPP 6 3/15/97 7:18p Steve_tall $ */
  15. /***********************************************************************************************
  16. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  17. ***********************************************************************************************
  18. * *
  19. * Project Name : Command & Conquer *
  20. * *
  21. * File Name : OPTIONS.CPP *
  22. * *
  23. * Programmer : Joe L. Bostic *
  24. * *
  25. * Start Date : June 8, 1994 *
  26. * *
  27. * Last Update : July 27, 1995 [JLB] *
  28. * *
  29. *---------------------------------------------------------------------------------------------*
  30. * Functions: *
  31. * OptionsClass::Process -- Handles all the options graphic interface. *
  32. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  33. #include "function.h"
  34. #include "goptions.h"
  35. #include "loaddlg.h"
  36. #include "sounddlg.h"
  37. #include "visudlg.h"
  38. #include "gamedlg.h"
  39. #include "textbtn.h"
  40. #include "descdlg.h"
  41. #ifdef FIXIT_VERSION_3 // Stalemate games.
  42. #include "WolStrng.h"
  43. #endif
  44. bool RedrawOptionsMenu;
  45. /***********************************************************************************************
  46. * OptionsClass::Process -- Handles all the options graphic interface. *
  47. * *
  48. * This routine is the main control for the visual representation of the options *
  49. * screen. It handles the visual overlay and the player input. *
  50. * *
  51. * INPUT: none *
  52. * *
  53. * OUTPUT: none *
  54. * *
  55. * WARNINGS: none *
  56. * *
  57. * HISTORY: 12/31/1994 MML : Created. *
  58. * 06/23/1995 JLB : Handles restating the mission objective. *
  59. * 07/27/1995 JLB : Adjusts menu for multiplay mode. *
  60. *=============================================================================================*/
  61. void GameOptionsClass::Process(void)
  62. {
  63. static struct {
  64. int ID; // Button ID to use.
  65. int Text; // Text number to use for this button.
  66. bool Multiplay; // Allowed in multiplayer version?
  67. } _constants[] = {
  68. {BUTTON_LOAD, TXT_LOAD_MISSION, false},
  69. #ifdef FIXIT_MULTI_SAVE
  70. {BUTTON_SAVE, TXT_SAVE_MISSION, true},
  71. #else
  72. {BUTTON_SAVE, TXT_SAVE_MISSION, false},
  73. #endif
  74. {BUTTON_DELETE, TXT_DELETE_MISSION, true},
  75. {BUTTON_GAME, TXT_GAME_CONTROLS, true},
  76. {BUTTON_QUIT, TXT_QUIT_MISSION, true},
  77. #ifdef FIXIT_VERSION_3 // Stalemate games.
  78. {BUTTON_DRAW, TXT_OK, true},
  79. #endif
  80. {BUTTON_RESUME, TXT_RESUME_MISSION, true},
  81. {BUTTON_RESTATE, TXT_RESTATE_MISSION, false},
  82. };
  83. /*
  84. ** Variables.
  85. */
  86. TextButtonClass * buttons = 0;
  87. int selection;
  88. bool pressed;
  89. #ifdef FIXIT_VERSION_3 // Stalemate games.
  90. int curbutton = 7;
  91. #else
  92. int curbutton = 6;
  93. #endif
  94. int y;
  95. TextButtonClass * buttonsel[ARRAY_SIZE(_constants)];
  96. static int num_buttons = sizeof(_constants)/sizeof(_constants[0]);
  97. int num_players = 0;
  98. int i;
  99. //
  100. // Compute the number of real players in the game; only allow saves
  101. // if there are more than 1.
  102. //
  103. for (i = 0; i < Session.Players.Count(); i++) {
  104. if (!(HouseClass::As_Pointer(Session.Players[i]->Player.ID)->IsDefeated)) {
  105. num_players++;
  106. }
  107. }
  108. Set_Logic_Page(SeenBuff);
  109. /*
  110. ** Build the button list for all of the buttons for this dialog.
  111. */
  112. int maxwidth = 0;
  113. for (int index = 0; index < num_buttons ; index++ ) {
  114. int text = _constants[index].Text;
  115. buttonsel[index] = NULL;
  116. if (Session.Type != GAME_NORMAL && !_constants[index].Multiplay) {
  117. continue;
  118. }
  119. if ( (Session.Type == GAME_SKIRMISH ||
  120. Session.Type == GAME_INTERNET) && text == TXT_SAVE_MISSION) {
  121. continue;
  122. }
  123. #ifdef FIXIT_VERSION_3
  124. if (Session.Type != GAME_NORMAL && ( num_players < 2 ) &&
  125. text == TXT_SAVE_MISSION) {
  126. continue;
  127. }
  128. #else
  129. #ifdef FIXIT_MULTI_SAVE
  130. if (Session.Type != GAME_NORMAL && (num_players < 2 || PlayingAgainstVersion == VERSION_RED_ALERT_104) &&
  131. text == TXT_SAVE_MISSION) {
  132. continue;
  133. }
  134. #endif //FIXIT_MULTI_SAVE
  135. #endif
  136. if (Session.Type == GAME_SKIRMISH && text == TXT_DELETE_MISSION) {
  137. continue;
  138. }
  139. if (Session.Type != GAME_NORMAL && text == TXT_DELETE_MISSION) {
  140. text = TXT_RESIGN;
  141. }
  142. #ifdef FIXIT_VERSION_3 // Stalemate games.
  143. if (index < 6) {
  144. #else
  145. if (index < 5) {
  146. #endif
  147. y = (SeenBuff.Get_Height() - OptionHeight)/2 + ButtonY + ((OButtonHeight+2) * index);
  148. } else {
  149. y = OptionY + ButtonResumeY;
  150. }
  151. #ifdef FIXIT_VERSION_3 // Stalemate games.
  152. TextButtonClass* g;
  153. if( _constants[index].ID == BUTTON_DRAW )
  154. {
  155. if( Session.Type != GAME_NORMAL && Session.Type != GAME_SKIRMISH && Session.Players.Count() == 2 )
  156. {
  157. if( Scen.bLocalProposesDraw )
  158. {
  159. if( !Scen.bOtherProposesDraw )
  160. g = new TextButtonClass( BUTTON_DRAW, TXT_WOL_RETRACT_DRAW, TPF_BUTTON, 0, y );
  161. else
  162. continue; // Game will end now anyway.
  163. }
  164. else
  165. {
  166. if( !Scen.bOtherProposesDraw )
  167. g = new TextButtonClass( BUTTON_DRAW, TXT_WOL_PROPOSE_DRAW, TPF_BUTTON, 0, y );
  168. else
  169. g = new TextButtonClass( BUTTON_DRAW, TXT_WOL_ACCEPT_DRAW, TPF_BUTTON, 0, y );
  170. }
  171. }
  172. else
  173. continue;
  174. }
  175. else
  176. g = new TextButtonClass(_constants[index].ID, text, TPF_BUTTON, 0, y);
  177. #else
  178. TextButtonClass * g = new TextButtonClass(_constants[index].ID, text, TPF_BUTTON, 0, y);
  179. #endif
  180. if (g->Width > maxwidth) {
  181. maxwidth = g->Width;
  182. }
  183. if (buttons == NULL) {
  184. buttons = g;
  185. } else {
  186. g->Add_Tail(*buttons);
  187. }
  188. buttonsel[index] = g;
  189. }
  190. /*
  191. ** BG: In skirmish mode, there is no 'restate' button, so we have to
  192. ** backtrack through the list to find the last valid button.
  193. */
  194. while(!buttonsel[curbutton-1]) curbutton--;
  195. buttonsel[curbutton-1]->Turn_On();
  196. /*
  197. ** Force all button lengths to match the maximum length of the widest button.
  198. */
  199. GadgetClass * g = buttons;
  200. while (g != NULL) {
  201. g->Width = max(maxwidth, 90 * RESFACTOR);
  202. g->X = OptionX+(OptionWidth-g->Width)/2;
  203. g = g->Get_Next();
  204. }
  205. //#ifdef FRENCH
  206. // buttonsel[BUTTON_RESUME-1]->Width = 110 * RESFACTOR;
  207. // buttonsel[BUTTON_RESUME-1]->X = OptionX + (17 * RESFACTOR) - 5;
  208. //#else
  209. buttonsel[BUTTON_RESUME-1]->Width = 90 * RESFACTOR;
  210. buttonsel[BUTTON_RESUME-1]->X = OptionX + (17 * RESFACTOR);
  211. //#endif
  212. if (Session.Type == GAME_NORMAL) {
  213. buttonsel[BUTTON_RESTATE-1]->Width = 90 * RESFACTOR;
  214. buttonsel[BUTTON_RESTATE-1]->X = OptionX+OptionWidth-(buttonsel[BUTTON_RESTATE-1]->Width+(17 * RESFACTOR));
  215. }
  216. /*
  217. ** This causes left mouse button clicking within the confines of the dialog to
  218. ** be ignored if it wasn't recognized by any other button or slider.
  219. */
  220. (new GadgetClass(OptionX, OptionY, OptionWidth, OptionHeight, GadgetClass::LEFTPRESS))->Add_Tail(*buttons);
  221. /*
  222. ** This cause a right click anywhere or a left click outside the dialog region
  223. ** to be equivalent to clicking on the return to game button.
  224. */
  225. (new ControlClass(BUTTON_RESUME, 0, 0, SeenBuff.Get_Width(), SeenBuff.Get_Height(), GadgetClass::LEFTPRESS|GadgetClass::RIGHTPRESS))->Add_Tail(*buttons);
  226. Keyboard->Clear();
  227. Fancy_Text_Print(TXT_NONE, 0, 0, GadgetClass::Get_Color_Scheme(), TBLACK, TPF_CENTER|TPF_TEXT);
  228. /*
  229. ** Main Processing Loop.
  230. */
  231. bool display = true;
  232. bool process = true;
  233. pressed = false;
  234. while (process) {
  235. /*
  236. ** Invoke game callback.
  237. */
  238. if (Session.Type == GAME_NORMAL || Session.Type == GAME_SKIRMISH) {
  239. Call_Back();
  240. } else {
  241. if (Main_Loop()) {
  242. process = false;
  243. }
  244. }
  245. #ifdef WIN32
  246. /*
  247. ** If we have just received input focus again after running in the background then
  248. ** we need to redraw.
  249. */
  250. if (AllSurfaces.SurfacesRestored) {
  251. AllSurfaces.SurfacesRestored = false;
  252. display = true;
  253. }
  254. #endif
  255. /*
  256. ** Refresh display if needed.
  257. */
  258. if (display || RedrawOptionsMenu) {
  259. /*
  260. ** Redraw the map.
  261. */
  262. HidPage.Clear();
  263. Map.Flag_To_Redraw(true);
  264. Map.Render();
  265. /*
  266. ** Reset up the window. Window x-coords are in bytes not pixels.
  267. */
  268. Set_Window(WINDOW_EDITOR, OptionX, OptionY, OptionWidth, OptionHeight);
  269. Hide_Mouse();
  270. /*
  271. ** Draw the background.
  272. */
  273. Dialog_Box(OptionX, OptionY, OptionWidth, OptionHeight);
  274. /*
  275. ** Draw the arrows border if requested.
  276. */
  277. Draw_Caption(TXT_OPTIONS, OptionX, OptionY, OptionWidth);
  278. /*
  279. ** Display the version number at the bottom of the dialog box.
  280. */
  281. #ifndef WIN32
  282. Fancy_Text_Print("%s\rV%s",
  283. (OptionX+OptionWidth)-(17 * RESFACTOR),
  284. OptionY+OptionHeight-((Session.Type == GAME_NORMAL) ? (32 * RESFACTOR) : (24 * RESFACTOR)),
  285. GadgetClass::Get_Color_Scheme(), TBLACK,
  286. TPF_EFNT|TPF_NOSHADOW|TPF_RIGHT,
  287. Scen.ScenarioName,
  288. Version_Name());
  289. #else
  290. #if (0)//PG
  291. Fancy_Text_Print("%s\rV%s",
  292. (OptionX+OptionWidth)-(25 * RESFACTOR),
  293. OptionY+OptionHeight-((Session.Type == GAME_NORMAL) ? (32 * RESFACTOR) : (24 * RESFACTOR)),
  294. GadgetClass::Get_Color_Scheme(), TBLACK,
  295. TPF_EFNT|TPF_NOSHADOW|TPF_RIGHT,
  296. Scen.ScenarioName,
  297. Version_Name());
  298. #endif
  299. #endif
  300. buttons->Draw_All();
  301. TabClass::Hilite_Tab(0);
  302. Show_Mouse();
  303. display = false;
  304. RedrawOptionsMenu = false;
  305. }
  306. /*
  307. ** Get user input.
  308. */
  309. KeyNumType input = buttons->Input();
  310. /*
  311. ** Process Input.
  312. */
  313. switch (input) {
  314. case (BUTTON_RESTATE | KN_BUTTON):
  315. selection = BUTTON_RESTATE;
  316. pressed = true;
  317. break;
  318. case (BUTTON_LOAD | KN_BUTTON):
  319. selection = BUTTON_LOAD;
  320. pressed = true;
  321. break;
  322. case (BUTTON_SAVE | KN_BUTTON):
  323. selection = BUTTON_SAVE;
  324. pressed = true;
  325. break;
  326. case (BUTTON_DELETE | KN_BUTTON):
  327. selection = BUTTON_DELETE;
  328. pressed = true;
  329. break;
  330. case (BUTTON_QUIT | KN_BUTTON):
  331. selection = BUTTON_QUIT;
  332. pressed = true;
  333. break;
  334. case (BUTTON_GAME | KN_BUTTON):
  335. selection = BUTTON_GAME;
  336. pressed = true;
  337. break;
  338. #ifdef FIXIT_VERSION_3 // Stalemate games.
  339. case (BUTTON_DRAW | KN_BUTTON):
  340. selection = BUTTON_DRAW;
  341. pressed = true;
  342. break;
  343. #endif
  344. case (KN_ESC):
  345. case (BUTTON_RESUME | KN_BUTTON):
  346. selection = BUTTON_RESUME;
  347. pressed = true;
  348. break;
  349. case (KN_UP):
  350. buttonsel[curbutton-1]->Turn_Off();
  351. buttonsel[curbutton-1]->Flag_To_Redraw();
  352. do {
  353. curbutton--;
  354. if (curbutton < 1) curbutton = num_buttons;
  355. } while (!buttonsel[curbutton-1]);
  356. buttonsel[curbutton-1]->Turn_On();
  357. buttonsel[curbutton-1]->Flag_To_Redraw();
  358. break;
  359. case (KN_DOWN):
  360. buttonsel[curbutton-1]->Turn_Off();
  361. buttonsel[curbutton-1]->Flag_To_Redraw();
  362. do {
  363. curbutton++;
  364. if ( curbutton > num_buttons ) curbutton = 1;
  365. } while (!buttonsel[curbutton-1]);
  366. buttonsel[curbutton-1]->Turn_On();
  367. buttonsel[curbutton-1]->Flag_To_Redraw();
  368. break;
  369. case (KN_RETURN):
  370. buttonsel[curbutton-1]->IsPressed = true;
  371. buttonsel[curbutton-1]->Draw_Me(true);
  372. selection = curbutton;
  373. pressed = true;
  374. Keyboard->Clear();
  375. break;
  376. default:
  377. break;
  378. }
  379. if (pressed) {
  380. buttonsel[curbutton-1]->Turn_Off();
  381. buttonsel[curbutton-1]->Flag_To_Redraw();
  382. curbutton = selection;
  383. buttonsel[curbutton-1]->Turn_On();
  384. buttonsel[curbutton-1]->Flag_To_Redraw();
  385. switch (selection) {
  386. case BUTTON_RESTATE:
  387. display = true;
  388. if (!Restate_Mission(Scen.ScenarioName, TXT_VIDEO, TXT_RESUME_MISSION/*KOTXT_OPTIONS*/)) {
  389. BreakoutAllowed = true;
  390. Play_Movie(Scen.BriefMovie);
  391. BlackPalette.Adjust(0x08, WhitePalette);
  392. BlackPalette.Set();
  393. BlackPalette.Adjust(0xFF);
  394. BlackPalette.Set();
  395. GamePalette.Set();
  396. Map.Flag_To_Redraw(true);
  397. Theme.Queue_Song(THEME_PICK_ANOTHER);
  398. process = false;
  399. } else {
  400. BlackPalette.Adjust(0x08, WhitePalette);
  401. BlackPalette.Set();
  402. BlackPalette.Adjust(0xFF);
  403. BlackPalette.Set();
  404. GamePalette.Set();
  405. Map.Flag_To_Redraw(true);
  406. process = false;
  407. }
  408. break;
  409. case (BUTTON_LOAD):
  410. display = true;
  411. if (LoadOptionsClass(LoadOptionsClass::LOAD).Process()) {
  412. process = false;
  413. }
  414. break;
  415. case (BUTTON_SAVE):
  416. display = true;
  417. if (Session.Type == GAME_NORMAL) {
  418. LoadOptionsClass(LoadOptionsClass::SAVE).Process();
  419. } else {
  420. OutList.Add(EventClass(EventClass::SAVEGAME));
  421. process = false;
  422. }
  423. break;
  424. case (BUTTON_DELETE):
  425. display = true;
  426. if (Session.Type != GAME_NORMAL) {
  427. if (Surrender_Dialog(TXT_SURRENDER)) {
  428. OutList.Add(EventClass(EventClass::DESTRUCT));
  429. }
  430. process = false;
  431. } else {
  432. LoadOptionsClass(LoadOptionsClass::WWDELETE).Process();
  433. }
  434. break;
  435. case (BUTTON_QUIT):
  436. if (Session.Type == GAME_NORMAL) {
  437. switch (WWMessageBox().Process(TXT_CONFIRM_EXIT, TXT_ABORT, TXT_CANCEL, TXT_RESTART)) {
  438. case 1:
  439. display = true;
  440. break;
  441. case 0:
  442. process = false;
  443. Queue_Exit();
  444. break;
  445. case 2:
  446. PlayerRestarts = true;
  447. process = false;
  448. break;
  449. }
  450. } else {
  451. if (Surrender_Dialog(TXT_CONFIRM_EXIT)) {
  452. process = false;
  453. Queue_Exit();
  454. } else {
  455. display = true;
  456. }
  457. //if (WWMessageBox().Process(TXT_CONFIRM_EXIT, TXT_YES, TXT_NO) == 0) {
  458. //process = false;
  459. //Queue_Exit();
  460. //} else {
  461. //display = true;
  462. //}
  463. }
  464. break;
  465. #ifdef FIXIT_VERSION_3 // Stalemate games.
  466. case BUTTON_DRAW:
  467. if( Scen.bLocalProposesDraw )
  468. {
  469. // Retract draw offer.
  470. OutList.Add(EventClass(EventClass::RETRACT_DRAW));
  471. process = false;
  472. }
  473. else
  474. {
  475. if( !Scen.bOtherProposesDraw )
  476. {
  477. // Propose a draw?
  478. if( Surrender_Dialog( TXT_WOL_PROPOSE_DRAW_CONFIRM ) )
  479. {
  480. OutList.Add(EventClass(EventClass::PROPOSE_DRAW));
  481. process = false;
  482. }
  483. else
  484. display = true;
  485. }
  486. else
  487. {
  488. // Accept a draw?
  489. if( Surrender_Dialog( TXT_WOL_ACCEPT_DRAW_CONFIRM ) )
  490. {
  491. OutList.Add(EventClass(EventClass::PROPOSE_DRAW));
  492. process = false;
  493. }
  494. else
  495. display = true;
  496. }
  497. }
  498. break;
  499. #endif
  500. case (BUTTON_GAME):
  501. display = true;
  502. GameControlsClass().Process();
  503. break;
  504. case (BUTTON_RESUME):
  505. Save_Settings();
  506. process = false;
  507. display = true;
  508. break;
  509. }
  510. pressed = false;
  511. buttonsel[curbutton-1]->IsPressed = false;
  512. buttonsel[curbutton-1]->Turn_Off();
  513. buttonsel[curbutton-1]->Flag_To_Redraw();
  514. }
  515. }
  516. /*
  517. ** Clean up and re-enter the game.
  518. */
  519. buttons->Delete_List();
  520. /*
  521. ** Redraw the map.
  522. */
  523. Keyboard->Clear();
  524. HidPage.Clear();
  525. Map.Flag_To_Redraw(true);
  526. Map.Render();
  527. }
  528. void GameOptionsClass::Adjust_Variables_For_Resolution(void)
  529. {
  530. OptionWidth = (216+8) * RESFACTOR;
  531. #ifdef FIXIT_VERSION_3 // Stalemate games.
  532. OptionHeight = 111 * RESFACTOR;
  533. #else
  534. OptionHeight = 100 * RESFACTOR;
  535. #endif
  536. OptionX = ((SeenBuff.Get_Width() - OptionWidth) / 2);
  537. OptionY = ((SeenBuff.Get_Height() - OptionHeight) / 2);
  538. ButtonWidth = 130 * RESFACTOR;
  539. OButtonHeight = 9 * RESFACTOR;
  540. CaptionYPos = 5 * RESFACTOR;
  541. ButtonY = 21 * RESFACTOR;
  542. Border1Len = 72 * RESFACTOR;
  543. Border2Len = 16 * RESFACTOR;
  544. ButtonResumeY = (OptionHeight - (19 * RESFACTOR));
  545. }