/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//Filename : OGFILE.CPP
//Description : Object Game file, save game and restore game
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// -------- define constant ----------//
#define MIN_FREE_SPACE 1000
//-------- Begin of function GameFile::save_game --------//
//
// return : 1 - saved successfully.
// 0 - not saved.
//
int GameFile::save_game(char* fileName)
{
File file;
String errStr;
power.win_opened=1; // to disable power.mouse_handler()
if( fileName )
strcpy( file_name, fileName );
int rc = 1;
char lowDiskSpaceFlag = 0;
DWORD sectorPerCluster = 0;
DWORD bytePerSector = 0;
DWORD freeCluster = 0;
DWORD totalCluster = 0;
if( GetDiskFreeSpace( NULL, // address of root path, NULL means the current root directory
§orPerCluster, &bytePerSector, &freeCluster, &totalCluster))
{
DWORD freeSpace = DWORD( (double)freeCluster * sectorPerCluster * bytePerSector / 1024.0);
if( m.is_file_exist(file_name) )
{
// if overwritting existing file, count the file size of the existing file
file.file_open(file_name);
freeSpace += file.file_size() / 1024; // count the existing space
file.file_close();
}
if( !(rc = freeSpace >= MIN_FREE_SPACE) )
{
errStr = "Insufficient disk space ! The game is not saved.";
lowDiskSpaceFlag = 1;
}
}
if( rc )
{
rc = file.file_create( file_name, 0, 1 ); // 0=tell File don't handle error itself
// 1=allow the writing size and the read size to be different
if( !rc )
errStr = "Error creating saved game file.";
}
if( rc )
{
save_process(); // process game data before saving the game
rc = write_game_header(&file); // write saved game header information
if( !rc )
errStr = "Error creating saved game header.";
if( rc )
{
rc = write_file(&file);
if( !rc )
errStr = "Error writing saved game data.";
}
}
file.file_close();
power.win_opened=0;
//------- when saving error ---------//
if( !rc )
{
if( !lowDiskSpaceFlag )
remove( file_name ); // delete the file as it is not complete
#ifndef DEBUG
errStr = "Insufficient disk space ! The game is not saved."; // use this message for all types of error message in the release version
#endif
box.msg( errStr );
}
return rc;
}
//--------- End of function GameFile::save_game --------//
//-------- Begin of function GameFile::load_game --------//
//
// return : 1 - loaded successfully.
// 0 - not loaded.
// -1 - error and partially loaded
//
int GameFile::load_game(char* fileName)
{
File file;
int rc=0;
char *errMsg = NULL;
power.win_opened=1; // to disable power.mouse_handler()
int oldCursor = mouse_cursor.get_icon();
mouse_cursor.set_icon( CURSOR_WAITING );
int powerEnableFlag = power.enable_flag;
if( fileName )
strcpy( file_name, fileName );
rc = 1;
if( !file.file_open( file_name, 0, 1 ) ) // 0=tell File don't handle error itself
{
rc = 0;
errMsg = "Cannot open save game file";
}
//-------- read in the GameFile class --------//
if( rc )
{
char gameFileName[MAX_PATH+1];
strcpy( gameFileName, file_name ); // save the file name actually read, in case that the file names are different
if( !file.file_read(this, sizeof(GameFile)) ) // read the whole object from the saved game file
{
rc = 0;
errMsg = "Cannot read file header";
}
if( rc )
{
if( !validate_header() )
{
rc = 0;
errMsg = "Save game incompatible";
}
else
strcpy( file_name, gameFileName );
}
}
//--------------------------------------------//
// 1=allow the writing size and the read size to be different
if( rc )
{
config.terrain_set = terrain_set;
game.deinit(1); // deinit last game first, 1-it is called during loading of a game
game.init(1); // init game
//-------- read in saved game ----------//
// ###### patch begin Gilbert 20/1 #######//
//if( !read_file(&file) )
//{
// rc = -1;
// errMsg = "Load game error";
//}
switch( read_file(&file) )
{
case 1:
rc = 1;
break;
case -1:
rc = 0; // consider cancel load game
errMsg = "Incompatible save game";
break;
case 0:
default:
rc = -1;
errMsg = "Load game error";
}
if( rc > 0 )
load_process(); // process game data after loading the game
// ###### patch end Gilbert 20/1 #######//
}
file.file_close();
power.enable_flag = powerEnableFlag;
mouse_cursor.restore_icon( oldCursor );
power.win_opened=0;
//---------------------------------------//
switch(rc) // don't display msg if loaded successfully (rc==1)
{
case 0:
case -1:
box.msg( errMsg );
break;
}
last_read_success_flag = rc; // for external functions to read.
return rc;
}
//--------- End of function GameFile::load_game --------//
//------- Begin of function GameFile::set_file_name -------//
//
// Set the game file name of current save game, called by
// GameFile::save_game().
//
// e.g. ENLI_001.SAV - the first saved game of the group "Enlight Enterprise"
//
void GameFile::set_file_name()
{
enum { NAME_PREFIX_LEN = 4, // Maximum 4 characters in name prefix, e.g. "ENLIG" for "Enlight Enterprise"
NAME_NUMBER_LEN = 3 };
String str, str2;
int i;
char nameChar;
char* baseName; // the long name which the file name is based on
char addStr[] = "0"; // as a small string for adding to the large string
baseName = (~nation_array)->king_name();
//--------- add the group name prfix ----------//
for( i=0 ; i<(int) strlen(baseName) && (int) str.len() < NAME_PREFIX_LEN ; i++ )
{
nameChar = m.upper(baseName[i]);
if( ( nameChar >= 'A' && nameChar <= 'Z' ) ||
( nameChar >= '0' && nameChar <= '9' ) )
{
addStr[0] = nameChar;
str += addStr;
}
}
//----- add tailing characters if prefix len < NAME_PREFIX_LEN+1 ---//
while( str.len() < NAME_PREFIX_LEN+1 ) // +1 is the "_" between the name and the number
str += "_";
//---- find the saved game number for this saved game ----//
int curNumber, lastNumber=0;
GameFile* gameFile;
for( i=1 ; i<=game_file_array.size() ; i++ )
{
gameFile = game_file_array[i];
// ##### begin Gilbert 3/10 ########//
// if( memcmp(gameFile->file_name, str, NAME_PREFIX_LEN)==0 )
if( strnicmp(gameFile->file_name, str, NAME_PREFIX_LEN)==0 )
// ##### end Gilbert 3/10 ########//
{
//------------------------------------------------//
//
// if there is a free number in the middle of the list
// (left by being deleted game), use this number.
//
//------------------------------------------------//
curNumber = atoi( gameFile->file_name+NAME_PREFIX_LEN+1 ); // +1 is to pass the "_" between the name and the number
if( curNumber > lastNumber+1 ) // normally, curNumber should be lastNumber+1
break;
lastNumber = curNumber;
}
}
//------- add saved game number after the prefix --------//
str2 = lastNumber+1; // use the next number after the last number
for( i=NAME_NUMBER_LEN-str2.len() ; i>0 ; i-- ) // add "0" before the number if the len of the number < NAME_NUMBER_LEN
str += "0";
str += str2;
str += ".SAV";
//----- copy the string to file_name ------//
strncpy( file_name, str, MAX_PATH );
file_name[MAX_PATH] = NULL;
}
//--------- End of function GameFile::set_file_name -------//
//-------- Begin of function GameFile::save_process -------//
//
// Make the game data ready for saving game
//
// Called before saving the game
//
void GameFile::save_process()
{
//--------- set the total playing time --------//
info.total_play_time += m.get_time()-info.start_play_time;
info.start_play_time = m.get_time();
}
//--------- End of function GameFile::save_process -------//
//-------- Begin of function GameFile::load_process -------//
//
// Make the game data ready after loading game
//
// Called after loading the game
//
void GameFile::load_process()
{
info.start_play_time = m.get_time(); // the time player start playing the game
config.disable_ai_flag = 0;
//-- if the player is in the diplomatic message screen, rebuild the talk choice list --//
if( sys.view_mode==MODE_NATION && info.nation_report_mode==NATION_REPORT_TALK )
talk_res.set_talk_choices();
mouse_cursor.set_frame(0); // to fix a frame bug with loading game
// reflect the effect of config.music_flag, config.wav_music_volume
audio.set_wav_volume(config.sound_effect_volume);
if( config.music_flag )
{
if( music.is_playing() )
{
music.change_volume(config.wav_music_volume);
}
}
else
{
music.stop();
}
}
//--------- End of function GameFile::load_process -------//
//------- Begin of function GameFile::write_game_header -------//
//
// Write saved game header info to the saved game file.
//
// Return : 1 - file written successfully
// 0 - not successful
//
int GameFile::write_game_header(File* filePtr)
{
class_size = sizeof(GameFile);
Nation* playerNation = ~nation_array;
strncpy( player_name, playerNation->king_name(), NationArray::HUMAN_NAME_LEN );
player_name[NationArray::HUMAN_NAME_LEN] = NULL;
race_id = playerNation->race_id;
nation_color = playerNation->nation_color;
terrain_set = config.terrain_set;
game_date = info.game_date;
//----- set the file date ------//
CoFileTimeNow(&file_date);
//------- write GameFile to the saved game file -------//
return filePtr->file_write( this, sizeof(GameFile) ); // write the whole object to the saved game file
}
//--------- End of function GameFile::write_game_header -------//
//--------- Begin of function GameFile::validate_header -------//
int GameFile::validate_header()
{
return class_size == sizeof(GameFile) && terrain_set > 0;
}
//--------- End of function GameFile::validate_header -------//