OGFILE.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /*
  2. * Seven Kingdoms: Ancient Adversaries
  3. *
  4. * Copyright 1997,1998 Enlight Software Ltd.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. //Filename : OGFILE.CPP
  21. //Description : Object Game file, save game and restore game
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <time.h>
  25. #include <OBOX.h>
  26. #include <OSTR.h>
  27. #include <ODATE.h>
  28. #include <OMOUSECR.h>
  29. #include <OTALKRES.h>
  30. #include <ONATION.h>
  31. #include <OWORLD.h>
  32. #include <OPOWER.h>
  33. #include <OGAME.h>
  34. #include <OINFO.h>
  35. #include <OGFILE.h>
  36. #include <OSYS.h>
  37. #include <OAUDIO.h>
  38. #include <OMUSIC.h>
  39. // -------- define constant ----------//
  40. #define MIN_FREE_SPACE 1000
  41. //-------- Begin of function GameFile::save_game --------//
  42. //
  43. // return : <int> 1 - saved successfully.
  44. // 0 - not saved.
  45. //
  46. int GameFile::save_game(char* fileName)
  47. {
  48. File file;
  49. String errStr;
  50. power.win_opened=1; // to disable power.mouse_handler()
  51. if( fileName )
  52. strcpy( file_name, fileName );
  53. int rc = 1;
  54. char lowDiskSpaceFlag = 0;
  55. DWORD sectorPerCluster = 0;
  56. DWORD bytePerSector = 0;
  57. DWORD freeCluster = 0;
  58. DWORD totalCluster = 0;
  59. if( GetDiskFreeSpace( NULL, // address of root path, NULL means the current root directory
  60. &sectorPerCluster, &bytePerSector, &freeCluster, &totalCluster))
  61. {
  62. DWORD freeSpace = DWORD( (double)freeCluster * sectorPerCluster * bytePerSector / 1024.0);
  63. if( m.is_file_exist(file_name) )
  64. {
  65. // if overwritting existing file, count the file size of the existing file
  66. file.file_open(file_name);
  67. freeSpace += file.file_size() / 1024; // count the existing space
  68. file.file_close();
  69. }
  70. if( !(rc = freeSpace >= MIN_FREE_SPACE) )
  71. {
  72. errStr = "Insufficient disk space ! The game is not saved.";
  73. lowDiskSpaceFlag = 1;
  74. }
  75. }
  76. if( rc )
  77. {
  78. rc = file.file_create( file_name, 0, 1 ); // 0=tell File don't handle error itself
  79. // 1=allow the writing size and the read size to be different
  80. if( !rc )
  81. errStr = "Error creating saved game file.";
  82. }
  83. if( rc )
  84. {
  85. save_process(); // process game data before saving the game
  86. rc = write_game_header(&file); // write saved game header information
  87. if( !rc )
  88. errStr = "Error creating saved game header.";
  89. if( rc )
  90. {
  91. rc = write_file(&file);
  92. if( !rc )
  93. errStr = "Error writing saved game data.";
  94. }
  95. }
  96. file.file_close();
  97. power.win_opened=0;
  98. //------- when saving error ---------//
  99. if( !rc )
  100. {
  101. if( !lowDiskSpaceFlag )
  102. remove( file_name ); // delete the file as it is not complete
  103. #ifndef DEBUG
  104. errStr = "Insufficient disk space ! The game is not saved."; // use this message for all types of error message in the release version
  105. #endif
  106. box.msg( errStr );
  107. }
  108. return rc;
  109. }
  110. //--------- End of function GameFile::save_game --------//
  111. //-------- Begin of function GameFile::load_game --------//
  112. //
  113. // return : <int> 1 - loaded successfully.
  114. // 0 - not loaded.
  115. // -1 - error and partially loaded
  116. //
  117. int GameFile::load_game(char* fileName)
  118. {
  119. File file;
  120. int rc=0;
  121. char *errMsg = NULL;
  122. power.win_opened=1; // to disable power.mouse_handler()
  123. int oldCursor = mouse_cursor.get_icon();
  124. mouse_cursor.set_icon( CURSOR_WAITING );
  125. int powerEnableFlag = power.enable_flag;
  126. if( fileName )
  127. strcpy( file_name, fileName );
  128. rc = 1;
  129. if( !file.file_open( file_name, 0, 1 ) ) // 0=tell File don't handle error itself
  130. {
  131. rc = 0;
  132. errMsg = "Cannot open save game file";
  133. }
  134. //-------- read in the GameFile class --------//
  135. if( rc )
  136. {
  137. char gameFileName[MAX_PATH+1];
  138. strcpy( gameFileName, file_name ); // save the file name actually read, in case that the file names are different
  139. if( !file.file_read(this, sizeof(GameFile)) ) // read the whole object from the saved game file
  140. {
  141. rc = 0;
  142. errMsg = "Cannot read file header";
  143. }
  144. if( rc )
  145. {
  146. if( !validate_header() )
  147. {
  148. rc = 0;
  149. errMsg = "Save game incompatible";
  150. }
  151. else
  152. strcpy( file_name, gameFileName );
  153. }
  154. }
  155. //--------------------------------------------//
  156. // 1=allow the writing size and the read size to be different
  157. if( rc )
  158. {
  159. config.terrain_set = terrain_set;
  160. game.deinit(1); // deinit last game first, 1-it is called during loading of a game
  161. game.init(1); // init game
  162. //-------- read in saved game ----------//
  163. // ###### patch begin Gilbert 20/1 #######//
  164. //if( !read_file(&file) )
  165. //{
  166. // rc = -1;
  167. // errMsg = "Load game error";
  168. //}
  169. switch( read_file(&file) )
  170. {
  171. case 1:
  172. rc = 1;
  173. break;
  174. case -1:
  175. rc = 0; // consider cancel load game
  176. errMsg = "Incompatible save game";
  177. break;
  178. case 0:
  179. default:
  180. rc = -1;
  181. errMsg = "Load game error";
  182. }
  183. if( rc > 0 )
  184. load_process(); // process game data after loading the game
  185. // ###### patch end Gilbert 20/1 #######//
  186. }
  187. file.file_close();
  188. power.enable_flag = powerEnableFlag;
  189. mouse_cursor.restore_icon( oldCursor );
  190. power.win_opened=0;
  191. //---------------------------------------//
  192. switch(rc) // don't display msg if loaded successfully (rc==1)
  193. {
  194. case 0:
  195. case -1:
  196. box.msg( errMsg );
  197. break;
  198. }
  199. last_read_success_flag = rc; // for external functions to read.
  200. return rc;
  201. }
  202. //--------- End of function GameFile::load_game --------//
  203. //------- Begin of function GameFile::set_file_name -------//
  204. //
  205. // Set the game file name of current save game, called by
  206. // GameFile::save_game().
  207. //
  208. // e.g. ENLI_001.SAV - the first saved game of the group "Enlight Enterprise"
  209. //
  210. void GameFile::set_file_name()
  211. {
  212. enum { NAME_PREFIX_LEN = 4, // Maximum 4 characters in name prefix, e.g. "ENLIG" for "Enlight Enterprise"
  213. NAME_NUMBER_LEN = 3 };
  214. String str, str2;
  215. int i;
  216. char nameChar;
  217. char* baseName; // the long name which the file name is based on
  218. char addStr[] = "0"; // as a small string for adding to the large string
  219. baseName = (~nation_array)->king_name();
  220. //--------- add the group name prfix ----------//
  221. for( i=0 ; i<(int) strlen(baseName) && (int) str.len() < NAME_PREFIX_LEN ; i++ )
  222. {
  223. nameChar = m.upper(baseName[i]);
  224. if( ( nameChar >= 'A' && nameChar <= 'Z' ) ||
  225. ( nameChar >= '0' && nameChar <= '9' ) )
  226. {
  227. addStr[0] = nameChar;
  228. str += addStr;
  229. }
  230. }
  231. //----- add tailing characters if prefix len < NAME_PREFIX_LEN+1 ---//
  232. while( str.len() < NAME_PREFIX_LEN+1 ) // +1 is the "_" between the name and the number
  233. str += "_";
  234. //---- find the saved game number for this saved game ----//
  235. int curNumber, lastNumber=0;
  236. GameFile* gameFile;
  237. for( i=1 ; i<=game_file_array.size() ; i++ )
  238. {
  239. gameFile = game_file_array[i];
  240. // ##### begin Gilbert 3/10 ########//
  241. // if( memcmp(gameFile->file_name, str, NAME_PREFIX_LEN)==0 )
  242. if( strnicmp(gameFile->file_name, str, NAME_PREFIX_LEN)==0 )
  243. // ##### end Gilbert 3/10 ########//
  244. {
  245. //------------------------------------------------//
  246. //
  247. // if there is a free number in the middle of the list
  248. // (left by being deleted game), use this number.
  249. //
  250. //------------------------------------------------//
  251. curNumber = atoi( gameFile->file_name+NAME_PREFIX_LEN+1 ); // +1 is to pass the "_" between the name and the number
  252. if( curNumber > lastNumber+1 ) // normally, curNumber should be lastNumber+1
  253. break;
  254. lastNumber = curNumber;
  255. }
  256. }
  257. //------- add saved game number after the prefix --------//
  258. str2 = lastNumber+1; // use the next number after the last number
  259. for( i=NAME_NUMBER_LEN-str2.len() ; i>0 ; i-- ) // add "0" before the number if the len of the number < NAME_NUMBER_LEN
  260. str += "0";
  261. str += str2;
  262. str += ".SAV";
  263. //----- copy the string to file_name ------//
  264. strncpy( file_name, str, MAX_PATH );
  265. file_name[MAX_PATH] = NULL;
  266. }
  267. //--------- End of function GameFile::set_file_name -------//
  268. //-------- Begin of function GameFile::save_process -------//
  269. //
  270. // Make the game data ready for saving game
  271. //
  272. // Called before saving the game
  273. //
  274. void GameFile::save_process()
  275. {
  276. //--------- set the total playing time --------//
  277. info.total_play_time += m.get_time()-info.start_play_time;
  278. info.start_play_time = m.get_time();
  279. }
  280. //--------- End of function GameFile::save_process -------//
  281. //-------- Begin of function GameFile::load_process -------//
  282. //
  283. // Make the game data ready after loading game
  284. //
  285. // Called after loading the game
  286. //
  287. void GameFile::load_process()
  288. {
  289. info.start_play_time = m.get_time(); // the time player start playing the game
  290. config.disable_ai_flag = 0;
  291. //-- if the player is in the diplomatic message screen, rebuild the talk choice list --//
  292. if( sys.view_mode==MODE_NATION && info.nation_report_mode==NATION_REPORT_TALK )
  293. talk_res.set_talk_choices();
  294. mouse_cursor.set_frame(0); // to fix a frame bug with loading game
  295. // reflect the effect of config.music_flag, config.wav_music_volume
  296. audio.set_wav_volume(config.sound_effect_volume);
  297. if( config.music_flag )
  298. {
  299. if( music.is_playing() )
  300. {
  301. music.change_volume(config.wav_music_volume);
  302. }
  303. }
  304. else
  305. {
  306. music.stop();
  307. }
  308. }
  309. //--------- End of function GameFile::load_process -------//
  310. //------- Begin of function GameFile::write_game_header -------//
  311. //
  312. // Write saved game header info to the saved game file.
  313. //
  314. // Return : <int> 1 - file written successfully
  315. // 0 - not successful
  316. //
  317. int GameFile::write_game_header(File* filePtr)
  318. {
  319. class_size = sizeof(GameFile);
  320. Nation* playerNation = ~nation_array;
  321. strncpy( player_name, playerNation->king_name(), NationArray::HUMAN_NAME_LEN );
  322. player_name[NationArray::HUMAN_NAME_LEN] = NULL;
  323. race_id = playerNation->race_id;
  324. nation_color = playerNation->nation_color;
  325. terrain_set = config.terrain_set;
  326. game_date = info.game_date;
  327. //----- set the file date ------//
  328. CoFileTimeNow(&file_date);
  329. //------- write GameFile to the saved game file -------//
  330. return filePtr->file_write( this, sizeof(GameFile) ); // write the whole object to the saved game file
  331. }
  332. //--------- End of function GameFile::write_game_header -------//
  333. //--------- Begin of function GameFile::validate_header -------//
  334. int GameFile::validate_header()
  335. {
  336. return class_size == sizeof(GameFile) && terrain_set > 0;
  337. }
  338. //--------- End of function GameFile::validate_header -------//