//--------- Begin of function Nation::attack_enemy_town_defense --------// // // Attack enemy's defending forces on the target town. // // <Town*> targetTown - the pointer to the target town. // [int] useAllCamp - whether use troops in all camps to attack the enemy town // (default: 0) // // return: <int> 1 - a troop has been sent to attack the target. // 0 - we don't have sufficient troops for attacking the target. // -1 - no defense on the target town, no attacking is needed. // int Nation::attack_enemy_town_defense(Town* targetTown, int useAllCamp) { err_when( targetTown->nation_recno == nation_recno ); // cannot attack itself if( targetTown->nation_recno == 0 ) return -1; //--- if there are any command bases linked to the town, attack them first ---// int campCombatLevel, maxCampCombatLevel= -1; Firm *firmPtr, *bestTargetFirm=NULL; 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 && firmPtr->firm_id == FIRM_CAMP ) { campCombatLevel = ((FirmCamp*)firmPtr)->total_combat_level(); if( campCombatLevel > maxCampCombatLevel ) { maxCampCombatLevel = campCombatLevel; bestTargetFirm = firmPtr; } } } //----- get the defense combat level of the mobile units around the town ----// int hasWar; int townMobileCombatLevel = mobile_defense_combat_level(targetTown->center_x, targetTown->center_y, targetTown->nation_recno, 0, hasWar); int totalDefenseCombatLevel = maxCampCombatLevel + townMobileCombatLevel; //----------------------------------------// if( bestTargetFirm ) { Nation* targetNation = nation_array[bestTargetFirm->nation_recno]; if( targetNation->is_at_war() ) // use all camps force if the nation is at war useAllCamp = 1; return ai_attack_target(bestTargetFirm->loc_x1, bestTargetFirm->loc_y1, totalDefenseCombatLevel, 0, 0, 0, 0, useAllCamp ); } else { //--- if there are any mobile defense force around the town ----// if( townMobileCombatLevel > 0 ) return ai_attack_target(targetTown->center_x, targetTown->center_y, totalDefenseCombatLevel, 0, 1 ); // 1-just all move there and wait for the units to attack the enemies automatically } return -1; }
//----- Begin of function Nation::think_eliminate_enemy_unit -----// // // This function is called to eliminate remaining enemy firms // when all enemy towns have been destroyed. // int Nation::think_eliminate_enemy_unit(int enemyNationRecno) { Unit *unitPtr; int hasWar; for( int i=unit_array.size() ; i>0 ; i-- ) { if( unit_array.is_deleted(i) ) continue; unitPtr = unit_array[i]; if( unitPtr->nation_recno != enemyNationRecno ) continue; if( !unitPtr->is_visible() || unitPtr->mobile_type != UNIT_LAND ) // only deal with land units now continue; //--- only attack if we have any base town in the enemy unit's region ---// if( base_town_count_in_region(unitPtr->region_id()) == 0 ) continue; //----- take into account of the mobile units around this town -----// int mobileCombatLevel = mobile_defense_combat_level(unitPtr->next_x_loc(), unitPtr->next_y_loc(), unitPtr->nation_recno, 1, hasWar); if( mobileCombatLevel == -1 ) // do not attack this town because a battle is already going on continue; return ai_attack_target(unitPtr->next_x_loc(), unitPtr->next_y_loc(), mobileCombatLevel + (int) unitPtr->unit_power()); } return 0; }
//----- Begin of function Nation::think_attack_enemy_firm -----// // // Think about attacking a specific type of firm of a specific enemy. // int Nation::think_attack_enemy_firm(int enemyNationRecno, int firmId) { if( !largest_town_recno ) return 0; Town* ourLargestTown = town_array[largest_town_recno]; Nation *nationPtr = nation_array[enemyNationRecno]; Firm *firmPtr, *targetFirm=NULL; int curRating, bestRating=0, targetCombatLevel, hasWar; for( int i=firm_array.size() ; i>0 ; i-- ) { if( firm_array.is_deleted(i) ) continue; firmPtr = firm_array[i]; if( firmPtr->firm_id != firmId || firmPtr->nation_recno != enemyNationRecno ) { continue; } int combatLevel = enemy_firm_combat_level(firmPtr, 1, hasWar); if( combatLevel==0 ) // no protection with this mine { targetFirm = firmPtr; targetCombatLevel = combatLevel; break; } curRating = world.distance_rating( firmPtr->center_x, firmPtr->center_y, ourLargestTown->center_x, ourLargestTown->center_y ); curRating += 1000 - combatLevel/5; if( curRating > bestRating ) { bestRating = curRating; targetFirm = firmPtr; targetCombatLevel = combatLevel; } } if( !targetFirm ) return 0; //---------------------------------------------// int useAllCamp=1; return ai_attack_target( targetFirm->loc_x1, targetFirm->loc_y1, targetCombatLevel, 0, 0, 0, 0, useAllCamp ); }
int Nation::think_attack_units_standing_on_mine() { for( int i=site_array.size() ; i>0 ; i-- ) { if( site_array.is_deleted(i) ) continue; Site* sitePtr = site_array[i]; if( sitePtr->site_type != SITE_RAW ) continue; Location* siteLocPtr = world.get_loc(sitePtr->map_x_loc, sitePtr->map_y_loc); if( world.can_build_firm(sitePtr->map_x_loc, sitePtr->map_y_loc, FIRM_MINE) ) continue; //----- attack enemy units standing on this location ----// for( int yLoc=sitePtr->map_y_loc ; yLoc<=sitePtr->map_y2 ; yLoc++ ) { for( int xLoc=sitePtr->map_x_loc ; xLoc<=sitePtr->map_x2 ; xLoc++ ) { Location* locPtr = world.get_loc(xLoc, yLoc); int unitRecno = locPtr->unit_recno('L'); if( !unitRecno ) continue; if( unit_array[unitRecno]->cur_action != SPRITE_IDLE ) // only attack units that stand on the mine continue; int nationRecno = unit_array[unitRecno]->nation_recno; if( nationRecno == nation_recno ) continue; //--- attack the units standing on the mine if the units' relationship <= Neutral ---// if( get_relation_status(nationRecno) <= RELATION_NEUTRAL ) { ai_attack_target( xLoc, yLoc, unit_array[unitRecno]->obj_power(), 0, 0, 0, 0, 1 ); // 1-use all camps return 1; } } } } return 0; }
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::think_eliminate_enemy_firm -----// // // This function is called to eliminate remaining enemy firms // when all enemy towns have been destroyed. // int Nation::think_eliminate_enemy_firm(int enemyNationRecno) { //---- look for enemy firms to attack ----// int hasWar; Firm *firmPtr; for( int i=firm_array.size() ; i>0 ; i-- ) { if( firm_array.is_deleted(i) ) continue; firmPtr = firm_array[i]; if( firmPtr->nation_recno != enemyNationRecno ) continue; //--- only attack if we have any base town in the enemy firm's region ---// if( base_town_count_in_region(firmPtr->region_id)==0 ) continue; //----- take into account of the mobile units around this town -----// int mobileCombatLevel = mobile_defense_combat_level(firmPtr->center_x, firmPtr->center_y, firmPtr->nation_recno, 1, hasWar); if( mobileCombatLevel == -1 ) // do not attack this town because a battle is already going on continue; //---- calculate the combat level of this target firm ----// int firmCombatLevel; if( firmPtr->firm_id == FIRM_CAMP ) // other civilian firms firmCombatLevel = ((FirmCamp*)firmPtr)->total_combat_level(); else firmCombatLevel = firmPtr->worker_count * 10; // civilian firms have very low combat level return ai_attack_target(firmPtr->loc_x1, firmPtr->loc_y1, mobileCombatLevel + firmCombatLevel); } return 0; }
//----- Begin of function Nation::think_eliminate_enemy_town -----// // // This function is called to eliminate remaining enemy firms // when all enemy towns have been destroyed. // int Nation::think_eliminate_enemy_town(int enemyNationRecno) { //---- look for enemy firms to attack ----// int hasWar; Town *townPtr; for( int i=town_array.size() ; i>0 ; i-- ) { if( town_array.is_deleted(i) ) continue; townPtr = town_array[i]; if( townPtr->nation_recno != enemyNationRecno ) continue; //--- only attack if we have any base town in the enemy town's region ---// if( base_town_count_in_region(townPtr->region_id)==0 ) continue; //----- take into account of the mobile units around this town -----// int mobileCombatLevel = mobile_defense_combat_level(townPtr->center_x, townPtr->center_y, townPtr->nation_recno, 1, hasWar); if( mobileCombatLevel == -1 ) // do not attack this town because a battle is already going on continue; //---- calculate the combat level of this target town ----// int townCombatLevel = townPtr->protection_available(); return ai_attack_target(townPtr->loc_x1, townPtr->loc_y1, mobileCombatLevel + townCombatLevel); } return 0; }
//--------- Begin of function Nation::think_destroy_raw_site_guard --------// // int Nation::think_destroy_raw_site_guard() { Site* sitePtr; Location* locPtr; Unit* unitPtr; for( int i=site_array.size() ; i>0 ; i-- ) { if( site_array.is_deleted(i) ) continue; sitePtr = site_array[i]; //--- if there is already a mine built on this raw site ---// if( sitePtr->has_mine ) continue; //----- if there is a unit standing on this site -----// locPtr = world.get_loc( sitePtr->map_x_loc, sitePtr->map_y_loc ); if( !locPtr->unit_recno(UNIT_LAND) ) continue; unitPtr = unit_array[ locPtr->unit_recno(UNIT_LAND) ]; if( unitPtr->cur_action != SPRITE_IDLE ) // only attack if this unit is idle continue; if( unitPtr->nation_recno == nation_recno ) // don't attack our own units continue; //------ check if we have a presence in this region ----// if( is_human() && base_town_count_in_region(sitePtr->region_id) == 0 ) continue; //------ check the relationship with this unit ------// // // If we are friendly with this nation, don't attack it. // //---------------------------------------------------// if( get_relation_status(unitPtr->nation_recno) >= RELATION_FRIENDLY ) continue; //--------- attack the enemy unit ---------// int hasWar; int enemyCombatLevel = mobile_defense_combat_level( sitePtr->map_x_loc, sitePtr->map_y_loc, unitPtr->nation_recno, 1, hasWar ); if( enemyCombatLevel == - 1 ) // a war is going on here, don't attack this target continue; if( ai_attack_target(sitePtr->map_x_loc, sitePtr->map_y_loc, enemyCombatLevel, 0, 0, 0, 0, 1) ) // 1-use all camps return 1; } return 0; }
//--------- Begin of function Nation::ai_attack_unit_in_area --------// // // AI attacks all units that are not friendly to us within the given area. // // <int> xLoc1, yLoc1, xLoc2, yLoc2 - coordination of the area. // void Nation::ai_attack_unit_in_area(int xLoc1, int yLoc1, int xLoc2, int yLoc2) { int enemyXLoc, enemyYLoc, enemyCombatLevel=0; int enemyStatus = RELATION_FRIENDLY; Location* locPtr; Unit* unitPtr; //--------------------------------------------------// for( int yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ ) { for( int xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++ ) { locPtr = world.get_loc(xLoc, yLoc); if( !locPtr->unit_recno(UNIT_LAND) ) continue; unitPtr = unit_array[ locPtr->unit_recno(UNIT_LAND) ]; //--- if there is an idle unit on the mine building site ---// if( unitPtr->cur_action != SPRITE_IDLE || unitPtr->nation_recno==0 ) continue; //----- if this is our spy cloaked in another nation, reveal its true identity -----// if( unitPtr->nation_recno != nation_recno && unitPtr->true_nation_recno() == nation_recno ) { unitPtr->spy_change_nation(nation_recno, COMMAND_AI); } //--- if this is our own unit, order him to stay out of the building site ---// if( unitPtr->nation_recno == nation_recno ) { unitPtr->think_normal_human_action(); // send the unit to a firm or a town } else //--- if it is an enemy unit, attack it ------// { int nationStatus = get_relation_status(unitPtr->nation_recno); if( nationStatus < enemyStatus ) // if the status is worse than the current target { enemyXLoc = xLoc; enemyYLoc = yLoc; enemyStatus = nationStatus; enemyCombatLevel += (int) unitPtr->obj_power(); } } } } //--- if there are enemies on our firm building site, attack them ---// if( enemyCombatLevel ) { ai_attack_target( enemyXLoc, enemyYLoc, enemyCombatLevel ); } }
//----- Begin of function Nation::think_against_mine_monopoly -----// // int Nation::think_against_mine_monopoly() { //-- only think this after the game has been running for at least one year --// if( config.ai_aggressiveness < OPTION_HIGH ) // only attack if aggressiveness >= high return 0; if( info.game_date - info.game_start_date > 365 ) return 0; if( profit_365days() > 0 ) // if we are making a profit, don't attack return 0; //-- for high aggressiveness, it will check cash before attack, for very high aggressiveness, it won't check cash before attack ---// if( config.ai_aggressiveness < OPTION_VERY_HIGH ) // only attack if aggressiveness >= high { if( cash > 2000 + 1000 * pref_cash_reserve / 100 ) // only attack if we run short of cash return 0; } //--------------------------------------------------------// if( !largest_town_recno ) return 0; //--------------------------------------------------// int baseRegionId = town_array[largest_town_recno]->region_id; // no region stat (region is too small), don't care if( !region_array[baseRegionId]->region_stat_id ) return 0; RegionStat* regionStat = region_array.get_region_stat(baseRegionId); //---- if we already have a mine in this region ----// if( regionStat->mine_nation_count_array[nation_recno-1] > 0 ) return 0; //----- if there is no mine in this region -----// if( regionStat->raw_count == 0 ) return 0; //----- if enemies have occupied all mines -----// int mineCount, totalMineCount=0; int curRating, bestRating=0, targetNationRecno=0; int i; for( i=nation_array.size() ; i>0 ; i-- ) { if( nation_array.is_deleted(i) ) continue; //------ only deal with human players ------// if( nation_array[i]->is_ai() || i==nation_recno ) continue; //------------------------------------------// mineCount = regionStat->mine_nation_count_array[i-1]; totalMineCount += mineCount; curRating = mineCount * 100 - get_relation(i)->ai_relation_level - trade_rating(i); if( curRating > bestRating ) { bestRating = curRating; targetNationRecno = i; } } if( !targetNationRecno ) return 0; //--- if the relationship with this nation is still good, don't attack yet, ask for aid first ---// NationRelation* nationRelation = get_relation(targetNationRecno); if( nationRelation->ai_relation_level > 30 ) { int talkId; if( nationRelation->status >= NATION_FRIENDLY ) talkId = TALK_DEMAND_AID; else talkId = TALK_DEMAND_TRIBUTE; if( should_diplomacy_retry(talkId, targetNationRecno) ) { static short aidAmountArray[] = { 500, 1000, 2000 }; int aidAmount = aidAmountArray[misc.random(3)]; talk_res.ai_send_talk_msg(targetNationRecno, nation_recno, talkId, aidAmount); } return 0; } //------- attack one of the target enemy's mines -------// Firm* firmPtr; for( i=firm_array.size() ; i>0 ; i-- ) { if( firm_array.is_deleted(i) ) continue; firmPtr = firm_array[i]; if( firmPtr->firm_id != FIRM_MINE || firmPtr->nation_recno != targetNationRecno || firmPtr->region_id != baseRegionId ) { continue; } //--------------------------------------------// int hasWar; int targetCombatLevel = enemy_firm_combat_level(firmPtr, 1, hasWar); return ai_attack_target( firmPtr->loc_x1, firmPtr->loc_y1, targetCombatLevel, 0, 0, 0, 0, 1 ); // 1-use all camps } return 0; }
void Nation::think_capturing_enemy_town() { if( !ai_capture_enemy_town_recno ) return; if( town_array.is_deleted(ai_capture_enemy_town_recno) || town_array[ai_capture_enemy_town_recno]->nation_recno == nation_recno ) // this town has been captured already { ai_capture_enemy_town_recno = 0; return; } //--- check the enemy's mobile defense combat level around the town ---// Town* targetTown = town_array[ai_capture_enemy_town_recno]; int hasWar; int mobileCombatLevel = mobile_defense_combat_level(targetTown->center_x, targetTown->center_y, targetTown->nation_recno, 0, hasWar); // 0-don't return immediately even if there is war around this town //---- if we haven't started attacking the town yet -----// if( !ai_capture_enemy_town_start_attack_date ) { if( hasWar==2 ) // we are at war with the nation now ai_capture_enemy_town_start_attack_date = info.game_date; if( info.game_date > ai_capture_enemy_town_plan_date + 90 ) // when 3 months have gone and there still hasn't been any attack on the town, there must be something bad happened to our troop, cancel the entire action ai_capture_enemy_town_recno = 0; return; // do nothing if the attack hasn't started yet } //--------- check if we need reinforcement --------// //-----------------------------------------------------------// // Check how long we have started attacking because only // when the it has been started for a while, our force // will reach the target and the offensive and defensive force // total can be calculated accurately. //-----------------------------------------------------------// if( info.game_date - ai_capture_enemy_town_start_attack_date >= 15 ) { //-------- check if we need any reinforcement --------// if( mobileCombatLevel > 0 && hasWar==2 ) // we are still in war with the enemy { ai_attack_target(targetTown->center_x, targetTown->center_y, mobileCombatLevel, 0, 1 ); // 1-just all move there and wait for the units to attack the enemies automatically return; } } //----- there is currently no war at the town -----// // // - either we are defeated or we have destroyed their command base. // //--------------------------------------------------// if( hasWar != 2 ) { //---- attack enemy's defending forces on the target town ----// int rc = attack_enemy_town_defense(targetTown, ai_capture_enemy_town_use_all_camp); if( rc == 1 ) // 1 means a troop has been sent to attack the town { ai_capture_enemy_town_start_attack_date = 0; return; } //---------- reset the vars --------// ai_capture_enemy_town_recno = 0; ai_capture_enemy_town_start_attack_date = 0; //--------- other situations --------// if( rc == -1 ) // -1 means no defense on the target town, no attacking is needed. { start_capture( targetTown->town_recno ); // call AI functions in OAI_CAPT.CPP to capture the town } // 0 means we don't have enough troop to attack the enemy } }
//----- Begin of function Nation::consider_military_aid -----// // int Nation::consider_military_aid(TalkMsg* talkMsg) { Nation* fromNation = nation_array[talkMsg->from_nation_recno]; NationRelation* fromRelation = get_relation(talkMsg->from_nation_recno); //----- don't aid too frequently ------// if( info.game_date < fromRelation->last_military_aid_date + 200 - pref_allying_tendency ) return 0; //------- only when the AI relation >= 60 --------// if( fromRelation->ai_relation_level < 60 ) return 0; //--- if the requesting nation is not at war now ----// if( !fromNation->is_at_war() ) return 0; //---- can't aid if we are at war ourselves -----// if( is_at_war() ) return 0; //--- if the nation is having a financial difficulty, it won't agree ---// if( cash < 2000 * pref_cash_reserve / 100 ) return 0; //----- can't aid if we are too weak ourselves ---// if( ai_general_count*10 + total_human_count + total_monster_count < 100-pref_military_courage/2 ) { return 0; } //----- see what units are attacking the nation -----// if( unit_array.is_deleted(fromNation->last_attacker_obj_recno) ) return 0; BaseObj* baseObj = base_obj_array[ fromNation->last_attacker_obj_recno ]; if( baseObj->nation_recno == nation_recno ) // if it's our own units return 0; if( baseObj->nation_recno == 0 ) return 0; if( !baseObj->is_visible() ) return 0; //------ only attack if it's a common enemy to us and our ally -----// if( get_relation(baseObj->nation_recno)->status != RELATION_HOSTILE ) return 0; //------- calculate the combat level of the target units there ------// int hasWar; int targetCombatLevel = mobile_defense_combat_level( baseObj->obj_loc_x1(), baseObj->obj_loc_y1(), baseObj->nation_recno, 0, hasWar ); if( ai_attack_target(baseObj->obj_loc_x1(), baseObj->obj_loc_y1(), targetCombatLevel, 0, 1 ) ) //0-not defense mode, 1-just move to flag { fromRelation->last_military_aid_date = info.game_date; return 1; } return 0; }