123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497 |
- /*
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
- //Filename : OAI_ACT.CPP
- //Description: AI - action progressing functions
- #include <ALL.h>
- #include <OBOX.h>
- #include <OSYS.h>
- #include <OSPY.h>
- #include <OINFO.h>
- #include <OUNIT.h>
- #include <OFIRM.h>
- #include <ONATION.h>
- //-------- 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 ----------//
|