GOPTIONS.CPP 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  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: F:\projects\c&c\vcs\code\goptions.cpv 2.17 16 Oct 1995 16:50:26 JOE_BOSTIC $ */
  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. * Draw_Caption -- Draws a caption on a dialog box. *
  33. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  34. #include "function.h"
  35. #include "goptions.h"
  36. #include "loaddlg.h"
  37. #include "sounddlg.h"
  38. #include "visudlg.h"
  39. #include "gamedlg.h"
  40. #include "textbtn.h"
  41. #include "confdlg.h"
  42. #include "descdlg.h"
  43. void GameOptionsClass::Adjust_Variables_For_Resolution(void)
  44. {
  45. int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2;
  46. OptionWidth = (216+8) * factor;
  47. OptionHeight = 100 * factor;
  48. OptionX = ((SeenBuff.Get_Width() - OptionWidth) / 2);
  49. OptionY = ((SeenBuff.Get_Height() - OptionHeight) / 2);
  50. ButtonWidth = 130 * factor;
  51. OButtonHeight = 9 * factor;
  52. CaptionYPos = 5 * factor;
  53. ButtonY = 21 * factor;
  54. Border1Len = 72 * factor;
  55. Border2Len = 16 * factor;
  56. ButtonResumeY = (OptionHeight - (15 * factor));
  57. }
  58. /***********************************************************************************************
  59. * OptionsClass::Process -- Handles all the options graphic interface. *
  60. * *
  61. * This routine is the main control for the visual representation of the options *
  62. * screen. It handles the visual overlay and the player input. *
  63. * *
  64. * INPUT: none *
  65. * *
  66. * OUTPUT: none *
  67. * *
  68. * WARNINGS: none *
  69. * *
  70. * HISTORY: 12/31/1994 MML : Created. *
  71. * 06/23/1995 JLB : Handles restating the mission objective. *
  72. * 07/27/1995 JLB : Adjusts menu for multiplay mode. *
  73. *=============================================================================================*/
  74. void GameOptionsClass::Process(void)
  75. {
  76. static struct {
  77. int ID; // Button ID to use.
  78. int Text; // Text number to use for this button.
  79. bool Multiplay; // Allowed in multiplayer version?
  80. } _constants[] = {
  81. {BUTTON_LOAD, TXT_LOAD_MISSION, false},
  82. {BUTTON_SAVE, TXT_SAVE_MISSION, false},
  83. {BUTTON_DELETE, TXT_DELETE_MISSION, true},
  84. {BUTTON_GAME, TXT_GAME_CONTROLS, true},
  85. {BUTTON_QUIT, TXT_QUIT_MISSION, true},
  86. {BUTTON_RESUME, TXT_RESUME_MISSION, true},
  87. {BUTTON_RESTATE, TXT_RESTATE_MISSION, false},
  88. };
  89. /*
  90. ** Variables.
  91. */
  92. TextButtonClass * buttons = 0;
  93. int selection;
  94. bool pressed;
  95. int curbutton = 6;
  96. int y;
  97. TextButtonClass *buttonsel[sizeof(_constants)/sizeof(_constants[0])];
  98. Set_Logic_Page(SeenBuff);
  99. /*
  100. ** Build the button list for all of the buttons for this dialog.
  101. */
  102. int maxwidth = 0;
  103. int resfactor = (SeenBuff.Get_Width() == 320) ? 1 : 2;
  104. for (int index = 0; index < sizeof(_constants)/sizeof(_constants[0]); index++ ) {
  105. int text = _constants[index].Text;
  106. buttonsel[index] = NULL;
  107. if (GameToPlay != GAME_NORMAL && !_constants[index].Multiplay) {
  108. buttonsel[index] = 0;
  109. continue;
  110. }
  111. if (GameToPlay != GAME_NORMAL && text == TXT_DELETE_MISSION) {
  112. text = TXT_RESIGN;
  113. }
  114. if (index < 5) {
  115. y = (SeenBuff.Get_Height() - OptionHeight)/2 + ButtonY + ((OButtonHeight+2) * index);
  116. } else {
  117. y = OptionY + ButtonResumeY;
  118. }
  119. TextButtonClass * g = new TextButtonClass(_constants[index].ID,
  120. text, TPF_6PT_GRAD|TPF_NOSHADOW, 0, y);
  121. if (g->Width > maxwidth) {
  122. maxwidth = g->Width;
  123. }
  124. if (!buttons) {
  125. buttons = g;
  126. } else {
  127. g->Add_Tail(*buttons);
  128. }
  129. buttonsel[index] = g;
  130. }
  131. buttonsel[curbutton-1]->Turn_On();
  132. /*
  133. ** Force all button lengths to match the maximum length of the widest button.
  134. */
  135. GadgetClass * g = buttons;
  136. while (g) {
  137. g->Width = MAX(maxwidth, 90 * resfactor);
  138. g->X = OptionX+(OptionWidth-g->Width)/2;
  139. g = g->Get_Next();
  140. }
  141. #ifdef FRENCH
  142. buttonsel[BUTTON_RESUME-1]->Width = 104 *resfactor;
  143. #else
  144. buttonsel[BUTTON_RESUME-1]->Width = 90 *resfactor;
  145. #endif
  146. buttonsel[BUTTON_RESUME-1]->X = OptionX+(5 * resfactor);
  147. if (GameToPlay == GAME_NORMAL) {
  148. buttonsel[BUTTON_RESTATE-1]->Width = 90 * resfactor;
  149. buttonsel[BUTTON_RESTATE-1]->X = OptionX+OptionWidth-(buttonsel[BUTTON_RESTATE-1]->Width+(5 * resfactor));
  150. }
  151. /*
  152. ** This causes left mouse button clicking within the confines of the dialog to
  153. ** be ignored if it wasn't recognized by any other button or slider.
  154. */
  155. (new GadgetClass(OptionX, OptionY, OptionWidth, OptionHeight, GadgetClass::LEFTPRESS))->Add_Tail(*buttons);
  156. /*
  157. ** This cause a right click anywhere or a left click outside the dialog region
  158. ** to be equivalent to clicking on the return to game button.
  159. */
  160. (new ControlClass(BUTTON_RESUME, 0, 0, SeenBuff.Get_Width(), SeenBuff.Get_Height(), GadgetClass::LEFTPRESS|GadgetClass::RIGHTPRESS))->Add_Tail(*buttons);
  161. Keyboard::Clear();
  162. Fancy_Text_Print(TXT_NONE, 0, 0, CC_GREEN, TBLACK, TPF_CENTER|TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_NOSHADOW);
  163. /*
  164. ** Main Processing Loop.
  165. */
  166. bool display = true;
  167. bool process = true;
  168. pressed = false;
  169. while (process) {
  170. /*
  171. ** If we have just received input focus again after running in the background then
  172. ** we need to redraw.
  173. */
  174. if (AllSurfaces.SurfacesRestored){
  175. AllSurfaces.SurfacesRestored=FALSE;
  176. display=TRUE;
  177. }
  178. /*
  179. ** Invoke game callback.
  180. */
  181. if (GameToPlay == GAME_NORMAL) {
  182. Call_Back();
  183. } else {
  184. if (Main_Loop()) {
  185. process = false;
  186. }
  187. }
  188. /*
  189. ** Refresh display if needed.
  190. */
  191. if (display) {
  192. /*
  193. ** Redraw the map.
  194. */
  195. HiddenPage.Clear();
  196. Map.Flag_To_Redraw(true);
  197. Map.Render();
  198. /*
  199. ** Reset up the window. Window x-coords are in bytes not pixels.
  200. */
  201. Set_Window(WINDOW_EDITOR, OptionX, OptionY, OptionWidth, OptionHeight);
  202. Hide_Mouse();
  203. /*
  204. ** Draw the background.
  205. */
  206. Window_Box (WINDOW_EDITOR, BOXSTYLE_GREEN_BORDER); // has border, raised up
  207. /*
  208. ** Draw the arrows border if requested.
  209. */
  210. Draw_Caption(TXT_OPTIONS, OptionX, OptionY, OptionWidth);
  211. /*
  212. ** Display the version number at the bottom of the dialog box.
  213. */
  214. #ifdef DEMO
  215. Version_Number();
  216. Fancy_Text_Print("DEMO%s",
  217. ((WindowList[WINDOW_EDITOR][WINDOWX]+WindowList[WINDOW_EDITOR][WINDOWWIDTH])<<3)-3*resfactor,
  218. WindowList[WINDOW_EDITOR][WINDOWY]+WindowList[WINDOW_EDITOR][WINDOWHEIGHT]-((GameToPlay == GAME_NORMAL) ? (32*resfactor) : (24*resfactor)),
  219. DKGREY, TBLACK,
  220. TPF_6POINT|TPF_NOSHADOW|TPF_RIGHT,
  221. ScenarioName,
  222. VersionText);
  223. #else
  224. Fancy_Text_Print("%s\rV.%d%s",
  225. ((WindowList[WINDOW_EDITOR][WINDOWX]+WindowList[WINDOW_EDITOR][WINDOWWIDTH])<<3)-3*resfactor,
  226. WindowList[WINDOW_EDITOR][WINDOWY]+WindowList[WINDOW_EDITOR][WINDOWHEIGHT]-((GameToPlay == GAME_NORMAL) ? (32*resfactor) : (24*resfactor)),
  227. DKGREY, TBLACK,
  228. TPF_6POINT|TPF_NOSHADOW|TPF_RIGHT,
  229. ScenarioName,
  230. Version_Number(),
  231. VersionText);
  232. #endif
  233. buttons->Draw_All();
  234. TabClass::Hilite_Tab(0);
  235. Show_Mouse();
  236. display = false;
  237. }
  238. /*
  239. ** Get user input.
  240. */
  241. KeyNumType input = buttons->Input();
  242. /*
  243. ** Process Input.
  244. */
  245. switch (input) {
  246. case (BUTTON_RESTATE | KN_BUTTON):
  247. selection = BUTTON_RESTATE;
  248. pressed = true;
  249. break;
  250. case (BUTTON_LOAD | KN_BUTTON):
  251. selection = BUTTON_LOAD;
  252. pressed = true;
  253. break;
  254. case (BUTTON_SAVE | KN_BUTTON):
  255. selection = BUTTON_SAVE;
  256. pressed = true;
  257. break;
  258. case (BUTTON_DELETE | KN_BUTTON):
  259. selection = BUTTON_DELETE;
  260. pressed = true;
  261. break;
  262. case (BUTTON_QUIT | KN_BUTTON):
  263. selection = BUTTON_QUIT;
  264. pressed = true;
  265. break;
  266. case (BUTTON_GAME | KN_BUTTON):
  267. selection = BUTTON_GAME;
  268. pressed = true;
  269. break;
  270. case (KN_ESC):
  271. case (BUTTON_RESUME | KN_BUTTON):
  272. selection = BUTTON_RESUME;
  273. pressed = true;
  274. break;
  275. case (KN_UP):
  276. buttonsel[curbutton-1]->Turn_Off();
  277. buttonsel[curbutton-1]->Flag_To_Redraw();
  278. curbutton--;
  279. if (GameToPlay == GAME_NORMAL) {
  280. if (curbutton < BUTTON_LOAD) {
  281. curbutton = (BUTTON_COUNT - 1);
  282. }
  283. } else {
  284. if (curbutton < BUTTON_DELETE) {
  285. curbutton = BUTTON_RESUME;
  286. // curbutton = (BUTTON_COUNT-1);
  287. }
  288. }
  289. buttonsel[curbutton-1]->Turn_On();
  290. buttonsel[curbutton-1]->Flag_To_Redraw();
  291. break;
  292. case (KN_DOWN):
  293. buttonsel[curbutton-1]->Turn_Off();
  294. buttonsel[curbutton-1]->Flag_To_Redraw();
  295. curbutton++;
  296. if (GameToPlay == GAME_NORMAL) {
  297. if (curbutton >= BUTTON_COUNT) {
  298. curbutton = BUTTON_LOAD;
  299. }
  300. } else {
  301. if (curbutton > BUTTON_RESUME) {
  302. curbutton = BUTTON_DELETE;
  303. }
  304. }
  305. buttonsel[curbutton-1]->Turn_On();
  306. buttonsel[curbutton-1]->Flag_To_Redraw();
  307. break;
  308. case (KN_RETURN):
  309. buttonsel[curbutton-1]->IsPressed = true;
  310. buttonsel[curbutton-1]->Draw_Me(true);
  311. selection = curbutton;
  312. pressed = true;
  313. break;
  314. default:
  315. break;
  316. }
  317. if (pressed) {
  318. buttonsel[curbutton-1]->Turn_Off();
  319. buttonsel[curbutton-1]->Flag_To_Redraw();
  320. curbutton = selection;
  321. buttonsel[curbutton-1]->Turn_On();
  322. buttonsel[curbutton-1]->Flag_To_Redraw();
  323. switch (selection) {
  324. case BUTTON_RESTATE:
  325. display = true;
  326. #ifdef JAPANESE
  327. if (!Restate_Mission(ScenarioName, TXT_VIDEO, TXT_TAB_BUTTON_CONTROLS)) {
  328. #else
  329. if (!Restate_Mission(ScenarioName, TXT_VIDEO, TXT_OPTIONS)) {
  330. #endif
  331. BreakoutAllowed = true;
  332. char buffer[25];
  333. sprintf(buffer, "%s.VQA", BriefMovie);
  334. if (CCFileClass(buffer).Is_Available()) {
  335. Play_Movie(BriefMovie);
  336. } else {
  337. Play_Movie(ActionMovie);
  338. }
  339. //BreakoutAllowed = false;
  340. memset(BlackPalette, 0x01, 768);
  341. Set_Palette(BlackPalette);
  342. memset(BlackPalette, 0x00, 768);
  343. Set_Palette(BlackPalette);
  344. Map.Flag_To_Redraw(true);
  345. Theme.Queue_Song(THEME_PICK_ANOTHER);
  346. process = false;
  347. }
  348. break;
  349. case (BUTTON_LOAD):
  350. display = true;
  351. if (LoadOptionsClass(LoadOptionsClass::LOAD).Process()) {
  352. process = false;
  353. }
  354. break;
  355. case (BUTTON_SAVE):
  356. display = true;
  357. LoadOptionsClass(LoadOptionsClass::SAVE).Process();
  358. break;
  359. case (BUTTON_DELETE):
  360. display = true;
  361. if (GameToPlay != GAME_NORMAL) {
  362. if (Surrender_Dialog()) {
  363. OutList.Add(EventClass(EventClass::DESTRUCT));
  364. }
  365. process = false;
  366. } else {
  367. LoadOptionsClass(LoadOptionsClass::WWDELETE).Process();
  368. }
  369. break;
  370. case (BUTTON_QUIT):
  371. if (GameToPlay == GAME_NORMAL) {
  372. #ifdef JAPANESE
  373. switch (CCMessageBox().Process(TXT_CONFIRM_EXIT, TXT_YES, TXT_NO, TXT_RESTART)) {
  374. #else
  375. switch (CCMessageBox().Process(TXT_CONFIRM_EXIT, TXT_ABORT, TXT_CANCEL, TXT_RESTART)) {
  376. #endif
  377. case 2:
  378. display = true;
  379. break;
  380. case 0:
  381. process = false;
  382. Queue_Exit();
  383. break;
  384. case 1:
  385. PlayerRestarts = true;
  386. process = false;
  387. break;
  388. }
  389. } else {
  390. if (ConfirmationClass().Process(TXT_CONFIRM_EXIT)) {
  391. process = false;
  392. Queue_Exit();
  393. } else {
  394. display = true;
  395. }
  396. }
  397. break;
  398. case (BUTTON_GAME):
  399. display = true;
  400. GameControlsClass().Process();
  401. break;
  402. case (BUTTON_RESUME):
  403. //Save_Settings();
  404. process = false;
  405. display = true;
  406. break;
  407. }
  408. pressed = false;
  409. buttonsel[curbutton-1]->IsPressed = false;
  410. //buttonsel[curbutton-1]->Turn_Off();
  411. buttonsel[curbutton-1]->Turn_On();
  412. buttonsel[curbutton-1]->Flag_To_Redraw();
  413. }
  414. }
  415. /*
  416. ** Clean up and re-enter the game.
  417. */
  418. buttons->Delete_List();
  419. /*
  420. ** Redraw the map.
  421. */
  422. Keyboard::Clear();
  423. Call_Back();
  424. HiddenPage.Clear();
  425. Call_Back();
  426. Map.Flag_To_Redraw(true);
  427. Map.Render();
  428. }
  429. /***********************************************************************************************
  430. * Draw_Caption -- Draws a caption on a dialog box. *
  431. * *
  432. * This routine draws the caption text and any fancy filigree that the dialog may require. *
  433. * *
  434. * INPUT: text -- The text of the caption. This is the text number. *
  435. * *
  436. * x,y -- The dialog box X and Y pixel coordinate of the upper left corner. *
  437. * *
  438. * w -- The width of the dialog box (in pixels). *
  439. * *
  440. * OUTPUT: none *
  441. * *
  442. * WARNINGS: none *
  443. * *
  444. * HISTORY: *
  445. * 06/23/1995 JLB : Created. *
  446. *=============================================================================================*/
  447. void Draw_Caption(int text, int x, int y, int w)
  448. {
  449. OptionControlType option = OPTION_NONE;
  450. int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2;
  451. /*
  452. ** Determine the filigree to use depending on the text of the caption.
  453. */
  454. switch (text) {
  455. case TXT_GAME_CONTROLS:
  456. case TXT_OPTIONS:
  457. option = OPTION_CONTROLS;
  458. break;
  459. case TXT_LOAD_MISSION:
  460. case TXT_SAVE_MISSION:
  461. case TXT_DELETE_MISSION:
  462. option = OPTION_DELETE;
  463. break;
  464. case TXT_NONE:
  465. case TXT_MODEM_SERIAL:
  466. case TXT_SELECT_MPLAYER_GAME:
  467. case TXT_SELECT_SERIAL_GAME:
  468. option = OPTION_DIALOG;
  469. break;
  470. case TXT_HOST_SERIAL_GAME:
  471. case TXT_JOIN_SERIAL_GAME:
  472. option = OPTION_SERIAL;
  473. break;
  474. case TXT_SETTINGS:
  475. case TXT_PHONE_LIST:
  476. case TXT_PHONE_LISTING:
  477. option = OPTION_PHONE;
  478. break;
  479. case TXT_JOIN_NETWORK_GAME:
  480. option = OPTION_JOIN_NETWORK;
  481. break;
  482. case TXT_NETGAME_SETUP:
  483. option = OPTION_NETWORK;
  484. break;
  485. case TXT_VISUAL_CONTROLS:
  486. option = OPTION_VISUAL;
  487. break;
  488. case TXT_SOUND_CONTROLS:
  489. option = OPTION_SOUND;
  490. break;
  491. default:
  492. option = OPTION_DIALOG;
  493. break;
  494. }
  495. /*
  496. ** Draw the filigree at the corners of the dialog.
  497. */
  498. if (option != OPTION_NONE) {
  499. CC_Draw_Shape(MixFileClass::Retrieve("OPTIONS.SHP"), (int)option, x+12, y+11, WINDOW_MAIN, SHAPE_CENTER);
  500. CC_Draw_Shape(MixFileClass::Retrieve("OPTIONS.SHP"), (int)option+1, x+w-14, y+11, WINDOW_MAIN, SHAPE_CENTER);
  501. }
  502. /*
  503. ** Draw the caption.
  504. */
  505. if (text != TXT_NONE) {
  506. Fancy_Text_Print(text, w/2 + x, 5*factor + y, CC_GREEN, TBLACK, TPF_CENTER|TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_NOSHADOW);
  507. int length = String_Pixel_Width(Text_String(text));
  508. LogicPage->Draw_Line((x+(w/2))-(length/2), y+FontHeight+FontYSpacing + 5*factor, (x+(w/2))+(length/2), y+FontHeight+FontYSpacing + 5*factor, CC_GREEN);
  509. }
  510. }