LOADDLG.CPP 28 KB

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