/*
* 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 : OINFO.CPP
//Description : Info class
#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
//------------ Define static vars ----------------//
static char* skill_name_array[] =
{
"Combat Skill",
"Construction Skill",
"Production Skill"
};
//------ define static vars --------//
static char *save_buf_1 = NULL;
static char *save_buf_1b = NULL;
static char *save_buf_2 = NULL;
static char *save_buf_3 = NULL;
static char *save_buf_4 = NULL;
//-------- Begin of function Info::Info --------//
//
Info::Info() : report_array(sizeof(short), 50),
report_array2(sizeof(short), 50),
talk_msg_disp_array(sizeof(TalkMsgDisp), 50)
{
info_background_bitmap = NULL;
}
//--------- End of function Info::Info ---------//
//-------- Begin of function Info::~Info --------//
//
Info::~Info()
{
deinit();
err_when( save_buf_1 );
}
//--------- End of function Info::~Info ---------//
//-------- Begin of function Info::init --------//
//
void Info::init()
{
deinit();
game_day = 1;
game_month = 6;
game_year = 1000;
game_start_date = date.julian( game_year, game_month, game_day );
game_date = game_start_date;
year_day = date.day_year( game_year, game_month, game_day );
year_passed= 0; // no. of years has been passed since the game begins
goal_deadline = date.julian( date.year(info.game_start_date)+config.goal_year_limit,
date.month(info.game_start_date),
date.day(info.game_start_date) );
goal_difficulty = 0;
goal_score_bonus = 0;
//------ reset report browsers recno -----//
browse_nation_recno = 0;
browse_race_recno = 0;
browse_firm_recno = 0;
browse_income_recno = 0;
browse_expense_recno = 0;
browse_troop_recno = 0;
browse_unit_recno = 0;
browse_tech_recno = 0;
browse_god_recno = 0;
browse_town_recno = 0;
browse_spy_recno = 0;
browse_caravan_recno = 0;
browse_ship_recno = 0;
browse_talk_msg_recno= 0;
browse_news_recno = 0;
browse_ai_action_recno = 0;
browse_ai_attack_recno = 0;
//------ vars of the nation report ------//
nation_report_mode = NATION_REPORT_INFO;
player_reply_mode = 0;
chat_receiver_type = CHAT_RECEIVER_CURRENT;
//----------------------------------//
start_play_time = m.get_time(); // the time player start playing the game
total_play_time = 0; // total time the player has played in all saved games
// these will be updated during loading game and saving game
err_when( MAX_REMOTE_CHAT_STR < DISP_NEWS_COUNT ); // it must not fewer then the maximum number of news that can be displayed on the screen at a time.
}
//--------- End of function Info::init ---------//
//-------- Begin of function Info::deinit --------//
//
void Info::deinit()
{
if( info_background_bitmap )
{
mem_del( info_background_bitmap );
info_background_bitmap = NULL;
}
}
//--------- End of function Info::deinit ---------//
//------- Begin of function Info::init_random_seed ------//
//
// [unsigned] randomSeed - if given, it will be the random seed of the game.
// random seed. otherwise a random seed will be
// picked.
// (default:0)
//
void Info::init_random_seed(int randomSeed)
{
if( randomSeed )
random_seed = randomSeed;
else
{
randomSeed = time(NULL);
randomSeed = (int) _rotr( randomSeed, 4 );
if( randomSeed < 0 )
randomSeed = ~randomSeed;
if( randomSeed == 0 )
randomSeed = 1;
random_seed = randomSeed;
}
m.set_random_seed(random_seed);
//------ write random seed --------//
if( sys.testing_session )
{
File fileMapSeed;
fileMapSeed.file_create( "MAP.RS" );
String str(m.format(random_seed,1));
fileMapSeed.file_write(str, str.len());
}
}
//------- End of function Info::init_random_seed ------//
//-------- Begin of function Info::next_day ---------//
//
void Info::next_day()
{
if( ++game_day > 30 )
game_day = 30; // game_day is limited to 1-30 for
// calculation of e.g. revenue_30days()
game_date++;
week_day=game_date%7;
//-----------------------------------------//
if( date.month(game_date) != game_month )
{
game_day = 1;
game_month = date.month(game_date);
firm_array.next_month();
nation_array.next_month();
}
if( date.year(game_date) != game_year )
{
game_month = 1;
game_year = date.year(game_date);
year_passed++;
firm_array.next_year();
nation_array.next_year();
}
//-------- set year_day ----------//
year_day = date.day_year( game_year, game_month, game_day );
//--- if a spy is viewing secret reports of other nations ---//
if( viewing_spy_recno )
process_viewing_spy();
//-------- deadline approaching message -------//
if( !game.game_has_ended && config.goal_year_limit_flag )
{
int dayLeft = goal_deadline-game_date;
int yearLeft = dayLeft/365;
if( dayLeft%365==0 && yearLeft>=1 && yearLeft<=5 )
news_array.goal_deadline( yearLeft, 0 );
if( dayLeft==0 ) // deadline arrives, everybody loses the game
game.game_end(0, 0);
}
}
//---------- End of function Info::next_day --------//
//-------- Begin of function Info::disp_panel --------//
//
void Info::disp_panel()
{
image_interface.put_to_buf( &vga_back, "MAINSCR" );
//------ keep a copy of bitmap of the panel texture -----//
if( !info_background_bitmap )
info_background_bitmap = mem_add( 4 + (INFO_X2-INFO_X1+1)*(INFO_Y2-INFO_Y1+1) );
vga_back.read_bitmap( INFO_X1, INFO_Y1, INFO_X2, INFO_Y2, info_background_bitmap );
}
//--------- End of function Info::disp_panel ---------//
//-------- Begin of function Info::disp --------//
//
// Display the side info area.
//
void Info::disp()
{
// mouse.handle_flicking = 0; // since it will be called by Firm detect functions directly which may have set mouse.handle_flicking to 1 first, so we need to cancel it here
if( !power.enable_flag )
return;
if( sys.signal_exit_flag )
return;
if( option_menu.is_active() )
return;
vga_back.put_bitmap( INFO_X1, INFO_Y1, info_background_bitmap );
vga_front.put_bitmap( INFO_X1, INFO_Y1, info_background_bitmap );
//------- use front buffer -------//
int saveUseBackBuf = vga.use_back_buf;
vga.use_front();
//------ if units/firm selected, display info --------//
if( firm_array.selected_recno )
{
firm_array[firm_array.selected_recno]->disp_info_both(INFO_REPAINT);
}
else if( town_array.selected_recno )
{
town_array[town_array.selected_recno]->disp_info(INFO_REPAINT);
}
else if( site_array.selected_recno )
{
site_array[site_array.selected_recno]->disp_info(INFO_REPAINT);
}
else if( unit_array.selected_recno )
{
unit_array[unit_array.selected_recno]->disp_info(INFO_REPAINT);
}
else if( wall_res.selected_x_loc >= 0 )
{
wall_res.disp_info(INFO_REPAINT);
}
//----- restore use back buffer if it was ----//
if( saveUseBackBuf )
vga.use_back();
}
//-------- End of function Info::disp --------//
//-------- Begin of function Info::update --------//
void Info::update()
{
if( !power.enable_flag )
return;
if( option_menu.is_active() )
return;
//-------------------------------------------//
disp_heading();
//------- use front buffer -------//
int saveUseBackBuf = vga.use_back_buf;
vga.use_front();
//-------------------------------------------//
if( firm_array.selected_recno )
{
firm_array[firm_array.selected_recno]->disp_info_both(INFO_UPDATE);
}
else if( town_array.selected_recno )
{
town_array[town_array.selected_recno]->disp_info(INFO_UPDATE);
}
else if( site_array.selected_recno )
{
site_array[site_array.selected_recno]->disp_info(INFO_UPDATE);
}
else if( unit_array.selected_recno )
{
unit_array[unit_array.selected_recno]->disp_info(INFO_UPDATE);
}
else if( wall_res.selected_x_loc >= 0 )
{
wall_res.disp_info(INFO_UPDATE);
}
//----- restore use back buffer if it was ----//
if( saveUseBackBuf )
vga.use_back();
}
//-------- End of function Info::update --------//
//-------- Begin of function Info::disp_heading --------//
void Info::disp_heading()
{
//---- display info on the top menu area ----//
int x=TOP_MENU_X2-250;
//---------- display date -----------//
font_mid.use_max_height();
font_mid.disp( 460, 10, date.date_str(game_date,1), 575);
font_mid.use_std_height();
if( !nation_array.player_recno ) // the player has lost the game
{
font_mid.disp( 307, 10, "", 445); // clear the display
font_mid.disp( 305, 30, "", 445);
// ##### begin Gilbert 4/11 #######//
image_icon.put_front(447,26, "REPU_DW" );
// ##### end Gilbert 4/11 #######//
font_mid.disp( 476, 30, "", 575);
return;
}
String str;
Nation* nationPtr = ~nation_array;
//------- display food and net food change --------//
err_when( vga.use_back_buf );
char* strPtr = nationPtr->food_str();
font_mid.disp( 307, 10, strPtr, 445);
//------- display cash and profit --------//
strPtr = nationPtr->cash_str();
font_mid.disp( 305, 30, strPtr, 445);
//------- display reputation ---------//
if( nationPtr->reputation >= 0 )
{
str = m.format( (int)nationPtr->reputation, 4 ); // format type 4 - no thousand separators
}
else
{
str = "-";
str += m.format( (int)-nationPtr->reputation, 4 ); // format type 4 - no thousand separators
}
int reputationChange = (int) nationPtr->reputation_change_365days();
if( reputationChange )
{
str += " (";
if( reputationChange > 0 )
str += "+";
else
str += "-";
str += abs(reputationChange);
str += ")";
}
image_icon.put_front(447,26, nationPtr->reputation_change_365days() >= (float)0.0 ? (char*)"REPU_UP" : (char*)"REPU_DW" );
font_mid.disp( 476, 30, str, 575);
}
//-------- End of function Info::disp_heading --------//
//-------- Begin of function Info::detect --------//
int Info::detect()
{
//------------ detect objects ------------//
if( firm_array.selected_recno )
{
firm_array[firm_array.selected_recno]->detect_info_both();
}
else if( town_array.selected_recno )
{
town_array[town_array.selected_recno]->detect_info();
}
else if( site_array.selected_recno )
{
site_array[site_array.selected_recno]->detect_info();
}
else if( unit_array.selected_recno )
{
unit_array[unit_array.selected_recno]->detect_info();
}
return 0;
}
//-------- End of function Info::detect --------//
//-------- Begin of function Info::draw_selected --------//
void Info::draw_selected()
{
if( firm_array.selected_recno )
firm_array[firm_array.selected_recno]->draw_selected();
else if( town_array.selected_recno )
town_array[town_array.selected_recno]->draw_selected();
else if( site_array.selected_recno )
site_array[site_array.selected_recno]->draw_selected();
else if( wall_res.selected_x_loc >= 0 )
wall_res.draw_selected();
}
//-------- End of function Info::draw_selected --------//
//-------- Begin of function Info::get_report_data --------//
short Info::get_report_data(int recNo)
{
err_when( recNo<1 || recNo>report_array.size() );
return *((short*)report_array.get(recNo));
}
//-------- End of function Info::get_report_data --------//
//-------- Begin of function Info::get_report_data2 --------//
short Info::get_report_data2(int recNo)
{
err_when( recNo<1 || recNo>report_array2.size() );
return *((short*)report_array2.get(recNo));
}
//-------- End of function Info::get_report_data2 --------//
//-------- Begin of function Info::process_viewing_spy --------//
void Info::process_viewing_spy()
{
//---- check if the viewing spy is still valid ----//
int isValid=1;
if( spy_array.is_deleted(viewing_spy_recno) ) // the spy is dead
{
isValid = 0;
}
else
{
Spy* spyPtr = spy_array[viewing_spy_recno];
//-- check if the spy still stay in the same place --//
if( spyPtr->spy_place_nation_recno() != info.viewing_nation_recno )
{
isValid = 0;
}
else
{
/*
//--- on average, a spy will get caught in 5 to 15 days when viewing the secret of its enemy ---//
if( m2.random(5+spyPtr->spy_skill/5) ) // use m2 to avoid multiplayer sync problem
{
spyPtr->set_exposed(COMMAND_PLAYER);
isValid = 0;
}
*/
}
}
if( !isValid ) //-- if not valid, set the mode back to normal viewing mode
sys.set_view_mode(MODE_NORMAL);
}
//-------- End of function Info::process_viewing_spy --------//
//------- Begin of function Info::play_time_str --------//
//
char* Info::play_time_str()
{
int totalMin = total_play_time / (60*1000);
int playHour = totalMin / 60;
int playMin = totalMin - playHour*60;
static String str;
str = "";
if( playHour > 0 )
{
str += playHour;
str += translate.process( playHour>1 ? (char*)" hours" : (char*)" hour" );
str += translate.process( " and " );
}
str += playMin;
str += translate.process( playMin>1 ? (char*)" minutes" : (char*)" minute" );
return str;
}
//---------- End of function Info::play_time_str ---------//
//------- Begin of function Info::game_duration_str --------//
//
char* Info::game_duration_str()
{
//------- get the true game start date --------//
int gameStartDate;
//-- For scenarios (whose goal_difficulty are > 0 ), the actual game start date is no info.game_start_date, we must calculate it
if( info.goal_difficulty )
{
gameStartDate = date.julian( date.year(info.goal_deadline)-config.goal_year_limit,
date.month(info.goal_deadline),
date.day(info.goal_deadline) );
}
else
{
gameStartDate = info.game_start_date;
}
//---------------------------------------------//
int totalDay = info.game_date - gameStartDate;
int playYear = totalDay / 365;
int playDay = totalDay - playYear*365;
static String str;
str = "";
if( playYear > 0 )
{
str += playYear;
str += translate.process( playYear>1 ? (char*)" years" : (char*)" year" );
str += translate.process( (char*)" and " );
}
str += playDay;
str += translate.process( playDay>1 ? (char*)" days" : (char*)" day" );
return str;
}
//---------- End of function Info::game_duration_str ---------//
//------- Begin of function Info::save_game_scr --------//
//
void Info::save_game_scr()
{
err_when( save_buf_1 );
// top and buttom
if( 0 < ZOOM_Y1 )
{
save_buf_1 = vga_front.save_area(0, 0, VGA_WIDTH-1, ZOOM_Y1-1);
save_buf_1b = vga_back.save_area(0, 0, VGA_WIDTH-1, ZOOM_Y1-1); // save the back buffer also as the top area of the back buf is used for font display
}
if( ZOOM_Y2 < VGA_HEIGHT-1 )
save_buf_2 = vga_front.save_area(0, ZOOM_Y2+1, VGA_WIDTH-1, VGA_HEIGHT-1);
// left and right
if( 0 < ZOOM_X1 )
save_buf_3 = vga_front.save_area(0, ZOOM_Y1, ZOOM_X1-1, ZOOM_Y2);
if( ZOOM_X2 < VGA_WIDTH-1 )
save_buf_4 = vga_front.save_area(ZOOM_X2+1, ZOOM_Y1, VGA_WIDTH-1, ZOOM_Y2);
}
//---------- End of function Info::save_game_scr ---------//
//------- Begin of function Info::rest_game_scr --------//
//
void Info::rest_game_scr()
{
// restore area outside front buffer
if(save_buf_4)
vga_front.rest_area(save_buf_4, 1);
if(save_buf_3)
vga_front.rest_area(save_buf_3, 1);
if(save_buf_2)
vga_front.rest_area(save_buf_2, 1);
if(save_buf_1)
vga_front.rest_area(save_buf_1, 1);
if(save_buf_1b)
vga_back.rest_area(save_buf_1b, 1);
save_buf_1 = NULL;
info.disp();
sys.blt_virtual_buf(); // blt the virtual front buffer to the screen
}
//---------- End of function Info::rest_game_scr ---------//
//------- Begin of function Info::free_game_scr --------//
//
void Info::free_game_scr()
{
if(save_buf_4)
mem_del(save_buf_4);
if(save_buf_3)
mem_del(save_buf_3);
if(save_buf_2)
mem_del(save_buf_2);
if(save_buf_1)
mem_del(save_buf_1);
if(save_buf_1b)
mem_del(save_buf_1b);
save_buf_1 = NULL;
}
//---------- End of function Info::free_game_scr ---------//
//------- Begin of function Info::disp_loyalty --------//
//
// return: x2 - the ending x position of the loyalty string.
//
int Info::disp_loyalty(int x, int y, int x2, int curLoyalty, int targetLoyalty, int nationRecno, int refreshFlag)
{
int endX;
if( x != x2 ) // if x==x2, don't display the field name.
{
font_san.field( x, y, "Loyalty", x2, curLoyalty, 1, INFO_X2-2, refreshFlag);
endX = x2 + 4 + font_san.text_width( m.format(curLoyalty) );
}
else
{
endX = font_san.put( x2+4, y+2, curLoyalty, 1 );
}
if( nation_array[nationRecno]->cash <= 0 ) // if the nation no longer has money to pay the unit
targetLoyalty = 0;
if( curLoyalty != targetLoyalty ) // only increase, no decrease. Decrease are caused by events. Increases are made gradually
{
int tx = x2+6+font_san.text_width( m.format(curLoyalty) );
if( targetLoyalty > curLoyalty )
image_icon.put_front( tx, y+2, "ARROWUP" );
else if( targetLoyalty < curLoyalty )
image_icon.put_front( tx, y+2, "ARROWDWN" );
endX = font_san.put( tx+10, y+2, targetLoyalty, 1 );
}
return endX;
}
//---------- End of function Info::disp_loyalty ---------//