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