784 lines
28 KiB
C++
784 lines
28 KiB
C++
//
|
|
// Copyright 2020 Electronic Arts Inc.
|
|
//
|
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
|
|
// software: you can redistribute it and/or modify it under the terms of
|
|
// the GNU General Public License as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
|
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
|
|
// in the hope that it will be useful, but with permitted additional restrictions
|
|
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
|
|
// distributed with this program. You should have received a copy of the
|
|
// GNU General Public License along with permitted additional restrictions
|
|
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
|
|
|
|
/* $Header: /CounterStrike/LOADDLG.CPP 1 3/03/97 10:25a Joe_bostic $ */
|
|
/***********************************************************************************************
|
|
*** 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 ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : Command & Conquer *
|
|
* *
|
|
* File Name : LOADDLG.CPP *
|
|
* *
|
|
* Programmer : Maria Legg, Joe Bostic, Bill Randolph *
|
|
* *
|
|
* Start Date : March 19, 1995 *
|
|
* *
|
|
* Last Update : June 25, 1995 [JLB] *
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* LoadOptionsClass::LoadOptionsClass -- class constructor *
|
|
* LoadOptionsClass::~LoadOptionsClass -- class destructor *
|
|
* LoadOptionsClass::Process -- main processing routine *
|
|
* LoadOptionsClass::Clear_List -- clears the list box & Files arrays *
|
|
* LoadOptionsClass::Fill_List -- fills the list box & GameNum arrays *
|
|
* LoadOptionsClass::Num_From_Ext -- clears the list box & GameNum arrays *
|
|
* LoadOptionsClass::Compare -- for qsort *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include "function.h"
|
|
#include <io.h> // for unlink
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LoadOptionsClass::LoadOptionsClass -- class constructor *
|
|
* *
|
|
* INPUT: *
|
|
* style style for this load/save dialog (LOAD/SAVE/DELETE) *
|
|
* *
|
|
* OUTPUT: *
|
|
* none. *
|
|
* *
|
|
* WARNINGS: *
|
|
* none. *
|
|
* *
|
|
* HISTORY: *
|
|
* 02/14/1995 BR : Created. *
|
|
*=============================================================================================*/
|
|
LoadOptionsClass::LoadOptionsClass(LoadStyleType style)
|
|
{
|
|
Style = style;
|
|
Files.Clear();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LoadOptionsClass::~LoadOptionsClass -- class destructor *
|
|
* *
|
|
* INPUT: *
|
|
* none. *
|
|
* *
|
|
* OUTPUT: *
|
|
* none. *
|
|
* *
|
|
* WARNINGS: *
|
|
* none. *
|
|
* *
|
|
* HISTORY: *
|
|
* 02/14/1995 BR : Created. *
|
|
*=============================================================================================*/
|
|
LoadOptionsClass::~LoadOptionsClass()
|
|
{
|
|
for (int i = 0; i < Files.Count(); i++) {
|
|
delete Files[i];
|
|
}
|
|
Files.Clear();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LoadOptionsClass::Process -- main processing routine *
|
|
* *
|
|
* INPUT: *
|
|
* none. *
|
|
* *
|
|
* OUTPUT: *
|
|
* false = User cancelled, true = operation completed *
|
|
* *
|
|
* WARNINGS: *
|
|
* none. *
|
|
* *
|
|
* HISTORY: *
|
|
* 02/14/1995 BR : Created. *
|
|
*=============================================================================================*/
|
|
int LoadOptionsClass::Process(void)
|
|
{
|
|
/*
|
|
** Dialog & button dimensions
|
|
*/
|
|
int d_dialog_w = 250 * RESFACTOR; // dialog width
|
|
int d_dialog_h = 156 * RESFACTOR; // dialog height
|
|
int d_dialog_x = (((320 * RESFACTOR) - d_dialog_w) / 2); // centered x-coord
|
|
int d_dialog_y = (((200 * RESFACTOR) - d_dialog_h) / 2); // centered y-coord
|
|
int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // coord of x-center
|
|
|
|
int d_txt8_h = 11 * RESFACTOR; // ht of 8-pt text
|
|
int d_margin = 7 * RESFACTOR; // margin width/height
|
|
int x_margin = 16 * RESFACTOR; // margin width/height
|
|
|
|
int d_list_w = d_dialog_w - (x_margin * 2);
|
|
int d_list_h = 104 * RESFACTOR;
|
|
int d_list_x = d_dialog_x + x_margin;
|
|
int d_list_y = d_dialog_y + d_margin + d_txt8_h + d_margin;
|
|
|
|
int d_edit_w = d_dialog_w - (x_margin * 2);
|
|
int d_edit_h = 13 * RESFACTOR;
|
|
int d_edit_x = d_dialog_x + x_margin;
|
|
int d_edit_y = d_list_y + d_list_h - (30 * RESFACTOR) + d_margin + d_txt8_h;
|
|
|
|
#if (GERMAN | FRENCH)
|
|
int d_button_w = 50 * RESFACTOR;
|
|
#else
|
|
int d_button_w = 40 * RESFACTOR;
|
|
#endif
|
|
int d_button_h = 13 * RESFACTOR;
|
|
int d_button_x = d_dialog_cx - d_button_w - d_margin;
|
|
int d_button_y = d_dialog_y + d_dialog_h - d_button_h - d_margin;
|
|
|
|
#if defined(GERMAN) || defined(FRENCH)
|
|
int d_cancel_w = 60 * RESFACTOR;//BG:40
|
|
#else
|
|
int d_cancel_w = 40 * RESFACTOR;
|
|
#endif
|
|
int d_cancel_h = 13 * RESFACTOR;
|
|
int d_cancel_x = d_dialog_cx + d_margin;
|
|
int d_cancel_y = d_dialog_y + d_dialog_h - d_cancel_h - d_margin;
|
|
|
|
/*
|
|
** Button enumerations
|
|
*/
|
|
enum {
|
|
BUTTON_LOAD = 100,
|
|
BUTTON_SAVE,
|
|
BUTTON_DELETE,
|
|
BUTTON_CANCEL,
|
|
BUTTON_LIST,
|
|
BUTTON_EDIT,
|
|
};
|
|
|
|
/*
|
|
** Redraw values: in order from "top" to "bottom" layer of the dialog
|
|
*/
|
|
typedef enum {
|
|
REDRAW_NONE = 0,
|
|
REDRAW_BUTTONS,
|
|
REDRAW_BACKGROUND,
|
|
REDRAW_ALL = REDRAW_BACKGROUND
|
|
} RedrawType;
|
|
|
|
/*
|
|
** Dialog variables
|
|
*/
|
|
bool cancel = false; // true = user cancels
|
|
int list_ht = d_list_h; // adjusted list box height
|
|
|
|
/*
|
|
** Other Variables
|
|
*/
|
|
int btn_txt; // text on the 'OK' button
|
|
int btn_id; // ID of 'OK' button
|
|
int caption; // dialog caption
|
|
int game_idx = 0; // index of game to save/load/etc
|
|
int game_num = 0; // file number of game to load/save/etc
|
|
char game_descr[DESCRIP_MAX] = {0}; // save-game description
|
|
char fname[_MAX_NAME+_MAX_EXT]; // for generating filename to delete
|
|
int rc; // return code
|
|
|
|
/*
|
|
** Buttons
|
|
*/
|
|
ControlClass * commands = NULL; // the button list
|
|
|
|
switch (Style) {
|
|
case LOAD:
|
|
btn_txt = TXT_LOAD_BUTTON;
|
|
btn_id = BUTTON_LOAD;
|
|
caption = TXT_LOAD_MISSION;
|
|
break;
|
|
|
|
case SAVE:
|
|
btn_txt = TXT_SAVE_BUTTON;
|
|
btn_id = BUTTON_SAVE;
|
|
caption = TXT_SAVE_MISSION;
|
|
list_ht -= 30;
|
|
break;
|
|
|
|
default:
|
|
btn_txt = TXT_DELETE_BUTTON;
|
|
btn_id = BUTTON_DELETE;
|
|
caption = TXT_DELETE_MISSION;
|
|
break;
|
|
}
|
|
|
|
TextButtonClass button (btn_id, btn_txt, TPF_BUTTON, d_button_x, d_button_y, d_button_w);
|
|
TextButtonClass cancelbtn (BUTTON_CANCEL, TXT_CANCEL, TPF_BUTTON, d_cancel_x, d_cancel_y, d_cancel_w);
|
|
|
|
ListClass listbtn (BUTTON_LIST, d_list_x, d_list_y, d_list_w, list_ht,
|
|
TPF_6PT_GRAD | TPF_NOSHADOW,
|
|
MFCD::Retrieve("BTN-UP.SHP"),
|
|
MFCD::Retrieve("BTN-DN.SHP"));
|
|
|
|
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);
|
|
|
|
/*
|
|
** Initialize.
|
|
*/
|
|
Set_Logic_Page(SeenBuff);
|
|
|
|
Fill_List(&listbtn);
|
|
|
|
/*
|
|
** Do nothing if list is empty.
|
|
*/
|
|
if ((Style == LOAD || Style == WWDELETE) && listbtn.Count()==0) {
|
|
Clear_List(&listbtn);
|
|
WWMessageBox().Process(TXT_NO_SAVES);
|
|
return(false);
|
|
}
|
|
|
|
/*
|
|
** Create the button list.
|
|
*/
|
|
commands = &button;
|
|
cancelbtn.Add_Tail(*commands);
|
|
listbtn.Add_Tail(*commands);
|
|
if (Style == SAVE) {
|
|
editbtn.Add_Tail(*commands);
|
|
editbtn.Set_Focus();
|
|
}
|
|
|
|
/*
|
|
** Main Processing Loop.
|
|
*/
|
|
Keyboard->Clear();
|
|
bool firsttime = true;
|
|
bool display = true;
|
|
bool process = true;
|
|
while (process) {
|
|
|
|
/*
|
|
** Invoke game callback.
|
|
*/
|
|
if (Session.Type == GAME_NORMAL || Session.Type == GAME_SKIRMISH) {
|
|
Call_Back();
|
|
} else {
|
|
if (Main_Loop()) {
|
|
process = false;
|
|
cancel = true;
|
|
}
|
|
}
|
|
|
|
#ifdef WIN32
|
|
/*
|
|
** If we have just received input focus again after running in the background then
|
|
** we need to redraw.
|
|
*/
|
|
if (AllSurfaces.SurfacesRestored) {
|
|
AllSurfaces.SurfacesRestored=FALSE;
|
|
display = true;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
** Refresh display if needed.
|
|
*/
|
|
if (display) {
|
|
|
|
/*
|
|
** Display the dialog box.
|
|
*/
|
|
Hide_Mouse();
|
|
if (display) {
|
|
Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h);
|
|
Draw_Caption(caption, d_dialog_x, d_dialog_y, d_dialog_w);
|
|
|
|
if (Style == SAVE) {
|
|
Fancy_Text_Print(TXT_MISSION_DESCRIPTION, d_dialog_cx,
|
|
d_edit_y - d_txt8_h, GadgetClass::Get_Color_Scheme(), TBLACK, TPF_TEXT | TPF_CENTER);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Redraw the buttons.
|
|
*/
|
|
if (display) {
|
|
commands->Flag_List_To_Redraw();
|
|
}
|
|
Show_Mouse();
|
|
display = false;
|
|
}
|
|
|
|
/*
|
|
** Get user input.
|
|
*/
|
|
KeyNumType input = commands->Input();
|
|
|
|
/*
|
|
** The first time through the processing loop, set the edit
|
|
** gadget to have the focus if this is the save dialog. The
|
|
** focus must be set here since the gadget list has changed
|
|
** and this change will cause any previous focus setting to be
|
|
** cleared by the input processing routine.
|
|
*/
|
|
if (firsttime && Style == SAVE) {
|
|
firsttime = false;
|
|
editbtn.Set_Focus();
|
|
editbtn.Flag_To_Redraw();
|
|
}
|
|
|
|
/*
|
|
** If the <RETURN> key was pressed, then default to the appropriate
|
|
** action button according to the style of this dialog box.
|
|
*/
|
|
if (input == KN_RETURN || input == (BUTTON_EDIT|KN_BUTTON)) {
|
|
ToggleClass * toggle = NULL;
|
|
switch (Style) {
|
|
case SAVE:
|
|
input = (KeyNumType)(BUTTON_SAVE|KN_BUTTON);
|
|
cancelbtn.Turn_Off();
|
|
// cancelbtn.IsOn = false;
|
|
toggle = (ToggleClass*)commands->Extract_Gadget(BUTTON_SAVE);
|
|
if (toggle != NULL) {
|
|
toggle->Turn_On();
|
|
// toggle->IsOn = true;
|
|
toggle->IsPressed = true;
|
|
}
|
|
break;
|
|
|
|
case LOAD:
|
|
input = (KeyNumType)(BUTTON_LOAD|KN_BUTTON);
|
|
// cancelbtn.IsOn = false;
|
|
cancelbtn.Turn_Off();
|
|
toggle = (ToggleClass *)commands->Extract_Gadget(BUTTON_LOAD);
|
|
if (toggle != NULL) {
|
|
toggle->IsOn = true;
|
|
toggle->IsPressed = true;
|
|
}
|
|
break;
|
|
|
|
case WWDELETE:
|
|
input = (KeyNumType)(BUTTON_DELETE|KN_BUTTON);
|
|
// cancelbtn.IsOn = false;
|
|
cancelbtn.Turn_Off();
|
|
toggle = (ToggleClass *)commands->Extract_Gadget(BUTTON_DELETE);
|
|
if (toggle != NULL) {
|
|
toggle->IsOn = true;
|
|
toggle->IsPressed = true;
|
|
}
|
|
break;
|
|
}
|
|
Hide_Mouse();
|
|
commands->Draw_All(true);
|
|
Show_Mouse();
|
|
}
|
|
|
|
/*
|
|
** Process input.
|
|
*/
|
|
switch (input) {
|
|
/*
|
|
** Load: if load fails, present a message, and stay in the dialog
|
|
** to allow the user to try another game
|
|
*/
|
|
case (BUTTON_LOAD | KN_BUTTON):
|
|
game_idx = listbtn.Current_Index();
|
|
game_num = Files[game_idx]->Num;
|
|
if (Files[game_idx]->Valid) {
|
|
|
|
/*
|
|
** Start a timer before we load the game
|
|
*/
|
|
CDTimerClass<SystemTimerClass> timer;
|
|
// timer.Start();
|
|
timer = TICKS_PER_SECOND*4;
|
|
|
|
WWMessageBox().Process(TXT_LOADING, TXT_NONE);
|
|
Theme.Fade_Out();
|
|
rc = Load_Game(game_num);
|
|
|
|
/*
|
|
** Make sure the message says on the screen at least 1 second
|
|
*/
|
|
while (timer > 0) {
|
|
Call_Back();
|
|
}
|
|
Keyboard->Clear();
|
|
|
|
if (!rc) {
|
|
WWMessageBox().Process(TXT_ERROR_LOADING_GAME);
|
|
} else {
|
|
Speak(VOX_LOAD1);
|
|
while (Is_Speaking()) {
|
|
Call_Back();
|
|
}
|
|
Hide_Mouse();
|
|
SeenPage.Clear();
|
|
GamePalette.Set();
|
|
// Set_Palette(GamePalette);
|
|
Show_Mouse();
|
|
process = false;
|
|
}
|
|
} else {
|
|
WWMessageBox().Process(TXT_OBSOLETE_SAVEGAME);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
** Save: Save the game & exit the dialog
|
|
*/
|
|
case (BUTTON_EDIT | KN_BUTTON):
|
|
|
|
case (BUTTON_SAVE | KN_BUTTON):
|
|
if (!strlen(game_descr)) {
|
|
WWMessageBox().Process(TXT_MUSTENTER_DESCRIPTION);
|
|
firsttime = true;
|
|
display = true;
|
|
break;
|
|
}
|
|
game_idx = listbtn.Current_Index();
|
|
if (Disk_Space_Available() < SAVE_GAME_DISK_SPACE && game_idx == 0) {
|
|
WWMessageBox().Process(TXT_SPACE_CANT_SAVE);
|
|
firsttime = true;
|
|
display = true;
|
|
break;
|
|
}
|
|
|
|
game_num = Files[game_idx]->Num;
|
|
if (!Save_Game(game_num, game_descr)) {
|
|
WWMessageBox().Process(TXT_ERROR_SAVING_GAME);
|
|
} else {
|
|
Speak(VOX_SAVE1);
|
|
while (Is_Speaking()) {
|
|
Call_Back();
|
|
}
|
|
CDTimerClass<SystemTimerClass> timer;
|
|
// timer.Start();
|
|
timer = TICKS_PER_SECOND*4;
|
|
|
|
WWMessageBox().Process(TXT_GAME_WAS_SAVED, TXT_NONE, TXT_NONE);
|
|
|
|
/*
|
|
** Delay to let the user read the message
|
|
*/
|
|
while (timer > 0) {
|
|
Call_Back();
|
|
}
|
|
Keyboard->Clear();
|
|
}
|
|
process = false;
|
|
break;
|
|
|
|
/*
|
|
** Delete: delete the file & stay in the dialog, to allow the user
|
|
** to delete multiple files.
|
|
*/
|
|
case (BUTTON_DELETE | KN_BUTTON):
|
|
game_idx = listbtn.Current_Index();
|
|
game_num = Files[game_idx]->Num;
|
|
if (WWMessageBox().Process(TXT_DELETE_FILE_QUERY, TXT_YES, TXT_NO)==0) {
|
|
sprintf(fname, "SAVEGAME.%03d", game_num);
|
|
unlink(fname);
|
|
Clear_List(&listbtn);
|
|
Fill_List(&listbtn);
|
|
if (listbtn.Count() == 0) {
|
|
process = false;
|
|
} else {
|
|
ToggleClass * toggle = (ToggleClass *)commands->Extract_Gadget(BUTTON_DELETE);
|
|
if (toggle != NULL) {
|
|
// toggle->IsOn = false;
|
|
toggle->Turn_Off();
|
|
toggle->IsPressed = false;
|
|
toggle->Flag_To_Redraw();
|
|
}
|
|
}
|
|
}
|
|
display = true;
|
|
break;
|
|
|
|
/*
|
|
** If the user clicks on the list, see if the there is a new current
|
|
** item; if so, and if we're in SAVE mode, copy the list item into
|
|
** the save-game description field.
|
|
*/
|
|
case (BUTTON_LIST | KN_BUTTON):
|
|
if (Style != SAVE) {
|
|
break;
|
|
}
|
|
|
|
if (listbtn.Count() && listbtn.Current_Index() != game_idx) {
|
|
game_idx = listbtn.Current_Index();
|
|
|
|
/*
|
|
** Copy the game's description, UNLESS it's the empty slot; if
|
|
** it is, set the edit buffer to empty.
|
|
*/
|
|
if (game_idx != 0) {
|
|
strcpy(game_descr, listbtn.Get_Item(game_idx));
|
|
|
|
/*
|
|
** Strip any leading parenthesis off of the description.
|
|
*/
|
|
if (game_descr[0] == '(') {
|
|
char * ptr = strchr(game_descr, ')');
|
|
if (ptr != NULL) {
|
|
strcpy(game_descr, ptr+1);
|
|
strtrim(game_descr);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
game_descr[0] = 0;
|
|
}
|
|
editbtn.Set_Text(game_descr, 40);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
** ESC/Cancel: break
|
|
*/
|
|
case (KN_ESC):
|
|
case (BUTTON_CANCEL | KN_BUTTON):
|
|
cancel = true;
|
|
process = false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
Clear_List(&listbtn);
|
|
|
|
if (cancel) return(false);
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LoadOptionsClass::Clear_List -- clears the list box & Files arrays *
|
|
* *
|
|
* This step is essential, because it frees all the strings allocated for list items. *
|
|
* *
|
|
* INPUT: *
|
|
* none. *
|
|
* *
|
|
* OUTPUT: *
|
|
* none. *
|
|
* *
|
|
* WARNINGS: *
|
|
* none. *
|
|
* *
|
|
* HISTORY: *
|
|
* 02/14/1995 BR : Created. *
|
|
*=============================================================================================*/
|
|
void LoadOptionsClass::Clear_List(ListClass * list)
|
|
{
|
|
/*
|
|
** For every item in the list, free its buffer & remove it from the list.
|
|
*/
|
|
int j = list->Count();
|
|
for (int i = 0; i < j; i++) {
|
|
list->Remove_Item(list->Get_Item(0));
|
|
}
|
|
|
|
/*
|
|
** Clear the array of game numbers
|
|
*/
|
|
for (int i = 0; i < Files.Count(); i++) {
|
|
delete Files[i];
|
|
}
|
|
Files.Clear();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LoadOptionsClass::Fill_List -- fills the list box & GameNum arrays *
|
|
* *
|
|
* INPUT: *
|
|
* none. *
|
|
* *
|
|
* OUTPUT: *
|
|
* none. *
|
|
* *
|
|
* WARNINGS: *
|
|
* none. *
|
|
* *
|
|
* HISTORY: *
|
|
* 02/14/1995 BR : Created. *
|
|
* 06/25/1995 JLB : Shows which saved games are "(old)". *
|
|
*=============================================================================================*/
|
|
void LoadOptionsClass::Fill_List(ListClass * list)
|
|
{
|
|
#if(0) //PG
|
|
FileEntryClass * fdata; // for adding entries to 'Files'
|
|
char descr[DESCRIP_MAX+32];
|
|
unsigned scenario; // scenario #
|
|
HousesType house; // house
|
|
struct find_t ff; // for _dos_findfirst
|
|
int id;
|
|
|
|
/*
|
|
** Make sure the list is empty
|
|
*/
|
|
Clear_List(list);
|
|
|
|
/*
|
|
** Add the Empty Slot entry
|
|
*/
|
|
if (Style == SAVE) {
|
|
fdata = new FileEntryClass;
|
|
strcpy(fdata->Descr, Text_String(TXT_EMPTY_SLOT));
|
|
fdata->DateTime = 0xffffffff; // will always be first
|
|
Files.Add(fdata);
|
|
}
|
|
|
|
/*
|
|
** Find all savegame files
|
|
*/
|
|
int rc = _dos_findfirst("SAVEGAME.*", _A_NORMAL, &ff);
|
|
|
|
while (!rc) {
|
|
|
|
if (stricmp(ff.name, NET_SAVE_FILE_NAME) != 0) {
|
|
|
|
/*
|
|
** Extract the game ID from the filename
|
|
*/
|
|
id = Num_From_Ext(ff.name);
|
|
|
|
/*
|
|
** get the game's info; if success, add it to the list
|
|
*/
|
|
bool ok = Get_Savefile_Info(id, descr, &scenario, &house);
|
|
|
|
fdata = new FileEntryClass;
|
|
|
|
fdata->Descr[0] = '\0';
|
|
if (!ok) {
|
|
strcpy(fdata->Descr, Text_String(TXT_OLD_GAME));
|
|
} else {
|
|
if (house == HOUSE_USSR || house == HOUSE_UKRAINE) {
|
|
#ifdef WIN32
|
|
sprintf(fdata->Descr, "(%s) ", Text_String(TXT_SOVIET));
|
|
#else
|
|
sprintf(fdata->Descr, "(%c) ", *Text_String(TXT_SOVIET));
|
|
#endif
|
|
} else {
|
|
#ifdef WIN32
|
|
sprintf(fdata->Descr, "(%s) ", Text_String(TXT_ALLIES));
|
|
#else
|
|
sprintf(fdata->Descr, "(%c) ", *Text_String(TXT_ALLIES));
|
|
#endif
|
|
}
|
|
}
|
|
strncat(fdata->Descr, descr, (sizeof(fdata->Descr)-strlen(fdata->Descr))-1);
|
|
fdata->Valid = ok;
|
|
fdata->Scenario = scenario;
|
|
fdata->House = house;
|
|
fdata->Num = id;
|
|
fdata->DateTime = (((unsigned long)ff.wr_date) << 16) | (unsigned long)ff.wr_time;
|
|
Files.Add(fdata);
|
|
}
|
|
|
|
/*
|
|
** Find the next file
|
|
*/
|
|
rc = _dos_findnext(&ff);
|
|
}
|
|
|
|
/*
|
|
** If saving a game, determine a unique file ID for the empty slot
|
|
*/
|
|
if (Style == SAVE) {
|
|
/*
|
|
** Find an un-used number to associate with the Empty Slot by looking in
|
|
** GameNum for each number from 0 to 'N', where 'N' is the # of entries
|
|
** in the list; if any number isn't found, use that number; otherwise,
|
|
** use 'N + 1'.
|
|
*/
|
|
for (int i = 0; i < Files.Count(); i++) { // i = the # we're searching for
|
|
id = -1; // mark as 'not found'
|
|
for (int j = 0; j < Files.Count(); j++) { // loop through all game ID's
|
|
if (Files[j]->Num==i) { // if found, mark as found
|
|
id = j;
|
|
break;
|
|
}
|
|
}
|
|
if (id == -1) break; // if ID not found, use this one
|
|
}
|
|
|
|
Files[0]->Num = i; // set the empty slot's ID
|
|
}
|
|
|
|
/*
|
|
** Now sort the list in order of Date/Time (newest first, oldest last)
|
|
*/
|
|
qsort((void *)(&Files[0]), Files.Count(), sizeof(class FileEntryClass *), LoadOptionsClass::Compare);
|
|
|
|
/*
|
|
** Now add every file's name to the list box
|
|
*/
|
|
for (int i = 0; i < Files.Count(); i++) {
|
|
list->Add_Item(Files[i]->Descr);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LoadOptionsClass::Num_From_Ext -- clears the list box & GameNum arrays *
|
|
* *
|
|
* INPUT: *
|
|
* fname filename to parse *
|
|
* *
|
|
* OUTPUT: *
|
|
* File number for this name. *
|
|
* *
|
|
* WARNINGS: *
|
|
* none. *
|
|
* *
|
|
* HISTORY: *
|
|
* 02/14/1995 BR : Created. *
|
|
*=============================================================================================*/
|
|
int LoadOptionsClass::Num_From_Ext(char * fname)
|
|
{
|
|
char ext[_MAX_EXT];
|
|
|
|
_splitpath(fname, NULL, NULL, NULL, ext);
|
|
int num = atoi(ext + 1); // skip the '.'
|
|
return(num);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LoadOptionsClass::Compare -- for qsort *
|
|
* *
|
|
* INPUT: *
|
|
* p1,p2 ptrs to elements to compare *
|
|
* *
|
|
* OUTPUT: *
|
|
* 0 = same, -1 = (*p1) goes BEFORE (*p2), 1 = (*p1) goes AFTER (*p2) *
|
|
* *
|
|
* WARNINGS: *
|
|
* none. *
|
|
* *
|
|
* HISTORY: *
|
|
* 02/14/1995 BR : Created. *
|
|
*=============================================================================================*/
|
|
int LoadOptionsClass::Compare(const void * p1, const void * p2)
|
|
{
|
|
class FileEntryClass * fe1, * fe2;
|
|
|
|
fe1 = *((class FileEntryClass **)p1);
|
|
fe2 = *((class FileEntryClass **)p2);
|
|
|
|
if (fe1->DateTime > fe2->DateTime) return(-1);
|
|
if (fe1->DateTime < fe2->DateTime) return(1);
|
|
return(0);
|
|
}
|
|
|