/*
* 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 : OAI_MAR3.CPP
//Description: AI functions on sea exploration, trading
#include
#include
#include
#include
#include
#include
#include
#include
//------ Begin of function Nation::ai_settle_to_region ------//
//
// destXLoc, destYLoc - the location of the destination to settle.
// seaActionId - SEA_ACTION_???
//
int Nation::ai_settle_to_region(int destXLoc, int destYLoc, int seaActionId)
{
#define SETTLE_REGION_UNIT_COUNT 9 // no. of units to move to settle on a new region each time
//---- think about which town to recruit the people -----//
int destRegionId = world.get_region_id(destXLoc, destYLoc);
int curRating, bestRating=0, seaRegionId;
Town *townPtr, *bestTown=NULL;
for( int i=0 ; ihas_linked_own_camp==0 ) // if there is no command base linked to this town, we cannot recruit any peasants from it
continue;
if( townPtr->jobless_population < SETTLE_REGION_UNIT_COUNT ) // don't get peasant from this town if the jobless population is less than 20
continue;
//--- only send units from this region if we have a harbor in that region ---//
// ###### patch begin Gilbert 16/3 #######//
// region_stat_id of a region may be zero
if(
//#ifdef AMPLUS
region_array[townPtr->region_id]->region_stat_id == 0 ||
//#endif
region_array.get_region_stat(townPtr->region_id)->harbor_nation_count_array[nation_recno-1] == 0 )
// ###### patch end Gilbert 16/3 #######//
continue;
curRating = world.distance_rating(destXLoc, destYLoc, townPtr->center_x, townPtr->center_y);
curRating += townPtr->jobless_population;
curRating += townPtr->average_loyalty(); // select a town with high loyalty
if( curRating <= bestRating )
continue;
//------- see if we have ships ready currently -----//
seaRegionId = region_array.get_sea_path_region_id(townPtr->region_id, destRegionId);
if( !ai_find_transport_ship(seaRegionId, townPtr->center_x, townPtr->center_y, 0) ) // 0-don't have to find the best, return immediately whenever a suitable one is found
continue;
bestRating = curRating;
bestTown = townPtr;
}
if( !bestTown )
return 0;
//------- try to recruit 9 units from one of our towns --------//
short recruitedUnitArray[SETTLE_REGION_UNIT_COUNT];
int recruitedCount=0;
int raceId = bestTown->majority_race();
int unitRecno;
int loopCount=0;
while( recruitedCount < SETTLE_REGION_UNIT_COUNT )
{
err_when( ++loopCount > 100 );
if( bestTown->recruitable_race_pop( raceId, 1 ) )
{
unitRecno = bestTown->recruit(-1, raceId, COMMAND_AI);
if( !unitRecno ) // no space for new unit
break;
err_when( unit_array.is_deleted(unitRecno) );
err_when( !unit_array[unitRecno]->is_visible() );
recruitedUnitArray[recruitedCount++] = unitRecno;
}
else
{
raceId = bestTown->pick_random_race(0, 1); // 0-recruitable only, 1-will also pick spies
if( !raceId )
break;
}
}
//--- if due to some reasons that the no. of units recruited is less than half of what we need, do not continue to sea travel.
if( recruitedCount < SETTLE_REGION_UNIT_COUNT/2 )
return 0;
int actionRecno = add_action( destXLoc, destYLoc, 0, 0, ACTION_AI_SEA_TRAVEL, seaActionId,
recruitedCount, 0, 0, recruitedUnitArray );
if( actionRecno ) // must process it immediately otherwise the recruited units will do something else
return process_action(actionRecno);
else
return 0;
}
//------ End of function Nation::ai_settle_to_region -------//
//------ Begin of function Nation::ai_patrol_to_region ------//
//
// Look for a military camp for moving all of its soldiers to
// a new region and set up a new military camp to host the soldiers.
//
// destXLoc, destYLoc - the location of the destination to set up
// a military camp.
// seaActionId - SEA_ACTION_???
//
int Nation::ai_patrol_to_region(int destXLoc, int destYLoc, int seaActionId)
{
#define SETTLE_REGION_UNIT_COUNT 9 // no. of units to move to settle on a new region each time
//---- think about which town to recruit the people -----//
int destRegionId = world.get_region_id(destXLoc, destYLoc);
int curRating, bestRating=0, seaRegionId;
int kingRecno = nation_array[nation_recno]->king_unit_recno;
FirmCamp *firmCamp, *bestCamp=NULL;
for( int i=0 ; ioverseer_recno && firmCamp->worker_count==MAX_WORKER) ) // only when the camp is filled with workers
continue;
if( firmCamp->ai_capture_town_recno ) // the base is trying to capture an independent town
continue;
if( firmCamp->is_attack_camp )
continue;
if( firmCamp->overseer_recno == kingRecno ) // if the king oversees this firm
continue;
//--- only send units from this region if we have a harbor in that region ---//
// ####### patch begin Gilbert 16/3 ########//
if(
//#ifdef AMPLUS
region_array[firmCamp->region_id]->region_stat_id == 0 ||
//#endif
region_array.get_region_stat(firmCamp->region_id)->harbor_nation_count_array[nation_recno-1] == 0 )
continue;
// ####### patch end Gilbert 16/3 ########//
curRating = world.distance_rating(destXLoc, destYLoc, firmCamp->center_x, firmCamp->center_y);
if( curRating <= bestRating )
continue;
//------- see if we have ships ready currently -----//
seaRegionId = region_array.get_sea_path_region_id(firmCamp->region_id, destRegionId);
if( !ai_find_transport_ship(seaRegionId, firmCamp->center_x, firmCamp->center_y, 0) ) // 0-don't have to find the best, return immediately whenever a suitable one is found
continue;
bestRating = curRating;
bestCamp = firmCamp;
}
if( !bestCamp )
return 0;
//----- patrol the camp troop ajnd assign it to a ship -----//
bestCamp->patrol();
if( bestCamp->patrol_unit_count > 0 ) // there could be chances that there are no some for mobilizing the units
{
int actionRecno = add_action( destXLoc, destYLoc, 0, 0, ACTION_AI_SEA_TRAVEL, seaActionId,
bestCamp->patrol_unit_count, 0, 0, bestCamp->patrol_unit_array );
if( actionRecno ) // must process it immediately otherwise the recruited units will do something else
return process_action(actionRecno);
}
return 0;
}
//------ End of function Nation::ai_patrol_to_region -------//
//------- Begin of function Nation::has_trade_ship -----------//
//
// Whether this nation already has a trade ship travelling between
// the two given harbors.
//
// return: recno of the ship.
// 0 - if there isn't any yet.
//
int Nation::has_trade_ship(int firmRecno1, int firmRecno2)
{
UnitMarine* unitMarine;
for( int i=ai_ship_count-1 ; i>=0 ; i-- )
{
unitMarine = (UnitMarine*) unit_array[ ai_ship_array[i] ];
err_when( unit_res[ unitMarine->unit_id ]->unit_class != UNIT_CLASS_SHIP );
if( unitMarine->stop_defined_num < 2 )
continue;
if( ( unitMarine->stop_array[0].firm_recno == firmRecno1 &&
unitMarine->stop_array[1].firm_recno == firmRecno2 ) ||
( unitMarine->stop_array[1].firm_recno == firmRecno1 &&
unitMarine->stop_array[0].firm_recno == firmRecno2 ) )
{
return unitMarine->sprite_recno;
}
}
return 0;
}
//--------- End of function Nation::has_trade_ship -----------//
//------ Begin of function Nation::think_move_to_region_with_mine ------//
//
// Think about moving to a region with mines and settle a town next to
// the mine.
//
int Nation::think_move_to_region_with_mine()
{
if( total_jobless_population < 30 )
return 0;
//---------------------------------------------------//
int curRating, bestRating=0, bestRegionId=0;
RegionStat* regionStat = region_array.region_stat_array;
int i;
for( i=0 ; itown_nation_count_array[nation_recno-1] > 0 ) // if we already have towns there
continue;
if( regionStat->raw_count==0 )
continue;
//-- if we have already build one camp there, just waiting for sending a few peasants there, then process it first --//
if( regionStat->camp_nation_count_array[nation_recno-1] > 0 )
{
bestRegionId = regionStat->region_id;
break;
}
//-----------------------------------------------//
curRating = regionStat->raw_count*3 - regionStat->nation_presence_count;
if( curRating > bestRating )
{
bestRating = curRating;
bestRegionId = regionStat->region_id;
}
}
if( !bestRegionId )
return 0;
//----- select the raw site to acquire -----//
Site* sitePtr;
for( i=site_array.size() ; i>0 ; i-- )
{
if( site_array.is_deleted(i) )
continue;
sitePtr = site_array[i];
if( sitePtr->region_id == bestRegionId )
break;
}
if( i==0 )
return 0;
//----- decide the location of the settlement -----//
return ai_build_camp_town_next_to( sitePtr->map_x_loc-1, sitePtr->map_y_loc-1,
sitePtr->map_x_loc+1, sitePtr->map_y_loc+1 );
}
//------ End of function Nation::think_move_to_region_with_mine -------//
//------ Begin of function Nation::ai_build_camp_town_next_to ------//
//
// Build a new camp and settle a new town next to the given location.
//
// xLoc1, yLoc1, xLoc2, yLoc2 - the location that the new camp
// and town should be built next to.
//
int Nation::ai_build_camp_town_next_to(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
{
//---- first see if we already have a camp in the region ---//
int regionId = world.get_region_id(xLoc1, yLoc1);
// ##### patch begin Gilbert 16/3 #######//
//#ifdef AMPLUS
if( region_array[regionId]->region_stat_id == 0)
return 0;
//#endif
// ##### patch end Gilbert 16/3 #######//
if( region_array.get_region_stat(regionId)->camp_nation_count_array[nation_recno-1] == 0 )
{
//--- if we don't have one yet, build one next to the destination ---//
if( !world.locate_space( xLoc1, yLoc1, xLoc2, yLoc2,
3, 3, UNIT_LAND, regionId, 1 ) ) // 1-locating the space for building
{
return 0;
}
if( !world.can_build_firm( xLoc1, yLoc1, FIRM_CAMP ) )
return 0;
return ai_patrol_to_region(xLoc1, yLoc1, SEA_ACTION_BUILD_CAMP);
}
else //-- if there's already a camp there, then set people there to settle --//
{
FirmCamp* firmCamp;
for( int i=0 ; iregion_id != regionId )
continue;
xLoc1 = firmCamp->loc_x1;
yLoc1 = firmCamp->loc_y1;
xLoc2 = firmCamp->loc_x2;
yLoc2 = firmCamp->loc_y2;
if( world.locate_space( xLoc1, yLoc1, xLoc2, yLoc2,
STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, UNIT_LAND, regionId, 1 ) ) // 1-locating the space for building
{
if( world.can_build_town( xLoc1, yLoc1 ) )
return ai_settle_to_region(xLoc1, yLoc1, SEA_ACTION_SETTLE);
}
}
}
return 0;
}
//------ End of function Nation::ai_build_camp_town_next_to -------//
//------ Begin of function Nation::ai_sea_attack_target ------//
//
// targetXLoc, targetYLoc - the location of the target.
//
int Nation::ai_sea_attack_target(int targetXLoc, int targetYLoc)
{
UnitMarine* unitMarine;
int targetRegionId = world.get_region_id(targetXLoc, targetYLoc);
int rc = 0;
for( int i=0 ; iattack_count==0 )
continue;
if( !unitMarine->is_ai_all_stop() )
continue;
//----- if the ship is in the harbor now -----//
if( unitMarine->unit_mode == UNIT_MODE_IN_HARBOR )
{
FirmHarbor* firmHarbor = (FirmHarbor*) firm_array[unitMarine->unit_mode_para];
if( firmHarbor->sea_region_id != targetRegionId )
continue;
firmHarbor->sail_ship(unitMarine->sprite_recno, COMMAND_AI);
}
if( !unitMarine->is_visible() ) // no space in the sea for placing the ship
continue;
if( unitMarine->region_id() != targetRegionId )
continue;
//------ order the ship to attack the target ------//
unitMarine->attack_unit( targetXLoc, targetYLoc );
rc = 1;
}
return rc;
}
//-------- End of function Nation::ai_sea_attack_target -------//