//--------- Begin of function Nation::ai_assign_spy_to_firm --------// // // Think about sending spies to the specific firm. // // return: <int> 1 - a spy is assigned successfully. // 0 - failure. // int Nation::ai_assign_spy_to_firm(int firmRecno) { Firm* firmPtr = firm_array[firmRecno]; err_when( !firmPtr->worker_array ); //---- check if the firm is full or not -----// if( firmPtr->nation_recno == nation_recno ) // if it's our own firm { if( firmPtr->is_worker_full() ) // use is_worker_full() for own firms as it take into account of units patrolling outside return 0; } else { if( firmPtr->worker_count == MAX_WORKER ) return 0; } //------ look for an existing spy -------// int raceId = firmPtr->majority_race(); int mobileOnly = firmPtr->nation_recno == nation_recno; // if assign to own firms/firms, only get mobile spies, don't get spies from existing firms/firms as that will result in a loop effect return ai_assign_spy( firmPtr->loc_x1, firmPtr->loc_y1, raceId, mobileOnly ); }
//--------- Begin of function Nation::ai_assign_spy_to_town --------// // // Think about sending spies to the specific town. // // <int> townRecno - recno of the town // [int] raceId - race id. of the spy // (default: majority_race() of the tonw) // // return: <int> 1 - a spy is assigned successfully. // 0 - failure. // int Nation::ai_assign_spy_to_town(int townRecno, int raceId) { Town* townPtr = town_array[townRecno]; if( townPtr->population >= MAX_TOWN_POPULATION ) return 0; if( !raceId ) raceId = townPtr->majority_race(); int mobileOnly = townPtr->nation_recno == nation_recno; // if assign to own towns/firms, only get mobile spies, don't get spies from existing towns/firms as that will result in a loop effect return ai_assign_spy( townPtr->loc_x1, townPtr->loc_y1, raceId, mobileOnly ); }
//------- Begin of function Nation::process_action --------// // // [int] priorityActionRecno - if this is given, this specific action will // be processed first. Otherwise it will process // actions in the array in a sequential order. // // [int] processActionMode - if this is given, only message of this type // will be processed and all messages in the queued of this // type will be processed. // // Note: priorityActionRecno and processActionMode couldn't be used at // the same time. // // return: <int> 1 - all messages of the specific action mode are processed or all messages are processed // or the priority message has been processed. // int Nation::process_action(int priorityActionRecno, int processActionMode) { err_when( priorityActionRecno && processActionMode ); int actionRecno, rc, delFlag, doneFlag=0; int thisSessionProcessCount=0; // actions processed in this call session ActionNode* actionNode; int divider = 1-config.ai_aggressiveness; // the more nations there, the less process count int nationRecno = nation_recno; int maxSessionProcessCount = 70 / nation_array.nation_count / max(divider,1); for( actionRecno=1 ; actionRecno<=action_count() && (thisSessionProcessCount < maxSessionProcessCount || processActionMode) && !doneFlag ; // if processActionMode has been specific, then all messages in the queue of this type will be processed actionRecno++ ) { //----- priority action ------// if( priorityActionRecno ) { actionRecno = priorityActionRecno; doneFlag = 1; // mark it done, so if the function "continue" to the next loop, the function will end } if( is_action_deleted(actionRecno) ) continue; actionNode = get_action(actionRecno); //----- if only process specific action mode -----// if( processActionMode && actionNode->action_mode != processActionMode ) continue; //--- if the AI action is about processing diplomatic message ---// if( actionNode->action_mode == ACTION_AI_PROCESS_TALK_MSG && processActionMode != ACTION_AI_PROCESS_TALK_MSG ) { if( m.random(10) > 0 ) // 1/10 chance of processing the diplomatic messages continue; } //----------------------------------------------// if( actionNode->processing_instance_count == actionNode->instance_count ) { //---------------------------------------------// // // If this action has been marked processing for over 6 months // and we still haven't received finishing notifications, // then there may be some accidents (or bugs) happened, and // we will need to delete the action. // //---------------------------------------------// if( info.game_date > actionNode->add_date + 30 * 6 ) { del_action(actionRecno); actionRecno--; // stay in this array position as the current one has been deleted, the following one replace the current one's position } continue; } err_when( actionNode->processing_instance_count > actionNode->instance_count ); if( info.game_date < actionNode->next_retry_date && !priorityActionRecno ) // priorityAction bypass retry date checking continue; if( actionNode->retry_count==0 ) // the actionNode may still exist even when retry_count==0, waiting for processed_count to reach processing_count continue; //---- if the assigned unit has been deleted, cancel the action ----// if( actionNode->unit_recno && unit_array.is_deleted(actionNode->unit_recno) ) { del_action(actionRecno); actionRecno--; // stay in this array position as the current one has been deleted, the following one replace the current one's position continue; } //-- there is an unprocessing action in this waiting node --// switch( actionNode->action_mode ) { case ACTION_AI_BUILD_FIRM: rc = ai_build_firm(actionNode); break; case ACTION_AI_ASSIGN_OVERSEER: rc = ai_assign_overseer(actionNode); break; case ACTION_AI_ASSIGN_SOLDIER: rc = ai_assign_soldier(actionNode); break; case ACTION_AI_ASSIGN_SPY: rc = ai_assign_spy(actionNode); break; case ACTION_AI_SCOUT: rc = ai_scout(actionNode); break; case ACTION_AI_BUILD_TOWN: rc = ai_build_town(actionNode); break; case ACTION_AI_SETTLE_TOWN: rc = ai_settle_town(actionNode); break; case ACTION_AI_PROCESS_TALK_MSG: rc = ai_process_talk_msg(actionNode); break; /* case ACTION_AI_SEA_TRAVEL: err_here(); rc = ai_sea_travel(actionNode); break; case ACTION_AI_SEA_TRAVEL2: err_here(); rc = ai_sea_travel2(actionNode); break; case ACTION_AI_SEA_TRAVEL3: err_here(); rc = ai_sea_travel3(actionNode); break; */ } if( nation_array.is_deleted(nationRecno) ) // diplomatic option can result in surrendering return 0; thisSessionProcessCount++; //------ check the return result -------// delFlag = 0; if( rc==1 ) // the action has been processed, but not sure whether it is complete or not { actionNode->processing_instance_count++; //---------------------------------------------------// // for ACTION_DYNAMIC, the action is immediately // deleted when processing_instance_count == instance_count. //---------------------------------------------------// if( actionNode->action_type == ACTION_DYNAMIC ) { if( actionNode->processing_instance_count > actionNode->instance_count ) delFlag = 1; } } else if( rc==0 ) // action failed, retry { if( actionNode->unit_recno ) // if the action is associated with a unit, delete the action if it fails as the associated the unit will do anything before the next try and the action will become invalid { delFlag = 1; } else { actionNode->next_retry_date = info.game_date + 7; // try again one week later if( --actionNode->retry_count==0 ) delFlag = 1; err_when( actionNode->retry_count < 0 ); } } else if( rc== -1 ) // action failed, remove immediately if return -1 { actionNode->retry_count = 0; delFlag = 1; } //-----------------------------------------// if( delFlag && actionNode->processing_instance_count == actionNode->processed_instance_count ) // if processing_count > processed_count, do not remove this ActionNode, as there are some unit using this actionNode, when they finish or fail the action, processed_count will increase and processing_count will reach processed_count { del_action(actionRecno); actionRecno--; // stay in this array position as the current one has been deleted, the following one replace the current one's position } } return actionRecno > action_count() || doneFlag; }