LOADDLG.CPP 27 KB

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