//--------- Begin of function Nation::capture_expected_resistance --------// // // The lowest resistance can be expected if we are going to capture the // town. // int Nation::capture_expected_resistance(int townRecno, int *captureUnitRecno) { //--- we have plenty of cash, use cash to decrease the resistance of the villagers ---// *captureUnitRecno = 0; if( should_use_cash_to_capture() ) return 0; // return zero resistance //----- the average resistance determines the captureRating ------// int captureRating = 0; Town* townPtr = town_array[townRecno]; int averageResistance; if( townPtr->nation_recno ) averageResistance = townPtr->average_loyalty(); else averageResistance = townPtr->average_resistance(nation_recno); //---- see if there are general available for capturing this town ---// int majorityRace = townPtr->majority_race(); int targetResistance; *captureUnitRecno = find_best_capturer(townRecno, majorityRace, /*out*/ targetResistance); if( !(*captureUnitRecno) ) return 100; int resultResistance = ( targetResistance * townPtr->race_pop_array[majorityRace-1] + averageResistance * (townPtr->population - townPtr->race_pop_array[majorityRace-1]) ) / townPtr->population; return resultResistance; }
//--------- Begin of function Nation::think_capture_independent --------// // // Think about capturing independent towns. // int Nation::think_capture_independent() { //------- Capture target choices -------// std::priority_queue<CaptureTown> captureTownQueue; //--- find the town that makes most sense to capture ---// int townRecno; Town* townPtr; for(townRecno=town_array.size(); townRecno>0; townRecno--) { if(town_array.is_deleted(townRecno)) continue; townPtr = town_array[townRecno]; if( townPtr->nation_recno ) // only capture independent towns continue; if( townPtr->no_neighbor_space ) // if there is no space in the neighbor area for building a new firm. continue; if( townPtr->rebel_recno ) // towns controlled by rebels will not drop in resistance even if a command base is present continue; //------ only if we have a presence/a base town in this region -----// if( !has_base_town_in_region(townPtr->region_id) ) continue; //---- check if there are already camps linked to this town ----// int i; for( i=townPtr->linked_firm_count-1 ; i>=0 ; i-- ) { Firm* firmPtr = firm_array[ townPtr->linked_firm_array[i] ]; if( firmPtr->firm_id != FIRM_CAMP ) continue; //------ if we already have a camp linked to this town -----// if( firmPtr->nation_recno == nation_recno ) break; //--- if there is an overseer with high leadership and right race in the opponent's camp, don't bother to compete with him ---// if( firmPtr->overseer_recno ) { Unit* unitPtr = unit_array[firmPtr->overseer_recno]; if( unitPtr->skill.skill_level >= 70 && unitPtr->race_id == townPtr->majority_race() ) { break; } } } if( i>=0 ) // there is already a camp linked to this town and we don't want to get involved with its capturing plan continue; //------ no linked camps interfering with potential capture ------// int captureUnitRecno; int targetResistance = capture_expected_resistance(townRecno, &captureUnitRecno); int averageResistance = townPtr->average_resistance(nation_recno); int minResistance = MIN( averageResistance, targetResistance ); if( minResistance < 50 - pref_peacefulness/5 ) // 30 to 50 depending on { captureTownQueue.push({townRecno, minResistance, captureUnitRecno}); } } //------- try to capture the town in their resistance order ----// const bool needToCheckDistance = !config.explore_whole_map && info.game_date-info.game_start_date > MAX(MAX_WORLD_X_LOC, MAX_WORLD_Y_LOC) * (5-config.ai_aggressiveness) / 5; // 3 to 5 / 5 while( captureTownQueue.size() > 0 ) { int captureRecno = captureTownQueue.top().town_recno; int captureUnitRecno = captureTownQueue.top().capture_unit_recno; captureTownQueue.pop(); err_when( town_array.is_deleted(captureRecno) ); //-------------------------------------------// // If the map is set to unexplored, wait for a // reasonable amount of time before moving out // to build the camp. //-------------------------------------------// if( needToCheckDistance ) { Town* targetTown = town_array[ captureRecno ]; int j; for( j=0 ; j<ai_town_count ; j++ ) { Town* ownTown = town_array[ ai_town_array[j] ]; int townDistance = misc.points_distance(targetTown->center_x, targetTown->center_y, ownTown->center_x, ownTown->center_y); if( info.game_date-info.game_start_date > townDistance * (5-config.ai_aggressiveness) / 5 ) // 3 to 5 / 5 { break; } } if( j==ai_town_count ) continue; } if( start_capture( captureRecno, captureUnitRecno ) ) return 1; } return 0; }
//--------- Begin of function Nation::capture_build_camp --------// // int Nation::capture_build_camp(int townRecno, int raceId, int captureUnitRecno) { Town* captureTown = town_array[townRecno]; //------- locate a place to build the camp -------// short buildXLoc, buildYLoc; if( !find_best_firm_loc(FIRM_CAMP, captureTown->loc_x1, captureTown->loc_y1, buildXLoc, buildYLoc) ) { captureTown->no_neighbor_space = 1; return 0; } //---- find the best available general for the capturing action ---// int unitRecno = captureUnitRecno; int targetResistance; if ( !unitRecno ) unitRecno = find_best_capturer(townRecno, raceId, targetResistance); if( !unitRecno ) unitRecno = hire_best_capturer(townRecno, raceId); if( !unitRecno ) { //--- if we have plenty of cash and can use cash to decrease the resistance of the independent villagers ---// if( should_use_cash_to_capture() ) { char resultFlag; Unit* skilledUnit = find_skilled_unit(SKILL_LEADING, raceId, captureTown->center_x, captureTown->center_y, resultFlag); if( skilledUnit ) unitRecno = skilledUnit->sprite_recno; } if( !unitRecno ) return 0; } //--- if the picked unit is an overseer of an existng camp ---// if( !mobilize_capturer(unitRecno) ) return 0; //---------- add the action to the queue now ----------// err_when( captureTown->nation_recno==0 && unit_array[unitRecno]->race_id != captureTown->majority_race() ); int actionRecno = add_action( buildXLoc, buildYLoc, captureTown->loc_x1, captureTown->loc_y1, ACTION_AI_BUILD_FIRM, FIRM_CAMP, 1, unitRecno ); if( actionRecno ) process_action(actionRecno); return 1; }
//--------- Begin of function Nation::think_capture_independent --------// // // Think about capturing independent towns. // int Nation::think_capture_independent() { //------- Capture target choices -------// #define MAX_CAPTURE_TOWN 30 CaptureTown capture_town_array[MAX_CAPTURE_TOWN]; short capture_town_count=0; //--- find the town that makes most sense to capture ---// int townRecno; Town* townPtr; for(townRecno=town_array.size(); townRecno>0; townRecno--) { if(town_array.is_deleted(townRecno)) continue; townPtr = town_array[townRecno]; if( townPtr->nation_recno ) // only capture independent towns continue; if( townPtr->no_neighbor_space ) // if there is no space in the neighbor area for building a new firm. continue; if( townPtr->rebel_recno ) // towns controlled by rebels will not drop in resistance even if a command base is present continue; //------ only if we have a presence/a base town in this region -----// if( !has_base_town_in_region(townPtr->region_id) ) continue; //---- check if there are already camps linked to this town ----// int i; for( i=townPtr->linked_firm_count-1 ; i>=0 ; i-- ) { Firm* firmPtr = firm_array[ townPtr->linked_firm_array[i] ]; if( firmPtr->firm_id != FIRM_CAMP ) continue; //------ if we already have a camp linked to this town -----// if( firmPtr->nation_recno == nation_recno ) break; //--- if there is an overseer with high leadership and right race in the opponent's camp, do bother to compete with him ---// if( firmPtr->overseer_recno ) { Unit* unitPtr = unit_array[firmPtr->overseer_recno]; if( unitPtr->skill.skill_level >= 70 && unitPtr->race_id == townPtr->majority_race() ) { break; } } } if( i>=0 ) // there is already a camp linked to this town and we don't want to get involved with its capturing plan continue; //-- if the town has linked military camps of the same nation --// int targetResistance = capture_expected_resistance(townRecno); int averageResistance = townPtr->average_resistance(nation_recno); int minResistance = MIN( averageResistance, targetResistance ); if( minResistance < 50 - pref_peacefulness/5 ) // 30 to 50 depending on { capture_town_array[capture_town_count].town_recno = townRecno; capture_town_array[capture_town_count].min_resistance = minResistance; capture_town_count++; } } //------ sort the capture target choices by min_resistance ----// qsort( &capture_town_array, capture_town_count, sizeof(capture_town_array[0]), sort_capture_town_function ); //------- try to capture the town in their resistance order ----// for( int i=0 ; i<capture_town_count ; i++ ) { err_when( town_array.is_deleted(capture_town_array[i].town_recno) ); //-------------------------------------------// // If the map is set to unexplored, wait for a // reasonable amount of time before moving out // to build the mine. //-------------------------------------------// if( !config.explore_whole_map ) { Town* targetTown = town_array[ capture_town_array[i].town_recno ]; int j; for( j=0 ; j<ai_town_count ; j++ ) { Town* ownTown = town_array[ ai_town_array[j] ]; int townDistance = m.points_distance(targetTown->center_x, targetTown->center_y, ownTown->center_x, ownTown->center_y); if( info.game_date-info.game_start_date > townDistance * (5-config.ai_aggressiveness) / 5 ) // 3 to 5 / 5 { break; } } if( j==ai_town_count ) continue; } if( start_capture( capture_town_array[i].town_recno ) ) return 1; } return 0; }
//--------- Begin of function Nation::optimize_town_race_region --------// // // Optimize the distribution of different races in different towns in // a single region. // void Nation::optimize_town_race_region(int regionId) { //---- reckon the minority jobless pop of each race ----// int racePopArray[MAX_RACE]; memset( racePopArray, 0, sizeof(racePopArray) ); int i, j, majorityRace; Town* townPtr; for( i=0 ; i<ai_town_count ; i++ ) { townPtr = town_array[ ai_town_array[i] ]; if( townPtr->region_id != regionId ) continue; majorityRace = townPtr->majority_race(); for( j=0 ; j<MAX_RACE ; j++ ) { if( j+1 != majorityRace ) racePopArray[j] += townPtr->jobless_race_pop_array[j]; } } //--- locate for towns with minority being majority and those minority race can move to ---// Town* destTown; for( int raceId=0 ; raceId<MAX_RACE ; raceId++ ) { if( racePopArray[raceId-1] == 0 ) // we don't have any minority of this race continue; destTown = NULL; for( i=0 ; i<ai_town_count ; i++ ) { townPtr = town_array[ ai_town_array[i] ]; if( townPtr->region_id != regionId ) continue; if( !townPtr->is_base_town ) continue; if( townPtr->majority_race() == raceId && townPtr->population < MAX_TOWN_POPULATION ) { destTown = townPtr; break; } } if( !destTown ) continue; //---- if there is a suitable town for minority to move to ---// for( i=0 ; i<ai_town_count ; i++ ) { townPtr = town_array[ ai_town_array[i] ]; if( townPtr->region_id != regionId ) continue; //---- move minority units from towns -----// int joblessCount = townPtr->jobless_race_pop_array[raceId-1]; if( joblessCount > 0 && townPtr->majority_race() != raceId ) { int migrateCount = MIN(8, joblessCount); // migrate a maximum of 8 units at a time add_action( destTown->loc_x1, destTown->loc_y1, townPtr->loc_x1, townPtr->loc_y1, ACTION_AI_SETTLE_TO_OTHER_TOWN, 0, migrateCount); } } } }
//------- Begin of function Town::think_split_town -------// // // Split the town into two, migrating some population to the new // town. // int Town::think_split_town() { if( jobless_population==0 ) // cannot move if we don't have any mobilizable unit return 0; //--- split when the population is close to its limit ----// Nation* nationPtr = nation_array[nation_recno]; if( population < 45 + nationPtr->pref_territorial_cohesiveness / 10 ) return 0; //-------- think about which race to move --------// int mostRaceId1, mostRaceId2, raceId=0; get_most_populated_race(mostRaceId1, mostRaceId2); if( mostRaceId2 && jobless_race_pop_array[mostRaceId2-1] > 0 && can_recruit(mostRaceId2) ) raceId = mostRaceId2; else if( mostRaceId1 && jobless_race_pop_array[mostRaceId1-1] > 0 && can_recruit(mostRaceId1) ) raceId = mostRaceId1; else raceId = pick_random_race(0, 1); // 0-recruitable only, 1-also pick spy. if( !raceId ) { //---- if the racial mix favors a split of town -----// // // This is when there are two major races, both of significant // population in the town. This is a good time for us to move // the second major race to a new town. // //---------------------------------------------------// if( mostRaceId2 && jobless_race_pop_array[mostRaceId2] > 0 && race_pop_array[mostRaceId2] >= population/3 && // the race's has at least 1/3 of the town's total population can_recruit(mostRaceId2) ) { raceId = mostRaceId2; } } if( !raceId ) return 0; //---- check if there is already a town of this race with low population linked to this town, then don't split a new one ---// Town* townPtr; for( int i=0 ; i<linked_town_count ; i++ ) { townPtr = town_array[ linked_town_array[i] ]; if( townPtr->nation_recno == nation_recno && townPtr->population < 20 && townPtr->majority_race() == raceId ) { return 0; } } //-------- settle to a new town ---------// return ai_settle_new(raceId); }