GOPTIONS.CPP 17 KB

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