/*
* 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 : ONATION.CPP
//Description : Object Nation - part 1
#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 variables --------//
char* NationRelation::relation_status_str_array[5] =
{
"War", "Tense", "Neutral", "Friendly", "Alliance"
};
//--------- Define static functions -------//
static int succeed_king_loyalty_change(int thisRaceId, int newKingRaceId, int oldKingRaceId);
//--------- Begin of function NationBase::Nation --------//
NationBase::NationBase()
{
memset( this, 0, sizeof(NationBase) );
}
//---------- End of function NationBase::Nation --------//
//--------- Begin of function NationBase::~Nation --------//
NationBase::~NationBase()
{
#ifdef DEBUG
err_when( nation_recno ); // deinit() must be called first before this destructor is called
for( int i=0 ; i 0 ); // it should be all zeros
#endif
}
//---------- End of function NationBase::~Nation --------//
//--------- Begin of function NationBase::init --------//
//
// This function will be called directly by
//
// nationType = the nation type (NATION_???)
// raceId = id. of the race
// colorSchemeId = color scheme id. of the nation
// [DWORD] playerId = an unique player id. (for multiplayer game)
//
void NationBase::init(int nationType, int raceId, int colorSchemeId, DWORD playerId)
{
//------------- set vars ---------------//
nation_type = nationType;
race_id = raceId;
color_scheme_id = colorSchemeId;
player_id = playerId;
colorSchemeId = min( colorSchemeId, MAX_COLOR_SCHEME );
nation_color = game.color_remap_array[colorSchemeId].main_color;
last_war_date = info.game_date;
//------- if this is the local player's nation -------//
if( nation_type==NATION_OWN )
nation_array.player_recno = nation_recno;
//---------- init game vars ------------//
static int start_up_cash_array[] = { 4000, 7000, 12000, 20000 };
if( is_ai() )
cash = (float) start_up_cash_array[config.ai_start_up_cash-1];
else
cash = (float) start_up_cash_array[config.start_up_cash-1];
food = (float) 5000; // startup food is 5000 for all nations in all settings
//---- initialize this nation's relation on other nations ----//
for( int i=nation_array.size() ; i>0 ; i-- )
{
if( nation_array.is_deleted(i) )
continue;
init_relation(i);
nation_array[i]->init_relation(nation_recno);
}
//--------- init technology ----------//
tech_res.init_nation_tech(nation_recno);
//------- reset all god knowledge --------//
god_res.init_nation_know(nation_recno);
//### begin alex 23/9 ###//
if(remote.is_enable() && nation_recno && !is_ai() && m.is_file_exist("TECHGOD.SYS"))
{
tech_res.inc_all_tech_level(nation_recno);
tech_res.inc_all_tech_level(nation_recno);
tech_res.inc_all_tech_level(nation_recno);
god_res.enable_know_all(nation_recno);
}
//#### end alex 23/9 ####//
}
//----------- End of function NationBase::init ---------//
//--------- Begin of function NationBase::deinit --------//
//
// When a nation is to be deleted, NationBase::deinit() must
// be called first from nation_array before calling its
// destructor as when it deinitalizes units, some functions
// will need to access the nation_array[].
//
void NationBase::deinit()
{
if( nation_recno==0 ) // has been deinitialized
return;
//---- delete all talk messages to/from this nation ----//
talk_res.del_all_nation_msg(nation_recno);
//------- close down all firms --------//
close_all_firm();
//---- neutralize all towns belong to this nation ----//
Town* townPtr;
int i;
for( i=town_array.size() ; i>0 ; i-- )
{
if( town_array.is_deleted(i) )
continue;
townPtr = town_array[i];
if( townPtr->nation_recno == nation_recno )
townPtr->set_nation(0);
}
//------------- deinit our spies -------------//
for( i=spy_array.size() ; i>0 ; i-- )
{
if( spy_array.is_deleted(i) )
continue;
Spy* spyPtr = spy_array[i];
//-----------------------------------------------------//
// Convert all of spies of this nation to normal units,
// so there will be no more spies of this nation.
//-----------------------------------------------------//
if( spyPtr->true_nation_recno == nation_recno ) // drop spy identities of spies in towns, firms and mobile ones
spyPtr->drop_spy_identity();
//-----------------------------------------------------//
// For spies of other nation cloaked as this nation,
// their will uncover their cloak and change back
// to their original nation.
//-----------------------------------------------------//
else if( spyPtr->cloaked_nation_recno == nation_recno )
spyPtr->change_cloaked_nation(spyPtr->true_nation_recno);
err_when( spyPtr->true_nation_recno == nation_recno || // there should be no more spies associated with this nation
spyPtr->cloaked_nation_recno == nation_recno );
}
//----- deinit all units belonging to this nation -----//
deinit_all_unit();
//-------- if the viewing nation is this nation -------//
if( !sys.signal_exit_flag )
{
if( info.default_viewing_nation_recno == nation_recno )
{
info.default_viewing_nation_recno = nation_array.player_recno;
sys.set_view_mode(MODE_NORMAL);
}
else if( info.viewing_nation_recno == nation_recno )
sys.set_view_mode(MODE_NORMAL); // it will set viewing_nation_recno to default_viewing_nation_recno
// ##### begin Gilbert 22/10 #######//
// if deleting own nation, darken view mode buttons
if( nation_recno == nation_array.player_recno )
{
sys.disp_view_mode(1);
}
// ##### end Gilbert 22/10 #######//
}
nation_recno = 0;
}
//----------- End of function NationBase::deinit ---------//
//--------- Begin of function NationBase::init_relation --------//
//
// Initialize the relation vars with the given nation.
//
// relationNationRecno - recno of the NationRelation to set.
//
void NationBase::init_relation(int relationNationRecno)
{
NationRelation* nationRelation = relation_array+relationNationRecno-1;
memset( nationRelation, 0, sizeof(NationRelation) );
set_relation_should_attack(relationNationRecno, relationNationRecno!=nation_recno, COMMAND_AUTO);
if( is_ai() && nation_array[relationNationRecno]->is_ai() ) // AI has contact with each other in the beginning of the game.
nationRelation->has_contact = 1;
else
nationRelation->has_contact = relationNationRecno==nation_recno || config.explore_whole_map; // if the map is blackened out, no contact in the beginning
nationRelation->trade_treaty = relationNationRecno==nation_recno;
nationRelation->status = NATION_NEUTRAL;
nationRelation->ai_relation_level = NATION_NEUTRAL * RELATION_LEVEL_PER_STATUS;
nationRelation->last_change_status_date = info.game_date;
if( relationNationRecno == nation_recno ) // own nation
relation_status_array[relationNationRecno-1] = NATION_ALLIANCE; // for facilitating searching
else
relation_status_array[relationNationRecno-1] = NATION_NEUTRAL;
set_relation_passable(relationNationRecno, NATION_FRIENDLY);
is_allied_with_player = 0;
}
//----------- End of function NationBase::init_relation ---------//
//--------- Begin of function NationBase::close_all_firm --------//
//
// Close down all firms under this nation.
//
void NationBase::close_all_firm()
{
int i;
for( i=firm_array.size() ; i>0 ; i-- )
{
if( !firm_array.is_deleted(i) &&
firm_array[i]->nation_recno == nation_recno )
{
firm_array.del_firm(i);
}
}
}
//----------- End of function NationBase::close_all_firm ---------//
//--------- Begin of function NationBase::deinit_all_unit --------//
//
// Deinit all units belonging to this nation when this nation is deinitialized.
//
void NationBase::deinit_all_unit()
{
//--- update total_human_unit so the numbers will be correct ---//
#ifndef DEBUG // only do this in release version to on-fly fix bug
nation_array.update_statistic();
#endif
//--------------------------------------//
int i;
Unit* unitPtr;
for( i=unit_array.size() ; i>0 ; i-- )
{
if( unit_array.is_deleted(i) )
{
unitPtr = (Unit*) unit_array.get_ptr(i); // this unit is dying, so is_deleted() return 1;
if( !unitPtr )
continue;
if( unitPtr->nation_recno == nation_recno )
unit_array.del(i);
continue;
}
//--------------------------------------------//
unitPtr = unit_array[i];
if( unitPtr->nation_recno != nation_recno )
continue;
//----- only human units will betray -----//
if( unitPtr->race_id )
{
unitPtr->loyalty = 0; // force it to detray
if( unitPtr->think_betray() )
continue;
}
//--- if the unit has not changed nation, the unit will disappear ---//
if( unit_array.get_ptr(i) )
unit_array.del(i);
}
//------------ debug code -------------//
for( i=unit_array.size() ; i>0 ; i-- )
{
if( unit_array.is_deleted(i) )
continue;
unitPtr = unit_array[i];
err_when( unitPtr->nation_recno == nation_recno ); // they should have been all deleted.
}
}
//----------- End of function NationBase::deinit_all_unit ---------//
//--------- Begin of function NationBase::hand_over_to --------//
//
// handoverNationRecno - hand over the entire nation to this nation.
//
void NationBase::hand_over_to(int handoverNationRecno)
{
rebel_array.stop_attack_nation(nation_recno);
town_array.stop_attack_nation(nation_recno);
unit_array.stop_all_war(nation_recno);
monster_res.stop_attack_nation(nation_recno);
nation_hand_over_flag = nation_recno;
//--- hand over units (should hand over units first as you cannot change a firm's nation without changing the nation of the overseer there ---//
Unit* unitPtr;
int i;
for( i=unit_array.size() ; i>0 ; i-- )
{
if( unit_array.is_deleted(i) )
{
//-- If the unit is dying and isn't truly deleted yet, delete it now --//
if( !unit_array.is_truly_deleted(i) &&
unit_array[i]->nation_recno == nation_recno )
{
unit_array.die(i);
}
continue;
}
//---------------------------------------//
unitPtr = unit_array[i];
if( unitPtr->nation_recno != nation_recno )
continue;
//----- if it is a god, resign it -------//
if( god_res.is_god_unit(unitPtr->unit_id) )
{
unitPtr->resign(COMMAND_AUTO);
continue;
}
//----- if it is a spy cloaked as this nation -------//
//
// If the unit is a overseer of a Camp or Base,
// the Camp or Base will change nation as a result.
//
//---------------------------------------------------//
if( unitPtr->spy_recno )
unitPtr->spy_change_nation(handoverNationRecno, COMMAND_AUTO);
else
unitPtr->change_nation(handoverNationRecno);
}
//------- hand over firms ---------//
for( i=firm_array.size() ; i>0 ; i-- )
{
if( !firm_array.is_deleted(i) &&
firm_array[i]->nation_recno == nation_recno )
{
firm_array[i]->change_nation(handoverNationRecno);
}
}
//------- hand over towns ---------//
for( i=town_array.size() ; i>0 ; i-- )
{
if( !town_array.is_deleted(i) &&
town_array[i]->nation_recno == nation_recno )
{
town_array[i]->set_nation(handoverNationRecno);
}
}
//-------------------------------------------------//
//
// For the spies of this nation cloaked into other nations,
// we need to update their true_nation_recno.
//
//-------------------------------------------------//
Spy* spyPtr;
for( i=spy_array.size() ; i>0 ; i-- )
{
if( spy_array.is_deleted(i) )
continue;
spyPtr = spy_array[i];
err_when( spyPtr->cloaked_nation_recno == nation_recno ); // there should be no units in this nation after the above deinitialization
if( spyPtr->true_nation_recno == nation_recno )
spyPtr->change_true_nation(handoverNationRecno);
}
//------- delete this nation from nation_array -------//
nation_array.del_nation(nation_recno);
nation_hand_over_flag = 0;
}
//----------- End of function NationBase::hand_over_to ---------//
//--------- Begin of function NationBase::set_king --------//
//
// Set the king unit recno.
//
// kingUnitRecno - unit recno of the king
// firstKing - whether this is the first king of the nation.
//
void NationBase::set_king(int kingUnitRecno, int firstKing)
{
king_unit_recno = kingUnitRecno;
Unit* kingUnit = unit_array[king_unit_recno];
//--- if this unit currently has not have leadership ---//
if( kingUnit->skill.skill_id != SKILL_LEADING )
{
kingUnit->skill.skill_id = SKILL_LEADING;
kingUnit->skill.skill_level = 0;
}
kingUnit->set_rank(RANK_KING);
kingUnit->stop2(); // clear the existing order, as there might be an assigning to firm/town order. But kings cannot be assigned to towns or firms as workers.
//---------- king related vars ----------//
if( nation_type == NATION_AI || !firstKing ) // for succession, no longer use the original player name
nation_name_id = kingUnit->name_id;
else
nation_name_id = -nation_recno; // for human players, the name is retrieved from NationArray::human_name_array
race_id = kingUnit->race_id;
king_leadership = kingUnit->skill.skill_level;
err_when( !nation_name_id );
err_when( !race_id );
}
//----------- End of function NationBase::set_king ---------//
//--------- Begin of function NationBase::nation_name --------//
//
char* NationBase::nation_name()
{
#if(defined(SPANISH))
strncpy( nation_name_str, "Reino de ", NATION_NAME_LEN );
nation_name_str[NATION_NAME_LEN]=NULL;
strncat( nation_name_str, king_name(1), NATION_NAME_LEN ); // 1-get the first word of the name only
nation_name_str[NATION_NAME_LEN]=NULL;
#elif(defined(FRENCH))
strncpy( nation_name_str, "Royaume de ", NATION_NAME_LEN );
nation_name_str[NATION_NAME_LEN]=NULL;
strncat( nation_name_str, king_name(1), NATION_NAME_LEN ); // 1-get the first word of the name only
nation_name_str[NATION_NAME_LEN]=NULL;
#else
// German and US
strncpy( nation_name_str, king_name(1), NATION_NAME_LEN ); // 1-get the first word of the name only
nation_name_str[NATION_NAME_LEN]=NULL;
strncat( nation_name_str, "'s ", NATION_NAME_LEN ); // 1-get the first word of the name only
nation_name_str[NATION_NAME_LEN]=NULL;
strncat( nation_name_str, translate.process("Kingdom"), NATION_NAME_LEN );
nation_name_str[NATION_NAME_LEN]=NULL;
#endif
return nation_name_str; // each name needs to have its own var as multiple nation names will be displayed at the same time in diplomatic talk choices
}
//----------- End of function NationBase::nation_name ---------//
//--------- Begin of function NationBase::king_name --------//
//
// [int] firstWordOnly - whether only get the first word of the name.
// (default: 0)
//
char* NationBase::king_name(int firstWordOnly)
{
if( nation_name_id < 0 ) // human player custom names
{
return nation_array.get_human_name(nation_name_id, firstWordOnly);
}
else
{
if( firstWordOnly )
return race_res[race_id]->get_single_name( (WORD) nation_name_id );
else
return race_res[race_id]->get_name( (WORD) nation_name_id );
}
}
//----------- End of function NationBase::king_name ---------//
//------- Begin of function NationBase::cash_str ------//
//
// Return a text string with the current nation treasure and profit
// in the past 30 days.
//
char* NationBase::cash_str()
{
static String str;
if( cash >= 0 )
{
str = m.format( (int)cash, 4 ); // format type 4 - no thousand separators
}
else
{
str = "-";
str += m.format( (int)-cash, 4 ); // format type 4 - no thousand separators
}
//--------------------------------------//
int curProfit = (int) profit_365days();
if( curProfit )
{
str += " (";
if( curProfit > 0 )
str += "+";
else
str += "-";
str += m.format( abs(curProfit), 4 ); // format type 4 - no thousand separators
str += ")";
}
return str;
}
//------- End of function NationBase::cash_str -------//
//------- Begin of function NationBase::food_str ------//
//
// Return a text string with the current nation treasure and profit
// in the past 30 days.
//
char* NationBase::food_str()
{
static String str;
if( food >= 0 )
{
str = m.format( (int)food, 4 ); // format type 4 - no thousand separators
}
else
{
str = "-";
str += m.format( (int)-food, 4 ); // format type 4 - no thousand separators
}
//--------------------------------------//
int foodChange = (int) food_change_365days();
if( foodChange )
{
str += " (";
if( foodChange > 0 )
str += "+";
else
str += "-";
str += m.format( abs(foodChange), 4 ); // format type 4 - no thousand separators
str += ")";
}
return str;
}
//------- End of function NationBase::food_str -------//
//---------- Begin of function NationBase::next_day --------//
//
// This function is called every day.
//
void NationBase::next_day()
{
//------ post is at war flag -------/
if( is_at_war_today )
last_war_date = info.game_date;
is_at_war_yesterday = is_at_war_today;
is_at_war_today = 0;
//--- if the king is dead, and now looking for a successor ---//
if( !king_unit_recno )
{
if( info.game_date%3 == nation_recno%3 ) // decrease 1 loyalty point every 3 days
change_all_people_loyalty(-1);
}
//---------- debug code ------------//
#ifdef DEBUG
//---------- check king -----------//
if( king_unit_recno )
{
Unit* unitPtr = unit_array[king_unit_recno];
err_when( unitPtr->rank_id != RANK_KING );
err_when( unitPtr->nation_recno != nation_recno );
}
//---------- check relation -----------//
err_when( get_relation_status(nation_recno) != NATION_ALLIANCE ); // relation to own nation must be alliance
#endif
//------ check if this nation has won the game -----//
check_win();
//-- if the player still hasn't selected a unit to succeed the died king, declare defeated if the all units are killed --//
if( !king_unit_recno )
check_lose();
//---------- debug code --------------//
/*
#ifdef DEBUG
int totalHumanCount=0;
for( int i=unit_array.size() ; i>0 ; i-- )
{
Unit* unitPtr = (Unit*) unit_array.get_ptr(i);
if( unitPtr &&
unitPtr->nation_recno == nation_recno &&
unitPtr->race_id &&
unitPtr->rank_id != RANK_KING )
{
totalHumanCount++;
}
}
for( i=firm_array.size() ; i>0 ; i-- )
{
if( firm_array.is_deleted(i) )
continue;
Firm* firmPtr = firm_array[i];
if( firmPtr->nation_recno != nation_recno )
continue;
if( firmPtr->firm_id == FIRM_CAMP ||
firmPtr->firm_id == FIRM_BASE )
{
totalHumanCount += firmPtr->worker_count;
}
}
err_when( total_human_count != totalHumanCount );
#endif
*/
}
//----------- End of function NationBase::next_day ---------//
//---------- Begin of function NationBase::next_month --------//
//
// This function is called every month.
//
void NationBase::next_month()
{
//--------------------------------------------------//
// When the two nations, whose relationship is Tense,
// do not have new conflicts for 3 years, their
// relationship automatically becomes Neutral.
//--------------------------------------------------//
NationRelation* nationRelation;
for( int i=1 ; i<=nation_array.size() ; i++ )
{
if( nation_array.is_deleted(i) )
continue;
nationRelation = get_relation(i);
if( nationRelation->status == NATION_TENSE &&
info.game_date >= nationRelation->last_change_status_date + 365*3 )
{
set_relation_status(i, NATION_NEUTRAL);
}
//--- update good_relation_duration_rating ---//
else if( nationRelation->status == NATION_FRIENDLY )
nationRelation->good_relation_duration_rating += (float) 0.2; // this is the monthly increase
else if( nationRelation->status == NATION_ALLIANCE )
nationRelation->good_relation_duration_rating += (float) 0.4;
}
//----- increase reputation gradually -----//
if( reputation < 100 )
change_reputation((float)0.5);
}
//---------- End of function NationBase::next_month --------//
//---------- Begin of function NationBase::next_year --------//
//
// This function is called every year
//
void NationBase::next_year()
{
//------ post financial data --------//
last_year_income = cur_year_income;
cur_year_income = (float) 0;
last_year_expense = cur_year_expense;
cur_year_expense = (float) 0;
last_year_fixed_income = cur_year_fixed_income;
cur_year_fixed_income = (float) 0;
last_year_fixed_expense = cur_year_fixed_expense;
cur_year_fixed_expense = (float) 0;
last_year_profit = cur_year_profit;
cur_year_profit = (float) 0;
last_year_cheat = cur_year_cheat;
cur_year_cheat = (float) 0;
//------ post income & expense breakdown ------//
int i;
for( i=0 ; ilast_year_import[j] = nationRelation->cur_year_import[j];
nationRelation->cur_year_import[j] = (float) 0;
}
}
//--------- post reputation ----------//
last_year_reputation_change = cur_year_reputation_change;
cur_year_reputation_change = (float) 0;
}
//---------- End of function NationBase::next_year --------//
//---------- Begin of function NationBase::add_income --------//
//
// incomeType - the income type
// incomeAmt - the amount of the income.
// [int] fixedIncome - whether this is a fixed income, or
// a variable income. (default: 0)
//
void NationBase::add_income(int incomeType, float incomeAmt, int fixedIncome)
{
err_when( incomeType < 0 || incomeType >= INCOME_TYPE_COUNT );
cash += incomeAmt;
cur_year_income_array[incomeType] += incomeAmt;
cur_year_income += incomeAmt;
cur_year_profit += incomeAmt;
if( fixedIncome )
cur_year_fixed_income += incomeAmt;
}
//---------- End of function NationBase::add_income --------//
//---------- Begin of function NationBase::add_expense --------//
//
// expenseType - the expense type
// incomeAmt - the amount of the income.
// fixedExpense - whether this is a fixed expense, or
// a variable income. (default: 0)
//
void NationBase::add_expense(int expenseType, float expenseAmt, int fixedExpense)
{
err_when( expenseType < 0 || expenseType >= EXPENSE_TYPE_COUNT );
cash -= expenseAmt;
cur_year_expense_array[expenseType] += expenseAmt;
cur_year_expense += expenseAmt;
cur_year_profit -= expenseAmt;
if( fixedExpense )
cur_year_fixed_expense += expenseAmt;
}
//---------- End of function NationBase::add_expense --------//
//---------- Begin of function NationBase::add_cheat --------//
//
// cheatAmount - the cheating amount.
//
void NationBase::add_cheat(float cheatAmount)
{
if( sys.testing_session || nation_type == NATION_OWN )
{
add_income(INCOME_CHEAT, cheatAmount);
}
else // cheat less obviously, randomly add to one of the account at a random amount //
{
add_income( m.random(INCOME_TYPE_COUNT-1)+1, cheatAmount );
cur_year_cheat += cheatAmount;
}
}
//---------- End of function NationBase::add_cheat --------//
//---------- Begin of function NationBase::import_goods --------//
//
// This function is called when the current nation imports
// goods from a specific nation.
//
// importType - type of goods imported.
//
// importNationRecno - recno of the nation from which this
// nation imports.
//
// importAmt - the import amount
//
void NationBase::import_goods(int importType, int importNationRecno, float importAmt)
{
if( importNationRecno == nation_recno )
return;
NationRelation* nationRelation = get_relation(importNationRecno);
nationRelation->cur_year_import[importType] += importAmt;
nationRelation->cur_year_import[IMPORT_TOTAL] += importAmt;
add_expense(EXPENSE_IMPORTS, importAmt, 1);
nation_array[importNationRecno]->add_income(INCOME_EXPORTS, importAmt, 1);
}
//---------- End of function NationBase::import_goods --------//
//---------- Begin of function NationBase::add_food --------//
//
// foodToAdd - quantity of food to be added
//
void NationBase::add_food(float foodToAdd)
{
food += foodToAdd;
cur_year_food_in += foodToAdd;
cur_year_food_change += foodToAdd;
}
//----------- End of function NationBase::add_food ---------//
//---------- Begin of function NationBase::consume_food --------//
//
// foodConsumed - quantity of food consumed
//
void NationBase::consume_food(float foodConsumed)
{
food -= foodConsumed;
cur_year_food_out += foodConsumed;
cur_year_food_change -= foodConsumed;
}
//----------- End of function NationBase::consume_food ---------//
//---------- Begin of function NationBase::change_reputation --------//
//
// changeLevel - level of reputation to be changed.
//
void NationBase::change_reputation(float changeLevel)
{
//--- reputation increase more slowly when it is close to 100 ----//
if( changeLevel > 0 && reputation > 0 )
changeLevel = changeLevel * (150-reputation) / 150;
//-----------------------------------------------//
reputation += changeLevel;
if( reputation > 100 )
reputation = (float) 100;
if( reputation < -100 )
reputation = (float) -100;
//------ update cur_year_reputation_change ------//
cur_year_reputation_change += changeLevel;
}
//---------- End of function NationBase::change_reputation --------//
//---------- Begin of function NationBase::change_ai_relation_level --------//
//
// Change this AI nation's subjectively relation levels towards the others,
// the opposite nation's relation level is not the same as this.
//
// ai_relation_level is for AI only and will only be reviewed by AI functions.
//
// nationRecno - the nation recno of the relation
// levelChange - the amount of change to the relation level
//
void NationBase::change_ai_relation_level(short nationRecno, int levelChange)
{
NationRelation* nationRelation = get_relation(nationRecno);
int newLevel = nationRelation->ai_relation_level + levelChange;
newLevel = min(newLevel, 100);
newLevel = max(newLevel, 0 );
nationRelation->ai_relation_level = newLevel;
}
//----------- End of function NationBase::change_ai_relation_level -----------//
//---------- Begin of function NationBase::set_relation_status --------//
//
// nationRecno - the nation recno of the relation
// newStatus - the new relationship status
// [char] recursiveCall - whether this is a recursive call from itself
// (default: 0)
//
void NationBase::set_relation_status(short nationRecno, char newStatus, char recursiveCall)
{
if( nationRecno == nation_recno ) // cannot set relation to itself
return;
NationRelation* nationRelation = get_relation(nationRecno);
//--------- debug code --------// BUGHERE
/*
#ifdef DEBUG
if( nation_array[nationRecno]->is_ai() && is_ai() ) // AI must terminate the treaty first before declaring war
{
err_when( nationRelation->status >= NATION_FRIENDLY &&
newStatus == NATION_HOSTILE );
}
#endif
*/
//-------------------------------------------------//
//
// When two nations agree to a cease-fire, there may
// still be some bullets on their ways, and those
// will set the status back to War status, so we need
// the following code to handle this case.
//
//-------------------------------------------------//
if( !recursiveCall &&
nationRelation->status == NATION_TENSE &&
newStatus == NATION_HOSTILE &&
info.game_date < nationRelation->last_change_status_date + 5 ) // 5 days after the cease-fire, the nation will remain cease-fire
{
return;
}
//-------------------------------------------------//
//
// If the nation cease fire or form a friendly/alliance
// treaty with a nation. And this nation current
// has plan to attack that nation, then cancel the plan.
//
//-------------------------------------------------//
if( is_ai() )
{
if( newStatus==NATION_TENSE || // cease fire
newStatus>=NATION_FRIENDLY ) // new friendly/alliance treaty
{
if( ((Nation*)this)->ai_attack_target_nation_recno == nationRecno )
((Nation*)this)->reset_ai_attack_target();
}
}
//------------------------------------------------//
relation_status_array[nationRecno-1] = newStatus;
nationRelation->status = newStatus;
nationRelation->last_change_status_date = info.game_date;
int newRelationLevel = newStatus * RELATION_LEVEL_PER_STATUS;
if( newRelationLevel < nationRelation->ai_relation_level ) // only set it when the new value is lower than the current value
nationRelation->ai_relation_level = newRelationLevel;
set_relation_passable(nationRecno, NATION_FRIENDLY);
//---------- set should_attack -------//
if( newStatus==NATION_ALLIANCE || newStatus==NATION_FRIENDLY ||
newStatus==NATION_TENSE )
{
set_relation_should_attack(nationRecno, 0, COMMAND_AUTO);
}
else if( newStatus==NATION_HOSTILE )
{
set_relation_should_attack(nationRecno, 1, COMMAND_AUTO);
}
//----- share the nation contact with each other -----//
/*
// these segment code will cause multiplayer sync problem
if( newStatus == NATION_ALLIANCE )
{
Nation* withNation = nation_array[nationRecno];
for( i=nation_array.size() ; i>0 ; i-- )
{
if( i==nation_recno || i==nationRecno )
continue;
if( nation_array.is_deleted(i) )
continue;
//-- if we have contact with this nation and our ally doesn't, share the contact with it --//
if( get_relation(i)->has_contact &&
withNation->get_relation(i)->has_contact==0 )
{
withNation->establish_contact(i);
}
}
}
*/
//--- if this is a call from a client function, not a recursive call ---//
if( !recursiveCall )
{
nation_array[nationRecno]->set_relation_status(nation_recno, newStatus, 1);
//-- auto terminate their trade treaty if two nations go into a war --//
if( newStatus == NATION_HOSTILE )
set_trade_treaty(nationRecno, 0);
}
}
//----------- End of function NationBase::set_relation_status -----------//
//---------- Begin of function NationBase::get_relation_status --------//
char NationBase::get_relation_status(short nationRecno)
{
return relation_status_array[nationRecno-1];
}
//----------- End of function NationBase::get_relation_status -----------//
//---------- Begin of function NationBase::set_relation_passable --------//
void NationBase::set_relation_passable(short nationRecno, char status)
{
relation_passable_array[nationRecno-1] = (relation_status_array[nationRecno-1] >= status);
}
//----------- End of function NationBase::set_relation_passable -----------//
//---------- Begin of function NationBase::get_relation_passable --------//
char NationBase::get_relation_passable(short nationRecno)
{
return relation_passable_array[nationRecno-1];
}
//----------- End of function NationBase::get_relation_passable -----------//
#ifdef DEBUG
//---------- Begin of function NationBase::get_relation --------//
//
NationRelation* NationBase::get_relation(int nationRecno)
{
if( nationRecno<1 || nationRecno>MAX_NATION )
err.run( "NationBase::get_relation()" );
return relation_array+nationRecno-1;
}
//---------- End of function NationBase::get_relation --------//
#endif
//---------- Begin of function NationBase::set_relation_should_attack --------//
void NationBase::set_relation_should_attack(short nationRecno, char newValue, char remoteAction)
{
if( !remoteAction && remote.is_enable() )
{
short *shortPtr = (short *) remote.new_send_queue_msg(MSG_NATION_SET_SHOULD_ATTACK, 3*sizeof(short));
*shortPtr = nation_recno;
shortPtr[1] = nationRecno;
shortPtr[2] = newValue;
}
else
{
relation_should_attack_array[nationRecno-1] = newValue;
get_relation(nationRecno)->should_attack = newValue;
}
}
//---------- End of function NationBase::set_relation_should_attack --------//
//---------- Begin of function NationBase::get_relation_should_attack --------//
char NationBase::get_relation_should_attack(short nationRecno)
{
// ###### begin Gilbert 3/9 #######//
// always can attack independent unit
return nationRecno == 0 || relation_should_attack_array[nationRecno-1];
// ###### end Gilbert 3/9 #######//
}
//---------- End of function NationBase::get_relation_should_attack --------//
//------- Begin of function NationBase::form_friendly_treaty ------//
//
// nationRecno - recno of the nation with which this nation
// will form treaty.
//
void NationBase::form_friendly_treaty(int nationRecno)
{
err_when( nationRecno == nation_recno );
err_when( nation_array.is_deleted(nationRecno) );
set_relation_status(nationRecno, NATION_FRIENDLY);
}
//------- End of function NationBase::form_friendly_treaty -------//
//------- Begin of function NationBase::form_alliance_treaty ------//
//
// nationRecno - recno of the nation with which this nation
// will form treaty.
//
void NationBase::form_alliance_treaty(int nationRecno)
{
err_when( nationRecno == nation_recno );
err_when( nation_array.is_deleted(nationRecno) );
set_relation_status(nationRecno, NATION_ALLIANCE);
//--- allied nations are oblied to trade with each other ---//
set_trade_treaty(nationRecno, 1);
//------ set is_allied_with_player -------//
if( nationRecno == nation_array.player_recno )
is_allied_with_player = 1;
if( nation_recno == nation_array.player_recno )
nation_array[nationRecno]->is_allied_with_player = 1;
}
//------- End of function NationBase::form_alliance_treaty -------//
//------- Begin of function NationBase::end_treaty ------//
//
// withNationRecno - recno of the nation which ends treaty
// with this nation. If it's an alliance treaty,
// allied nations with break treaty with
// this nation.
//
// newStatus - the new status after breaking the treaty.
//
void NationBase::end_treaty(int withNationRecno,int newStatus)
{
//----- decrease reputation when terminating a treaty -----//
Nation* withNation = nation_array[withNationRecno];
if( withNation->reputation > 0 )
{
int curStatus = get_relation_status(withNationRecno);
if( curStatus == TALK_END_FRIENDLY_TREATY )
change_reputation( -withNation->reputation * 10 / 100 );
else
change_reputation( -withNation->reputation * 20 / 100 );
}
//------- reset good_relation_duration_rating -----//
if( newStatus <= NATION_NEUTRAL )
{
get_relation(withNationRecno)->good_relation_duration_rating = (float) 0;
withNation->get_relation(nation_recno)->good_relation_duration_rating = (float) 0;
}
//------- set new relation status --------//
set_relation_status(withNationRecno, newStatus);
//------ set is_allied_with_player -------//
if( withNationRecno == nation_array.player_recno )
is_allied_with_player = 0;
if( nation_recno == nation_array.player_recno )
nation_array[withNationRecno]->is_allied_with_player = 0;
}
//------- End of function NationBase::end_treaty -------//
//------- Begin of function NationBase::set_trade_treaty ------//
//
// nationRecno - recno of the nation to change the trade allow flag
//
void NationBase::set_trade_treaty(int nationRecno, char treatyFlag)
{
err_when( nation_recno==nationRecno ); // cannot set trade treaty with oneself
get_relation(nationRecno)->trade_treaty = treatyFlag;
nation_array[nationRecno]->get_relation(nation_recno)->trade_treaty = treatyFlag;
}
//------- End of function NationBase::set_trade_treaty -------//
//------- Begin of function NationBase::establish_contact ------//
//
// nationRecno - recno of the nation to establish contact with
//
void NationBase::establish_contact(int nationRecno)
{
get_relation(nationRecno)->has_contact = 1;
nation_array[nationRecno]->get_relation(nation_recno)->has_contact = 1;
}
//------- End of function NationBase::establish_contact -------//
//------- Begin of function NationBase::being_attacked ------//
//
// attackNationRecno - recno of the nation that does the attack.
//
void NationBase::being_attacked(int attackNationRecno)
{
if( nation_array.is_deleted(attackNationRecno) || attackNationRecno==nation_recno )
return;
//--- if it is an accidential attack (e.g. bullets attack with spreading damages) ---//
Nation* attackNation = nation_array[attackNationRecno];
if( attackNation->get_relation(nation_recno)->should_attack==0 )
return;
//--- check if there a treaty between these two nations ---//
NationRelation* nationRelation = get_relation(attackNationRecno);
if( nationRelation->status != NATION_HOSTILE )
{
//--- if this nation (the one being attacked) has a higher than 0 reputation, the attacker's reputation will decrease ---//
if( reputation > 0 )
attackNation->change_reputation( -reputation * 40 / 100 );
nationRelation->started_war_on_us_count++; // how many times this nation has started a war with us, the more the times the worse this nation is.
if( nationRelation->status == NATION_ALLIANCE ||
nationRelation->status == NATION_FRIENDLY )
{
attackNation->end_treaty(nation_recno, NATION_HOSTILE); // the attacking nation abruptly terminates the treaty with us, not we terminate the treaty with them, so attackNation->end_treaty() should be called instead of end_treaty()
}
else
{
set_relation_status(attackNationRecno, NATION_HOSTILE);
}
}
//---- reset the inter-national peace days counter ----//
nation_array.nation_peace_days = 0;
}
//------- End of function NationBase::being_attacked -------//
//------- Begin of function NationBase::disp_nation_color ------//
//
// Display the color of the nation in a rectangular box.
//
void NationBase::disp_nation_color(int x, int y)
{
vga.active_buf->bar( x, y-2, x+12, y+10, nation_color );
vga.active_buf->rect( x, y-2, x+12, y+10, 1, nation_color+2 );
}
//------- End of function NationBase::disp_nation_color -------//
//------- Begin of function NationBase::trade_rating ------//
//
// Return a rating from 0 to 100 telling the significance of
// trading with the specific nation in this nation's regard.
//
int NationBase::trade_rating(int nationRecno)
{
// use an absolute value 5000 as the divider.
int tradeRating1 = 100 * (int) total_year_trade(nationRecno) / 5000;
int tradeRating2 = 50 * (int) nation_array[nationRecno]->get_relation(nation_recno)->last_year_import[IMPORT_TOTAL] / (int) (last_year_income+1) +
50 * (int) get_relation(nationRecno)->last_year_import[IMPORT_TOTAL] / (int) (last_year_expense+1);
return max(tradeRating1, tradeRating2);
}
//------- End of function NationBase::trade_rating -------//
//------- Begin of function NationBase::revealed_by_phoenix ------//
//
// Whether the area is revealed by phoenix of the nation or not.
//
// xLoc, yLoc - the location
//
int NationBase::revealed_by_phoenix(int xLoc, int yLoc)
{
Unit* unitPtr;
int effectiveRange = unit_res[UNIT_PHOENIX]->visual_range;
for( int i=unit_array.size() ; i>0 ; i-- )
{
if( unit_array.is_deleted(i) )
continue;
unitPtr = unit_array[i];
if( unitPtr->unit_id == UNIT_PHOENIX &&
unitPtr->nation_recno == nation_recno )
{
if( m.points_distance( xLoc, yLoc,
unitPtr->next_x_loc(), unitPtr->next_y_loc() ) <= effectiveRange )
{
return 1;
}
}
}
return 0;
}
//------- End of function NationBase::revealed_by_phoenix -------//
//------- Begin of function NationBase::total_tech_level -------//
//
// The sum of the tech levels of weapons that this nation possesses.
//
// [int] unitClass - only calculate total tech levels of this
// unit class. (default: 0, any classes)
//
int NationBase::total_tech_level(int unitClass)
{
TechInfo* techInfo;
int techLevel, totalTechLevel=0;
for( int i=1 ; i<=tech_res.tech_count ; i++ )
{
techInfo = tech_res[i];
techLevel = techInfo->get_nation_tech_level(nation_recno);
if( techLevel > 0 )
{
if( !unitClass ||
(unit_res[techInfo->unit_id]->unit_class == unitClass) )
{
totalTechLevel += techLevel;
}
}
}
return totalTechLevel;
}
//-------- End of function NationBase::total_tech_level -------//
//---------- Begin of function NationBase::civilian_killed --------//
//
// This function is called when civilian units are killed and this
// nation either killed the civilian units or this nation's civilian
// units are killed.
//
// civilianRaceId - the race id. of the civilian unit killed
// 0 - all races, when a Caravan is killed, 0 will
// be passed, the loyalty of all races will be decreased.
//
// isAttacker - 1 if the nation is the offensive attacker.
// 0 if the nation that suffers the atttack.
//
void NationBase::civilian_killed(int civilianRaceId, int isAttacker)
{
if( isAttacker )
{
change_all_people_loyalty(-3, civilianRaceId);
if( civilianRaceId==0 ) // a caravan
change_reputation(-(float)10);
else
change_reputation(-(float)1);
}
else
{
change_all_people_loyalty(-1, civilianRaceId);
if( civilianRaceId==0 ) // a caravan
change_reputation(-(float)3);
else
change_reputation(-(float)0.3);
}
}
//----------- End of function NationBase::civilian_killed ---------//
//--------- Begin of function NationBase::succeed_king --------//
//
// Appoint a unit to succeed the king who has died.
//
// The loyalty of the people in the natino may change due
// to the succession.
//
void NationBase::succeed_king(int kingUnitRecno)
{
Unit* newKing = unit_array[kingUnitRecno];
err_when( newKing->skill.combat_level <= 0 );
int newKingLeadership=0;
if( newKing->skill.skill_id == SKILL_LEADING )
newKingLeadership = newKing->skill.skill_level;
newKingLeadership = max( 20, newKingLeadership ); // give the king a minimum level of leadership
//----- set the common loyalty change for all races ------//
int loyaltyChange=0;
if( newKingLeadership < king_leadership )
loyaltyChange = (newKingLeadership-king_leadership)/2;
if( newKing->rank_id != RANK_GENERAL )
loyaltyChange -= 20;
//---- update loyalty of units in this nation ----//
Unit* unitPtr;
int i;
for( i=unit_array.size() ; i>0 ; i-- )
{
if( unit_array.is_deleted(i) )
continue;
if( i==king_unit_recno || i==kingUnitRecno )
continue;
unitPtr = unit_array[i];
if( unitPtr->nation_recno != nation_recno )
continue;
//--------- update loyalty change ----------//
unitPtr->change_loyalty( loyaltyChange +
succeed_king_loyalty_change(unitPtr->race_id, newKing->race_id, race_id) );
}
//---- update loyalty of units in camps ----//
Firm* firmPtr;
for( i=firm_array.size() ; i>0 ; i-- )
{
if( firm_array.is_deleted(i) )
continue;
firmPtr = firm_array[i];
if( firmPtr->nation_recno != nation_recno )
continue;
//------ process military camps and seat of power -------//
if( firmPtr->firm_id == FIRM_CAMP || firmPtr->firm_id == FIRM_BASE )
{
Worker* workerPtr = firmPtr->worker_array;
for(int j=firmPtr->worker_count-1 ; j>=0 ; j--, workerPtr++ )
{
//--------- update loyalty change ----------//
workerPtr->change_loyalty( loyaltyChange +
succeed_king_loyalty_change(workerPtr->race_id, newKing->race_id, race_id ) );
}
}
}
//---- update loyalty of town people ----//
Town* townPtr;
for( i=town_array.size() ; i>0 ; i-- )
{
if( town_array.is_deleted(i) )
continue;
townPtr = town_array[i];
if( townPtr->nation_recno != nation_recno )
continue;
for(int raceId=1 ; raceId<=MAX_RACE ; raceId++ )
{
if( townPtr->race_pop_array[raceId-1]==0 )
continue;
//------ update loyalty now ------//
townPtr->change_loyalty(raceId, (float) loyaltyChange +
succeed_king_loyalty_change( raceId, newKing->race_id, race_id ) );
}
}
//------- add news --------//
news_array.new_king(nation_recno, kingUnitRecno);
//-------- set the new king now ------//
set_king(kingUnitRecno, 0); // 0-not the first king, it is a succession
//------ if the new king is a spy -------//
if( newKing->spy_recno )
{
Spy* spyPtr = spy_array[newKing->spy_recno];
if( newKing->true_nation_recno() == nation_recno ) // if this is your spy
spyPtr->drop_spy_identity();
else
spyPtr->think_become_king();
err_when( newKing->rank_id==RANK_KING && newKing->spy_recno ); // it can't still be a spy when it asscends as the king
}
}
//----------- End of function NationBase::succeed_king ---------//
//------ Begin of static function succeed_king_loyalty_change -----//
//
// Return the amount of loyalty should be changed.
//
static int succeed_king_loyalty_change(int thisRaceId, int newKingRaceId, int oldKingRaceId)
{
#define SAME_RACE_LOYALTY_INC 20
#define DIFFERENT_RACE_LOYALTY_DEC 30
//----- the races of the new and old kings are different ----//
if( newKingRaceId != oldKingRaceId )
{
//--- if this unit's race is the same as the new king ---//
if( thisRaceId == newKingRaceId )
return SAME_RACE_LOYALTY_INC;
//--- if this unit's race is the same as the old king ---//
else if( thisRaceId == oldKingRaceId )
return DIFFERENT_RACE_LOYALTY_DEC;
}
return 0;
}
//-------- End of static function succeed_king_loyalty_change ------//
//--------- Begin of function NationBase::has_people --------//
//
// Whether the nation has any people (but not counting the king).
// If no, then the nation is going to end.
//
int NationBase::has_people()
{
return all_population() > 0;
}
//----------- End of function NationBase::has_people ---------//
//--------- Begin of function NationBase::surrender --------//
//
// This nation surrenders.
//
// toNationRecno - the recno of the nation this nation
// surrenders to.
//
void NationBase::surrender(int toNationRecno)
{
news_array.nation_surrender(nation_recno, toNationRecno);
//---- the king demote himself to General first ----//
if( king_unit_recno )
{
unit_array[king_unit_recno]->set_rank(RANK_GENERAL);
king_unit_recno = 0;
}
//------- if the player surrenders --------//
if( nation_recno==nation_array.player_recno )
game.game_end(0, 1, toNationRecno);
//--- hand over the entire nation to another nation ---//
hand_over_to(toNationRecno);
}
//----------- End of function NationBase::surrender ---------//
//--------- Begin of function NationBase::defeated --------//
//
// This nation is defeated.
//
void NationBase::defeated()
{
//---- if the defeated nation is the player's nation ----//
if( nation_recno == nation_array.player_recno )
{
game.game_end(0, 1); // the player lost the game
}
else // AI and remote players
{
news_array.nation_destroyed(nation_recno);
}
//---- delete this nation from nation_array ----//
nation_array.del_nation(nation_recno);
}
//----------- End of function NationBase::defeated ---------//
//------- Begin of function NationBase::change_all_people_loyalty ------//
//
// Change the loyalty of all the people in your nation.
//
// loyaltyChange - degree of loyalty change
// [int] raceId - if this is given, then only people of this race
// will be affected. (default: 0)
//
void NationBase::change_all_people_loyalty(int loyaltyChange, int raceId)
{
//---- update loyalty of units in this nation ----//
Unit* unitPtr;
int i;
for( i=unit_array.size() ; i>0 ; i-- )
{
if( unit_array.is_deleted(i) )
continue;
if( i==king_unit_recno )
continue;
unitPtr = unit_array[i];
if( unitPtr->nation_recno != nation_recno )
continue;
//--------- update loyalty change ----------//
if( !raceId || unitPtr->race_id == raceId )
unitPtr->change_loyalty(loyaltyChange);
}
//---- update loyalty of units in camps ----//
Firm* firmPtr;
for( i=firm_array.size() ; i>0 ; i-- )
{
if( firm_array.is_deleted(i) )
continue;
firmPtr = firm_array[i];
if( firmPtr->nation_recno != nation_recno )
continue;
//------ process military camps and seat of power -------//
if( firmPtr->firm_id == FIRM_CAMP || firmPtr->firm_id == FIRM_BASE )
{
Worker* workerPtr = firmPtr->worker_array;
for(int j=firmPtr->worker_count-1 ; j>=0 ; j--, workerPtr++ )
{
if( !raceId || workerPtr->race_id == raceId )
workerPtr->change_loyalty(loyaltyChange);
}
}
}
//---- update loyalty of town people ----//
Town* townPtr;
for( i=town_array.size() ; i>0 ; i-- )
{
if( town_array.is_deleted(i) )
continue;
townPtr = town_array[i];
if( townPtr->nation_recno != nation_recno )
continue;
//--------------------------------------//
if( raceId ) // decrease loyalty of a specific race
{
if( townPtr->race_pop_array[raceId-1] > 0 )
townPtr->change_loyalty(raceId, (float) loyaltyChange);
}
else // decrease loyalty of all races
{
for(int j=0 ; jrace_pop_array[j]==0 )
continue;
townPtr->change_loyalty(j+1, (float) loyaltyChange);
}
}
}
}
//------- End of function NationBase::change_all_people_loyalty -------//
//------- Begin of function NationBase::total_year_trade ------//
//
// Return the total trade (import + export) with the specific
// trade in the last year.
//
float NationBase::total_year_trade(int nationRecno)
{
return get_relation(nationRecno)->last_year_import[IMPORT_TOTAL] +
nation_array[nationRecno]->get_relation(nation_recno)->last_year_import[IMPORT_TOTAL];
}
//------- End of function NationBase::total_year_trade -------//
//---------- Begin of function NationBase::check_win --------//
//
// Check if the player has won the game.
//
void NationBase::check_win()
{
int hasWon = goal_destroy_nation_achieved() ||
goal_destroy_monster_achieved() ||
goal_population_achieved() ||
goal_economic_score_achieved() ||
goal_total_score_achieved();
if( !hasWon )
return;
//--------------------------------------//
game.game_end(nation_recno, 0); // if the player achieves the goal, the player wins, if one of the other kingdoms achieves the goal, it wins.
}
//----------- End of function NationBase::check_win ---------//
//---------- Begin of function NationBase::check_lose --------//
//
// Check if the player has lost the game.
//
// If the player still hasn't selected a unit to succeed the
// died king, declare defeated if the all units are killed.
//
void NationBase::check_lose()
{
//---- if the king of this nation is dead and it has no people left ----//
if( !king_unit_recno && !has_people() )
defeated();
}
//----------- End of function NationBase::check_lose ---------//
//---------- Begin of function NationBase::give_tribute --------//
//
// Give tribute or aid to a nation.
//
// toNationRecno - give tribute to this nation
// tributeAmt - the amount of the tribute
//
void NationBase::give_tribute(int toNationRecno, int tributeAmt)
{
Nation* toNation = nation_array[toNationRecno];
add_expense( EXPENSE_TRIBUTE, (float) tributeAmt );
toNation->add_income( INCOME_TRIBUTE, (float) tributeAmt );
NationRelation* nationRelation = get_relation(toNationRecno);
nationRelation->last_give_gift_date = info.game_date;
nationRelation->total_given_gift_amount += tributeAmt;
//---- set the last rejected date so it won't request or give again soon ----//
nationRelation->last_talk_reject_date_array[TALK_GIVE_AID-1] = 0;
nationRelation->last_talk_reject_date_array[TALK_DEMAND_AID-1] = 0;
nationRelation->last_talk_reject_date_array[TALK_GIVE_TRIBUTE-1] = 0;
nationRelation->last_talk_reject_date_array[TALK_DEMAND_TRIBUTE-1] = 0;
NationRelation* nationRelation2 = toNation->get_relation(nation_recno);
nationRelation2->last_talk_reject_date_array[TALK_GIVE_AID-1] = 0;
nationRelation2->last_talk_reject_date_array[TALK_DEMAND_AID-1] = 0;
nationRelation2->last_talk_reject_date_array[TALK_GIVE_TRIBUTE-1] = 0;
nationRelation2->last_talk_reject_date_array[TALK_DEMAND_TRIBUTE-1] = 0;
}
//----------- End of function NationBase::give_tribute ---------//
//---------- Begin of function NationBase::give_tech --------//
//
// Give tribute or aid to a nation.
//
// toNationRecno - give tribute to this nation
// techId - id. of the technology
// techVersion - version of the technology
//
void NationBase::give_tech(int toNationRecno, int techId, int techVersion)
{
Nation* toNation = nation_array[toNationRecno];
int curVersion = tech_res[techId]->get_nation_tech_level(toNationRecno);
if( curVersion < techVersion )
tech_res[techId]->set_nation_tech_level( toNationRecno, techVersion );
NationRelation* nationRelation = get_relation(toNationRecno);
nationRelation->last_give_gift_date = info.game_date;
nationRelation->total_given_gift_amount += (techVersion-curVersion) * 500; // one version level is worth $500
//---- set the last rejected date so it won't request or give again soon ----//
nationRelation->last_talk_reject_date_array[TALK_GIVE_TECH-1] = 0;
nationRelation->last_talk_reject_date_array[TALK_DEMAND_TECH-1] = 0;
NationRelation* nationRelation2 = toNation->get_relation(nation_recno);
nationRelation2->last_talk_reject_date_array[TALK_GIVE_TECH-1] = 0;
nationRelation2->last_talk_reject_date_array[TALK_DEMAND_TECH-1] = 0;
}
//----------- End of function NationBase::give_tech ---------//
//----- Begin of function NationBase::base_town_count_in_region -----//
//
// Return the number of base towns in the given region.
//
int NationBase::base_town_count_in_region(int regionId)
{
// ###### patch begin Gilbert 16/3 #######//
// regionStatId may be zero
int regionStatId = region_array[regionId]->region_stat_id;
if( regionStatId )
{
return region_array.get_region_stat2(regionStatId)->
base_town_nation_count_array[nation_recno-1];
}
else if( region_array[regionId]->region_size < STD_TOWN_LOC_WIDTH*STD_TOWN_LOC_HEIGHT)
{
return 0; // not enough to build any town
}
else
{
int townCount = 0;
for( int townRecno = town_array.size(); townRecno > 0; --townRecno )
{
if( town_array.is_deleted(townRecno) )
continue;
Town *townPtr = town_array[townRecno];
if( townPtr->region_id == regionId && townPtr->nation_recno == nation_recno )
townCount++;
}
return townCount == 0;
}
// ###### patch end Gilbert 16/3 #######//
}
//------ End of function NationBase::base_town_count_in_region -----//
//----- Begin of function NationBase::peace_duration_str -----//
//
char* NationBase::peace_duration_str()
{
int peaceDays = peaceful_days();
int peaceYear = peaceDays / 365;
int peaceMonth = (peaceDays - peaceYear * 365) / 30;
static String str;
str = "";
if( peaceYear > 0 )
{
str += peaceYear;
str += translate.process( peaceYear>1 ? (char*)" years" : (char*)" year" );
str += translate.process( (char*)" and " );
}
str += peaceMonth;
str += translate.process( peaceMonth>1 ? (char*)" months" : (char*)" month" );
return str;
}
//------ End of function NationBase::peace_duration_str -----//
//----- Begin of function NationBase::true_income_365days -----//
//
// Return the total income of the nation, excluding cheats.
//
float NationBase::true_income_365days()
{
float curYearIncome=(float)0, lastYearIncome=(float)0;
for( int i=0 ; itotal_firm_count == 0 &&
unit_res.mobile_monster_count == 0 )
{
Nation* nationPtr;
float maxScore=(float)0;
for( int i=nation_array.size() ; i>0 ; i-- )
{
if( nation_array.is_deleted(i) )
continue;
nationPtr = nation_array[i];
if( nationPtr->kill_monster_score > maxScore )
maxScore = nationPtr->kill_monster_score;
}
//-- if this nation is the one that has destroyed most monsters, it wins, otherwise it loses --//
return maxScore == kill_monster_score;
}
return 0;
}
//------- End of function NationBase::goal_destroy_monster_achieved --------//
//------- Begin of function NationBase::goal_population_achieved --------//
int NationBase::goal_population_achieved()
{
if( !config.goal_population_flag ) // this is not one of the required goals.
return 0;
return all_population() >= config.goal_population;
}
//------- End of function NationBase::goal_population_achieved --------//
//------ Begin of function NationBase::goal_economic_score_achieved ------//
int NationBase::goal_economic_score_achieved()
{
if( !config.goal_economic_score_flag )
return 0;
info.set_rank_data(0); // 0-set all nations, not just those that have contact with us
return info.get_rank_score(3,nation_recno) >= config.goal_economic_score;
}
//------- End of function NationBase::goal_economic_score_achieved -------//
//------ Begin of function NationBase::goal_total_score_achieved -------//
int NationBase::goal_total_score_achieved()
{
if( !config.goal_total_score_flag )
return 0;
info.set_rank_data(0); // 0-set all nations, not just those that have contact with us
return info.get_total_score(nation_recno) >= config.goal_total_score;
}
//------- End of function NationBase::goal_total_score_achieved --------//
//----- Begin of function NationBase::set_auto_collect_tax_loyalty -----//
//
void NationBase::set_auto_collect_tax_loyalty(int loyaltyLevel)
{
auto_collect_tax_loyalty = loyaltyLevel;
if( loyaltyLevel && auto_grant_loyalty >= auto_collect_tax_loyalty )
{
auto_grant_loyalty = auto_collect_tax_loyalty-10;
}
}
//------ End of function NationBase::set_auto_collect_tax_loyalty -----//
//----- Begin of function NationBase::set_auto_grant_loyalty -----//
//
void NationBase::set_auto_grant_loyalty(int loyaltyLevel)
{
auto_grant_loyalty = loyaltyLevel;
if( loyaltyLevel && auto_grant_loyalty >= auto_collect_tax_loyalty )
{
auto_collect_tax_loyalty = auto_grant_loyalty+10;
if( auto_collect_tax_loyalty > 100 )
auto_collect_tax_loyalty = 0; // disable auto collect tax if it's over 100
}
}
//------ End of function NationBase::set_auto_grant_loyalty -----//
//----- Begin of function NationRelation::status_duration_str -----//
//
char* NationRelation::status_duration_str()
{
int statusDays = info.game_date - last_change_status_date;
int statusYear = statusDays / 365;
int statusMonth = (statusDays - statusYear * 365) / 30;
static String str;
str = "";
if( statusYear > 0 )
{
str += statusYear;
str += translate.process( statusYear>1 ? (char*)" years" : (char*)" year" );
str += translate.process( (char*)" and " );
}
str += statusMonth;
str += translate.process( statusMonth>1 ? (char*)" months" : (char*)" month" );
return str;
}
//------ End of function NationRelation::status_duration_str -----//