int Nation::think_attack_monster() { if( config.monster_type == OPTION_MONSTER_NONE ) // no monsters in the game return 0; //--- if the AI has run out of money and is currently cheating, it will have a urgent need to attack monsters to get money ---// int useAllCamp = income_365days(INCOME_CHEAT) > 0; if( !useAllCamp ) // use all camps to attack the monster { if( !is_at_war() ) { if( cash < 500 && military_rank_rating() >= 75-pref_attack_monster/4 ) // 50 to 75 useAllCamp = 1 ; } } if( !useAllCamp ) { if( military_rank_rating() < 50-pref_attack_monster/4 ) // don't attack if the military strength is too low, 25 to 50 return 0; } //------- select a monster target ---------// int targetCombatLevel; int targetFirmRecno = think_monster_target(targetCombatLevel); if( !targetFirmRecno ) return 0; targetCombatLevel = targetCombatLevel * 150 / 100; // X 150% //--- we need to use veteran soldiers to attack powerful monsters ---// FirmMonster* targetFirm = (FirmMonster*) firm_array[targetFirmRecno]; int monsterLevel = monster_res[targetFirm->monster_id]->level; int attackerMinCombatLevel = 0; if( targetCombatLevel > 100 ) // if the nation's cash runs very low, it will attack anyway attackerMinCombatLevel = 20 + monsterLevel*3; //--- call ai_attack_target() to attack the target town ---// return ai_attack_target(targetFirm->loc_x1, targetFirm->loc_y1, targetCombatLevel, 0, 0, attackerMinCombatLevel, 0, useAllCamp ); }
//--------- Begin of function Nation::should_use_cash_to_capture --------// // int Nation::should_use_cash_to_capture() { //--- if we have plenty of cash, use cash to decrease the resistance of the villagers ---// return military_rank_rating() < 50+pref_peacefulness/5 && // 50 to 70 ai_should_spend(pref_loyalty_concern/4); }
//----- Begin of function Nation::consider_give_tribute -----// // // talkMsg->talk_para1 - amount of the tribute. // int Nation::consider_give_tribute(TalkMsg* talkMsg) { //-------- don't give tribute too frequently -------// NationRelation* nationRelation = get_relation(talkMsg->from_nation_recno); if( info.game_date < nationRelation->never_accept_until_date_array[TALK_GIVE_TRIBUTE-1] ) return 0; //---------------------------------------------// int relationStatus = get_relation_status(talkMsg->from_nation_recno); Nation* fromNation = nation_array[talkMsg->from_nation_recno]; if( true_profit_365days() < 0 ) // don't give tribute if we are losing money return 0; int reserveYears = 1 + 3 * pref_cash_reserve / 100; // 1 to 4 years if( cash-talkMsg->talk_para1 < fixed_expense_365days() * reserveYears ) return 0; int militaryDiff = fromNation->military_rank_rating() - military_rank_rating(); if( militaryDiff > 10+pref_military_courage/2 ) { nationRelation->set_never_accept_until_date(TALK_GIVE_TRIBUTE, 180); return 1; } return 0; }
//----- Begin of function Nation::consider_alliance_rating -----// // // Return a rating from 0 to 100 for whether this nation should ally // with the given nation. // int Nation::consider_alliance_rating(int nationRecno) { Nation* nationPtr = nation_array[nationRecno]; //---- the current relation affect the alliance tendency ---// NationRelation* nationRelation = get_relation(nationRecno); int allianceRating = nationRelation->ai_relation_level-20; //--- if the nation has a bad record of starting wars with us before, decrease the rating ---// allianceRating -= nationRelation->started_war_on_us_count * 20; //------ add the trade rating -------// int tradeRating = trade_rating(nationRecno) + // existing trade amount ai_trade_with_rating(nationRecno)/2; // possible trade allianceRating += tradeRating; //---- if the nation's power is larger than us, it's a plus ----// int powerRating = nationPtr->military_rank_rating() - military_rank_rating(); // if the nation's power is larger than ours, it's good to form treaty with them if( powerRating > 0 ) allianceRating += powerRating; return allianceRating; }
//----- Begin of function Nation::ai_should_spend_war -----// // // This function returns whether the nation should spend money // or war. // // <int> enemyMilitaryRating - the military_rank_rating() of the enemy // [int] considerCeaseFire - whether this function is called when considering ceasing fire // (default:0) // int Nation::ai_should_spend_war(int enemyMilitaryRating, int considerCeaseFire) { int importanceRating = 30 + pref_military_development/5; // 30 to 50 importanceRating += military_rank_rating() - enemyMilitaryRating*2; if( considerCeaseFire ) // only when we are very powerful, we will start a battle. So won't cease fire too soon after declaring war importanceRating += 20; // less eary to return 0, for cease fire return ai_should_spend(importanceRating); }
//----- Begin of function Nation::think_deal_with_all_enemy -----// // // Think about dealing with the enemy. The following are the // actions a nation can take to deal with its enemies. // // >ask our allies to attack the enemy. // // >try to break the enemy's existing alliance/friendly treaty with other // nations - to reduce its alliance strength. // // >convert enemy's allies to ours. // // >ask other nations to impose trade embargos on the enemy. // void Nation::think_deal_with_all_enemy() { Nation* nationPtr; int ourMilitary = military_rank_rating(); int enemyCount = total_enemy_count(); for( int i=1 ; i<=nation_array.size() ; i++ ) { if( nation_array.is_deleted(i) || nation_recno == i ) continue; if( get_relation_status(i) != NATION_HOSTILE ) continue; nationPtr = nation_array[i]; //------- think about eliminating the enemy ------// int rc = 0; if( nationPtr->total_population==0 ) // the enemy has no towns left rc = 1; if( enemyCount==1 && ourMilitary > 100-pref_military_courage/5 ) // 80 to 100 { int enemyMilitary = nationPtr->military_rank_rating(); if( enemyMilitary < 20 && ai_should_spend_war(enemyMilitary) ) rc = 1; } if( rc ) { if( think_eliminate_enemy_firm(i) ) continue; if( think_eliminate_enemy_town(i) ) continue; think_eliminate_enemy_unit(i); continue; } //----- think about dealing with the enemy with diplomacy -----// think_deal_with_one_enemy(i); } }
//----- Begin of function Nation::consider_declare_war -----// // // Consider the request of declaring war on the target nation. // // talk_para1 - the recno nation to declare war with. // int Nation::consider_declare_war(TalkMsg* talkMsg) { //--- if it even won't consider trade embargo, there is no reason that it will consider declaring war ---// if( !consider_trade_embargo(talkMsg) ) return 0; //---------------------------------------// int fromRelationRating = ai_overall_relation_rating(talkMsg->from_nation_recno); int againstRelationRating = ai_overall_relation_rating(talkMsg->talk_para1); Nation* againstNation = nation_array[talkMsg->talk_para1]; NationRelation* fromRelation = get_relation(talkMsg->from_nation_recno); NationRelation* againstRelation = get_relation(talkMsg->talk_para1); //--- if we don't have a good enough relation with the requesting nation, turn down the request ---// if( fromRelation->good_relation_duration_rating < 10 ) return 0; //--- if we are more friendly with the against nation than the requesting nation, turn down the request ---// if( againstRelation->good_relation_duration_rating > fromRelation->good_relation_duration_rating ) { return 0; } //--- if the nation is having a financial difficulty, it won't agree ---// if( cash < 2000 * pref_cash_reserve / 100 ) return 0; //--------------------------------------------// int acceptRating = 100 + againstNation->total_enemy_military() - military_rank_rating(); //--- it won't declare war with a friendly or allied nation easily ---// if( againstRelation->status >= RELATION_FRIENDLY ) // no need to handle RELATION_ALLIANCE separately as ai_overall_relation_relation() has already taken it into account acceptRating += 100; return fromRelationRating - againstRelationRating > acceptRating; }
//----- Begin of function Nation::ai_should_attack_friendly -----// // // This function returns whether this nation should attack // the given friendly nation. // // <int> friendlyNationRecno - the nation recno of the friendly nation. // <int> attackTemptation - a rating from 0 to 100 indicating // temptation of attacking the target. // int Nation::ai_should_attack_friendly(int friendlyNationRecno, int attackTemptation) { Nation *friendlyNation = nation_array[friendlyNationRecno]; NationRelation *nationRelation = get_relation(friendlyNationRecno); //--- don't change terminate treaty too soon ---// if( info.game_date < nationRelation->last_change_status_date+60+pref_honesty/2 ) // only after 60 to 110 days return 0; //------------------------------------------------// int resistanceRating = friendlyNation->military_rank_rating() - military_rank_rating(); resistanceRating += nationRelation->ai_relation_level - 50; resistanceRating += trade_rating(friendlyNationRecno); return attackTemptation > resistanceRating; }
//----- Begin of function Nation::total_alliance_military -----// // // Return the total power of this nation and its friendly/allied // nation. // int Nation::total_alliance_military() { int totalPower = military_rank_rating(); for( int i=nation_array.size() ; i>0 ; i-- ) { if( nation_array.is_deleted(i) || i==nation_recno ) continue; switch( get_relation_status(i) ) { case NATION_ALLIANCE: totalPower += nation_array[i]->military_rank_rating() * 3 / 4; // 75% break; /* case NATION_FRIENDLY: totalPower += nation_array[i]->military_rank_rating() / 2; //50% break; */ } } return totalPower; }
//----- Begin of function Nation::think_demand_tribute_aid -----// // // Demand tribute when the nation's economy is good and its // military is weak. // int Nation::think_demand_tribute_aid() { if( info.game_date < info.game_start_date + 180 + nation_recno*50 ) // don't ask for tribute too soon, as in the beginning, the ranking are all the same for all nations return 0; //--------------------------------------// Nation* nationPtr; int totalNation=nation_array.size(); int nationRecno=m.random(totalNation)+1; int curRating, requestRating; int talkId; int ourMilitary = military_rank_rating(); int ourEconomy = economic_rank_rating(); for( int i=totalNation ; i>0 ; i-- ) { if( ++nationRecno > totalNation ) nationRecno = 1; if( nation_array.is_deleted(nationRecno) || nationRecno==nation_recno ) continue; nationPtr = nation_array[nationRecno]; //-- only demand tribute from non-friendly nations --// if( get_relation(nationRecno)->status <= RELATION_NEUTRAL ) talkId = TALK_DEMAND_TRIBUTE; else talkId = TALK_DEMAND_AID; //-----------------------------------------------// float fixedExpense = fixed_expense_365days(); if( talkId == TALK_DEMAND_TRIBUTE ) { if( !should_diplomacy_retry(talkId, nationRecno) ) continue; curRating = ourMilitary - nationPtr->military_rank_rating(); //---- if this is a Fryhtan nation, the tendency to request tribute is higher -----// if( is_monster() && nationPtr->is_human() ) // and the target is a human nation { curRating *= 2; //-- if we are running low of live points, it's time to kill somebody --// if( live_points < 500 * (100+pref_live_points_reserve) / 100 ) curRating *= 2; } if( curRating < 0 ) continue; //----------------------------------------------// // // Some nation will actually consider the ability // of the target nation to pay tribute, so nation // will not and just ask anyway. // //----------------------------------------------// if( pref_economic_development > 50 ) { int addRating = nationPtr->economic_rank_rating()-ourEconomy; if( addRating > 0 ) curRating += addRating; } requestRating = 20 + trade_rating(nationRecno)/2 + (100-pref_peacefulness)/3; if( cash < fixedExpense && fixedExpense != 0 ) requestRating -= int( (float) requestRating * cash / fixedExpense); } else { if( cash >= fixedExpense ) continue; if( cash > fixedExpense * (50+pref_cash_reserve) / 300 && // if the nation is runing short of cash, don't wait a while until next retry, retry immediately !should_diplomacy_retry(talkId, nationRecno) ) { continue; } //----- only ask for aid when the nation is short of cash ----// curRating = (ourMilitary - nationPtr->military_rank_rating())/2 + ( nationPtr->economic_rank_rating()-ourEconomy ); requestRating = 20 + 50 * (int)(cash / fixedExpense); } //----- if the target is a human player's nation -----// if( !nationPtr->is_ai() ) { switch( config.ai_aggressiveness ) { case OPTION_NONE: requestRating += 60; // don't go against the player too easily break; case OPTION_LOW: requestRating += 40; // don't go against the player too easily break; case OPTION_HIGH: requestRating -= 20; break; case OPTION_VERY_HIGH: requestRating -= 40; break; } //--- if the nation has plenty of cash, demand from it ----// if( nationPtr->cash > cash && config.ai_aggressiveness >= OPTION_HIGH ) { requestRating -= (int) (nationPtr->cash - cash)/500; } } //--------------------------------------// if( curRating > requestRating ) { int tributeAmount; if( curRating - requestRating > 120 ) tributeAmount = 4000; else if( curRating - requestRating > 80 ) tributeAmount = 3000; else if( curRating - requestRating > 40 ) tributeAmount = 2000; else if( curRating - requestRating > 20 ) tributeAmount = 1000; else tributeAmount = 500; //------ stop in here if in tutorial mode -----// if( game.game_mode != GAME_TUTORIAL ) { cash += tributeAmount; return 0; } talk_res.ai_send_talk_msg(nationRecno, nation_recno, talkId, tributeAmount); return 1; } } return 0; }
//----- Begin of function Nation::think_give_tribute_aid -----// // // This function is called when a nation rejected our request // which is important to us and we want to give tribute to the // nation so it may accept next time. // // <TalkMsg*> rejectedMsg - the TalkMsg that has been rejected. // int Nation::think_give_tribute_aid(TalkMsg* rejectedMsg) { //-----------get the talk id. ------------// int talkId; int talkNationRecno = rejectedMsg->to_nation_recno; int rejectedTalkId = rejectedMsg->talk_id; NationRelation* nationRelation = get_relation(talkNationRecno); if( nationRelation->status >= RELATION_FRIENDLY ) talkId = TALK_GIVE_AID; else talkId = TALK_GIVE_TRIBUTE; //-------- don't give tribute too frequently -------// if( info.game_date < nationRelation->never_accept_until_date_array[talkId-1] ) return 0; //---- think if the nation should spend money now ----// static short tributeAmountArray[] = { 500, 1000 }; int tributeAmount = tributeAmountArray[m.random(2)]; if( !ai_should_spend(0, (float) tributeAmount) ) // importance rating is 0 return 0; //--------------------------------------// Nation* talkNation = nation_array[talkNationRecno]; int rc; if( rejectedTalkId == TALK_PROPOSE_TRADE_TREATY ) { rc = ai_trade_with_rating(talkNationRecno) > 100-pref_trading_tendency/2; } else if ( rejectedTalkId == TALK_PROPOSE_FRIENDLY_TREATY || rejectedTalkId == TALK_PROPOSE_ALLIANCE_TREATY ) { int curRating = talkNation->trade_rating(talkNationRecno) + ai_trade_with_rating(talkNationRecno) + talkNation->overall_rating - overall_rating; int acceptRating = 200-pref_trading_tendency/4 -pref_allying_tendency/4; rc = curRating >= acceptRating; } //--------------------------------------// else if( rejectedTalkId == TALK_REQUEST_CEASE_WAR ) { rc = talkNation->military_rank_rating() > military_rank_rating() + (100-pref_peacefulness)/2; } //--------------------------------------// if( rc ) { //------ give tribute --------// talk_res.ai_send_talk_msg(talkNationRecno, nation_recno, talkId, tributeAmount); nationRelation->set_never_accept_until_date(talkId, 100); // don't offer tribute too often //------ request again after giving tribute ----// nationRelation->last_talk_reject_date_array[rejectedTalkId-1] = 0; // reset the rejected talk id. nationRelation->never_accept_until_date_array[rejectedTalkId-1] = 0; // reset the rejected talk id. talk_res.ai_send_talk_msg(talkNationRecno, nation_recno, rejectedTalkId, rejectedMsg->talk_para1, rejectedMsg->talk_para2 ); } return rc; }
//--------- Begin of function Nation::think_capture_enemy_town_target --------// // // <Town*> capturerTown - our town to capture enemy towns. // // Motives for attacking another nation: // // 1. Capture towns // 2. Conquer land // 3. Defeat enemies // Town* Nation::think_capture_enemy_town_target(Town* capturerTown) { int townRecno, curRating; Town* targetTown, *bestTown=NULL; Firm* firmPtr; int ourMilitary = military_rank_rating(); Nation* ownNation = nation_array[nation_recno]; int bestRating = -1000; int hasWar; int neededCombatLevel=0; for( townRecno=town_array.size() ; townRecno>0 ; townRecno-- ) { if( town_array.is_deleted(townRecno) ) continue; targetTown = town_array[townRecno]; if( targetTown->nation_recno == 0 || targetTown->nation_recno == nation_recno ) { continue; } if( targetTown->region_id != capturerTown->region_id ) continue; //----- if we have already built a camp next to this town -----// if( targetTown->has_linked_camp(nation_recno, 0) ) //0-count both camps with or without overseers continue; //--------- only attack enemies -----------// NationRelation* nationRelation = get_relation(targetTown->nation_recno); int rc=0; if( nationRelation->status == NATION_HOSTILE ) rc = 1; else if( nationRelation->ai_relation_level < 10 ) // even if the relation is not hostile, if the ai_relation_level is < 10, attack anyway rc = 1; else if( nationRelation->status <= NATION_NEUTRAL && targetTown->nation_recno == nation_array.max_overall_nation_recno && // if this is our biggest enemy nationRelation->ai_relation_level < 30 ) { rc = 1; } if( !rc ) continue; //----- if this town does not have any linked camps, capture this town immediately -----// if( targetTown->has_linked_camp(targetTown->nation_recno, 0) ) //0-count both camps with or without overseers return targetTown; //--- if the enemy is very powerful overall, don't attack it yet ---// if( nation_array[targetTown->nation_recno]->military_rank_rating() > ourMilitary * (80+pref_military_courage/2) / 100 ) { continue; } //------ only attack if we have enough money to support the war ----// if( !ai_should_spend_war( nation_array[targetTown->nation_recno]->military_rank_rating() ) ) continue; //-------------------------------------------------------// int townCombatLevel = enemy_town_combat_level(targetTown, 1, hasWar); // 1-return a rating if there is war with the town if( townCombatLevel == -1 ) // do not attack this town because a battle is already going on continue; //------- calculate the rating --------------// curRating = world.distance_rating(capturerTown->center_x, capturerTown->center_y, targetTown->center_x, targetTown->center_y); curRating -= townCombatLevel/10; curRating -= targetTown->average_loyalty(); curRating += targetTown->population; // put a preference on capturing villages with large population //----- the power of between the nation also affect the rating ----// curRating += 2 * (ourMilitary - nation_array[targetTown->nation_recno]->military_rank_rating()); //-- AI Aggressive is set above Low, than the AI will try to capture the player's town first ---// if( !targetTown->ai_town ) { if( game.game_mode == GAME_TUTORIAL ) // next attack the player in a tutorial game { continue; } else { switch( config.ai_aggressiveness ) { case OPTION_MODERATE: curRating += 100; break; case OPTION_HIGH: curRating += 300; break; case OPTION_VERY_HIGH: curRating += 500; break; } } } //--- if there are mines linked to this town, increase its rating ---// for( int i=targetTown->linked_firm_count-1 ; i>=0 ; i-- ) { firmPtr = firm_array[ targetTown->linked_firm_array[i] ]; if( firmPtr->nation_recno != targetTown->nation_recno ) continue; if( firmPtr->firm_id == FIRM_MINE ) { //--- if this mine's raw materials is one that we don't have --// if( raw_count_array[ ((FirmMine*)firmPtr)->raw_id-1 ]==0 ) curRating += 150 * (int) ((FirmMine*)firmPtr)->reserve_qty / MAX_RAW_RESERVE_QTY; } } //--- more linked towns increase the attractiveness rating ---// curRating += targetTown->linked_firm_count*5; //-------- compare with the current best rating ---------// if( curRating > bestRating ) { bestRating = curRating; bestTown = targetTown; neededCombatLevel = townCombatLevel; } } return bestTown; }
//----- Begin of function Nation::consider_cease_war -----// // // This function is shared by think_request_cease_war(). // int Nation::consider_cease_war(int withNationRecno) { NationRelation* nationRelation = get_relation(withNationRecno); if( nationRelation->status != RELATION_HOSTILE ) return -1; // -1 means don't reply //---- if we are attacking the nation, don't cease fire ----// if( ai_attack_target_nation_recno == withNationRecno ) return -1; //---- if we are planning to capture the enemy's town ---// if( ai_capture_enemy_town_recno && !town_array.is_deleted(ai_capture_enemy_town_recno) && town_array[ai_capture_enemy_town_recno]->nation_recno == withNationRecno ) { return -1; } //--- don't cease fire too soon after a war is declared ---// if( info.game_date < nationRelation->last_change_status_date + 60 + (100-pref_peacefulness) ) // more peaceful nation may cease fire sooner (but the minimum is 60 days). return -1; //------ if we're run short of money for war -----// Nation* withNation = nation_array[withNationRecno]; if( !ai_should_spend_war(withNation->military_rank_rating(), 1) ) // if we shouldn't spend any more on war, then return 1 return 1; //------------------------------------------------// int curRating = consider_alliance_rating(withNationRecno); //------------------------------------// // // Tend to be easilier to accept cease-fire if this nation's // military strength is weak. // // If the nation's peacefulness concern is high, it will // also be more likely to accept cease-fire. // //-------------------------------------// //--- if the enemy is more power than us, tend more to request cease-fire ---// curRating += total_enemy_military() - military_rank_rating(); curRating += ai_trade_with_rating(withNationRecno) * (100+pref_trading_tendency) / 300; // when we have excessive supply, we may want to cease-fire with our enemy curRating -= (military_rank_rating()-50)/2; // if our military ranking is high, we may like to continue the war, otherwise the nation should try to cease-fire curRating -= nationRelation->started_war_on_us_count*10; // the number of times this nation has started a war with us, the higher the number, the more unlikely we will accept cease-fire int acceptRating = pref_peacefulness/4; return curRating - acceptRating; }