//----- Begin of function Nation::think_build_harbor_network ----// // // Think about thinking a harbor network so that we have harbors // from every region to any other regions. // int Nation::think_build_harbor_network() { //--- only build one harbor at a time, to avoid double building ---// if( is_action_exist( ACTION_AI_BUILD_FIRM, FIRM_HARBOR ) ) return 0; //--------------------------------------------// RegionStat* regionStat = region_array.region_stat_array; RegionPath* regionPath; for( int i=0 ; i<region_array.region_stat_count ; i++, regionStat++ ) { //--- only build on those regions that this nation has base towns ---// if( !regionStat->base_town_nation_count_array[nation_recno-1] ) continue; if( regionStat->harbor_nation_count_array[nation_recno-1] > 0 ) // if we already have a harbor in this region continue; err_when( regionStat->harbor_nation_count_array[nation_recno-1] > 1 ); // this shouldn't happen if the AI works properly //-----------------------------------------------------------------------// // // Scan thru all regions which this region can be connected to thru sea. // If one of them is worth our landing, then builld a harbor in this // region so we can sail to that region. // //-----------------------------------------------------------------------// regionPath = regionStat->reachable_region_array; for( int j=0 ; j<regionStat->reachable_region_count ; j++, regionPath++ ) { err_when( regionPath->land_region_stat_id == i+1 ); // pointing back to its own //--------------------------------------// if( ai_harbor_count == 0 && // if we have already built one harbor, then we should continue to build others asa single harbor isn't useful ai_should_sail_to_rating(regionPath->land_region_stat_id) <= 0 ) { continue; } //--------- build a harbor now ---------// if( ai_build_harbor( regionStat->region_id, regionPath->sea_region_id ) ) return 1; } } return 0; }
//--------- Begin of function Nation::ai_should_build_mine --------// // int Nation::ai_should_build_mine() { //---- only build mines when it has enough population ----// if( total_jobless_population < (100-pref_economic_development)/2 ) return 0; if( total_jobless_population < 16 ) // only build mine when you have enough population to support the economic chain: mine + factory + camp return 0; if( site_array.untapped_raw_count==0 ) return 0; if( !can_ai_build(FIRM_MINE) ) return 0; //--- don't build additional mines unless we have enough population and demand to support it ----// if( ai_mine_count >= 1 ) { if( true_profit_365days() < 0 || total_population < 40+pref_economic_development/5 ) return 0; } //-- if the nation is already in the process of building a new one --// if( is_action_exist( ACTION_AI_BUILD_FIRM, FIRM_MINE ) ) return 0; //--- if the population is low, make sure existing mines are in full production before building a new one ---// if( total_jobless_population < 30 ) { FirmMine* firmMine; for( int i=0 ; i<ai_mine_count ; i++ ) { firmMine = firm_array[ ai_mine_array[i] ]->cast_to_FirmMine(); err_when( !firmMine ); if( firmMine->worker_count < MAX_WORKER ) return 0; if( firmMine->linked_firm_count==0 && !firmMine->no_neighbor_space ) // if the firm does not have any linked firms, that means the firm is still not in full operation return 0; } } return 1; }
//--------- Begin of function Nation::add_action --------// // // <short> xLoc, yLoc - location of the action // <short> refXLoc, refYLoc - reference location (optional, not all action types need this) // <int> actionMode - action mode // <int> actionPara - action parameter // [int] instanceCount - no. of instances of this action should be carried out // (default: 1) // [int] unitRecno - recno of the unit responsible for this action // if not given, an appropriate unit will be found. // [int] actionPara2 - action para2 // [short*] groupUnitArray - array of unit recno in the group for the action // the no. of units in the array is stored in instance_count // (default: NULL) // // return: <int> recno of the action added in action_array // 0 - if the action is not added as it is already in action_array. // int Nation::add_action(short xLoc, short yLoc, short refXLoc, short refYLoc, int actionMode, int actionPara, int instanceCount, int unitRecno, int actionPara2, short* groupUnitArray) { err_when( instanceCount < 1 ); //--- check if the action has been added already or not ---// if( is_action_exist(xLoc, yLoc, refXLoc, refYLoc, actionMode, actionPara, unitRecno) ) return 0; //---------- queue the action ----------// ActionNode actionNode; memset( &actionNode, 0, sizeof(ActionNode) ); actionNode.action_mode = actionMode; // what kind of action actionNode.action_para = actionPara; // parameter of the action actionNode.action_para2 = actionPara2; // parameter of the action actionNode.action_x_loc = xLoc; // location to act to actionNode.action_y_loc = yLoc; actionNode.ref_x_loc = refXLoc; // the refective location of this action make to actionNode.ref_y_loc = refYLoc; actionNode.retry_count = STD_ACTION_RETRY_COUNT; // number of term to wait before discarding this action actionNode.instance_count = instanceCount; // num of this action being processed in the waiting queue int immediateProcess=0; if( groupUnitArray ) { // the no. of units in the array is stored in instance_count err_when( instanceCount < 1 ); err_when( instanceCount > ActionNode::MAX_ACTION_GROUP_UNIT ); memcpy( actionNode.group_unit_array, groupUnitArray, instanceCount * sizeof(groupUnitArray[0]) ); immediateProcess = 1; // have to execute this command immediately as the unit in unit_array[] may change actionNode.retry_count = 1; // only try once as the unit in unit_array[] may change } if( unitRecno ) { //-- this may happen when the unit is a spy and has just changed cloak --// if( !nation_array[unit_array[unitRecno]->true_nation_recno()]->is_ai() && !nation_array[unit_array[unitRecno]->nation_recno]->is_ai() ) { return 0; } //-------------------------------------// actionNode.unit_recno = unitRecno; err_when( actionMode == ACTION_AI_ASSIGN_OVERSEER && // an overseer must be a military unit unit_array[unitRecno]->is_civilian() ); if( unit_array[unitRecno]->is_visible() ) { immediateProcess = 1; // have to execute this command immediately as the unit in unit_array[] may change actionNode.retry_count = 1; // only try once as the unit in unit_array[] may change } else //--- the unit is still being trained ---// { err_here(); // actionNode.next_retry_date = info.game_date + TOTAL_TRAIN_DAYS + 1; } } //-------- set action type ---------// actionNode.action_type = ACTION_FIXED; // default action type //------- link into action_array --------// return add_action( &actionNode, immediateProcess ); }
//--------- Begin of function Nation::seek_mine --------// // // <short&> xLoc, yLoc - reference vars for returning the building // location. // <short&> refXLoc, refYLoc - reference vars for returning the exact // location of the raw material. // // return: <int> >0 the raw id. of the site. // ==0 no suitable site found. // int Nation::seek_mine(short& xLoc, short& yLoc, short& refXLoc, short& refYLoc) { err_when( site_array.untapped_raw_count < 0 ); if( site_array.untapped_raw_count==0 ) return 0; int raw_kind_mined[MAX_RAW], i; Firm *firmPtr; FirmMine *minePtr; //-----------------------------------------------------------------// // count each kind of raw material that is being mined //-----------------------------------------------------------------// memset(raw_kind_mined, 0, sizeof(int)*MAX_RAW); for(i=0; i<ai_mine_count; i++) { firmPtr = firm_array[ai_mine_array[i]]; minePtr = firmPtr->cast_to_FirmMine(); if( minePtr->raw_id>=1 && minePtr->raw_id<=MAX_RAW ) raw_kind_mined[minePtr->raw_id-1]++; } //-------------------- define parameters ----------------------// FirmInfo *firmInfo = firm_res[FIRM_MINE]; Location *locPtr, *siteLocPtr; Site *sitePtr; Town *townPtr; int nearSite[MAX_RAW], minDist[MAX_RAW], townWithMine[MAX_RAW]; short buildXLoc[MAX_RAW], buildYLoc[MAX_RAW]; short dist; int canBuild, connected, allHave; int j, k, siteId; int effectiveDis = world.effective_distance(FIRM_MINE,0); memset(townWithMine, 0, sizeof(int)*MAX_RAW); memset(nearSite, 0, sizeof(int)*MAX_RAW); memset(buildXLoc, 0, sizeof(short)*MAX_RAW); memset(buildYLoc, 0, sizeof(short)*MAX_RAW); for(i=0; i<MAX_RAW; i++) minDist[i] = 0x7FFFFF; //--------------------------------------------// // scan for the site array //--------------------------------------------// for(i=site_array.size(); i>0; i--) { if(site_array.is_deleted(i)) continue; sitePtr = site_array[i]; if( sitePtr->site_type != SITE_RAW ) continue; siteLocPtr = world.get_loc(sitePtr->map_x_loc, sitePtr->map_y_loc); if(!siteLocPtr->can_build_firm()) continue; siteId = sitePtr->object_id - 1; err_when(siteId<0 || siteId>MAX_RAW); if(townWithMine[siteId]) continue; // a site connected to town is found before //--------------------------------------------// // continue if action to this site already exist //--------------------------------------------// if(is_action_exist(-1, -1, sitePtr->map_x_loc, sitePtr->map_y_loc, ACTION_AI_BUILD_FIRM, FIRM_MINE)) continue; for(j=0; j<ai_town_count; j++) { townPtr = town_array[ai_town_array[j]]; locPtr = world.get_loc(townPtr->loc_x1, townPtr->loc_y1); //-********* codes to move to other territory ***********-// if(siteLocPtr->region_id!=locPtr->region_id) continue; // not on the same territory dist = m.points_distance(sitePtr->map_x_loc, sitePtr->map_y_loc, townPtr->center_x, townPtr->center_y); //-------------------------------------------------------------------------// // check whether a mine is already connected to this town, if so, use it //-------------------------------------------------------------------------// for(connected=0, k=townPtr->linked_firm_count-1; k>=0; k--) { err_when(!townPtr->linked_firm_array[k] || firm_array.is_deleted(townPtr->linked_firm_array[k])); firmPtr = firm_array[townPtr->linked_firm_array[k]]; if(firmPtr->nation_recno==nation_recno && firmPtr->firm_id==FIRM_MINE) { connected++; break; } } //-------------------------------------------------------------------------// // calculate the minimum distance from own towns //-------------------------------------------------------------------------// if(dist<minDist[siteId] || (connected && dist<=effectiveDis)) { //------ can build or not ----------// canBuild = 0; for(int ix=sitePtr->map_x_loc-firmInfo->loc_width+1; ix<=sitePtr->map_x_loc && !canBuild; ix++) { if(ix<0 || ix>=MAX_WORLD_X_LOC) continue; for(int iy=sitePtr->map_y_loc-firmInfo->loc_height+1; iy<=sitePtr->map_y_loc && !canBuild; iy++) { if(iy<0 || iy>=MAX_WORLD_Y_LOC) continue; if(world.can_build_firm(ix, iy, FIRM_MINE)) { canBuild++; buildXLoc[siteId] = ix; buildYLoc[siteId] = iy; break; } } } if(canBuild) { nearSite[siteId] = i; minDist[siteId] = dist; if(connected && dist<=effectiveDis) townWithMine[siteId]++; } } } for(allHave=1, j=0; j<MAX_RAW; j++) { if(!townWithMine[j])//if(!nearSite[j]) { allHave = 0; break; } } if(allHave) break; // sites of each raw material have been found } //---------------------------------------------------------------------------// // determine which raw material is the best choice to build // Note: a better sorting algorithm should be used if there are many kind of // raw material //---------------------------------------------------------------------------// int weight, pos; // weight is the such kind of material mined, pos is the position in the array int siteRecno = 0; // siteRecno is the recno of site to build int withoutThisRaw = 0; // withoutThisRaw shows that this raw material is strongly recommended int closestDist=0x7FFFFF; for(pos=-1, weight=0x7FFFFF, j=0 ;j<MAX_RAW; j++) { if(!nearSite[j]) continue; // no such kind of raw material if(!raw_kind_mined[j]) // no such kind of material and there is a possible site { if(withoutThisRaw) { if(minDist[j]<closestDist) // more than one kind of material we don't have { siteRecno = nearSite[j]; closestDist = minDist[j]; pos = j; } } else { siteRecno = nearSite[j]; closestDist = minDist[j]; withoutThisRaw++; pos = j; } } else if(!withoutThisRaw && weight>raw_kind_mined[j]) // scan for the kind of material with least num of this site { weight = raw_kind_mined[j]; pos = j; } } if(!siteRecno && pos>=0) siteRecno = nearSite[pos]; if(siteRecno) { sitePtr = site_array[siteRecno]; xLoc = buildXLoc[pos]; yLoc = buildYLoc[pos]; refXLoc = sitePtr->map_x_loc; refYLoc = sitePtr->map_y_loc; err_when((xLoc-refXLoc)>=firm_res[FIRM_MINE]->loc_width || (yLoc-refYLoc)>=firm_res[FIRM_MINE]->loc_height); //--------------------------------------------------------------// // do some adjustment such that the firm will be built far away // from other firms by at least one step. //--------------------------------------------------------------// seek_best_build_mine_location(xLoc, yLoc, sitePtr->map_x_loc, sitePtr->map_y_loc); err_when((xLoc-refXLoc)>=firm_res[FIRM_MINE]->loc_width || (yLoc-refYLoc)>=firm_res[FIRM_MINE]->loc_height); return sitePtr->object_id; // the raw id. } return 0; }