CnC_Remastered_Collection

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

LOADDLG.CPP (28815B)


      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/LOADDLG.CPP 1     3/03/97 10:25a 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 : LOADDLG.CPP                                                  *
     24  *                                                                                             *
     25  *                   Programmer : Maria Legg, Joe Bostic, Bill Randolph                        *
     26  *                                                                                             *
     27  *                   Start Date : March 19, 1995                                               *
     28  *                                                                                             *
     29  *                  Last Update : June 25, 1995 [JLB]                                          *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Functions:                                                                                  *
     33  *   LoadOptionsClass::LoadOptionsClass -- class constructor                                   *
     34  *   LoadOptionsClass::~LoadOptionsClass -- class destructor                                   *
     35  *   LoadOptionsClass::Process -- main processing routine                                      *
     36  *   LoadOptionsClass::Clear_List -- clears the list box & Files arrays                        *
     37  *   LoadOptionsClass::Fill_List -- fills the list box & GameNum arrays                        *
     38  *   LoadOptionsClass::Num_From_Ext -- clears the list box & GameNum arrays                    *
     39  *   LoadOptionsClass::Compare -- for qsort                                                    *
     40  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     41 
     42 #include "function.h"
     43 #include <io.h>				// for unlink
     44 
     45 
     46 /***********************************************************************************************
     47  * LoadOptionsClass::LoadOptionsClass -- class constructor                                     *
     48  *                                                                                             *
     49  * INPUT:                                                                                      *
     50  *      style      style for this load/save dialog (LOAD/SAVE/DELETE)                          *
     51  *                                                                                             *
     52  * OUTPUT:                                                                                     *
     53  *      none.                                                                                  *
     54  *                                                                                             *
     55  * WARNINGS:                                                                                   *
     56  *      none.                                                                                  *
     57  *                                                                                             *
     58  * HISTORY:                                                                                    *
     59  *   02/14/1995 BR : Created.                                                                  *
     60  *=============================================================================================*/
     61 LoadOptionsClass::LoadOptionsClass(LoadStyleType style)
     62 {
     63 	Style = style;
     64 	Files.Clear();
     65 }
     66 
     67 
     68 /***********************************************************************************************
     69  * LoadOptionsClass::~LoadOptionsClass -- class destructor                                     *
     70  *                                                                                             *
     71  * INPUT:                                                                                      *
     72  *      none.                                                                                  *
     73  *                                                                                             *
     74  * OUTPUT:                                                                                     *
     75  *      none.                                                                                  *
     76  *                                                                                             *
     77  * WARNINGS:                                                                                   *
     78  *      none.                                                                                  *
     79  *                                                                                             *
     80  * HISTORY:                                                                                    *
     81  *   02/14/1995 BR : Created.                                                                  *
     82  *=============================================================================================*/
     83 LoadOptionsClass::~LoadOptionsClass()
     84 {
     85 	for (int i = 0; i < Files.Count(); i++) {
     86 		delete Files[i];
     87 	}
     88 	Files.Clear();
     89 }
     90 
     91 
     92 /***********************************************************************************************
     93  * LoadOptionsClass::Process -- main processing routine                                        *
     94  *                                                                                             *
     95  * INPUT:                                                                                      *
     96  *      none.                                                                                  *
     97  *                                                                                             *
     98  * OUTPUT:                                                                                     *
     99  *      false = User cancelled, true = operation completed                                     *
    100  *                                                                                             *
    101  * WARNINGS:                                                                                   *
    102  *      none.                                                                                  *
    103  *                                                                                             *
    104  * HISTORY:                                                                                    *
    105  *   02/14/1995 BR : Created.                                                                  *
    106  *=============================================================================================*/
    107 int LoadOptionsClass::Process(void)
    108 {
    109 	/*
    110 	**	Dialog & button dimensions
    111 	*/
    112 	int d_dialog_w = 250 * RESFACTOR;											// dialog width
    113 	int d_dialog_h = 156 * RESFACTOR;											// dialog height
    114 	int d_dialog_x = (((320 * RESFACTOR) - d_dialog_w) / 2);				// centered x-coord
    115 	int d_dialog_y = (((200 * RESFACTOR) - d_dialog_h) / 2);				// centered y-coord
    116 	int d_dialog_cx = d_dialog_x + (d_dialog_w / 2);		// coord of x-center
    117 
    118 	int d_txt8_h = 11 * RESFACTOR;												// ht of 8-pt text
    119 	int d_margin = 7 * RESFACTOR;												// margin width/height
    120 	int x_margin = 16 * RESFACTOR;												// margin width/height
    121 
    122 	int d_list_w = d_dialog_w - (x_margin * 2);
    123 	int d_list_h = 104 * RESFACTOR;
    124 	int d_list_x = d_dialog_x + x_margin;
    125 	int d_list_y = d_dialog_y + d_margin + d_txt8_h + d_margin;
    126 
    127 	int d_edit_w = d_dialog_w - (x_margin * 2);
    128 	int d_edit_h = 13 * RESFACTOR;
    129 	int d_edit_x = d_dialog_x + x_margin;
    130 	int d_edit_y = d_list_y + d_list_h - (30 * RESFACTOR) + d_margin + d_txt8_h;
    131 
    132 #if (GERMAN | FRENCH)
    133 	int d_button_w = 50 * RESFACTOR;
    134 #else
    135 	int d_button_w = 40 * RESFACTOR;
    136 #endif
    137 	int d_button_h = 13 * RESFACTOR;
    138 	int d_button_x = d_dialog_cx - d_button_w - d_margin;
    139 	int d_button_y = d_dialog_y + d_dialog_h - d_button_h - d_margin;
    140 
    141 #if defined(GERMAN) || defined(FRENCH)
    142 	int d_cancel_w = 60 * RESFACTOR;//BG:40
    143 #else
    144 	int d_cancel_w = 40 * RESFACTOR;
    145 #endif
    146 	int d_cancel_h = 13 * RESFACTOR;
    147 	int d_cancel_x = d_dialog_cx + d_margin;
    148 	int d_cancel_y = d_dialog_y + d_dialog_h - d_cancel_h - d_margin;
    149 
    150 	/*
    151 	**	Button enumerations
    152 	*/
    153 	enum {
    154 		BUTTON_LOAD = 100,
    155 		BUTTON_SAVE,
    156 		BUTTON_DELETE,
    157 		BUTTON_CANCEL,
    158 		BUTTON_LIST,
    159 		BUTTON_EDIT,
    160 	};
    161 
    162 	/*
    163 	**	Redraw values: in order from "top" to "bottom" layer of the dialog
    164 	*/
    165 	typedef enum {
    166 		REDRAW_NONE = 0,
    167 		REDRAW_BUTTONS,
    168 		REDRAW_BACKGROUND,
    169 		REDRAW_ALL = REDRAW_BACKGROUND
    170 	} RedrawType;
    171 
    172 	/*
    173 	**	Dialog variables
    174 	*/
    175 	bool cancel = false;						// true = user cancels
    176 	int list_ht = d_list_h;					// adjusted list box height
    177 
    178 	/*
    179 	**	Other Variables
    180 	*/
    181 	int btn_txt;								// text on the 'OK' button
    182 	int btn_id;									// ID of 'OK' button
    183 	int caption;								// dialog caption
    184 	int game_idx = 0;							// index of game to save/load/etc
    185 	int game_num = 0;							// file number of game to load/save/etc
    186 	char game_descr[DESCRIP_MAX] = {0};				// save-game description
    187 	char fname[_MAX_NAME+_MAX_EXT];							// for generating filename to delete
    188 	int rc;										// return code
    189 
    190 	/*
    191 	**	Buttons
    192 	*/
    193 	ControlClass * commands = NULL;		// the button list
    194 
    195 	switch (Style) {
    196 		case LOAD:
    197 			btn_txt = TXT_LOAD_BUTTON;
    198 			btn_id = BUTTON_LOAD;
    199 			caption = TXT_LOAD_MISSION;
    200 			break;
    201 
    202 		case SAVE:
    203 			btn_txt = TXT_SAVE_BUTTON;
    204 			btn_id = BUTTON_SAVE;
    205 			caption = TXT_SAVE_MISSION;
    206 			list_ht -= 30;
    207 			break;
    208 
    209 		default:
    210 			btn_txt = TXT_DELETE_BUTTON;
    211 			btn_id = BUTTON_DELETE;
    212 			caption = TXT_DELETE_MISSION;
    213 			break;
    214 	}
    215 
    216 	TextButtonClass button (btn_id, btn_txt, TPF_BUTTON, d_button_x, d_button_y, d_button_w);
    217 	TextButtonClass cancelbtn (BUTTON_CANCEL, TXT_CANCEL, TPF_BUTTON, d_cancel_x, d_cancel_y, d_cancel_w);
    218 
    219 	ListClass listbtn (BUTTON_LIST, d_list_x, d_list_y, d_list_w, list_ht,
    220 		TPF_6PT_GRAD | TPF_NOSHADOW,
    221 		MFCD::Retrieve("BTN-UP.SHP"),
    222 		MFCD::Retrieve("BTN-DN.SHP"));
    223 
    224 	EditClass editbtn (BUTTON_EDIT, game_descr, sizeof(game_descr)-4, TPF_6PT_GRAD|TPF_NOSHADOW, d_edit_x, d_edit_y, d_edit_w, -1, EditClass::ALPHANUMERIC);
    225 
    226 	/*
    227 	**	Initialize.
    228 	*/
    229 	Set_Logic_Page(SeenBuff);
    230 
    231 	Fill_List(&listbtn);
    232 
    233 	/*
    234 	**	Do nothing if list is empty.
    235 	*/
    236 	if ((Style == LOAD || Style == WWDELETE) && listbtn.Count()==0) {
    237 		Clear_List(&listbtn);
    238 		WWMessageBox().Process(TXT_NO_SAVES);
    239 		return(false);
    240 	}
    241 
    242 	/*
    243 	**	Create the button list.
    244 	*/
    245 	commands = &button;
    246 	cancelbtn.Add_Tail(*commands);
    247 	listbtn.Add_Tail(*commands);
    248 	if (Style == SAVE) {
    249 		editbtn.Add_Tail(*commands);
    250 		editbtn.Set_Focus();
    251 	}
    252 
    253 	/*
    254 	**	Main Processing Loop.
    255 	*/
    256 	Keyboard->Clear();
    257 	bool firsttime = true;
    258 	bool display = true;
    259 	bool process = true;
    260 	while (process) {
    261 
    262 		/*
    263 		**	Invoke game callback.
    264 		*/
    265 		if (Session.Type == GAME_NORMAL || Session.Type == GAME_SKIRMISH) {
    266 			Call_Back();
    267 		} else {
    268 			if (Main_Loop()) {
    269 				process = false;
    270 				cancel = true;
    271 			}
    272 		}
    273 
    274 		#ifdef WIN32
    275 		/*
    276 		** If we have just received input focus again after running in the background then
    277 		** we need to redraw.
    278 		*/
    279 		if (AllSurfaces.SurfacesRestored) {
    280 			AllSurfaces.SurfacesRestored=FALSE;
    281 			display = true;
    282 		}
    283 		#endif
    284 
    285 		/*
    286 		**	Refresh display if needed.
    287 		*/
    288 		if (display) {
    289 
    290 			/*
    291 			**	Display the dialog box.
    292 			*/
    293 			Hide_Mouse();
    294 			if (display) {
    295 				Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h);
    296 				Draw_Caption(caption, d_dialog_x, d_dialog_y, d_dialog_w);
    297 
    298 				if (Style == SAVE) {
    299 					Fancy_Text_Print(TXT_MISSION_DESCRIPTION, d_dialog_cx,
    300 						d_edit_y - d_txt8_h, GadgetClass::Get_Color_Scheme(), TBLACK, TPF_TEXT | TPF_CENTER);
    301 				}
    302 			}
    303 
    304 			/*
    305 			**	Redraw the buttons.
    306 			*/
    307 			if (display) {
    308 				commands->Flag_List_To_Redraw();
    309 			}
    310 			Show_Mouse();
    311 			display = false;
    312 		}
    313 
    314 		/*
    315 		**	Get user input.
    316 		*/
    317 		KeyNumType input = commands->Input();
    318 
    319 		/*
    320 		**	The first time through the processing loop, set the edit
    321 		**	gadget to have the focus if this is the save dialog. The
    322 		**	focus must be set here since the gadget list has changed
    323 		**	and this change will cause any previous focus setting to be
    324 		**	cleared by the input processing routine.
    325 		*/
    326 		if (firsttime && Style == SAVE) {
    327 			firsttime = false;
    328 			editbtn.Set_Focus();
    329 			editbtn.Flag_To_Redraw();
    330 		}
    331 
    332 		/*
    333 		**	If the <RETURN> key was pressed, then default to the appropriate
    334 		**	action button according to the style of this dialog box.
    335 		*/
    336 		if (input == KN_RETURN || input == (BUTTON_EDIT|KN_BUTTON)) {
    337 			ToggleClass * toggle = NULL;
    338 			switch (Style) {
    339 				case SAVE:
    340 					input = (KeyNumType)(BUTTON_SAVE|KN_BUTTON);
    341 					cancelbtn.Turn_Off();
    342 //					cancelbtn.IsOn = false;
    343 					toggle = (ToggleClass*)commands->Extract_Gadget(BUTTON_SAVE);
    344 					if (toggle != NULL) {
    345 						toggle->Turn_On();
    346 //						toggle->IsOn = true;
    347 						toggle->IsPressed = true;
    348 					}
    349 					break;
    350 
    351 				case LOAD:
    352 					input = (KeyNumType)(BUTTON_LOAD|KN_BUTTON);
    353 //					cancelbtn.IsOn = false;
    354 					cancelbtn.Turn_Off();
    355 					toggle = (ToggleClass *)commands->Extract_Gadget(BUTTON_LOAD);
    356 					if (toggle != NULL) {
    357 						toggle->IsOn = true;
    358 						toggle->IsPressed = true;
    359 					}
    360 					break;
    361 
    362 				case WWDELETE:
    363 					input = (KeyNumType)(BUTTON_DELETE|KN_BUTTON);
    364 //					cancelbtn.IsOn = false;
    365 					cancelbtn.Turn_Off();
    366 					toggle = (ToggleClass *)commands->Extract_Gadget(BUTTON_DELETE);
    367 					if (toggle != NULL) {
    368 						toggle->IsOn = true;
    369 						toggle->IsPressed = true;
    370 					}
    371 					break;
    372 			}
    373 			Hide_Mouse();
    374 			commands->Draw_All(true);
    375 			Show_Mouse();
    376 		}
    377 
    378 		/*
    379 		**	Process input.
    380 		*/
    381 		switch (input) {
    382 			/*
    383 			** Load: if load fails, present a message, and stay in the dialog
    384 			** to allow the user to try another game
    385 			*/
    386 			case (BUTTON_LOAD | KN_BUTTON):
    387 				game_idx = listbtn.Current_Index();
    388 				game_num = Files[game_idx]->Num;
    389 				if (Files[game_idx]->Valid) {
    390 
    391 					/*
    392 					** Start a timer before we load the game
    393 					*/
    394 					CDTimerClass<SystemTimerClass> timer;
    395 //					timer.Start();
    396 					timer = TICKS_PER_SECOND*4;
    397 
    398 					WWMessageBox().Process(TXT_LOADING, TXT_NONE);
    399 					Theme.Fade_Out();
    400 					rc = Load_Game(game_num);
    401 
    402 					/*
    403 					** Make sure the message says on the screen at least 1 second
    404 					*/
    405 					while (timer > 0) {
    406 						Call_Back();
    407 					}
    408 					Keyboard->Clear();
    409 
    410 					if (!rc) {
    411 						WWMessageBox().Process(TXT_ERROR_LOADING_GAME);
    412 					} else {
    413 						Speak(VOX_LOAD1);
    414 						while (Is_Speaking()) {
    415 							Call_Back();
    416 						}
    417 						Hide_Mouse();
    418 						SeenPage.Clear();
    419 						GamePalette.Set();
    420 //						Set_Palette(GamePalette);
    421 						Show_Mouse();
    422 						process = false;
    423 					}
    424 				} else {
    425 					WWMessageBox().Process(TXT_OBSOLETE_SAVEGAME);
    426 				}
    427 				break;
    428 
    429 			/*
    430 			** Save: Save the game & exit the dialog
    431 			*/
    432 			case (BUTTON_EDIT | KN_BUTTON):
    433 
    434 			case (BUTTON_SAVE | KN_BUTTON):
    435 				if (!strlen(game_descr)) {
    436 					WWMessageBox().Process(TXT_MUSTENTER_DESCRIPTION);
    437 					firsttime = true;
    438 					display = true;
    439 					break;
    440 				}
    441 				game_idx = listbtn.Current_Index();
    442 				if (Disk_Space_Available() < SAVE_GAME_DISK_SPACE && game_idx == 0) {
    443 					WWMessageBox().Process(TXT_SPACE_CANT_SAVE);
    444 					firsttime = true;
    445 					display = true;
    446 					break;
    447 				}
    448 
    449 				game_num = Files[game_idx]->Num;
    450 				if (!Save_Game(game_num, game_descr)) {
    451 					WWMessageBox().Process(TXT_ERROR_SAVING_GAME);
    452 				} else {
    453 					Speak(VOX_SAVE1);
    454 					while (Is_Speaking()) {
    455 						Call_Back();
    456 					}
    457 					CDTimerClass<SystemTimerClass> timer;
    458 //					timer.Start();
    459 					timer = TICKS_PER_SECOND*4;
    460 
    461 					WWMessageBox().Process(TXT_GAME_WAS_SAVED, TXT_NONE, TXT_NONE);
    462 
    463 					/*
    464 					**	Delay to let the user read the message
    465 					*/
    466 					while (timer > 0) {
    467 						Call_Back();
    468 					}
    469 					Keyboard->Clear();
    470 				}
    471 				process = false;
    472 				break;
    473 
    474 			/*
    475 			** Delete: delete the file & stay in the dialog, to allow the user
    476 			** to delete multiple files.
    477 			*/
    478 			case (BUTTON_DELETE | KN_BUTTON):
    479 				game_idx = listbtn.Current_Index();
    480 				game_num = Files[game_idx]->Num;
    481 				if (WWMessageBox().Process(TXT_DELETE_FILE_QUERY, TXT_YES, TXT_NO)==0) {
    482 					sprintf(fname, "SAVEGAME.%03d", game_num);
    483 					unlink(fname);
    484 					Clear_List(&listbtn);
    485 					Fill_List(&listbtn);
    486 					if (listbtn.Count() == 0) {
    487 						process = false;
    488 					} else {
    489 						ToggleClass * toggle = (ToggleClass *)commands->Extract_Gadget(BUTTON_DELETE);
    490 						if (toggle != NULL) {
    491 //							toggle->IsOn = false;
    492 							toggle->Turn_Off();
    493 							toggle->IsPressed = false;
    494 							toggle->Flag_To_Redraw();
    495 						}
    496 					}
    497 				}
    498 				display = true;
    499 				break;
    500 
    501 			/*
    502 			** If the user clicks on the list, see if the there is a new current
    503 			** item; if so, and if we're in SAVE mode, copy the list item into
    504 			** the save-game description field.
    505 			*/
    506 			case (BUTTON_LIST | KN_BUTTON):
    507 				if (Style != SAVE) {
    508 					break;
    509 				}
    510 
    511 				if (listbtn.Count() && listbtn.Current_Index() != game_idx) {
    512 					game_idx = listbtn.Current_Index();
    513 
    514 					/*
    515 					** Copy the game's description, UNLESS it's the empty slot; if
    516 					** it is, set the edit buffer to empty.
    517 					*/
    518 					if (game_idx != 0) {
    519 						strcpy(game_descr, listbtn.Get_Item(game_idx));
    520 
    521 						/*
    522 						**	Strip any leading parenthesis off of the description.
    523 						*/
    524 						if (game_descr[0] == '(') {
    525 							char * ptr = strchr(game_descr, ')');
    526 							if (ptr != NULL) {
    527 								strcpy(game_descr, ptr+1);
    528 								strtrim(game_descr);
    529 							}
    530 						}
    531 
    532 					} else {
    533 						game_descr[0] = 0;
    534 					}
    535 					editbtn.Set_Text(game_descr, 40);
    536 				}
    537 				break;
    538 
    539 			/*
    540 			** ESC/Cancel: break
    541 			*/
    542 			case (KN_ESC):
    543 			case (BUTTON_CANCEL | KN_BUTTON):
    544 				cancel = true;
    545 				process = false;
    546 				break;
    547 
    548 			default:
    549 				break;
    550 		}
    551 	}
    552 
    553 	Clear_List(&listbtn);
    554 
    555 	if (cancel) return(false);
    556 
    557 	return(true);
    558 }
    559 
    560 
    561 /***********************************************************************************************
    562  * LoadOptionsClass::Clear_List -- clears the list box & Files arrays                          *
    563  *                                                                                             *
    564  * This step is essential, because it frees all the strings allocated for list items.          *
    565  *                                                                                             *
    566  * INPUT:                                                                                      *
    567  *      none.                                                                                  *
    568  *                                                                                             *
    569  * OUTPUT:                                                                                     *
    570  *      none.                                                                                  *
    571  *                                                                                             *
    572  * WARNINGS:                                                                                   *
    573  *      none.                                                                                  *
    574  *                                                                                             *
    575  * HISTORY:                                                                                    *
    576  *   02/14/1995 BR : Created.                                                                  *
    577  *=============================================================================================*/
    578 void LoadOptionsClass::Clear_List(ListClass * list)
    579 {
    580 	/*
    581 	** For every item in the list, free its buffer & remove it from the list.
    582 	*/
    583 	int j = list->Count();
    584 	for (int i = 0; i < j; i++) {
    585 		list->Remove_Item(list->Get_Item(0));
    586 	}
    587 
    588 	/*
    589 	** Clear the array of game numbers
    590 	*/
    591 	for (int i = 0; i < Files.Count(); i++) {
    592 		delete Files[i];
    593 	}
    594 	Files.Clear();
    595 }
    596 
    597 
    598 /***********************************************************************************************
    599  * LoadOptionsClass::Fill_List -- fills the list box & GameNum arrays                          *
    600  *                                                                                             *
    601  * INPUT:                                                                                      *
    602  *      none.                                                                                  *
    603  *                                                                                             *
    604  * OUTPUT:                                                                                     *
    605  *      none.                                                                                  *
    606  *                                                                                             *
    607  * WARNINGS:                                                                                   *
    608  *      none.                                                                                  *
    609  *                                                                                             *
    610  * HISTORY:                                                                                    *
    611  *   02/14/1995 BR : Created.                                                                  *
    612  *   06/25/1995 JLB : Shows which saved games are "(old)".                                     *
    613  *=============================================================================================*/
    614 void LoadOptionsClass::Fill_List(ListClass * list)
    615 {
    616 #if(0)		//PG
    617 	FileEntryClass * fdata;	// for adding entries to 'Files'
    618 	char descr[DESCRIP_MAX+32];
    619 	unsigned scenario;			// scenario #
    620 	HousesType house;				// house
    621 	struct find_t ff;		// for _dos_findfirst
    622 	int id;
    623 
    624 	/*
    625 	** Make sure the list is empty
    626 	*/
    627 	Clear_List(list);
    628 
    629 	/*
    630 	** Add the Empty Slot entry
    631 	*/
    632 	if (Style == SAVE) {
    633 		fdata = new FileEntryClass;
    634 		strcpy(fdata->Descr, Text_String(TXT_EMPTY_SLOT));
    635 		fdata->DateTime = 0xffffffff;	// will always be first
    636 		Files.Add(fdata);
    637 	}
    638 
    639 	/*
    640 	** Find all savegame files
    641 	*/
    642 	int rc = _dos_findfirst("SAVEGAME.*", _A_NORMAL, &ff);
    643 
    644 	while (!rc) {
    645 
    646 		if (stricmp(ff.name, NET_SAVE_FILE_NAME) != 0) {
    647 
    648 			/*
    649 			** Extract the game ID from the filename
    650 			*/
    651 			id = Num_From_Ext(ff.name);
    652 
    653 			/*
    654 			** get the game's info; if success, add it to the list
    655 			*/
    656 			bool ok = Get_Savefile_Info(id, descr, &scenario, &house);
    657 
    658 			fdata = new FileEntryClass;
    659 
    660 			fdata->Descr[0] = '\0';
    661 			if (!ok) {
    662 				strcpy(fdata->Descr, Text_String(TXT_OLD_GAME));
    663 			} else {
    664 				if (house == HOUSE_USSR || house == HOUSE_UKRAINE) {
    665 #ifdef WIN32
    666 					sprintf(fdata->Descr, "(%s) ", Text_String(TXT_SOVIET));
    667 #else
    668 					sprintf(fdata->Descr, "(%c) ", *Text_String(TXT_SOVIET));
    669 #endif
    670 				} else {
    671 #ifdef WIN32
    672 					sprintf(fdata->Descr, "(%s) ", Text_String(TXT_ALLIES));
    673 #else
    674 					sprintf(fdata->Descr, "(%c) ", *Text_String(TXT_ALLIES));
    675 #endif
    676 				}
    677 			}
    678 			strncat(fdata->Descr, descr, (sizeof(fdata->Descr)-strlen(fdata->Descr))-1);
    679 			fdata->Valid = ok;
    680 			fdata->Scenario = scenario;
    681 			fdata->House = house;
    682 			fdata->Num = id;
    683 			fdata->DateTime = (((unsigned long)ff.wr_date) << 16) | (unsigned long)ff.wr_time;
    684 			Files.Add(fdata);
    685 		}
    686 
    687 		/*
    688 		** Find the next file
    689 		*/
    690 		rc = _dos_findnext(&ff);
    691 	}
    692 
    693 	/*
    694 	** If saving a game, determine a unique file ID for the empty slot
    695 	*/
    696 	if (Style == SAVE) {
    697 		/*
    698 		** Find an un-used number to associate with the Empty Slot by looking in
    699 		** GameNum for each number from 0 to 'N', where 'N' is the # of entries
    700 		** in the list; if any number isn't found, use that number; otherwise,
    701 		** use 'N + 1'.
    702 		*/
    703 		for (int i = 0; i < Files.Count(); i++) {		// i = the # we're searching for
    704 			id = -1;											// mark as 'not found'
    705 			for (int j = 0; j < Files.Count(); j++) {	// loop through all game ID's
    706 				if (Files[j]->Num==i) {					// if found, mark as found
    707 					id = j;
    708 					break;
    709 				}
    710 			}
    711 			if (id == -1)	break;							// if ID not found, use this one
    712 		}
    713 
    714 		Files[0]->Num = i;								// set the empty slot's ID
    715 	}
    716 
    717 	/*
    718 	** Now sort the list in order of Date/Time (newest first, oldest last)
    719 	*/
    720 	qsort((void *)(&Files[0]), Files.Count(), sizeof(class FileEntryClass *), LoadOptionsClass::Compare);
    721 
    722 	/*
    723 	** Now add every file's name to the list box
    724 	*/
    725 	for (int i = 0; i < Files.Count(); i++) {
    726 		list->Add_Item(Files[i]->Descr);
    727 	}
    728 #endif
    729 }
    730 
    731 
    732 /***********************************************************************************************
    733  * LoadOptionsClass::Num_From_Ext -- clears the list box & GameNum arrays                      *
    734  *                                                                                             *
    735  * INPUT:                                                                                      *
    736  *      fname      filename to parse                                                           *
    737  *                                                                                             *
    738  * OUTPUT:                                                                                     *
    739  *      File number for this name.                                                             *
    740  *                                                                                             *
    741  * WARNINGS:                                                                                   *
    742  *      none.                                                                                  *
    743  *                                                                                             *
    744  * HISTORY:                                                                                    *
    745  *   02/14/1995 BR : Created.                                                                  *
    746  *=============================================================================================*/
    747 int LoadOptionsClass::Num_From_Ext(char * fname)
    748 {
    749 	char ext[_MAX_EXT];
    750 
    751 	_splitpath(fname, NULL, NULL, NULL, ext);
    752 	int num = atoi(ext + 1);		// skip the '.'
    753 	return(num);
    754 }
    755 
    756 
    757 /***********************************************************************************************
    758  * LoadOptionsClass::Compare -- for qsort                                                      *
    759  *                                                                                             *
    760  * INPUT:                                                                                      *
    761  *      p1,p2      ptrs to elements to compare                                                 *
    762  *                                                                                             *
    763  * OUTPUT:                                                                                     *
    764  *      0 = same, -1 = (*p1) goes BEFORE (*p2), 1 = (*p1) goes AFTER (*p2)                     *
    765  *                                                                                             *
    766  * WARNINGS:                                                                                   *
    767  *      none.                                                                                  *
    768  *                                                                                             *
    769  * HISTORY:                                                                                    *
    770  *   02/14/1995 BR : Created.                                                                  *
    771  *=============================================================================================*/
    772 int LoadOptionsClass::Compare(const void * p1, const void * p2)
    773 {
    774 	class FileEntryClass * fe1, * fe2;
    775 
    776 	fe1 = *((class FileEntryClass **)p1);
    777 	fe2 = *((class FileEntryClass **)p2);
    778 
    779 	if (fe1->DateTime > fe2->DateTime) return(-1);
    780 	if (fe1->DateTime < fe2->DateTime) return(1);
    781 	return(0);
    782 }
    783