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