/*
* 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_ACT.CPP
//Description: AI - action progressing functions
#include
#include
#include
#include
#include
#include
#include
#include
//-------- Begin of function Nation::ai_build_firm -------//
//
// action_x_loc, action_y_loc - location of the building site.
// ref_x_loc, ref_y_loc - location of the town which the base
// should be built next to.
// action_para - firm id.
// action_para2 - firm race id. (for FirmBase only)
//
int Nation::ai_build_firm(ActionNode* actionNode)
{
if(!seek_path.total_node_avail)
return 0;
err_when( actionNode->action_x_loc < 0 || actionNode->action_y_loc < 0 ); // they must be given when this function is called
//-------- determine the skill id. needed -------//
int firmId = actionNode->action_para;
int raceId = actionNode->action_para2;
int skillId = firm_res[firmId]->firm_skill_id;
if( !skillId ) // if the firm does not have a specific skill (e.g. Inn), use the general SKILL_CONSTRUCTION
skillId = SKILL_CONSTRUCTION; // for military camps, use construction workers instead of generals for facilitating migration of military camps
//---- if there are camps that should be closed available now, transfer soldiers there to the new camp, ask a construction worker to build the camp so we can transfer the whole troop to the new camp ---//
if( firmId==FIRM_CAMP &&
ai_has_should_close_camp( world.get_region_id( actionNode->action_x_loc, actionNode->action_y_loc ) ) )
{
skillId = SKILL_CONSTRUCTION; // for military camps, use construction workers instead of generals for facilitating migration of military camps
}
//------------- get a skilled unit --------------//
Unit* skilledUnit = get_skilled_unit(skillId, raceId, actionNode);
if( !skilledUnit )
return 0;
//--- a unit with the specific skill is not found, try to find a construction unit instead ---//
if( skillId != SKILL_CONSTRUCTION )
{
Unit* skilledUnit = get_skilled_unit(skillId, raceId, actionNode);
if( !skilledUnit )
return 0;
}
//------- build the firm now ---------//
skilledUnit->build_firm(actionNode->action_x_loc, actionNode->action_y_loc, firmId, COMMAND_AI);
if(skilledUnit->action_x_loc==actionNode->action_x_loc && skilledUnit->action_y_loc==actionNode->action_y_loc)
{
err_when( skilledUnit->nation_recno==0 );
skilledUnit->ai_action_id = actionNode->action_id;
actionNode->unit_recno = skilledUnit->sprite_recno;
return 1;
}
else
{
skilledUnit->stop2();
return 0;
}
}
//-------- End of function Nation::ai_build_firm -------//
//----- Begin of function Nation::ai_assign_overseer -----//
//
// action_x_loc, action_y_loc - location of the firm to which the overseer should be assigned.
// ref_x_loc, ref_y_loc - not used
// action_para - firm id.
// [action_para2] - race id of the overseer
// (if not given, the majority race will be used.)
//
int Nation::ai_assign_overseer(ActionNode* actionNode)
{
//---------------------------------------------------------------------------//
// cancel action if the firm is deleted, has incorrect firm_id or nation is
// changed
//---------------------------------------------------------------------------//
int firmId = actionNode->action_para;
err_when( !firmId );
if(!check_firm_ready(actionNode->action_x_loc, actionNode->action_y_loc, firmId)) // return 0 to cancel action
return -1; // -1 means remove the current action immediately
if(!seek_path.total_node_avail)
return 0;
//-------- get the poisnter to the firm -------//
Location* locPtr = world.get_loc(actionNode->action_x_loc, actionNode->action_y_loc);
err_when(!locPtr->is_firm());
Firm* firmPtr = firm_array[ locPtr->firm_recno() ];
//-------- get a skilled unit --------//
int raceId; // the race of the needed unit
if( actionNode->action_para2 )
{
raceId = actionNode->action_para2;
}
else
{
if( firmPtr->firm_id == FIRM_BASE ) // for seat of power, the race must be specific
raceId = firm_res.get_build(firmPtr->firm_build_id)->race_id;
else
raceId = firmPtr->majority_race();
}
Unit* skilledUnit = get_skilled_unit(SKILL_LEADING, raceId, actionNode);
if( !skilledUnit )
return 0;
//---------------------------------------------------------------------------//
FirmInfo* firmInfo = firm_res[firmId];
err_when( !firmInfo->need_overseer );
if(skilledUnit->rank_id==RANK_SOLDIER)
skilledUnit->set_rank(RANK_GENERAL);
skilledUnit->assign(actionNode->action_x_loc, actionNode->action_y_loc);
skilledUnit->ai_action_id = actionNode->action_id;
err_when( skilledUnit->nation_recno != nation_recno );
actionNode->unit_recno = skilledUnit->sprite_recno;
return 1;
}
//----- End of function Nation::ai_assign_overseer -----//
//----- Begin of function Nation::ai_assign_construction_worker -----//
//
// action_x_loc, action_y_loc - location of the firm to which the overseer should be assigned.
// ref_x_loc, ref_y_loc - not used
//
int Nation::ai_assign_construction_worker(ActionNode* actionNode)
{
//---------------------------------------------------------------------------//
// cancel action if the firm is deleted, has incorrect firm_id or nation is
// changed
//---------------------------------------------------------------------------//
if(!check_firm_ready(actionNode->action_x_loc, actionNode->action_y_loc)) // return 0 to cancel action
return -1; // -1 means remove the current action immediately
if(!seek_path.total_node_avail)
return 0;
//-------- get the poisnter to the firm -------//
Location* locPtr = world.get_loc(actionNode->action_x_loc, actionNode->action_y_loc);
err_when(!locPtr->is_firm());
Firm* firmPtr = firm_array[ locPtr->firm_recno() ];
if( firmPtr->builder_recno ) // if the firm already has a construction worker
return -1;
//-------- get a skilled unit --------//
Unit* skilledUnit = get_skilled_unit(SKILL_CONSTRUCTION, 0, actionNode);
if( !skilledUnit )
return 0;
//------------------------------------------------------------------//
skilledUnit->assign(actionNode->action_x_loc, actionNode->action_y_loc);
skilledUnit->ai_action_id = actionNode->action_id;
err_when( skilledUnit->nation_recno != nation_recno );
actionNode->unit_recno = skilledUnit->sprite_recno;
return 1;
}
//----- End of function Nation::ai_assign_construction_worker -----//
//----- Begin of function Nation::ai_assign_worker -----//
//
// action_x_loc, action_y_loc - location of the firm to which the overseer should be assigned.
// ref_x_loc, ref_y_loc - not used
// action_para - firm id.
// [action_para2] - race id of the overseer
// (if not given, the majority race will be used.)
//
int Nation::ai_assign_worker(ActionNode* actionNode)
{
//---------------------------------------------------------------------------//
// cancel action if the firm is deleted, has incorrect firm_id or nation is
// changed
//---------------------------------------------------------------------------//
int firmId = actionNode->action_para;
err_when( !firmId );
if(!check_firm_ready(actionNode->action_x_loc, actionNode->action_y_loc, firmId)) // return 0 to cancel action
return -1; // -1 means remove the current action immediately
if(!seek_path.total_node_avail)
return 0;
//---------------------------------------------------------------------------//
// cancel this action if the firm already has enough workers
//---------------------------------------------------------------------------//
Location* locPtr = world.get_loc(actionNode->action_x_loc, actionNode->action_y_loc);
err_when(!locPtr->is_firm());
Firm* firmPtr = firm_array[locPtr->firm_recno()];
err_when( firmPtr->firm_id != firmId );
err_when( !firm_res[firmPtr->firm_id]->need_worker );
if(firmPtr->worker_count>=MAX_WORKER)
return -1;
if( MAX_WORKER - firmPtr->worker_count < actionNode->instance_count ) // if the firm now has more workers, reduce the number needed to be assigned to the firm
{
err_when( actionNode->processing_instance_count >= actionNode->instance_count );
actionNode->instance_count = max( actionNode->processing_instance_count+1, MAX_WORKER - firmPtr->worker_count );
}
//---------------------------------------------------------------------------//
// firm exists and belongs to our nation. Assign worker to firm
//---------------------------------------------------------------------------//
int unitRecno=0;
Unit* unitPtr = NULL;
//----------- use a trained unit --------//
if( actionNode->unit_recno )
unitPtr = unit_array[actionNode->unit_recno];
//------ recruit on job worker ----------//
if( !unitPtr && firmPtr->firm_id != FIRM_BASE ) // seat of power shouldn't call this function at all, as it doesn't handle the racial issue.
{
unitRecno = recruit_on_job_worker(firmPtr, actionNode->action_para2);
if( unitRecno )
unitPtr = unit_array[unitRecno];
}
//------- train a unit --------------//
if( !unitPtr &&
firmPtr->firm_id == FIRM_CAMP &&
ai_should_spend( 20+pref_military_development/2 ) ) // 50 to 70
{
int trainTownRecno;
if( train_unit( firmPtr->firm_skill_id, firmPtr->majority_race(),
actionNode->action_x_loc, actionNode->action_y_loc,
trainTownRecno, actionNode->action_id ) )
{
actionNode->next_retry_date = info.game_date + TOTAL_TRAIN_DAYS + 1;
actionNode->retry_count++;
return 0; // training in process
}
}
//-------- recruit a unit ----------//
if( !unitPtr )
{
unitRecno = recruit_jobless_worker(firmPtr, actionNode->action_para2);
if( unitRecno )
unitPtr = unit_array[unitRecno];
}
if( !unitPtr )
return 0;
//---------------------------------------------------------------------------//
FirmInfo* firmInfo = firm_res[firmId];
if( !world.get_loc(actionNode->action_x_loc, actionNode->action_y_loc)->is_firm() ) // firm exists, so assign
return -1;
err_when( unitPtr->rank_id != RANK_SOLDIER );
unitPtr->assign(actionNode->action_x_loc, actionNode->action_y_loc);
unitPtr->ai_action_id = actionNode->action_id;
err_when( unitPtr->nation_recno != nation_recno );
return 1;
}
//----- End of function Nation::ai_assign_worker -----//
//----- Begin of function Nation::ai_settle_to_other_town -----//
//
// action_x_loc, action_y_loc - location of the destination town.
// ref_x_loc, ref_y_loc - location of the origin town.
//
int Nation::ai_settle_to_other_town(ActionNode* actionNode)
{
if(!seek_path.total_node_avail)
return 0;
//------- check if both towns are ready first --------//
if(!check_town_ready(actionNode->action_x_loc, actionNode->action_y_loc) ||
!check_town_ready(actionNode->ref_x_loc, actionNode->ref_y_loc))
{
return -1;
}
//----------------------------------------------------//
// stop if no jobless population
//----------------------------------------------------//
Location* locPtr = world.get_loc(actionNode->ref_x_loc, actionNode->ref_y_loc);
err_when(!locPtr->is_town() || town_array.is_deleted(locPtr->town_recno()));
Town* townPtr = town_array[locPtr->town_recno()]; // point to the old town
int raceId = townPtr->pick_random_race(0, 1); // 0-don't pick has job unit, 1-pick spies
if( !raceId )
return -1;
//---- if cannot recruit because the loyalty is too low ---//
if( !townPtr->can_recruit(raceId) && townPtr->has_linked_own_camp )
{
int minRecruitLoyalty = MIN_RECRUIT_LOYALTY + townPtr->recruit_dec_loyalty(raceId, 0);
//--- if cannot recruit because of low loyalty, reward the town people now ---//
if( townPtr->race_loyalty_array[raceId-1] < minRecruitLoyalty )
{
if( cash > 0 && townPtr->accumulated_reward_penalty==0 )
{
townPtr->reward(COMMAND_AI);
}
if( !townPtr->can_recruit(raceId) ) // if still cannot be recruited, return 0 now
return 0;
}
return 0;
}
//------------------------------------------------------//
// recruit
//------------------------------------------------------//
int unitRecno = townPtr->recruit(-1, raceId, COMMAND_AI);
if( !unitRecno )
return 0;
//---------------------------------------------------------------------------//
// since it is not an important action, no need to add processing action
//---------------------------------------------------------------------------//
Unit* unitPtr = unit_array[unitRecno];
unitPtr->assign(actionNode->action_x_loc, actionNode->action_y_loc); // assign to the town
unitPtr->ai_action_id = actionNode->action_id;
err_when( unitPtr->nation_recno==0 );
return 1;
}
//----- End of function Nation::ai_settle_to_other_town -----//
//--------- Begin of function Nation::ai_scout ----------//
//
// action_x_loc, action_y_loc - location of the destination town.
// ref_x_loc, ref_y_loc - location of the origin town.
//
int Nation::ai_scout(ActionNode* actionNode)
{
if(!seek_path.total_node_avail)
return 0;
//------- check if both towns are ready first --------//
if(!check_town_ready(actionNode->action_x_loc, actionNode->action_y_loc) ||
!check_town_ready(actionNode->ref_x_loc, actionNode->ref_y_loc))
{
return -1;
}
//----------------------------------------------------//
// stop if no jobless population
//----------------------------------------------------//
Location* locPtr = world.get_loc(actionNode->ref_x_loc, actionNode->ref_y_loc);
err_when(!locPtr->is_town() || town_array.is_deleted(locPtr->town_recno()));
Town* townPtr = town_array[locPtr->town_recno()]; // point to the old town
int raceId = townPtr->pick_random_race(0, 1); // 0-don't pick has job unit, 1-pick spies
if( !raceId )
return -1;
//---- if cannot recruit because the loyalty is too low ---//
if( !townPtr->can_recruit(raceId) && townPtr->has_linked_own_camp )
return 0;
//------------------------------------------------------//
// recruit
//------------------------------------------------------//
int unitRecno = townPtr->recruit(-1, raceId, COMMAND_AI);
if( !unitRecno )
return 0;
//---------------------------------------------------------------------------//
// since it is not an important action, no need to add processing action
//---------------------------------------------------------------------------//
Unit* unitPtr = unit_array[unitRecno];
short selectedArray[1];
selectedArray[0] = unitRecno;
//-- must use unit_array.move_to() instead of unit.move_to() because the destination may be reachable, it can be in a different region --//
unit_array.move_to( actionNode->action_x_loc, actionNode->action_y_loc, 0, selectedArray, 1, COMMAND_AI );
unitPtr->ai_action_id = actionNode->action_id;
err_when( unitPtr->nation_recno==0 );
return 1;
}
//-------- End of function Nation::ai_scout ----------//