CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

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 }