/*
* 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 : OSYS.CPP
//Description : System resource management object
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// ##### begin Gilbert 23/10 ######//
#include
#include
// ##### end Gilbert 23/10 ######//
//----------- Declare static functions -----------//
static long FAR PASCAL static_main_win_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
//------- Define static functions -----------//
LRESULT CALLBACK win_hook_proc(int nCode, WORD wParam, LONG lParam);
static void test_lzw();
static void locate_king_general(int rankId);
static void locate_spy();
static void locate_ship();
static void locate_camp();
static int locate_ship_in_harbor();
static int locate_visible_ship();
static int detect_scenario_cheat_key(unsigned scanCode, unsigned skeyState);
static int get_mouse_loc_in_zoom_map(int &x, int &y);
//----------- Define static variables ------------//
static unsigned long last_frame_time=0, last_resend_time=0;
static char remote_send_success_flag=1;
static HHOOK win_hook_handle=NULL;
static char scenario_cheat_flag=0;
//----------- Begin of function Sys::Sys -----------//
Sys::Sys()
{
memset(this, 0, sizeof(Sys) );
common_data_buf = mem_add( COMMON_DATA_BUF_SIZE );
view_mode = MODE_NORMAL; // the animation mode
}
//----------- End of function Sys::Sys -----------//
//----------- Begin of function Sys::~Sys -----------//
Sys::~Sys()
{
mem_del(common_data_buf);
deinit();
}
//----------- End of function Sys::~Sys -----------//
//------------ Begin of function Sys::init ----------//
//
int Sys::init( HINSTANCE hInstance )
{
err_when( init_flag );
//------- initialize basic vars --------//
app_hinstance = hInstance;
#ifdef BETA
debug_session = m.is_file_exist("DEBUG.SYS");
testing_session = m.is_file_exist("TESTING.SYS");
scenario_cheat_flag = m.is_file_exist("CHEAT.SYS");
#endif
#ifdef DEBUG
debug_session = m.is_file_exist("DEBUG.SYS");
testing_session = m.is_file_exist("TESTING.SYS");
scenario_cheat_flag = m.is_file_exist("CHEAT.SYS");
#endif
// debug_session = m.is_file_exist("DEBUG.SYS");
set_game_dir(); // set game directories names and game version
//------- initialize more stuff ---------//
if( !init_win() )
return FALSE;
if( !init_directx() )
return FALSE;
if( !init_objects() ) // initialize system objects which do not change from games to games.
return FALSE;
init_flag = 1;
return TRUE;
}
//------------ End of function Sys::init ----------//
//-------- Begin of function Sys::deinit --------//
//
// Finished with all objects we use; release them
//
void Sys::deinit()
{
if( !init_flag )
return;
game.deinit(); // actually game.deinit() will be called by main_win_proc() and calling it here will have no effect
deinit_objects();
//-------------------------------------//
if( vga_back.buf_locked )
vga_back.unlock_buf();
if( vga_front.buf_locked )
vga_front.unlock_buf();
//-------------------------------------//
/*
extern char low_video_memory_flag;
if( low_video_memory_flag )
{
ShowWindow(sys.main_hwnd, SW_MINIMIZE );
unsigned curTime = m.get_time();
while( m.get_time() < curTime + 4000 );
}
*/
//---------------------------------------//
PostMessage(main_hwnd, WM_CLOSE, 0, 0);
init_flag = 0;
MSG msg;
while( GetMessage(&msg, NULL, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//--------- End of function Sys::deinit ---------//
//-------- Begin of function Sys::init_win --------//
//
int Sys::init_win()
{
//--------- register window class --------//
WNDCLASS wc;
BOOL rc;
wc.style = CS_DBLCLKS;
wc.lpfnWndProc = static_main_win_proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = app_hinstance;
wc.hIcon = LoadIcon( app_hinstance, MAKEINTATOM(IDI_ICON1));
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = WIN_CLASS_NAME;
rc = RegisterClass( &wc );
if( !rc )
return FALSE;
//------ install keyboard hook ---------//
/*
win_hook_handle = SetWindowsHookEx(WH_CBT, (HOOKPROC) win_hook_proc, sys.app_hinstance, NULL);
if( !win_hook_handle )
err.run( "Failed installing keyboard hook." );
*/
//--------- create window -----------//
main_hwnd = CreateWindowEx(
WS_EX_APPWINDOW | WS_EX_TOPMOST,
WIN_CLASS_NAME,
WIN_TITLE,
WS_VISIBLE | // so we dont have to call ShowWindow
WS_POPUP,
0,
0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN),
NULL,
NULL,
app_hinstance,
NULL );
if( !main_hwnd )
return FALSE;
UpdateWindow( main_hwnd );
SetFocus( main_hwnd );
return TRUE;
}
//-------- End of function Sys::init_win --------//
//------- Begin of function win_hook_proc --------//
LRESULT CALLBACK win_hook_proc(int nCode, WORD wParam, LONG lParam)
{
static int lastnCode;
int a=0;
if( vga_true_front.dd_buf && vga_true_front.dd_buf->IsLost() )
a = 1;
lastnCode = nCode;
if( sys.init_flag && nCode == HCBT_SETFOCUS )
sys.pause();
return CallNextHookEx(win_hook_handle, nCode, wParam, lParam);
}
//-------- End of function win_hook_proc --------//
//-------- Begin of function Sys::init_directx --------//
//
int Sys::init_directx()
{
DEBUG_LOG("Attempt audio.init()");
audio.init();
DEBUG_LOG(audio.wav_init_flag);
music.init();
se_ctrl.init();
//---------------------------------------//
ShowCursor(FALSE);
//-------- initialize DirectDraw --------//
DEBUG_LOG("Attempt vga.init()");
if( !vga.init() )
return FALSE;
DEBUG_LOG("vga.init() ok");
DEBUG_LOG("Attempt vga.load_pal()");
vga.load_pal(DIR_RES"PAL_STD.RES");
DEBUG_LOG("vga.load_pal() finish");
if( sys.debug_session ) // if we are currently in a debug session, don't lock the front buffer otherwise the system will hang up
{
DEBUG_LOG("Attempt vga_front.init_back()");
vga_front.init_back( vga.dd_obj );
vga_front.is_front = 1; // set it to 1, overriding the setting in init_back()
DEBUG_LOG("Attempt vga_true_front.init_front()");
vga_true_front.init_front( vga.dd_obj );
DEBUG_LOG("Attempt vga.activate_pal()");
vga.activate_pal(&vga_true_front);
DEBUG_LOG("vga.activate_pal() finish");
}
else
{
vga_front.init_front( vga.dd_obj );
vga.activate_pal(&vga_front);
}
DEBUG_LOG("Attempt vga_back.init_back()");
vga_back.init_back( vga.dd_obj );
DEBUG_LOG("vga_back.init_back() finish");
DEBUG_LOG("Attempt vga_front.lock_buf()");
vga_front.lock_buf();
DEBUG_LOG("vga_front.lock_buf() finish");
DEBUG_LOG("Attempt vga_back.lock_buf()");
vga_back.lock_buf();
DEBUG_LOG("vga_back.lock_buf() finish");
return TRUE;
}
//-------- End of function Sys::init_directx --------//
//-------- Begin of function Sys::deinit_directx --------//
//
void Sys::deinit_directx()
{
if( vga_back.dd_buf && vga_back.buf_locked )
{
DEBUG_LOG("Attempt vga_back.unlock_buf()");
vga_back.unlock_buf();
DEBUG_LOG("vga_back.unlock_buf() finish");
}
if( vga_front.dd_buf && vga_front.buf_locked )
{
DEBUG_LOG("Attempt vga_front.unlock_buf()");
vga_front.unlock_buf();
DEBUG_LOG("vga_front.unlock_buf() finish");
}
DEBUG_LOG("Attempt vga_back.deinit()");
vga_back.deinit();
DEBUG_LOG("vga_back.deinit() finish");
if( sys.debug_session )
{
DEBUG_LOG("Attempt vga_true_front.deinit()");
vga_true_front.deinit();
DEBUG_LOG("vga_true_front.deinit() finish");
}
DEBUG_LOG("Attempt vga_front.deinit()");
vga_front.deinit();
DEBUG_LOG("Attempt vga_front.deinit() finish");
DEBUG_LOG("Attempt vga.deinit()");
vga.deinit();
DEBUG_LOG("vga.deinit() finish");
//------------------------------//
se_ctrl.deinit();
music.deinit();
DEBUG_LOG("Attempt audio.deinit()");
audio.deinit();
DEBUG_LOG("audio.deinit() finish");
}
//--------- End of function Sys::deinit_directx ---------//
//------- Begin of function Sys::init_objects -----------//
//
// Initialize system objects which do not change from games to games.
//
int Sys::init_objects()
{
//--------- init system class ----------//
mouse_cursor.init();
mouse_cursor.set_frame_border(ZOOM_X1,ZOOM_Y1,ZOOM_X2,ZOOM_Y2);
mouse.init(app_hinstance, main_hwnd, NULL);
//------- init resource class ----------//
#if( defined(GERMAN) || defined(FRENCH) || defined(SPANISH) )
font_std.init("SAN", 1);
font_hall.init("HALL", 1);
#else
font_std.init("STD", 2);
#endif
font_san.init("SAN", 0); // 0-zero inter-character space
font_mid.init("MID");
font_small.init("SMAL");
font_news.init("NEWS");
font_hitpoint.init("HITP");
font_bible.init("CASA", 1, 3);
font_bard.init("CASA", 0);
image_icon.init(DIR_RES"I_ICON.RES",1,0); // 1-read into buffer
image_interface.init(DIR_RES"I_IF.RES",0,0); // 0-don't read into the buffer, don't use common buffer
#ifndef DEMO // do not load these in the demo verison
image_menu.init(DIR_RES"I_MENU.RES",0,0); // 0-don't read into the buffer, don't use common buffer
image_encyc.init(DIR_RES"I_ENCYC.RES",0,0); // 0-don't read into the buffer, don't use common buffer
#endif
image_button.init(DIR_RES"I_BUTTON.RES",1,0);
image_spict.init(DIR_RES"I_SPICT.RES",1,0);
image_tutorial.init(DIR_RES"TUT_PICT.RES",0,0);
#ifdef AMPLUS
#ifndef DEMO // do not load these in the demo verison
image_menu_plus.init(DIR_RES"I_MENU2.RES",0,0); // 0-don't read into the buffer, don't use common buffer
#endif
#endif
seek_path.init(MAX_BACKGROUND_NODE);
seek_path_s2.init(1);//seek_path_s2.init(MAX_BACKGROUND_NODE);
seek_path_reuse.init(MAX_BACKGROUND_NODE);
group_select.init();
//------------ init flame ------------//
for(int i = 0; i < FLAME_GROW_STEP; ++i)
flame[i].init(Flame::default_width(i), Flame::default_height(i), Flame::base_width(i), FLAME_WIDE);
//------------ init animated line drawer -------//
anim_line.init(ZOOM_X1, ZOOM_Y1, ZOOM_X2, ZOOM_Y2);
//---------- init other objects ----------//
game_set.init(); // this must be called before game.init() as game.init() assume game_set has been initialized
help.init("HELP.RES");
#if( defined(GERMAN) || defined(FRENCH) || defined(SPANISH) )
translate.init();
#endif
tutor.init();
game_file_array.init("*.SAV");
//---------- init game_set -----------//
DEBUG_LOG("Sys::init_objects finish");
return TRUE;
}
//------- End of function Sys::init_objects -----------//
//------- Begin of function Sys::deinit_objects -----------//
void Sys::deinit_objects()
{
//--------- deinit system class ----------//
mouse.deinit(); // mouse must be deinitialized first
mouse_cursor.deinit();
//------- deinit resource class ----------//
font_std.deinit();
font_san.deinit();
font_mid.deinit();
font_small.deinit();
font_news.deinit();
font_hitpoint.deinit();
font_bible.deinit();
font_bard.deinit();
#if( defined(GERMAN) || defined(FRENCH) || defined(SPANISH) )
font_hall.deinit();
#endif
image_icon.deinit();
image_interface.deinit();
image_menu.deinit();
image_button.deinit();
image_spict.deinit();
image_encyc.deinit();
image_tutorial.deinit();
seek_path.deinit();
seek_path_s2.deinit();
seek_path_reuse.deinit();
group_select.deinit();
for(int i = 0; i < FLAME_GROW_STEP; ++i)
flame[i].deinit();
//--------- deinit other objects ----------//
game_set.deinit();
help.deinit();
#if( defined(GERMAN) || defined(FRENCH) || defined(SPANISH) )
translate.deinit();
#endif
tutor.deinit();
config.deinit();
game_file_array.deinit();
}
//------- End of function Sys::deinit_objects -----------//
//-------- Begin of function Sys::run --------//
//
void Sys::run(int isLoadedGame)
{
//-*********** simulate aat ************-//
#ifdef DEBUG
//--------- enable only when simulation -------//
debug_sim_game_type = (m.is_file_exist("sim.sys")) ? 2 : 0;
#endif
//-*********** simulate aat ************-//
sys_flag = SYS_RUN;
view_mode = MODE_NORMAL;
//------- test LZW compression ---------//
#ifdef DEBUG_LZW
test_lzw();
#endif
//------ reset mouse ---------//
mouse.reset_click();
mouse_cursor.set_frame(0);
//-- enable power after the game objets has been initialized --//
power.enable(); // enable power, which handle mouse inputs
//----- sys::disp_frame() will redraw everything when this flag is set to 1 ----//
sys.need_redraw_flag = 1;
option_menu.active_flag = 0;
in_game_menu.active_flag = 0;
sys.disp_frame();
disp_view_mode();
//----------- run the main loop -----------//
main_loop(isLoadedGame);
//-----------------------------------------//
m.unlock_seed();
}
//--------- End of function Sys::run --------//
//-------- Begin of static function test_lzw --------//
//
static void test_lzw()
{
// test lzw compress
if( m.is_file_exist("NORMAL.SAV"))
{
File f,g;
Lzw lzw_c, lzw_d; // one for compress, the other for decompress
f.file_open("NORMAL.SAV");
// read into buffer
long fileSize = f.file_size();
unsigned char *srcPtr = (unsigned char *) mem_add(fileSize);
f.file_read(srcPtr, fileSize);
// find compressed size to allocate space
long compSize = lzw_c.compress(srcPtr, fileSize);
unsigned char *destPtr = (unsigned char *) mem_add( compSize/8+ 4 ); // alloc 4 bytes more
if( compSize != lzw_c.compress(srcPtr, fileSize, destPtr) )
{
err_here();
}
// decompress again
long backSize = lzw_d.expand(destPtr, compSize, NULL);
err_when(backSize != fileSize);
unsigned char *backPtr = (unsigned char *) mem_add( backSize+4 );
if( backSize != lzw_d.expand(destPtr, compSize, backPtr) )
{
err_here();
}
// finally compare srcPtr and backPtr
err_when( memcmp(srcPtr, backPtr, fileSize) );
f.file_close();
// write it to a file
{
unsigned char *writePtr = destPtr;
long writeSize = (compSize +7) / 8;
g.file_create("NORMAL.LZ1");
for( ; writeSize > 0; writeSize -= 0x4000)
{
g.file_write(writePtr, writeSize > 0x4000 ? 0x4000 : writeSize);
writePtr += 0x4000;
}
g.file_close();
}
// test two, compress to a file
g.file_create("NORMAL.LZW");
compSize = lzw_c.compress(srcPtr, fileSize, &g);
g.file_close();
g.file_open("NORMAL.LZW");
backSize = lzw_d.expand(&g, NULL);
err_when(backSize != fileSize);
backPtr = (unsigned char *) mem_resize(backPtr, backSize+4 );
g.file_close();
g.file_open("NORMAL.LZW");
if( backSize != lzw_d.expand(&g, backPtr))
{
err_here();
}
err_when( memcmp(srcPtr,backPtr, fileSize) );
mem_del(destPtr);
mem_del(backPtr);
mem_del(srcPtr);
}
}
//--------- End of static function test_lzw --------//
//-------- Begin of function Sys::main_loop --------//
//
void Sys::main_loop(int isLoadedGame)
{
MSG msg;
// #### begin Gilbert 31/10 #####//
// int rc;
// #### end Gilbert 31/10 #####//
//-------- reset day_frame_count -------//
if( !isLoadedGame )
{
day_frame_count = 0; // for determining when the day counter should be increased.
frame_count = 1;
}
//----- initialize these vars for every game -----//
for( int i=nation_array.size() ; i>0 ; i-- )
{
if( !nation_array.is_deleted(i) )
nation_array[i]->next_frame_ready = 0;
}
remote.packet_send_count = 0;
remote.packet_receive_count = 0;
last_frame_time = m.get_time()+60000; // plus 60 seconds buffer for game loading/starting time
//frame_count = 1;
is_sync_frame = 0;
//----------------------------------------------//
mp_clear_request_save();
remote.enable_poll_msg();
remote.enable_process_queue();
remote_send_success_flag = 1;
#ifdef DEBUG
char longLogSuffix = 'A';
if( remote.is_enable() )
{
if(long_log)
delete long_log;
long_log = new LongLog(longLogSuffix);
}
#endif
//-*********** syn game test ***********-//
#ifdef DEBUG
if(debug_seed_status_flag==DEBUG_SYN_LOAD_AND_COMPARE_ONCE)
sp_load_seed_file();
#endif
//-*********** syn game test ***********-//
vga_front.unlock_buf();
// ------- establish_contact again --------//
// if the game saved after NationRelation::contact_msg_flag set, but
// remote players may have not receive MSG_NATION_CONTACT
//
// send MSG_NATION_CONTACT now
if( !config.explore_whole_map && nation_array.player_recno &&
!nation_array.is_deleted(nation_array.player_recno) )
{
for(short nationRecno = 1; nationRecno <= nation_array.size(); ++nationRecno )
{
if( nationRecno == nation_array.player_recno ||
nation_array.is_deleted(nationRecno) )
continue;
NationRelation *relation = (~nation_array)->get_relation(nationRecno);
if( relation->contact_msg_flag && !relation->has_contact)
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_NATION_CONTACT, 2*sizeof(short));
*shortPtr = nation_array.player_recno;
shortPtr[1] = nationRecno;
}
}
}
// #### begin Gilbert 23/10 #######//
option_menu.active_flag = 0;
in_game_menu.active_flag = 0;
// #### end Gilbert 23/10 #######//
// ##### begin Gilbert 4/11 ######//
DWORD lastDispFrameTime = m.get_time();
// ##### end Gilbert 4/11 ######//
// ##### patch begin Gilbert 17/11 #######//
DWORD firstUnreadyTime = 0;
// ##### patch end Gilbert 17/11 #######//
while( 1 )
{
if (PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!GetMessage( &msg, NULL, 0, 0))
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else if ( !paused_flag && active_flag )
{
// #### begin Gilbert 31/10 ######//
int rc = 0;
// #### end Gilbert 31/10 ######//
if( sys.signal_exit_flag )
break;
vga_front.lock_buf();
yield(); // could be improved, give back the control to Windows, so it can do some OS management. Maybe call WaitMessage() here and set up a timer to get messages regularly.
detect();
//--------------------------------//
// ###### begin Gilbert 4/11 ######//
DWORD markTime = m.get_time(); // a time taken earlier than should_next_frame takes
// ###### end Gilbert 4/11 ######//
// ##### patch begin Gilbert 17/11 #######//
int unreadyPlayerFlag = 0;
// ##### patch end Gilbert 17/11 #######//
if( config.frame_speed>0 ) // 0-frozen
{
if( remote.is_enable() ) // && is_sync_frame )
{
remote.poll_msg();
m.unlock_seed();
rc = is_mp_sync(&unreadyPlayerFlag); // if all players are synchronized
m.lock_seed();
}
else
rc = should_next_frame();
if( rc )
{
LOG_BEGIN;
m.unlock_seed();
#ifdef DEBUG
if( remote.is_enable() )
{
long_log->printf("begin process frame %d\n", frame_count);
}
#endif
process();
if(remote.is_enable() )
m.lock_seed(); // such that random seed is unchanged outside sys::process()
LOG_END;
// -------- compare objects' crc --------- //
// ###### patch begin Gilbert 20/1 ######//
if( remote.is_enable() && (remote.sync_test_level & 2) &&(frame_count % (remote.get_process_frame_delay()+3)) == 0)
{
// cannot compare every frame, as PROCESS_FRAME_DELAY >= 1
crc_store.record_all();
crc_store.send_all();
}
// ###### patch end Gilbert 20/1 ######//
}
}
// ###### begin Gilbert 4/11 #######//
// ------- display graduately, keep on displaying --------- //
if( rc )
{
lastDispFrameTime = m.get_time();
// ####### patch begin Gilbert 17/11 ######//
// reset firstUnreadyTime
firstUnreadyTime = 0;
// ####### patch end Gilbert 17/11 ######//
}
else
{
// ####### patch begin Gilbert 17/11 ######//
// set firstUnreadyTime, begin of a delay
if( !firstUnreadyTime )
firstUnreadyTime = m.get_time();
// ####### patch end Gilbert 17/11 ######//
if( config.frame_speed == 0 || markTime-lastDispFrameTime >= DWORD(1000/config.frame_speed)
#ifdef AMPLUS
|| zoom_need_redraw || map_need_redraw
#endif
)
{
// on second condition, it should be happened when
// in multiplayer, where should_next_frame passed
// but is_mp_sync not passed
disp_frame();
lastDispFrameTime = markTime;
// ####### patch begin Gilbert 17/11 ######//
// display player not ready
if( firstUnreadyTime && m.get_time() - firstUnreadyTime > 5000 )
{
int y = ZOOM_Y1 + 10;
int x = ZOOM_X1 + 10;
for( int nationRecno = 1; nationRecno <= MAX_NATION; ++nationRecno )
{
if( unreadyPlayerFlag & (1 << (nationRecno-1)) )
{
if( !nation_array.is_deleted(nationRecno) )
{
int x2 = font_news.put( x, y, "Waiting for ");
x2 = font_news.put( x2, y, nation_array[nationRecno]->nation_name() );
y += font_news.height() + 5;
}
}
}
}
// ####### patch end Gilbert 17/11 ######//
}
}
// ###### end Gilbert 4/11 #######//
// ----------- detect sond is ended, play another -----------//
if( config.frame_speed == 0 || day_frame_count == 0)
music.yield();
#ifdef DEBUG
if( rc && remote.is_enable() && day_frame_count == 0 )
{
if( long_log)
delete long_log;
if( ++longLogSuffix > 'Z' )
{
longLogSuffix = 'A';
}
long_log = new LongLog(longLogSuffix);
long_log->printf("Game Date : %d/%d/%d\n", info.game_month, info.game_day, info.game_year);
}
#endif
if(rc)
{
//-*********** syn game test ***********-//
//-------------------------------------------------------------//
// record random seed for comparison
//-------------------------------------------------------------//
#ifdef DEBUG
if(debug_seed_status_flag==DEBUG_SYN_LOAD_AND_COMPARE_ONCE ||
debug_seed_status_flag==DEBUG_SYN_AUTO_LOAD)
sp_compare_seed();
else if(debug_seed_status_flag==DEBUG_SYN_AUTO_SAVE)
sp_record_seed();
#endif
//-*********** syn game test ***********-//
//------ auto save -------//
auto_save();
}
//------ detect save game triggered by remote player ------//
if( mp_save_flag && mp_save_frame == frame_count )
{
mp_clear_request_save(); // clear request first before save game
if( nation_array.player_recno ) // only save then the player is still in the game
{
game_file.save_game( remote.save_file_name );
// ####### begin Gilbert 24/10 ######//
//static String str;
//str = "The current game has been saved to ";
//str += remote.save_file_name;
//str += ".";
//box.msg( str );
news_array.multi_save_game();
// ####### end Gilbert 24/10 ######//
}
}
vga_front.unlock_buf();
if( sys.signal_exit_flag )
break;
}
else
{
WaitMessage();
}
}
// #### begin Gilbert 23/10 #######//
in_game_menu.active_flag = 0;
option_menu.active_flag = 0;
// #### end Gilbert 23/10 #######//
vga_front.lock_buf();
#ifdef DEBUG
if(remote.is_enable())
{
if(long_log)
delete long_log;
long_log = NULL;
}
#endif
music.stop();
remote.disable_process_queue();
remote.disable_poll_msg();
mp_clear_request_save();
}
//--------- End of function Sys::main_loop --------//
//-------- Begin of function Sys::auto_save --------//
//
void Sys::auto_save()
{
if( nation_array.player_recno == 0 )
return;
//---------- single player auto save ----------//
if( !remote.is_enable() && // no auto save in a multiplayer game
info.game_month%2==0 && info.game_day==1 && day_frame_count==0)
{
#ifdef DEBUG2
if(1)
#else
if( sys.debug_session || sys.testing_session )
#endif
{
static int saveCount = 0;
switch(saveCount)
{
case 0: game_file.save_game( "AUTO1.SAV" );
break;
case 1: game_file.save_game( "AUTO2.SAV" );
break;
case 2: game_file.save_game( "AUTO3.SAV" );
break;
}
if( ++saveCount>3 )
saveCount = 0;
}
else
{
//--- rename the existing AUTO.SAV to AUTO2.SAV and save a new game ---//
if( m.is_file_exist( "AUTO.SAV" ) )
{
if( m.is_file_exist( "AUTO2.SAV" ) ) // if there is already an AUTO2.SAV, delete it
remove( "AUTO2.SAV" );
rename( "AUTO.SAV", "AUTO2.SAV" );
}
}
game_file.save_game( "AUTO.SAV" );
//-*********** syn game test ***********-//
#ifdef DEBUG
if(debug_seed_status_flag==DEBUG_SYN_AUTO_SAVE)
{
sp_write_seed();
sp_close_seed_file();
//if(info.game_date-info.game_start_date<=365)
if(0)
{
sp_open_seed_file("nseed.rs");
debug_seed_status_flag = DEBUG_SYN_AUTO_SAVE; // continue recording
}
else
{
debug_seed_status_flag = NO_DEBUG_SYN;
//sp_load_seed_file();
//SendMessage(main_hwnd, WM_KEYDOWN, 'L', 0);
mouse.add_key_event(DIK_BACKSLASH, m.get_time()); // load file for comparison
}
}
//debug_seed_status_flag = 2;
//sp_seed_pos_reset();
//sp_record_match_seed();
#endif
//-*********** syn game test ***********-//
}
// --------- multiplayer autosave game --------//
// ###### patch begin Gilbert 23/1 #######//
if( remote.is_enable() && remote.sync_test_level >= 0 && // disable autosave after un-sync
day_frame_count==0 && info.game_day==1 && info.game_month%2==0 )
// ###### patch end Gilbert 23/1 #######//
{
//--- rename the existing AUTO.SVM to AUTO2.SVM and save a new game ---//
if( m.is_file_exist( "AUTO.SVM" ) )
{
if( m.is_file_exist( "AUTO2.SVM" ) ) // if there is already an AUTO2.SVM, delete it
remove( "AUTO2.SVM" );
rename( "AUTO.SVM", "AUTO2.SVM" );
}
game_file.save_game( "AUTO.SVM" );
}
}
//-------- End of function Sys::auto_save --------//
//-------- Begin of function Sys::pause --------//
//
void Sys::pause()
{
if( paused_flag )
return;
InvalidateRect(main_hwnd, NULL, TRUE);
paused_flag = TRUE;
}
//--------- End of function Sys::pause ---------//
//-------- Begin of function Sys::unpause --------//
//
void Sys::unpause()
{
if( !paused_flag )
return;
// ####### begin Gilbert 3/11 #######//
//if( GetForegroundWindow() != main_hwnd )
// return;
// ####### end Gilbert 3/11 #######//
if( !restore() )
{
//-----------------------------------------------------//
// we are unable to restore, this can happen when
// the screen resolution or bitdepth has changed
// we just reload all the art again and re-create
// the front and back buffers. this is a little
// overkill we could handle a screen res change by
// just recreating the front and back buffers we dont
// need to redo the art, but this is way easier.
//-----------------------------------------------------//
if (init_directx())
{
if( !restore() ) // if still not successful, quit
return;
}
}
// ####### begin Gilbert 31/10 #######//
mouse.update_skey_state(); // update ctrl/shift/alt key state after switch task
// ####### end Gilbert 31/10 #######//
//---- restore the saved screen before killing the focus ----//
paused_flag = FALSE;
}
//--------- End of function Sys::unpause ---------//
//-------- Begin of function Sys::restore --------//
//
int Sys::restore()
{
if( !vga_front.restore_buf() )
return 0;
if( !vga_back.restore_buf() )
return 0;
if( sys.debug_session )
{
if( !vga_true_front.restore_buf() )
return 0;
}
// ####### begin Gilbert 16/9 ########//
//else
// vga_front.lock_buf();
// ####### end Gilbert 16/9 ########//
return 1;
}
//--------- End of function Sys::restore ---------//
//-------- Begin of function Sys::yield --------//
//
void Sys::yield()
{
static int isYielding=0;
if( isYielding )
return;
isYielding=1;
handle_window_messages();
mouse.poll_event();
audio.yield();
if( remote.is_enable() )
{
//yield_wsock_msg();
remote.poll_msg();
remote.process_specific_msg(MSG_SET_SPEED); // need to test it here for restoring the speed from frozen to normal
if( config.frame_speed > 0 )
{
remote.process_specific_msg(MSG_TELL_SEND_TIME);
remote.process_specific_msg(MSG_REQUEST_RESEND);
}
//-------- display debug info -----------//
if( power.enable_flag && (testing_session || debug_session) )
{
String str;
str = "Player: ";
str += nation_array.player_recno;
str += "/";
str += nation_array.size();
str += " Send:";
str += remote.packet_send_count;
str += " Recv:";
str += remote.packet_receive_count;
str += " Frame:";
str += frame_count;
font_san.disp( ZOOM_X1, 4, str, ZOOM_X1+300);
}
}
isYielding=0;
}
//--------- End of function Sys::yield ---------//
//-------- Begin of function Sys::yield_wsock_msg --------//
//
void Sys::yield_wsock_msg()
{
// MSG msg;
//------ only get WinSock messages (WSA_ACCEPT & WSA_READ) ------//
// if( PeekMessage(&msg, NULL, WSA_ACCEPT, WSA_READ, PM_NOREMOVE) )
// {
// if (!GetMessage( &msg, NULL, WSA_ACCEPT, WSA_READ))
// return;
// TranslateMessage(&msg);
// DispatchMessage(&msg);
//}
}
//--------- End of function Sys::yield_wsock_msg ---------//
//-------- Begin of function Sys::is_mp_sync --------//
//
// Multiplayer synchronization.
//
// Check all players are ready to proceed to the next frame.
//
int Sys::is_mp_sync(int *unreadyPlayerFlag)
{
#define RESEND_TIME_OUT 2000 // if the other machines still aren't ready after 2 seconds, send the notification again
#define RESEND_AGAIN_TIME_OUT 1000 // keep resending if no responses
#define CONNECTION_LOST_TIME_OUT 20000 // ask for connection lost handling aftering waiting for 5 seconds.
//---- if we haven't been ready for the next frame yet ----//
#ifdef DEBUG
int n;
DEBUG_LOG("begin nation's next_frame_ready");
for (n = 1; n <= nation_array.size(); ++n)
{
DEBUG_LOG(nation_array[n]->next_frame_ready);
}
DEBUG_LOG("end nation's next_frame_ready");
#endif
// ####### patch begin Gilbert 17/11 ######//
if( unreadyPlayerFlag )
*unreadyPlayerFlag = 0;
// ####### end begin Gilbert 17/11 ######//
// if last remote.send was fail, attempt to send it again
if( !nation_array.player_recno )
{
// observation mode
if( !should_next_frame() )
return 0;
remote_send_success_flag = 1;
}
else if( remote_send_success_flag
&& remote.has_send_frame(nation_array.player_recno, frame_count)
&& (~nation_array)->next_frame_ready==0 )
{
DEBUG_LOG("Local player not ready");
if( !should_next_frame() ) // not ready to proceed yet
return 0;
//------------ queue MSG_NEXT_FRAME ----------//
short* shortPtr = (short*) remote.new_send_queue_msg(MSG_NEXT_FRAME, sizeof(short));
shortPtr[0] = nation_array.player_recno; // short_para1 is the nation recno of the current player
//------------ queue MSG_QUEUE_TRAILER ----------//
shortPtr = (short*) remote.new_send_queue_msg(MSG_QUEUE_TRAILER, sizeof(short));
shortPtr[0] = nation_array.player_recno; // short_para1 is the nation recno of the current player
//------ copy all queued action to our own receive buffer to merge with other player's action ----//
remote.append_send_to_receive();
//--- copy the whole queue to a buffer in case of resend request from other players ---//
remote.copy_send_to_backup();
//----------- queue MSG_TELL_SEND_TIME ----------//
/*
unsigned long* longPtr = (unsigned long*) remote.new_send_queue_msg(MSG_TELL_SEND_TIME, sizeof(unsigned long));
longPtr[0] = m.get_time();
*/
//---------- send out all messages in the queue ---------//
remote_send_success_flag = remote.send_queue_now(); // if not sent successfully, try again next time
if( remote_send_success_flag ) // still failed, try again next time
{
DEBUG_LOG("first send sucess" );
remote.init_send_queue(frame_count+1, nation_array.player_recno); // frame_count, initialize for next frame's send queue
// sent random seed
char *p = (char *)remote.new_send_queue_msg(MSG_TELL_RANDOM_SEED, sizeof(short)+sizeof(long));
*(short *)p = nation_array.player_recno;
p += sizeof(short);
*(long *)p = m.get_random_seed();
}
else
{
// re_transmit as quickly as possible
ec_remote.re_transmit(5);
}
}
else
{
DEBUG_LOG("Local player nation ready");
}
//----- if previous sending was not successful, send again now -----//
if( !remote_send_success_flag )
{
remote_send_success_flag = remote.send_queue_now(); // if not sent successfully, try again next time
if( remote_send_success_flag ) // still failed, try again next time
{
DEBUG_LOG("resending ok");
remote.init_send_queue(frame_count+1, nation_array.player_recno); // frame_count, initialize for next frame's send queue
// sent random seed
char *p = (char *)remote.new_send_queue_msg(MSG_TELL_RANDOM_SEED, sizeof(short)+sizeof(long));
*(short *)p = nation_array.player_recno;
p += sizeof(short);
*(long *)p = m.get_random_seed();
}
else
{
// re_transmit as quickly as possible
ec_remote.re_transmit(5);
DEBUG_LOG("resending not ok");
return 0;
}
}
//------ pre_process MSG_NEXT_FRAME in the queue -----//
remote.process_specific_msg(MSG_NEXT_FRAME);
#ifdef DEBUG
DEBUG_LOG("begin nation's next_frame_ready");
for (n = 1; n <= nation_array.size(); ++n)
{
DEBUG_LOG(nation_array[n]->next_frame_ready);
}
DEBUG_LOG("end nation's next_frame_ready");
#endif
//------ check if all remote players are ready to proceed -----//
int nationRecno;
Nation* nationPtr;
for( nationRecno=nation_array.size() ; nationRecno>0 ; nationRecno-- )
{
if( nation_array.is_deleted(nationRecno) )
continue;
nationPtr = nation_array[nationRecno];
//------- if some remote machines are not ready yet -------//
// ###### patch begin Gilbert 17/11 ######//
if( nationPtr->is_remote() &&
(remote.has_send_frame(nationRecno, frame_count) && !nationPtr->next_frame_ready) )
{
if( unreadyPlayerFlag )
*unreadyPlayerFlag |= ( 1 << (nationRecno-1) );
break;
}
// ###### end begin Gilbert 17/11 ######//
}
//------- if some remote machines are not ready yet -------//
if( nationRecno>0 )
{
DEBUG_LOG("a nation not ready");
DEBUG_LOG(nationRecno);
if( m.get_time() >= last_frame_time+RESEND_TIME_OUT )
{
//---- if it has been time out for too long, carry out connection lost handling ---//
if( // m.get_time() >= last_frame_time+CONNECTION_LOST_TIME_OUT ||
!ec_remote.is_player_valid(nationRecno))
{
DEBUG_LOG( "Connection Lost" );
// ###### begin Gilbert 24/10 ######//
// box.msg( "Connection Lost!" ); //**BUGHERE, should have a function to set all units, structures of this nation to AI
news_array.multi_connection_lost(nationRecno);
// may allow save game here, ask user whether to save the game
// ###### end Gilbert 24/10 ######//
nationPtr->nation_type = NATION_AI; // let computer take over the nation
nation_array.ai_nation_count++;
}
//------- re-send the message -------//
/* re-send is now done by ec_remote
else if( m.get_time() >= last_resend_time + RESEND_AGAIN_TIME_OUT ) // resent once per half second
{
DEBUG_LOG( "send retransmit request" );
RemoteMsg* remoteMsg = remote.new_msg(MSG_REQUEST_RESEND, sizeof(int) + sizeof(DWORD) );
DWORD* dwordPtr = (DWORD*) remoteMsg->data_buf;
dwordPtr[0] = (~nation_array)->player_id; // send to us
dwordPtr[1] = frame_count; // request it to send us queue of this frame
remote.send_free_msg( remoteMsg, nation_array[nationRecno]->player_id ); // send to that nationRecno only
last_resend_time = m.get_time();
}
*/
}
return 0;
}
//--------------------------------------------------------//
//
// When all players are ready to proceed to the next frame
//
// As we have already know all players are ready, we can
// reset the next_frame_ready flag for all nations.
//
//--------------------------------------------------------//
DEBUG_LOG("all nation ready");
for( int i=nation_array.size() ; i>0 ; i-- )
{
if( nation_array.is_deleted(i) )
continue;
nation_array[i]->next_frame_ready=0; // -- instead of set to 0, set it may be 2 if it has just received an notifying signal for the further next frame from a player as it also sent out a next frame ready msg to all other players
}
//--------- process msgs in the receive queue ----------//
remote.process_receive_queue();
#ifdef DEBUG
DEBUG_LOG("begin nation's next_frame_ready");
for (n = 1; n <= nation_array.size(); ++n)
{
DEBUG_LOG(nation_array[n]->next_frame_ready);
}
DEBUG_LOG("end nation's next_frame_ready");
#endif
//-------- record this frame's time -------//
last_frame_time = m.get_time();
last_resend_time = 0;
return 1;
}
//---------- End of function Sys::is_mp_sync --------//
//-------- Begin of function Sys::should_next_frame --------//
//
// Check if it's now the time for processing the next frame.
//
int Sys::should_next_frame()
{
//----- special modes: 0-frozen, 9-fastest possible -----//
if( config.frame_speed==99 )
return 1;
if( config.frame_speed==0 )
return 0;
//---- check if it's now the time for processing the next frame ----//
DWORD curTime = m.get_time();
if( next_frame_time ) // if next_frame_time==0, it's the first frame of the game
{
if( next_frame_time < 1000 ) // the DWORD variable has been overflow
{
if( curTime < next_frame_time || curTime >= 1000 ) // >= 1000 if the curTime has been overflow yet, wait for it to overflow so we can compare it when next_frame_time
return 0;
}
else // normal non-overflow case
{
if( curTime < next_frame_time )
return 0;
}
}
//--- Time between frames = 1000 milliseconds / frames per second ---//
next_frame_time = curTime + 1000 / config.frame_speed;
return 1;
}
//--------- End of function Sys::should_next_frame ---------//
//-------- Begin of function Sys::main_win_proc --------//
//
long Sys::main_win_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch( message )
{
case WM_CREATE:
sys.main_hwnd = hWnd;
break;
case WM_ACTIVATEAPP:
// ####### begin Gilbert 3/11 #######//
// active_flag = (BOOL)wParam && GetForegroundWindow() == hWnd && !IsIconic(hWnd);
active_flag = (BOOL)wParam && !IsIconic(hWnd);
// ####### end Gilbert 3/11 #######//
//--------------------------------------------------------------//
// while we were not-active something bad happened that caused us
// to pause, like a surface restore failing or we got a palette
// changed, now that we are active try to fix things
//--------------------------------------------------------------//
if( active_flag )
{
unpause();
need_redraw_flag = 1; // for Sys::disp_frame to redraw the screen
}
else
pause();
break;
case WM_DESTROY:
main_hwnd = NULL;
// game.deinit(); // end of game
deinit_directx();
PostQuitMessage( 0 );
break;
case WM_ERASEBKGND:
// do not erase the background
return 1;
case WM_PALETTECHANGED:
// if we changed the palette, do nothing
if ((HWND)wParam == hWnd) break;
// we can't restore if dd_pal is not initialized
if (!vga.dd_pal) break;
// if we are temporarily overriding, then we should be okay
if (vga.back_up_pal) break;
// restore palette
vga.dd_pal->SetEntries(0, 0, 256, vga.pal_entry_buf);
break;
default:
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
//--------- End of function Sys::main_win_proc ---------//
//-------- Begin of function Sys::handle_window_messages --------//
void Sys::handle_window_messages()
{
static int lastTick;
int tick = GetTickCount();
if (lastTick == tick)
return;
lastTick = tick;
MSG msg;
while (PeekMessage(&msg, sys.main_hwnd, 0, 0, PM_NOREMOVE))
{
BOOL r;
r = GetMessage(&msg, sys.main_hwnd, 0, 0);
if (r == -1)
{
// not handled
return;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//-------- End of function Sys::handle_window_messages --------//
//-------- Begin of function Sys::process_key --------//
//
void Sys::process_key(unsigned scanCode, unsigned skeyState)
{
detect_function_key(scanCode, skeyState);
//----- don't detect letter keys when in chat mode ----//
if( !(view_mode == MODE_NATION &&
info.nation_report_mode == NATION_REPORT_CHAT) )
{
if( sys.debug_session || sys.testing_session || scenario_cheat_flag )
{
detect_cheat_key(scanCode, skeyState);
detect_debug_cheat_key(scanCode, skeyState);
if( detect_scenario_cheat_key(scanCode, skeyState) )
return;
}
else
{
if( nation_array.player_recno && !remote.is_enable() ) // not allowed in multiplayer mode
{
if( (~nation_array)->cheat_enabled_flag )
{
detect_cheat_key(scanCode, skeyState);
}
else
{
#ifdef GERMAN
if( detect_key_str(1, "!!!###") )
#else
if( detect_key_str(1, "!!!@@@###") )
#endif
{
box.msg( "Cheat Mode Enabled." );
(~nation_array)->cheat_enabled_flag = 1;
}
}
}
}
detect_letter_key(scanCode, skeyState);
detect_set_speed(scanCode, skeyState); // set the speed of the game
}
}
//--------- End of function Sys::process_key ---------//
//-------- Begin of function Sys::detect_letter_key --------//
//
void Sys::detect_letter_key(unsigned scanCode, unsigned skeyState)
{
int keyCode;
if((keyCode = mouse.is_key(scanCode, skeyState, (WORD) 0, K_IS_CTRL)))
{
int groupId;
switch(keyCode)
{
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
groupId = keyCode-'0';
group_select.group_units(groupId);
break;
}
}
if((keyCode = mouse.is_key(scanCode, skeyState, (WORD) 0, K_IS_ALT)))
{
int groupId;
switch(keyCode)
{
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
groupId = keyCode-'0';
group_select.select_grouped_units(groupId);
break;
}
}
if( (keyCode = mouse.is_key(scanCode, skeyState, (WORD) 0, K_UNIQUE_KEY)) )
{
keyCode = m.lower(keyCode);
switch(keyCode)
{
case KEY_ESC:
set_view_mode(MODE_NORMAL);
break;
//---- keys for toggling map mode ----//
case 'q':
world.map_matrix->toggle_map_mode(0);
break;
case 'w':
world.map_matrix->toggle_map_mode(1);
break;
case 'e':
world.map_matrix->toggle_map_mode(2);
break;
//--------- opaque report mode --------//
case 'p':
config.opaque_report = !config.opaque_report;
if( config.opaque_report )
box.msg( "Opaque report mode." );
else
box.msg( "Transparent report mode." );
break;
//------ clear news messages ------//
case 'x':
news_array.clear_news_disp();
break;
//------ jump to a location with natural resource ---//
case 'j':
site_array.go_to_a_raw_site();
break;
//--------- bring up the option menu ----------//
case 'o':
// ##### begin Gilbert 5/11 #######//
// game.in_game_option_menu();
option_menu.enter(!remote.is_enable());
// ##### end Gilbert 5/11 #######//
break;
//--------- forward/backward tutorial text block --------//
case ',':
if( game.game_mode == GAME_TUTORIAL )
tutor.prev_text_block();
break;
case '.':
if( game.game_mode == GAME_TUTORIAL )
tutor.next_text_block();
break;
//---- keys for saving and loading game -----//
case 's':
save_game();
break;
case 'l':
load_game();
break;
case KEY_UP:
world.disp_next(-1, 0); // previous same object type of any nation
break;
case KEY_DOWN:
world.disp_next(1, 0); // next same object type of any nation
break;
case KEY_LEFT:
world.disp_next(-1, 1); // prevous same object type of the same nation
break;
case KEY_RIGHT:
world.disp_next(1, 1); // next same object type of the same nation
break;
//---- key for quick locate -----//
case 'k':
locate_king_general(RANK_KING);
break;
case 'g':
locate_king_general(RANK_GENERAL);
break;
case 'y':
locate_spy();
break;
case 'h':
locate_ship();
break;
case 'f':
locate_camp();
break;
}
}
}
//--------- End of function Sys::detect_letter_key ---------//
//-------- Begin of function Sys::detect_function_key --------//
//
void Sys::detect_function_key(unsigned scanCode, unsigned skeyState)
{
int keyCode;
if( (keyCode = mouse.is_key(scanCode, skeyState, (WORD) 0, K_UNIQUE_KEY)) )
{
switch(keyCode)
{
case KEY_ESC:
set_view_mode(MODE_NORMAL);
break;
case KEY_F1:
if( view_mode==MODE_NATION )
set_view_mode(MODE_NORMAL);
else
set_view_mode(MODE_NATION);
break;
case KEY_F2:
if( view_mode==MODE_TOWN )
set_view_mode(MODE_NORMAL);
else
set_view_mode(MODE_TOWN);
break;
case KEY_F3:
if( view_mode==MODE_ECONOMY )
set_view_mode(MODE_NORMAL);
else
set_view_mode(MODE_ECONOMY);
break;
case KEY_F4:
if( view_mode==MODE_TRADE )
set_view_mode(MODE_NORMAL);
else
set_view_mode(MODE_TRADE);
break;
case KEY_F5:
if( view_mode==MODE_MILITARY )
set_view_mode(MODE_NORMAL);
else
set_view_mode(MODE_MILITARY);
break;
case KEY_F6:
if( view_mode==MODE_TECH )
set_view_mode(MODE_NORMAL);
else
set_view_mode(MODE_TECH);
break;
case KEY_F7:
if( view_mode==MODE_SPY )
set_view_mode(MODE_NORMAL);
else
set_view_mode(MODE_SPY);
break;
case KEY_F8:
if( view_mode==MODE_RANK )
set_view_mode(MODE_NORMAL);
else
set_view_mode(MODE_RANK);
break;
case KEY_F9:
if( view_mode==MODE_NEWS_LOG )
set_view_mode(MODE_NORMAL);
else
set_view_mode(MODE_NEWS_LOG);
break;
case KEY_F10:
// ##### begin Gilbert 5/11 ######//
//game.in_game_menu();
in_game_menu.enter(!remote.is_enable());
// ##### end Gilbert 5/11 ######//
break;
case KEY_F11:
capture_screen();
break;
case KEY_F12:
capture_minimap();
break;
}
}
}
//--------- End of function Sys::detect_function_key ---------//
//-------- Begin of function Sys::detect_cheat_key --------//
//
void Sys::detect_cheat_key(unsigned scanCode, unsigned skeyState)
{
if( remote.is_enable() ) // no cheat keys in multiplayer games
return;
int keyCode = mouse.is_key( scanCode, skeyState, (WORD) 0, K_CHAR_KEY );
if( !keyCode ) // since all keys concern are printable
return;
keyCode = m.lower(keyCode);
switch( keyCode )
{
//-------- cheat keys ---------//
case 'c': // add cash
if( nation_array.player_recno )
(~nation_array)->add_cheat((float)1000);
break;
case '\\': // add food
if( nation_array.player_recno )
(~nation_array)->add_food((float)1000);
break;
case 't':
tech_res.inc_all_tech_level(nation_array.player_recno);
god_res.enable_know_all(nation_array.player_recno);
box.msg( "Your technology has advanced.\nYou can now invoke all Greater Beings." );
break;
case 'm':
world.unveil(0, 0, MAX_WORLD_X_LOC-1, MAX_WORLD_Y_LOC-1);
world.visit(0, 0, MAX_WORLD_X_LOC-1, MAX_WORLD_Y_LOC-1, 0, 0);
break;
case ';': // increase town population
if( town_array.selected_recno )
{
Town* townPtr = town_array[town_array.selected_recno];
#ifdef DEBUG2
for(int di=0; dirace_pop_array[di])
{
townPtr->init_pop(di+1, 10, 100);
break;
}
}
#else
townPtr->init_pop( m.random(MAX_RACE)+1, 10, 100 );
#endif
townPtr->auto_set_layout();
}
break;
case 'u':
config.king_undie_flag = !config.king_undie_flag;
if( config.king_undie_flag )
box.msg( "Your king is now immortal." );
else
box.msg( "King immortal mode is now disabled." );
break;
case '=':
if( firm_array.selected_recno )
{
Firm* firmPtr = firm_array[firm_array.selected_recno];
if( firmPtr->firm_id == FIRM_BASE )
{
((FirmBase*)firmPtr)->pray_points = (float) MAX_PRAY_POINTS;
info.disp();
}
}
break;
case 'b': // finish building a firm instantly or increase the hit points of a firm to its max
if( firm_array.selected_recno )
{
Firm* firmPtr = firm_array[firm_array.selected_recno];
firmPtr->hit_points = firmPtr->max_hit_points;
}
break;
case 'z': // toggle fast_build
config.fast_build = !config.fast_build;
if( !config.fast_build )
box.msg( "Fast build is now disabled" );
else
box.msg( "Fast build is now enabled" );
break;
//----- increase the combat level -------//
case '[':
if( unit_array.selected_recno )
{
Unit* unitPtr = unit_array[unit_array.selected_recno];
unitPtr->set_combat_level( min(100, unitPtr->skill.combat_level+20) );
}
break;
//----- increase the skill level of the unit -------//
case ']':
if( unit_array.selected_recno )
{
Unit* unitPtr = unit_array[unit_array.selected_recno];
if( unitPtr->skill.skill_id )
unitPtr->skill.skill_level = min(100, unitPtr->skill.skill_level+20);
}
break;
//----- increase the spying skill -------//
case '\'':
if( unit_array.selected_recno )
{
Unit* unitPtr = unit_array[unit_array.selected_recno];
if( unitPtr->spy_recno )
{
Spy* spyPtr = spy_array[unitPtr->spy_recno];
spyPtr->spy_skill = min(100, spyPtr->spy_skill+20);
}
}
break;
}
}
//--------- End of function Sys::detect_cheat_key ---------//
//-------- Begin of function Sys::detect_debug_cheat_key --------//
//
void Sys::detect_debug_cheat_key(unsigned scanCode, unsigned skeyState)
{
if( remote.is_enable() ) // no cheat keys in multiplayer games
return;
int keyCode = mouse.is_key( scanCode, skeyState, (WORD) 0, K_UNIQUE_KEY );
if( !keyCode ) // since all keys concern are printable
return;
keyCode = m.lower(keyCode);
switch( keyCode )
{
/*
case 'j': // allow all nations to have all god creatures
for( i=1; i<=nation_array.size() ; i++ )
{
if( !nation_array.is_deleted(i) )
god_res.enable_know_all(i);
}
box.msg( "Now knowledge of seat of power is available to all nations." );
break;
*/
case 'n':
config.blacken_map = !config.blacken_map;
config.fog_of_war = config.blacken_map;
break;
case 'r': // set default report nation
if( firm_array.selected_recno )
{
info.default_viewing_nation_recno = firm_array[firm_array.selected_recno]->nation_recno;
}
else if( town_array.selected_recno )
{
int nationRecno = town_array[town_array.selected_recno]->nation_recno;
if( nationRecno )
info.default_viewing_nation_recno = nationRecno;
}
else if( unit_array.selected_recno )
{
int nationRecno = unit_array[unit_array.selected_recno]->nation_recno;
if( nationRecno )
info.default_viewing_nation_recno = nationRecno;
}
break;
case 'a':
if( view_mode==MODE_AI_ACTION )
set_view_mode(MODE_NORMAL);
else
set_view_mode(MODE_AI_ACTION);
break;
//-----------------------------------//
/*
case 't': // next town layout
if( town_array.selected_recno )
town_array[town_array.selected_recno]->auto_set_layout();
break;
*/
//-------------------------------//
case 'i':
config.disable_ai_flag = !config.disable_ai_flag;
if( config.disable_ai_flag )
box.msg( "AI is now disabled" );
else
box.msg( "AI is now enabled" );
break;
case 'd':
config.show_ai_info = !config.show_ai_info;
info.disp();
if( config.show_ai_info )
box.msg( "Now AI info will be displayed." );
else
box.msg( "Now AI info will not be displayed." );
break;
case '/':
config.show_all_unit_icon = !config.show_all_unit_icon;
if( config.show_all_unit_icon )
box.msg( "Now all unit icons will be displayed." );
else
box.msg( "Now all unit icons will not be displayed." );
break;
#ifdef DEBUG
case '~':
sys.testing_session = !sys.testing_session;
if( sys.testing_session )
box.msg( "sys.testing_session is now 1." );
else
box.msg( "sys.testing_session is now 0." );
break;
case '\r':
if(debug2_enable_flag)
debug2_enable_flag = 0;
else
debug2_enable_flag = 1;
break;
/* //-*********** syn game test ***********-//
case '\'':
//if(debug2_enable_flag && debug_sim_game_type)
//game_file_array[0]->load_game("syn.sav");
game_file.load_game("syn.sav");
sp_load_seed_file();
debug_seed_status_flag = DEBUG_SYN_AUTO_LOAD;
break;
case '[':
if(m.is_file_exist("SYN.SYS"))
{
debug_seed_status_flag = DEBUG_SYN_AUTO_SAVE;
sp_seed_pos_reset();
sp_record_match_seed();
sp_create_seed_file("nseed.rs");
game_file.save_game("syn.sav");
}
break;
case ']':
if(debug_seed_status_flag==NO_DEBUG_SYN)
{
if(m.is_file_exist("SYN.SYS"))
{
debug_seed_status_flag = DEBUG_SYN_LOAD_AND_COMPARE_ONCE;
game_file.load_game("syn.sav");
sp_load_seed_file();
}
else
debug_seed_status_flag = NO_DEBUG_SYN;
}
break;
*/ //-*********** syn game test ***********-//
#endif
}
}
//--------- End of function Sys::detect_debug_cheat_key ---------//
//-------- Start of function detect_scenario_cheat_key -------------//
static int detect_scenario_cheat_key(unsigned scanCode, unsigned skeyState)
{
if( remote.is_enable() ) // no cheat keys in multiplayer games
return 0;
int keyCode = mouse.is_key(scanCode, skeyState, (WORD) 0, K_IS_CTRL);
if( !keyCode )
return 0;
//------------------------------------------//
int keyProcessed = 0;
Firm *firmPtr;
Unit *unitPtr;
Town *townPtr;
Nation *nationPtr;
Site *sitePtr;
Spy *spyPtr;
Location *locPtr;
int i, j, curXLoc, curYLoc;
switch(keyCode)
{
case 'p': //-------- get scroll of power for the race of selected unit --------//
if(unit_array.selected_recno)
{
unitPtr = unit_array[unit_array.selected_recno];
if(unitPtr->nation_recno==nation_array.player_recno && unitPtr->race_id)
{
god_res[unitPtr->race_id]->enable_know(unitPtr->nation_recno);
//box.msg( "Get Scroll of Power of selected unit for his race" );
keyProcessed++;
}
}
keyProcessed++;
break;
case 't': //-------- get all technology except scrolls of power -------//
tech_res.inc_all_tech_level(nation_array.player_recno);
//box.msg( "Your technology has advanced." );
keyProcessed++;
break;
case 'g': //------- get galleon and cannon technologies -------//
err_when(tech_res[4]->unit_id != UNIT_CANNON);
err_when(tech_res[7]->unit_id != UNIT_GALLEON);
i = tech_res[4]->get_nation_tech_level(nation_array.player_recno);
if(i < tech_res[4]->max_tech_level)
tech_res[4]->set_nation_tech_level(nation_array.player_recno, i+1);
i = tech_res[7]->get_nation_tech_level(nation_array.player_recno);
if(i < tech_res[7]->max_tech_level)
tech_res[7]->set_nation_tech_level(nation_array.player_recno, i+1);
//box.msg( "Get technologies of Galleon and Cannon." );
keyProcessed++;
break;
case 'q': //-- decrease population of a selected race in a selected village by 10 --//
if(town_array.selected_recno)
{
townPtr = town_array[town_array.selected_recno];
if(townPtr->nation_recno == nation_array.player_recno)
{
i = townPtr->get_selected_race();
if(i && townPtr->race_pop_array[i-1])
{
for(j=10; j>0 && !town_array.is_deleted(townPtr->town_recno); --j)
townPtr->kill_town_people(i);
//box.msg( "Population decrease by 10." );
keyProcessed++;
}
townPtr->auto_set_layout();
}
}
keyProcessed++;
break;
case 'w': //-- increase population of a selected race in a selected village by 10 --//
if(town_array.selected_recno)
{
townPtr = town_array[town_array.selected_recno];
if(townPtr->nation_recno == nation_array.player_recno)
{
i = townPtr->get_selected_race();
if(i && townPtr->race_pop_array[i-1])
{
townPtr->init_pop(i, 10, 100);
//box.msg( "Population increase by 10." );
keyProcessed++;
}
townPtr->auto_set_layout();
}
}
keyProcessed++;
break;
case 'e': //-------- decrease the reputation by 10 -----------//
nationPtr = nation_array[nation_array.player_recno];
nationPtr->reputation -= 10;
if(nationPtr->reputation < -100)
nationPtr->reputation = (float) -100;
//box.msg( "Reputation decrease by 10." );
keyProcessed++;
break;
case 'r': //-------- increase the reputation by 10 -----------//
nationPtr = nation_array[nation_array.player_recno];
nationPtr->reputation += 10;
if(nationPtr->reputation > 100)
nationPtr->reputation = (float) 100;
//box.msg( "Reputation increase by 10." );
keyProcessed++;
break;
case 'j': //--------- damage a building by 20 pt -----------//
if(firm_array.selected_recno)
{
firmPtr = firm_array[firm_array.selected_recno];
if(firmPtr->nation_recno==nation_array.player_recno)
{
firmPtr->hit_points -= 20;
if(firmPtr->hit_points < 1)
firmPtr->hit_points = (float) 1;
//box.msg( "damage firm by 20 points." );
keyProcessed++;
}
}
keyProcessed++;
break;
case 'k': //--------- repair a building by 20 pt -----------//
if(firm_array.selected_recno)
{
firmPtr = firm_array[firm_array.selected_recno];
if(firmPtr->nation_recno==nation_array.player_recno)
{
firmPtr->hit_points += 20;
if(firmPtr->hit_points > firmPtr->max_hit_points)
firmPtr->hit_points = firmPtr->max_hit_points;
//box.msg( "Repair firm by 20 points." );
keyProcessed++;
}
}
keyProcessed++;
break;
case 'x': //------ decrease cash by 1000 --------//
nationPtr = nation_array[nation_array.player_recno];
nationPtr->cash -= 1000;
if(nationPtr->cash < 0)
nationPtr->cash = (float) 0;
//box.msg( "Decrease cash by 1000." );
keyProcessed++;
break;
case 'c': //------ decrease food by 1000 --------//
nationPtr = nation_array[nation_array.player_recno];
nationPtr->food -= 1000;
if(nationPtr->food < 0)
nationPtr->food = (float) 0;
//box.msg( "Decrease food by 1000." );
keyProcessed++;
break;
case 'm': //----- add natural resource to cursor pos / remove existing resource ------//
if(get_mouse_loc_in_zoom_map(curXLoc, curYLoc))
{
locPtr = world.get_loc(curXLoc, curYLoc);
if(locPtr->has_site()) // remove site
{
i = locPtr->site_recno();
sitePtr = site_array[i];
if(!sitePtr->has_mine)
{
site_array.del_site(i);
//box.msg( "Site deleted." );
keyProcessed++;
}
}
else if(locPtr->can_build_site(1) && !locPtr->is_power_off()) // add site
{
i = MAX_RAW_RESERVE_QTY * (50 + m.random(50)) / 100;
site_array.add_site(curXLoc, curYLoc, SITE_RAW, m.random(MAX_RAW)+1, i);
//box.msg( "Site added." );
keyProcessed++;
}
}
keyProcessed++;
break;
case 'b': //------------ add reserve of natural resource by 100 ----------//
if(get_mouse_loc_in_zoom_map(curXLoc, curYLoc))
{
locPtr = world.get_loc(curXLoc, curYLoc);
if(locPtr->has_site())
{
i = locPtr->site_recno();
sitePtr = site_array[i];
if(!sitePtr->has_mine)
{
sitePtr->reserve_qty += 100;
//box.msg( "increase reserve by 100." );
keyProcessed++;
info.disp();
}
}
}
keyProcessed++;
break;
case 'v': //------------ reduce reserve of natural resource by 100 ----------//
if(get_mouse_loc_in_zoom_map(curXLoc, curYLoc))
{
locPtr = world.get_loc(curXLoc, curYLoc);
if(locPtr->has_site())
{
i = locPtr->site_recno();
sitePtr = site_array[i];
if(!sitePtr->has_mine && sitePtr->reserve_qty>100)
{
sitePtr->reserve_qty -= 100;
//box.msg( "reduce reserve by 100." );
keyProcessed++;
info.disp();
}
}
}
keyProcessed++;
break;
case 'h': //-------- hide map except for areas around your village, people --------//
if( config.explore_whole_map ) // no action if the setting of the map is explored
break;
vga_back.bar(MAP_X1, MAP_Y1, MAP_X2, MAP_Y2, UNEXPLORED_COLOR);
for(j=0; jexplored_off();
}
for(i=town_array.size(); i>0; --i)
{
if(town_array.is_deleted(i))
continue;
townPtr = town_array[i];
if(townPtr->nation_recno == nation_array.player_recno)
world.unveil(townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2);
}
for(i=firm_array.size(); i>0; --i)
{
if(firm_array.is_deleted(i))
continue;
firmPtr = firm_array[i];
if(firmPtr->nation_recno == nation_array.player_recno)
world.unveil(firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2);
}
for(i=unit_array.size(); i>0; --i)
{
if(unit_array.is_deleted(i))
continue;
unitPtr = unit_array[i];
if(unitPtr->nation_recno == nation_array.player_recno)
world.unveil(unitPtr->next_x_loc(), unitPtr->next_y_loc(), unitPtr->next_x_loc(), unitPtr->next_y_loc());
}
for(i=spy_array.size(); i>0; --i)
{
if(spy_array.is_deleted(i))
continue;
spyPtr = spy_array[i];
if(spyPtr->true_nation_recno!=nation_array.player_recno)
continue;
if(spyPtr->spy_place == SPY_FIRM)
{
if(!firm_array.is_deleted(spyPtr->spy_place_para))
{
firmPtr = firm_array[spyPtr->spy_place_para];
world.unveil(firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2);
}
}
else if(spyPtr->spy_place == SPY_TOWN)
{
if(!town_array.is_deleted(spyPtr->spy_place_para))
{
townPtr = town_array[spyPtr->spy_place_para];
world.unveil(townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2);
}
}
}
for(i=2; i<=nation_array.size(); ++i) // assume player_nation_recno = 1
{
if( nation_array.is_deleted(i) )
continue;
(~nation_array)->init_relation(i);
nation_array[i]->init_relation(1);
}
keyProcessed++;
break;
case 'z': //------------ put the selected unit to the cursor position ------------//
if(unit_array.selected_recno)
{
unitPtr = unit_array[unit_array.selected_recno];
if(get_mouse_loc_in_zoom_map(curXLoc, curYLoc))
{
if(unitPtr->mobile_type!=UNIT_LAND)
{
curXLoc = (curXLoc/2) * 2;
curYLoc = (curYLoc/2) * 2;
}
locPtr = world.get_loc(curXLoc, curYLoc);
if(locPtr->can_move(unitPtr->mobile_type))
{
world.set_unit_recno(unitPtr->next_x_loc(), unitPtr->next_y_loc(), unitPtr->mobile_type, 0);
unitPtr->stop2();
unitPtr->next_x = curXLoc << ZOOM_X_SHIFT_COUNT;
unitPtr->next_y = curYLoc << ZOOM_Y_SHIFT_COUNT;
unitPtr->cur_x = unitPtr->go_x = unitPtr->next_x;
unitPtr->cur_y = unitPtr->go_y = unitPtr->next_y;
unitPtr->move_to_x_loc = curXLoc;
unitPtr->move_to_y_loc = curYLoc;
world.set_unit_recno(curXLoc, curYLoc, unitPtr->mobile_type, unitPtr->sprite_recno);
//box.msg( "move unit." );
keyProcessed++;
}
}
}
keyProcessed++;
break;
case 's':
if( info.default_viewing_nation_recno &&
nation_array.player_recno &&
nation_array[info.default_viewing_nation_recno]->is_ai() )
{
nation_array[info.default_viewing_nation_recno]->surrender(nation_array.player_recno);
}
keyProcessed++;
break;
}
return keyProcessed;
}
//--------- End of function detect_scenario_cheat_key ---------------//
//-------- Begin of function Sys::detect_set_speed --------//
//
int Sys::detect_set_speed(unsigned scanCode, unsigned skeyState)
{
int keyCode = mouse.is_key( scanCode, skeyState, (WORD) 0, K_CHAR_KEY );
if( !keyCode ) // since all keys concern are printable
return 0;
//------- determine the speed to set of the key pressed -------//
if( keyCode >= '0' && keyCode <= '8' )
{
set_speed( (keyCode-'0') * 3 );
return 1;
}
else if( keyCode == '9' )
{
set_speed( 99 ); // highest possible speed
return 1;
}
return 0;
}
//--------- End of function Sys::detect_set_speed ---------//
//--------- Begin of function Sys::detect_key_str --------//
//
// Detect for continous input of a string from the keyboard
//
// keyStrId = the id. of the key string
// each id has its individual key_str_pos
// keyStr = the string to detect
//
// return : 1 - complete string detected
// 0 - not detected
//
int Sys::detect_key_str(int keyStrId, char* keyStr)
{
err_when( keyStrId < 0 || keyStrId >= MAX_KEY_STR );
unsigned char* keyStr2 = (unsigned char*) keyStr;
if( mouse.key_code == keyStr2[key_str_pos[keyStrId]] )
key_str_pos[keyStrId]++;
else
key_str_pos[keyStrId]=0; // when one key unmatched, reset the counter
if( key_str_pos[keyStrId] >= (int) strlen(keyStr) )
{
key_str_pos[keyStrId]=0; // the full string has been entered successfully without any mistakes
return 1;
}
else
return 0;
}
//----------- End of function Sys::detect_key_str --------//
//-------- Begin of function Sys::set_speed --------//
//
void Sys::set_speed(int frameSpeed, int remoteCall)
{
//--------- if multiplayer, update remote players setting -------//
if( remote.is_enable() && !remoteCall )
{
RemoteMsg *remoteMsg = remote.new_msg(MSG_SET_SPEED, sizeof(short));
*((short*)remoteMsg->data_buf) = frameSpeed;
remote.send_free_msg( remoteMsg ); // send out the message and free it after finishing sending
}
//---------- set the speed now ----------//
if( config.frame_speed==0 ) // if it's currently frozen, set last_frame_time to avoid incorrect timeout
last_frame_time = m.get_time();
config.frame_speed = frameSpeed;
}
//--------- End of function Sys::set_speed ---------//
//-------- Begin of function Sys::capture_screen --------//
//
void Sys::capture_screen()
{
String str;
int i;
for (i = 0; i <= 999; i++)
{
str = m.format(info.random_seed, 1);
str += "_";
if (i < 100) str += "0";
if (i < 10) str += "0";
str += i;
str += ".BMP";
if( !m.is_file_exist(str) )
break;
}
if (i > 999) // all file names from DWORLD000 to DWORLD999 have been occupied
return;
if( sys.debug_session ) // in debug session, the buffer is not locked, we need to lock it for capturing the screen
{
vga_true_front.lock_buf();
vga_true_front.write_bmp_file(str);
vga_true_front.unlock_buf();
}
else
{
vga_front.write_bmp_file(str);
}
//------ display msg --------//
String str2;
#if(defined(SPANISH))
str2 = "Pantalla actual guardada en el archivo ";
str2 += str;
str2 += ".";
#elif(defined(FRENCH))
str2 = "Cet écran a été sauvegardé dans le fichier ";
str2 += str;
str2 += ".";
#else
str2 = "The current screen has been written to file ";
str2 += str;
str2 += ".";
#endif
box.msg( str2 );
}
//--------- End of function Sys::capture_screen ---------//
//-------- Begin of function Sys::capture_minimap --------//
//
void Sys::capture_minimap()
{
String str;
int i;
for (i = 0; i <= 999; i++)
{
str = m.format(info.random_seed, 1);
str += "_";
if (i < 100) str += "0";
if (i < 10) str += "0";
str += i;
str += ".BMP";
if( !m.is_file_exist(str) )
break;
}
if (i > 999) // all file names from DWORLD000 to DWORLD999 have been occupied
return;
if( sys.debug_session ) // in debug session, the buffer is not locked, we need to lock it for capturing the screen
{
vga_true_front.lock_buf();
vga_true_front.write_bmp_file(str, 588, 56, 200, 200);
vga_true_front.unlock_buf();
}
else
{
vga_front.write_bmp_file(str, 588, 56, 200, 200);
}
//------ display msg --------//
String str2;
str2 = "The current minimap has been written to file ";
str2 += str;
str2 += ".";
box.msg( str2 );
}
//--------- End of function Sys::capture_minimap ---------//
//--------- Begin of static function static_main_win_proc --------//
//
// Callback for all Windows messages
//
static long FAR PASCAL static_main_win_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return sys.main_win_proc(hWnd, message, wParam, lParam);
}
//--------- End of static function static_main_win_proc --------//
//-------- Begin of function Sys::load_game --------//
//
void Sys::load_game()
{
//--- load game not enabled in multiplayer game ---//
if( remote.is_enable() )
return;
signal_exit_flag=1; // for deinit functions to recognize that this is an end game deinitialization instead of a normal deinitialization
int rc=0;
game_file_array.init("*.SAV"); // reload any save game file
game_file_array.menu(-2); // save screen area to back buffer
switch( game_file_array.menu(2) )
{
case 1:
rc = 1; // fall through to case 0
case 0:
signal_exit_flag = 0;
break;
// case -1 and otherwise, left sys.signal_exit_flag 1 to exit the game
}
game_file_array.menu(-1); // restore screen area from back buffer
//-----------------------------------//
if( rc == -1)
{
box.msg( "Fail Loading Game" );
return;
}
if( rc ) // if rc==0, leave signal_exit_flag 1, which the game will then quit
{
need_redraw_flag = 1;
disp_frame();
// #### begin Gilbert 22/10 ######//
disp_view_mode();
// #### end Gilbert 22/10 ######//
box.msg( "Game Loaded Successfully" );
signal_exit_flag=0;
info.disp();
}
}
//--------- End of function Sys::load_game ---------//
//-------- Begin of function Sys::save_game --------//
//
void Sys::save_game()
{
if( nation_array.player_recno==0 ) // cannot save game when the player's kingdom has been destroyed
return;
if( remote.is_enable() )
{
DWORD *dwordPtr = (DWORD *)remote.new_send_queue_msg( MSG_REQUEST_SAVE, sizeof(DWORD) );
*dwordPtr = remote.next_send_frame(nation_array.player_recno, sys.frame_count+remote.process_frame_delay)+2;
return;
}
game_file_array.init("*.SAV"); // reload any save game file
game_file_array.menu(-2); // save screen area to back buffer
if( game_file_array.menu(1) == 1 )
{
if( GameFile::last_read_success_flag )
box.msg( "Game Saved Successfully" );
}
game_file_array.menu(-1); // restore screen area from back buffer
// ##### patch begin Gilbert 16/3 #######//
info.disp();
// ##### patch end Gilbert 16/3 #######//
}
//-------- End of function Sys::save_game --------//
// --------- begin of function Sys::mp_request_save ----------//
void Sys::mp_request_save(DWORD frame)
{
if( !mp_save_flag )
{
mp_save_flag = 1;
mp_save_frame = frame;
}
}
// --------- end of function Sys::mp_request_save ----------//
// --------- begin of function Sys::mp_clear_request_save ----------//
void Sys::mp_clear_request_save()
{
mp_save_flag = 0;
mp_save_frame = 0;
}
// --------- end of function Sys::mp_clear_request_save ----------//
//-------- Begin of function Sys::set_game_dir ----------//
//
// Set all game directories.
//
void Sys::set_game_dir()
{
//------- If it should run from the CDROM ------//
get_cdrom_drive();
set_one_dir( "IMAGE\\HALLFAME.ICN" , "IMAGE\\", dir_image );
set_one_dir( "ENCYC\\SEAT\\NORMAN.ICN", "ENCYC\\", dir_encyc );
#ifdef AMPLUS
set_one_dir( "ENCYC2\\SEAT\\EGYPTIAN.ICN", "ENCYC2\\", dir_encyc2 );
#endif
set_one_dir( "MOVIE\\INTRO.AVI" , "MOVIE\\", dir_movie );
#ifdef DEMO
set_one_dir( "MUSIC\\DEMO.WAV" , "MUSIC\\", dir_music );
set_one_dir( "TUTORIAL\\STANDARD.TUT" , "TUTORIAL\\", dir_tutorial );
set_one_dir( "SCENARIO\\DEMO.SCN" , "SCENARIO\\", dir_scenario );
#else
set_one_dir( "MUSIC\\NORMAN.WAV" , "MUSIC\\", dir_music );
set_one_dir( "TUTORIAL\\1BAS_MIL.TUT" , "TUTORIAL\\", dir_tutorial );
set_one_dir( "SCENARIO\\7FOR7.SCN" , "SCENARIO\\", dir_scenario );
#endif
#if(MAX_SCENARIO_PATH >= 2)
set_one_dir( "SCENARI2\\SCN_01.SCN" , "SCENARI2\\", dir_scenario_path[1] );
#endif
//-------- set game version ---------//
#ifdef BETA
game_version = VERSION_FULL;
#else
#ifdef DEMO
game_version = VERSION_DEMO;
#else
if( 1 ) // no longer checkcd if( cdrom_drive )
game_version = VERSION_FULL; // single player game is not available when game_version == VERSION_FULL
else
game_version = VERSION_MULTIPLAYER_ONLY;
#endif
#endif
}
//----------- End of function Sys::set_game_dir ----------//
//-------- Begin of function Sys::set_one_dir ----------//
//
int Sys::set_one_dir( char* checkFileName, char* defaultDir, char* trueDir )
{
if( m.is_file_exist( checkFileName ) )
{
strcpy( trueDir, defaultDir );
}
else
{
if( cdrom_drive )
{
strcpy( trueDir, "D:\\" );
strcat( trueDir, defaultDir );
trueDir[0] = cdrom_drive;
}
else
{
strcpy( trueDir, "" );
return 0;
}
}
return 1;
}
//----------- End of function Sys::set_one_dir ----------//
//-------- Start of function Sys::get_cdrom_drive -------------//
//
// Get the drive letter of the CDROM and restore the result in cdrom_drive.
//
void Sys::get_cdrom_drive()
{
unsigned char i;
char driveStr[4];
static char checkFileName[30] = "D:\\7K.EXE"; // check this file to identify the disc
cdrom_drive = 0;
driveStr[1] = ':';
driveStr[2] = '\\';
driveStr[3] = 0;
// ##### patch begin Gilbert 14/10 ######//
for(i='C'; i<='Z'; i++)
// ##### patch end Gilbert 14/10 ######//
{
checkFileName[0] = i;
driveStr[0] = i;
if(GetDriveType(driveStr) == DRIVE_CDROM)
{
if( m.is_file_exist(checkFileName) )
{
cdrom_drive = i;
break;
}
}
}
}
//--------- End of function Sys::get_cdrom_drive ---------------//
//-------- Start of function locate_king_general -------------//
//
static void locate_king_general(int rankId)
{
if( !nation_array.player_recno )
return;
int unitRecno = 0;
if(unit_array.selected_recno)
unitRecno = unit_array.selected_recno;
else if(rankId!=RANK_KING && firm_array.selected_recno)
{
Firm *firmPtr = firm_array[firm_array.selected_recno];
if((firmPtr->firm_id==FIRM_CAMP || firmPtr->firm_id==FIRM_BASE) && firmPtr->overseer_recno)
unitRecno = firmPtr->overseer_recno;
}
for( int i=unit_array.size() ; i>0 ; i-- )
{
if( ++unitRecno > unit_array.size() )
unitRecno = 1;
if( unit_array.is_deleted(unitRecno) )
continue;
Unit* unitPtr = unit_array[unitRecno];
if( unitPtr->nation_recno == nation_array.player_recno &&
unitPtr->rank_id == rankId )
{
short xLoc, yLoc;
if( unitPtr->get_cur_loc(xLoc, yLoc) )
{
world.go_loc(xLoc, yLoc, 1);
return;
}
}
}
}
//--------- End of function locate_king_general ---------------//
//-------- Start of function locate_spy -------------//
//
static void locate_spy()
{
if( !nation_array.player_recno )
return;
int unitRecno = unit_array.selected_recno;
for( int i=unit_array.size() ; i>0 ; i-- )
{
if( ++unitRecno > unit_array.size() )
unitRecno = 1;
if( unit_array.is_deleted(unitRecno) )
continue;
Unit* unitPtr = unit_array[unitRecno];
if( unitPtr->true_nation_recno() == nation_array.player_recno &&
unitPtr->spy_recno && unitPtr->is_visible() )
{
short xLoc, yLoc;
if( unitPtr->get_cur_loc(xLoc, yLoc) )
{
world.go_loc(xLoc, yLoc, 1);
return;
}
}
}
}
//--------- End of function locate_spy ---------------//
//-------- Start of function locate_ship -------------//
//
static void locate_ship()
{
if( !nation_array.player_recno )
return;
//----------------------------------------------------------------------------//
// The order is
// 1) visible ships by their sprite_recno in ascending order
// 2) FirmHarbors with ships (num of ships >= 1) by their firm_recno in ascending
// order
//
// Start the scaning in one of the following cases
// 1) a unit is selected
// 2) a firm is selected
// 3) neither unit or firm is selected
//----------------------------------------------------------------------------//
if(firm_array.selected_recno)
{
if(!locate_ship_in_harbor()) // harbor first, then unit
locate_visible_ship();
}
else // if(unit_array.selected_recno) or neither of them is selected
{
if(!locate_visible_ship()) // unit first, then harbor
locate_ship_in_harbor();
}
}
//--------- End of function locate_ship ---------------//
//-------- Start of function locate_ship_in_harbor -------------//
// return 1 if found
// return 0 otherwise
//
static int locate_ship_in_harbor()
{
int firmRecno = firm_array.selected_recno;
int checkSize = firm_array.size();
if(firmRecno)
checkSize--; // not include the selected firm
for( int i=checkSize ; i>0 ; i-- )
{
if( ++firmRecno > firm_array.size() )
firmRecno = 1;
if( firm_array.is_deleted(firmRecno) )
continue;
Firm* firmPtr = firm_array[firmRecno];
if(firmPtr->firm_id!=FIRM_HARBOR ||
firmPtr->nation_recno != nation_array.player_recno)
continue;
if(((FirmHarbor*)firmPtr)->ship_count==0)
continue; // not interested
world.go_loc(firmPtr->center_x, firmPtr->center_y, 1);
return 1;
}
return 0;
}
//--------- End of function locate_ship_in_harbor ---------------//
//-------- Start of function locate_visible_ship -------------//
// return 1 if found
// return 0 otherwise
//
static int locate_visible_ship()
{
int unitRecno = unit_array.selected_recno;
int checkSize = unit_array.size();
if(unitRecno)
checkSize--; // not include the selected unit
for( int i=checkSize ; i>0 ; i-- )
{
if( ++unitRecno > unit_array.size() )
unitRecno = 1;
if( unit_array.is_deleted(unitRecno) )
continue;
Unit* unitPtr = unit_array[unitRecno];
if(!unitPtr->is_visible()) // skip the case unit_mode==UNIT_MODE_IN_HARBOR in calling Unit::get_cur_loc()
continue;
if( unitPtr->nation_recno == nation_array.player_recno &&
unit_res[unitPtr->unit_id]->unit_class == UNIT_CLASS_SHIP )
{
short xLoc, yLoc;
if( unitPtr->get_cur_loc(xLoc, yLoc) )
{
world.go_loc(xLoc, yLoc, 1);
return 1;
}
}
}
return 0;
}
//--------- End of function locate_visible_ship ---------------//
//-------- Start of function locate_camp -------------//
//
static void locate_camp()
{
if( !nation_array.player_recno )
return;
int firmRecno = firm_array.selected_recno;
for( int i=firm_array.size() ; i>0 ; i-- )
{
if( ++firmRecno > firm_array.size() )
firmRecno = 1;
if( firm_array.is_deleted(firmRecno) )
continue;
Firm* firmPtr = firm_array[firmRecno];
if( firmPtr->nation_recno == nation_array.player_recno &&
firmPtr->firm_id == FIRM_CAMP )
{
world.go_loc(firmPtr->center_x, firmPtr->center_y, 1);
return;
}
}
}
//--------- End of function locate_camp ---------------//
//-------- Start of function get_mouse_loc_in_zoom_map -------------//
static int get_mouse_loc_in_zoom_map(int &x, int &y)
{
int mouseX = mouse.cur_x;
int mouseY = mouse.cur_y;
if(mouseX >= ZOOM_X1 && mouseX <= ZOOM_X2 && mouseY >= ZOOM_Y1 && mouseY <= ZOOM_Y2)
{
x = world.zoom_matrix->top_x_loc + (mouseX-ZOOM_X1)/ZOOM_LOC_WIDTH;
y = world.zoom_matrix->top_y_loc + (mouseY-ZOOM_Y1)/ZOOM_LOC_HEIGHT;
return 1;
}
return 0; // out of zoom map boundary
}
//--------- End of function get_mouse_loc_in_zoom_map ---------------//