/* * 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 . * */ //cFilename : OTOWN.CPP //Description : Object Town #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // ##### begin Gilbert 9/10 ######// #include // ##### end Gilbert 9/10 ######// #include #include //--------- Begin of function Town::Town ----------// // Town::Town() { memset( this, 0, sizeof(Town) ); } //---------- End of function Town::Town ----------// //--------- Begin of function Town::init ----------// // // nationRecno - the nation recno // raceId - the race of the majority of the town poulation // xLoc, yLoc - location of the town // void Town::init(int nationRecno, int raceId, int xLoc, int yLoc) { nation_recno = nationRecno; race_id = raceId; err_when( raceId<1 || raceId>MAX_RACE ); //---- set the town section's absolute positions on the map ----// loc_x1 = xLoc; loc_y1 = yLoc; loc_x2 = loc_x1 + STD_TOWN_LOC_WIDTH - 1; loc_y2 = loc_y1 + STD_TOWN_LOC_HEIGHT - 1; abs_x1 = xLoc * ZOOM_LOC_WIDTH; abs_y1 = yLoc * ZOOM_LOC_HEIGHT; abs_x2 = abs_x1 + STD_TOWN_LOC_WIDTH * ZOOM_LOC_WIDTH - 1; abs_y2 = abs_y1 + STD_TOWN_LOC_HEIGHT * ZOOM_LOC_HEIGHT - 1; center_x = (loc_x1+loc_x2)/2; center_y = (loc_y1+loc_y2)/2; region_id = world.get_region_id( center_x, center_y ); ai_town = !nation_recno || nation_array[nation_recno]->nation_type == NATION_AI; // nation_recno==0 for independent towns ai_link_checked = 1; // check the linked towns and firms connected only if ai_link_checked==0 independent_unit_join_nation_min_rating = 100 + m.random(150); // the minimum rating a nation must have in order for an independent unit to join it setup_date = info.game_date; //-------- init resistance ------------// if( nationRecno==0 ) { for( int i=0 ; iadd_town_info(town_recno); update_base_town_status(); } //------ set national auto policy -----// if( nation_recno ) { Nation* nationPtr = nation_array[nation_recno]; set_auto_collect_tax_loyalty( nationPtr->auto_collect_tax_loyalty ); set_auto_grant_loyalty( nationPtr->auto_grant_loyalty ); } } //--------- End of function Town::init ----------// //--------- Begin of function Town::deinit ----------// // void Town::deinit() { if( !town_recno ) return; clear_defense_mode(); //------- if it's an AI town --------// if( ai_town && nation_recno ) nation_array[nation_recno]->del_town_info(town_recno); //------ if this town is the nation's larget town, reset it ----// if( nation_recno && nation_array[nation_recno]->largest_town_recno == town_recno ) { nation_array[nation_recno]->largest_town_recno = 0; } //-----------------------------------// restore_world_matrix(); release_link(); //-- if there is a unit being trained when the town vanishes --// if(train_unit_recno) unit_array.disappear_in_town(train_unit_recno, town_recno); //------- if the current town is the selected -----// if( town_array.selected_recno == town_recno ) { town_array.selected_recno = 0; info.disp(); } //------- reset parameters ---------// town_recno = 0; } //--------- End of function Town::deinit ----------// //------- Begin of function Town::set_world_matrix --------// // // Set the cargo id of current town section on the world matrix // void Town::set_world_matrix() { //--- if a nation set up a town in a location that the player has explored, contact between the nation and the player is established ---// int xLoc, yLoc; Location* locPtr; for( yLoc=loc_y1 ; yLoc<=loc_y2 ; yLoc++ ) { for( xLoc=loc_x1 ; xLoc<=loc_x2 ; xLoc++ ) { locPtr = world.get_loc(xLoc, yLoc); if(!locPtr->cargo_recno) // skip the location where the settle unit is standing locPtr->set_town(town_recno); } } //--- if a nation set up a town in a location that the player has explored, contact between the nation and the player is established ---// establish_contact_with_player(); //---- set this town's influence on the map ----// if( nation_recno ) world.set_power(loc_x1, loc_y1, loc_x2, loc_y2, nation_recno); //------------ reveal new land ----------// if( nation_recno == nation_array.player_recno || ( nation_recno && nation_array[nation_recno]->is_allied_with_player ) ) { world.unveil( loc_x1, loc_y1, loc_x2, loc_y2 ); world.visit( loc_x1, loc_y1, loc_x2, loc_y2, EXPLORE_RANGE-1 ); } //---- if the newly built firm is visual in the zoom window, redraw the zoom buffer ----// if( is_in_zoom_win() ) sys.zoom_need_redraw = 1; // set the flag on so it will be redrawn in the next frame } //-------- End of function Town::set_world_matrix --------// //------- Begin of function Town::establish_contact_with_player --------// // // See if the town's location is an explored area, establish contact // with the player. // void Town::establish_contact_with_player() { if( !nation_recno ) return; //--- if a nation set up a town in a location that the player has explored, contact between the nation and the player is established ---// int xLoc, yLoc; Location* locPtr; for( yLoc=loc_y1 ; yLoc<=loc_y2 ; yLoc++ ) { for( xLoc=loc_x1 ; xLoc<=loc_x2 ; xLoc++ ) { locPtr = world.get_loc(xLoc, yLoc); if( locPtr->explored() && nation_array.player_recno ) { NationRelation *relation = (~nation_array)->get_relation(nation_recno); if( !remote.is_enable() ) { relation->has_contact = 1; } else { if( !relation->contact_msg_flag && !relation->has_contact ) { // packet structure : short *shortPtr = (short *)remote.new_send_queue_msg(MSG_NATION_CONTACT, 2*sizeof(short)); *shortPtr = nation_array.player_recno; shortPtr[1] = nation_recno; relation->contact_msg_flag = 1; } } } } } } //-------- End of function Town::establish_contact_with_player --------// //--------- Begin of function Town::restore_world_matrix --------// // // When the town section is destroyed, restore the original land id // void Town::restore_world_matrix() { int xLoc, yLoc; for( yLoc=loc_y1 ; yLoc<=loc_y2 ; yLoc++ ) { for( xLoc=loc_x1 ; xLoc<=loc_x2 ; xLoc++ ) { world.get_loc(xLoc,yLoc)->remove_town(); } } //---- restore this town's influence on the map ----// if( nation_recno ) world.restore_power(loc_x1, loc_y1, loc_x2, loc_y2, town_recno, 0); //---- if the newly built firm is visual in the zoom window, redraw the zoom buffer ----// if( is_in_zoom_win() ) sys.zoom_need_redraw = 1; } //----------- End of function Town::restore_world_matrix --------// //---------- Begin of function Town::next_day --------// // void Town::next_day() { err_when( population>MAX_TOWN_POPULATION ); err_when( town_recno<1 ); err_when( town_recno>town_array.size() ); int townRecno = town_recno; //------ update quality_of_life --------// update_quality_of_life(); //---------- update population ----------// #if defined(DEBUG) && defined(ENABLE_LOG) String logStr; logStr = "begin Town::next_day, town_recno = "; logStr += townRecno; logStr += " nation="; logStr += nation_recno; LOG_MSG(logStr); #endif if( info.game_date%30 == town_recno%30 ) { LOG_MSG(" population_grow"); population_grow(); LOG_MSG(m.get_random_seed()); } err_when(population>MAX_TOWN_POPULATION); //------- update link status to camps ------// LOG_MSG(" update_camp_link"); update_camp_link(); LOG_MSG(m.get_random_seed()); //------ update target loyalty/resistance -------// if( info.game_date%15 == town_recno%15 ) { if( nation_recno ) { LOG_MSG(" update_target_loyalty"); update_target_loyalty(); } else { LOG_MSG(" update_target_resistance"); update_target_resistance(); // update resistance for independent towns } LOG_MSG(m.get_random_seed()); } //------ update loyalty/resistance -------// if( info.game_date%5 == town_recno%5 ) { if( nation_recno ) { LOG_MSG(" update_target_loyalty"); update_loyalty(); } else { LOG_MSG(" update_target_resistance"); update_resistance(); } LOG_MSG(m.get_random_seed()); if( town_array.is_deleted(townRecno) ) return; } //------ think town people migration -------// LOG_MSG(" think_migrate"); think_migrate(); LOG_MSG(m.get_random_seed()); if( town_array.is_deleted(townRecno) ) return; //-------- think about rebel -----// if( nation_recno && info.game_date%15 == town_recno%15 ) { LOG_MSG(" think_rebel"); think_rebel(); LOG_MSG(m.get_random_seed() ); if( town_array.is_deleted(townRecno) ) return; } //-------- think about surrender -----// if( nation_recno && ( info.game_date%15==town_recno%15 || average_loyalty()==0 ) ) { LOG_MSG(" think_surrender"); think_surrender(); // for nation town only, independent town surrender is handled in update_resistance() LOG_MSG(m.get_random_seed() ); if( town_array.is_deleted(townRecno) ) return; } //------- process training -------// //### begin alex 6/9 ###// /*if( nation_recno && train_unit_recno ) { process_train(); if( town_array.is_deleted(townRecno) ) // when the last peasant in the town is trained, the town disappear return; }*/ if(nation_recno) { if(train_unit_recno) { LOG_MSG(" process_train"); process_train(); LOG_MSG(m.get_random_seed() ); } else { LOG_MSG(" process_queue"); process_queue(); LOG_MSG(m.get_random_seed() ); } if( town_array.is_deleted(townRecno) ) // when the last peasant in the town is trained, the town disappear return; } //#### end alex 6/9 ####// //-------- process food ---------// if( nation_recno ) { LOG_MSG(" process_food"); process_food(); LOG_MSG(m.get_random_seed()); if( town_array.is_deleted(townRecno) ) return; } //------ auto collect tax and auto grant -------// if( nation_recno ) { LOG_MSG(" process_auto"); process_auto(); LOG_MSG(m.get_random_seed() ); if( town_array.is_deleted(townRecno) ) return; } //------ collect yearly tax -------// if( nation_recno && info.game_month==1 && info.game_day==1 ) { collect_yearly_tax(); } //------ catching spies -------// LOG_MSG(" process_auto"); if( info.game_date%30 == town_recno%30 ) spy_array.catch_spy(SPY_TOWN, town_recno); LOG_MSG(m.get_random_seed() ); if( town_array.is_deleted(townRecno) ) return; //-------- update visibility ---------// if( nation_recno == nation_array.player_recno || (nation_recno && nation_array[nation_recno]->is_allied_with_player) ) { world.visit( loc_x1, loc_y1, loc_x2, loc_y2, EXPLORE_RANGE-1 ); } //--- recheck no_neighbor_space after a period, there may be new space available now ---// if( no_neighbor_space && info.game_date%180 == town_recno%180 ) { LOG_MSG("begin finding neighor space"); short buildXLoc, buildYLoc; //--- for independent town, since we can't call find_best_firm_loc(), we just set no_neighbor_space to 0 every 6 months, if it still has no space, then no_neighbor_space will be set 1 again. ---// if( nation_recno==0 || nation_array[nation_recno]->find_best_firm_loc(FIRM_INN, loc_x1, loc_y1, buildXLoc, buildYLoc) ) // whether it's FIRM_INN or not really doesn't matter, just any firm type will do no_neighbor_space = 0; LOG_MSG(m.get_random_seed()); } //------ decrease penalties -----// if( accumulated_collect_tax_penalty > 0 ) accumulated_collect_tax_penalty--; if( accumulated_reward_penalty > 0 ) accumulated_reward_penalty--; if( accumulated_recruit_penalty > 0 ) accumulated_recruit_penalty--; if( accumulated_enemy_grant_penalty > 0 ) accumulated_enemy_grant_penalty--; //------------------------------------------------------------// // check for population for each town //------------------------------------------------------------// //err_when( town_array.is_deleted(townRecno) ); if( town_array.is_deleted(townRecno) ) return; #ifdef DEBUG Firm *firmPtr; int i, j; short pop[MAX_RACE]; memset(pop, 0, sizeof(short)*MAX_RACE); for(i=linked_firm_count-1; i>=0; i--) { err_when(!linked_firm_array[i] || firm_array.is_deleted(linked_firm_array[i])); firmPtr = firm_array[linked_firm_array[i]]; if(firmPtr->overseer_recno) { if(firmPtr->overseer_town_recno==town_recno) { Unit *unitPtr = unit_array[firmPtr->overseer_recno]; pop[unitPtr->race_id-1]++; } } if(firmPtr->worker_count) { for(j=firmPtr->worker_count-1; j>=0; j--) { if((firmPtr->worker_array[j]).town_recno==town_recno) pop[(firmPtr->worker_array[j]).race_id-1]++; } } } for(i=0; i0 ; i-- ) { if( spy_array.is_deleted(i) ) continue; Spy* spyPtr = spy_array[i]; if( spyPtr->spy_place == SPY_TOWN && spyPtr->spy_place_para == town_recno ) raceSpyCountArray[spyPtr->race_id-1]++; } for( i=0 ; i jobless_race_pop_array[i] ); } town_res.get_name(town_name_id); #endif } //----------- End of function Town::next_day ---------// //---------- Begin of function Town::process_food --------// // void Town::process_food() { //--------- Peasants produce food ---------// nation_array[nation_recno]->add_food( (float) jobless_population * PEASANT_FOOD_YEAR_PRODUCTION / 365 ); //---------- People consume food ----------// nation_array[nation_recno]->consume_food( (float) population * PERSON_FOOD_YEAR_CONSUMPTION / 365 ); } //----------- End of function Town::process_food ---------// //---------- Begin of function Town::process_auto --------// // void Town::process_auto() { if( !has_linked_own_camp ) // can only collect or grant when there is a linked camp of its own. return; Nation* nationPtr = nation_array[nation_recno]; //----- auto collect tax -----// if( auto_collect_tax_loyalty > 0 ) { if( accumulated_collect_tax_penalty == 0 && average_loyalty() >= auto_collect_tax_loyalty ) { collect_tax(COMMAND_AI); } } //---------- auto grant -----------// if( auto_grant_loyalty > 0 ) { if( accumulated_reward_penalty == 0 && average_loyalty() < auto_grant_loyalty && nationPtr->cash > 0 ) { reward(COMMAND_AI); } } } //----------- End of function Town::process_auto ---------// //---------- Begin of function Town::set_nation --------// // // Set the nation of this town. // // Possible changes: // // independent town -> nation town // nation A's town -> nation B's town (surrender) // void Town::set_nation(int newNationRecno) { if( nation_recno == newNationRecno ) return; clear_defense_mode(); //------------- stop all actions to attack this town ------------// unit_array.stop_attack_town(town_recno); rebel_array.stop_attack_town(town_recno); //--------- update AI town info ---------// if( ai_town && nation_recno ) { nation_array[nation_recno]->del_town_info(town_recno); } //--------- reset vars ---------// is_base_town = 0; town_defender_count = 0; // reset defender count //----- set power region of the new nation ------// world.restore_power(loc_x1, loc_y1, loc_x2, loc_y2, town_recno, 0); // restore power of the old nation world.set_power(loc_x1, loc_y1, loc_x2, loc_y2, newNationRecno); // set power of the new nation //--- update the cloaked_nation_recno of all spies in the firm ---// spy_array.change_cloaked_nation(SPY_TOWN, town_recno, nation_recno, newNationRecno); // check the cloaked nation recno of all spies in the firm //--------- set nation_recno --------// int oldNationRecno = nation_recno; nation_recno = newNationRecno; if( nation_recno ) // reset rebel_recno if the town is then ruled by a nation { if( rebel_recno ) { Rebel* rebelPtr = rebel_array[rebel_recno]; err_when( rebelPtr->mobile_rebel_count > 0 ); // change nation shouldn't happen if mobile_rebel_count > 0 rebel_array.del_rebel(rebel_recno); // delete the rebel group rebel_recno = 0; } } //--------- update ai_town ----------// ai_town = 0; if( nation_recno==0 ) // independent town { ai_town = 1; } else if( nation_array[nation_recno]->nation_type==NATION_AI ) { ai_town = 1; nation_array[nation_recno]->add_town_info(town_recno); } //------ set the loyalty of the town people ------// int i, nationRaceId; if( nation_recno ) nationRaceId = nation_array[nation_recno]->race_id; for( i=0 ; ichange_nation(newNationRecno); //-------- update loyalty ---------// update_target_loyalty(); //--- if a nation set up a town in a location that the player has explored, contact between the nation and the player is established ---// establish_contact_with_player(); //----- if an AI nation took over this town, see if the AI can capture all firms linked to this town ----// if( nation_recno && nation_array[nation_recno]->is_ai() ) think_capture_linked_firm(); //--- when a town change nation, call the AI function of call linked firms ---// Firm* firmPtr; for( i=0 ; ifirm_ai ) // tell linked firms that this town has changed nation firmPtr->think_linked_town_change_nation(town_recno, oldNationRecno, newNationRecno); } //------ set national auto policy -----// if( nation_recno ) { Nation* nationPtr = nation_array[nation_recno]; set_auto_collect_tax_loyalty( nationPtr->auto_collect_tax_loyalty ); set_auto_grant_loyalty( nationPtr->auto_grant_loyalty ); } //---- reset the action mode of all spies in this town ----// spy_array.set_action_mode( SPY_TOWN, town_recno, SPY_IDLE ); // we need to reset it. e.g. when we have captured an enemy town, SPY_SOW_DISSENT action must be reset to SPY_IDLE //-------- refresh display ----------// if( town_array.selected_recno == town_recno ) info.disp(); } //----------- End of function Town::set_nation ---------// //------ Begin of function Town::set_hostile_nation -------// void Town::set_hostile_nation(int nationRecno) { if(nationRecno==0) return; err_when(nationRecno>7); // only 8 bits independ_town_nation_relation |= (0x1 << nationRecno); } //----------- End of function Town::set_hostile_nation ---------// //------ Begin of function Town::reset_hostile_nation -------// void Town::reset_hostile_nation(int nationRecno) { if(nationRecno==0) return; err_when(nationRecno>7); // only 8 bits independ_town_nation_relation &= ~(0x1 << nationRecno); } //----------- End of function Town::reset_hostile_nation ---------// //------ Begin of function Town::is_hostile_nation -------// // return 1 for hostile nation // return 0 otherwise // int Town::is_hostile_nation(int nationRecno) { if(nationRecno==0) return 0; err_when(nationRecno>7); // only 8 bits return (independ_town_nation_relation & (0x1 << nationRecno)); } //----------- End of function Town::is_hostile_nation ---------// //--------- Begin of function Town::init_pop ----------// // // Initialize population of the town. // // raceId - the id. of the race to add. // addPop - the no. of people to add. // addLoyalty - loyalty of the people to add to the town // [int] hasJob - whether the units will have jobs or not after moving into this town // (default: 0) // [int] firstInit - first initialization at the beginning of the game // (default: 0) // void Town::init_pop(int raceId, int addPop, int addLoyalty, int hasJob, int firstInit) { if(population>=MAX_TOWN_POPULATION) return; int addPopulation = min(addPop, MAX_TOWN_POPULATION-population); //-------- update population ---------// race_pop_array[raceId-1] += addPopulation; population += addPopulation; err_when( race_pop_array[raceId-1] > MAX_TOWN_POPULATION ); err_when( population > MAX_TOWN_POPULATION ); if( !hasJob ) { jobless_population += addPopulation; jobless_race_pop_array[raceId-1] += addPopulation; } err_when( jobless_race_pop_array[raceId-1] > MAX_TOWN_POPULATION ); err_when( jobless_population > MAX_TOWN_POPULATION ); //------- update loyalty --------// err_when( race_loyalty_array[raceId-1]<0 || race_loyalty_array[raceId-1]>100 ); if( firstInit ) // first initialization at the beginning of the game { if( nation_recno ) { race_loyalty_array[raceId-1] = (float) addLoyalty; race_target_loyalty_array[raceId-1] = addLoyalty; } else { for( int j=0 ; j100 ); err_when( race_loyalty_array[raceId-1]<0 || race_loyalty_array[raceId-1]>100 ); err_when( race_target_loyalty_array[raceId-1]<0 || race_target_loyalty_array[raceId-1]>100 ); //---------- update town parameters ----------// town_array.distribute_demand(); if( nation_recno ) update_loyalty(); else update_resistance(); } //--------- End of function Town::init_pop ----------// //--------- Begin of function Town::inc_pop -------// // // raceId - the race id. of the population // unitHasJob - whether the unit will get a job after moving into the town // unitLoyalty - loyalty of the unit. // void Town::inc_pop(int raceId, int unitHasJob, int unitLoyalty) { err_when( unitLoyalty < 0 ); //---------- increase population ----------// population++; race_pop_array[raceId-1]++; err_when( race_pop_array[raceId-1] > MAX_TOWN_POPULATION ); err_when( population > MAX_TOWN_POPULATION ); if( !unitHasJob ) { jobless_population++; jobless_race_pop_array[raceId-1]++; err_when( jobless_race_pop_array[raceId-1] > MAX_TOWN_POPULATION ); err_when( jobless_population > MAX_TOWN_POPULATION ); } //------- update loyalty --------// if( nation_recno ) // if the unit has an unit { err_when( race_loyalty_array[raceId-1]<0 || race_loyalty_array[raceId-1]>100 ); race_loyalty_array[raceId-1] = ( race_loyalty_array[raceId-1] * (race_pop_array[raceId-1]-1) + (float) unitLoyalty ) / race_pop_array[raceId-1]; err_when( unitLoyalty<0 || unitLoyalty>100 ); err_when( race_loyalty_array[raceId-1]<0 || race_loyalty_array[raceId-1]>100 ); } //-- if the race's population exceeds the capacity of the town layout --// if( race_pop_array[raceId-1] > max_race_pop_array[raceId-1] ) { auto_set_layout(); } } //---------- End of function Town::inc_pop --------// //--------- Begin of function Town::dec_pop -------// // // raceId - the race id. of the population // unitHasJob - whether the unit current has a job or not // void Town::dec_pop(int raceId, int unitHasJob) { population--; race_pop_array[raceId-1]--; err_when( population < 0 ); err_when( race_pop_array[raceId-1] < 0 ); if( !unitHasJob ) { jobless_population--; jobless_race_pop_array[raceId-1]--; err_when( jobless_population < 0 ); err_when( jobless_race_pop_array[raceId-1] < 0 ); } err_when( race_pop_array[raceId-1] < jobless_race_pop_array[raceId-1] ); //------- if all the population are gone --------// if( population==0 ) // it will be deleted in TownArray::process() { if( nation_recno == nation_array.player_recno ) news_array.town_abandoned(town_recno); deinit(); return; } //-- if the race's population drops to too low, change the town layout --// if( race_pop_array[raceId-1] <= max_race_pop_array[raceId-1]-POPULATION_PER_HOUSE ) { auto_set_layout(); } } //---------- End of function Town::dec_pop --------// //--------- Begin of function Town::population_grow --------// // void Town::population_grow() { if( town_defender_count ) return; if( population >= MAX_TOWN_GROWTH_POPULATION || population >= MAX_TOWN_POPULATION ) return; //-------- population growth by birth ---------// #ifdef DEBUG short debugPopulation = population; char debugRaceGrowth[MAX_RACE] = {0}; #endif int i, autoSetFlag=0; for( i=0 ; i 100 ) { err_when( loopCount++ > 100 ); race_pop_growth_array[i] -= 100; race_pop_array[i]++; jobless_race_pop_array[i]++; population++; jobless_population++; err_when( race_pop_array[i] > MAX_TOWN_POPULATION ); err_when( jobless_race_pop_array[i] > MAX_TOWN_POPULATION ); err_when( population > MAX_TOWN_POPULATION ); err_when( jobless_population > MAX_TOWN_POPULATION ); #ifdef DEBUG debugRaceGrowth[i]++; #endif //-- if the race's population drops to too low, change the town layout --// if( race_pop_array[i] > max_race_pop_array[i] ) { autoSetFlag = 1; } if(population>=MAX_TOWN_POPULATION) break; } if(population>=MAX_TOWN_POPULATION) break; } if( autoSetFlag ) auto_set_layout(); } //----------- End of function Town::population_grow --------// //-------- Begin of function Town::race_harmony --------// // // Return a harmony rating of the given race. // // raceId - id. of the race // int Town::race_harmony(int raceId) { if( population==0 ) return 0; else return 100 * race_pop_array[raceId-1] / population; } //--------- End of function Town::race_harmony ---------// //---------- Begin of function Town::update_target_loyalty --------// // // Update loyalty for nation towns. // void Town::update_target_loyalty() { if( !nation_recno ) // return if independent towns return; //----- update loyalty of individual races -------// // // Loyalty is determined by: // // - residential harmony // - whether the people are racially homogeneous to the king // - the nation's reputation // - command bases overseeing the town. // - quality of life // - employment rate // // Quality of life is determined by: // // - The provision of goods to the villagers. A more constant // supply and a bigger variety of goods give to high quality of life. // //------------------------------------------------// //------- set target loyalty of each race --------// Nation* nationPtr = nation_array[nation_recno]; int i, targetLoyalty; int nationRaceId = nationPtr->race_id; for( i=0 ; ireputation/4; // -25 to +25 (quality_of_life-50)/3; // -17 to +17 //---- employment help increase loyalty ----// targetLoyalty += 30 - 30 * jobless_race_pop_array[i] / race_pop_array[i]; // +0 to +30 if( race_res.is_same_race(i+1, nationRaceId) ) targetLoyalty += 10; if( targetLoyalty < 0 ) // targetLoyalty can be negative if there are hostile races conflicts targetLoyalty = 0; if( targetLoyalty > 100 ) targetLoyalty = 100; //----------------------------------------// race_target_loyalty_array[i] = targetLoyalty; err_when( targetLoyalty<0 || targetLoyalty>100 ); } //----- process command bases that have influence on this town -----// int baseInfluence, thisInfluence, commanderRaceId; Firm* firmPtr; Nation *baseNationPtr; Unit* unitPtr; for( i=0 ; ifirm_id!=FIRM_CAMP || !firmPtr->overseer_recno ) continue; //-------- get nation and commander info ------------// unitPtr = unit_array[firmPtr->overseer_recno]; commanderRaceId = unitPtr->race_id; baseNationPtr = nation_array[firmPtr->nation_recno]; //------ if this race is the overseer's race -------// baseInfluence = unitPtr->skill.get_skill(SKILL_LEADING)/3; // 0 to 33 if( unitPtr->rank_id == RANK_KING ) // 20 points bonus for king baseInfluence += 20; //------------ update all race -----------// for( int j=0 ; jrace_id == j+1 ) thisInfluence += 8; //--- if the overseer's nation's race is the same as this race ---// if( baseNationPtr->race_id == j+1 ) thisInfluence += 8; //------------------------------------------// if( firmPtr->nation_recno == nation_recno ) // if the command base belongs to the same nation { targetLoyalty = race_target_loyalty_array[j] + thisInfluence; race_target_loyalty_array[j] = min(100, targetLoyalty); } else if( unitPtr->race_id == j+1 ) // for enemy camps, only decrease same race peasants { targetLoyalty = race_target_loyalty_array[j] - thisInfluence; race_target_loyalty_array[j] = max(0, targetLoyalty); } } } //------- update link status to linked enemy camps -------// for( i=0 ; ifirm_id != FIRM_CAMP ) continue; //------------------------------------------// // If this town is linked to a own camp, // disable all links to enemy camps, otherwise // enable all links to enemy camps. //------------------------------------------// if( firmPtr->nation_recno != nation_recno ) toggle_firm_link( i+1, !has_linked_own_camp, COMMAND_AUTO ); } } //----------- End of function Town::update_target_loyalty ---------// //------ Begin of function Town::update_loyalty -----// // // Update loyalty and resistance towards the target. // void Town::update_loyalty() { if( !nation_recno ) return; //------------- update loyalty -------------// float targetLoyalty, loyaltyInc, loyaltyDec; for(int i=0; i targetLoyalty) { loyaltyDec = (race_loyalty_array[i]-targetLoyalty) / 30; change_loyalty( i+1, -max(loyaltyDec, (float)0.5) ); } } } //------- End of function Town::update_loyalty ------// //------ Begin of function Town::change_loyalty -----// // // raceId - id. of the race to be changed in loyalty. // loyaltyChange - the amount of change in loyalty. // void Town::change_loyalty(int raceId, float loyaltyChange) { float newLoyalty = race_loyalty_array[raceId-1] + loyaltyChange; newLoyalty = min( 100, newLoyalty ); newLoyalty = max( 0, newLoyalty ); race_loyalty_array[raceId-1] = newLoyalty; } //------- End of function Town::change_loyalty ------// //------ Begin of function Town::change_resistance -----// // // raceId - id. of the race to be changed in loyalty. // nationRecno - recno of the nation which the resistance is towards // resistanceChange - the amount of change in resistance. // void Town::change_resistance(int raceId, int nationRecno, float resistanceChange) { err_when( raceId < 1 || raceId > MAX_RACE ); err_when( nation_array.is_deleted(nationRecno) ); float newResistance = race_resistance_array[raceId-1][nationRecno-1] + resistanceChange; newResistance = min( 100, newResistance ); newResistance = max( 0, newResistance ); race_resistance_array[raceId-1][nationRecno-1] = newResistance; } //------- End of function Town::change_resistance ------// //------ Begin of function Town::update_target_resistance ------// // // Influence from a command base to a town (simplied version) // ---------------------------------------------------------- // -Reputation of the nation // -Race of the general and the king (whether its race is the same as the town people's race) // -Leadership of the general // // If the conqueror's race id is the same as the town people's race id. // Influence = reputation/2 // else // Influence = reputation/4 // // If the general's race is the same as the town people's race, // Influence += general leadership/2 // else // Influence += general leadership/4 // void Town::update_target_resistance() { int i, j; Firm* firmPtr; Unit* unitPtr; if( population==0 || linked_firm_count==0 ) return; for( i=0 ; ifirm_id!=FIRM_CAMP || !firmPtr->overseer_recno ) continue; //-------- get nation and commander info ------------// unitPtr = unit_array[firmPtr->overseer_recno]; curValue = race_target_resistance_array[unitPtr->race_id-1][unitPtr->nation_recno-1]; newValue = 100-camp_influence(firmPtr->overseer_recno); err_when( newValue < 0 ); if( curValue == -1 || newValue < curValue ) // need to do this comparsion as there may be more than one command bases of the same nation linked to this town, we use the one with the most influence. race_target_resistance_array[unitPtr->race_id-1][unitPtr->nation_recno-1] = newValue; } } //------- End of function Town::update_target_resistance ------// //------ Begin of function Town::camp_influence ------// // // Return a specific military camp's influence on this town. // // The influence is calculated based on : // - the leadership of the commander // - whether the leader is racially homogenous to this town. // - whether the king is racially homogenous to this town. // - the reputation of the nation // // unitRecno - unit recno of the commander in the military camp. // // return: influence index (0-100) // int Town::camp_influence(int unitRecno) { Unit* unitPtr = unit_array[unitRecno]; Nation* nationPtr = nation_array[unitPtr->nation_recno]; // nation of the unit int thisInfluence = unitPtr->skill.get_skill(SKILL_LEADING)*2/3; // 66% of the leadership if( race_res.is_same_race(nationPtr->race_id, unitPtr->race_id) ) thisInfluence += thisInfluence/3; // 33% bonus if the king's race is also the same as the general thisInfluence += (int) nationPtr->reputation/2;; thisInfluence = min(100, thisInfluence); return thisInfluence; } //------- End of function Town::camp_influence ------// //------ Begin of function Town::update_resistance -----// // // Update loyalty and resistance towards the target. // void Town::update_resistance() { //------------- update resistance ----------------// int i, j, maxNation = nation_array.size(); char zeroResistance[MAX_NATION]; float targetResistance; memset( zeroResistance, 1, MAX_NATION ); for(i=0; i= 0 ) { targetResistance = (float) race_target_resistance_array[i][j]; if(race_resistance_array[i][j] > targetResistance) // only decrease, no increase for resistance { float decValue = (race_resistance_array[i][j]-targetResistance) / 30; race_resistance_array[i][j] -= max(1, decValue); if(race_resistance_array[i][j] < targetResistance) // avoid resistance oscillate between taregtLoyalty-1 and taregtLoyalty+1 race_resistance_array[i][j] = (float)targetResistance; } } if( race_resistance_array[i][j] >= (float) 1 ) // also values between consider 0 and 1 as zero as they are displayed as 0 in the interface zeroResistance[j] = 0; } } //--- if the town is zero resistance towards any nation, convert to that nation ---// for(j=0; jadd_income(INCOME_TAX, (float)population * TAX_PER_PERSON ); } //----------- End of function Town::collect_yearly_tax ---------// //---------- Begin of function Town::collect_tax --------// // // Collect tax from this town. // void Town::collect_tax(char remoteAction) { if( !has_linked_own_camp ) return; //------------------------------------------// if( !remoteAction && remote.is_enable() ) { // packet structure : short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_COLLECT_TAX, sizeof(short)); shortPtr[0] = town_recno; return; } //----- calculate the loyalty decrease amount ------// // // If you reward too frequently, the negative effect // on loyalty will get larger. // //--------------------------------------------------// int loyaltyDecrease = COLLECT_TAX_LOYALTY_DECREASE + accumulated_collect_tax_penalty/5; loyaltyDecrease = min(loyaltyDecrease, COLLECT_TAX_LOYALTY_DECREASE+10); accumulated_collect_tax_penalty += 10; //------ decrease the loyalty of the town people ------// // ##### patch begin Gilbert 5/8 ######// // for( int i=0 ; iadd_income(INCOME_TAX, (float)population * TAX_PER_PERSON ); // ------ cash increase depend on loyalty drop --------// float taxCollected = 0.0f; for( int i = 0; i < MAX_RACE; i++ ) { float beforeLoyalty = race_loyalty_array[i]; change_loyalty( i+1, (float) -loyaltyDecrease ); taxCollected += (beforeLoyalty - race_loyalty_array[i]) * race_pop_array[i] * TAX_PER_PERSON / loyaltyDecrease; } //----------- increase cash ------------// nation_array[nation_recno]->add_income(INCOME_TAX, taxCollected ); // ##### patch end Gilbert 5/8 ######// //------------ think rebel -------------// think_rebel(); } //----------- End of function Town::collect_tax ---------// //---------- Begin of function Town::reward --------// // // Reward cash to the peasants. // void Town::reward(char remoteAction) { if( !has_linked_own_camp ) return; //------------------------------------------// if( !remoteAction && remote.is_enable() ) { // packet structure : short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_REWARD, sizeof(short)); shortPtr[0] = town_recno; return; } //----- calculate the loyalty increase amount ------// // // If you reward too frequently, the effect of the // granting will be diminished. // //--------------------------------------------------// int loyaltyIncrease = TOWN_REWARD_LOYALTY_INCREASE - accumulated_reward_penalty/5; loyaltyIncrease = max(3, loyaltyIncrease); accumulated_reward_penalty += 10; //------ increase the loyalty of the town people ------// for( int i=0 ; iadd_expense(EXPENSE_GRANT_OWN_TOWN, (float)population * TOWN_REWARD_PER_PERSON ); } //----------- End of function Town::reward ---------// //------- Begin of function Town::think_surrender ---------// // // Think about surrendering to a nation with camps linked to // this town. // int Town::think_surrender() { if( !nation_recno ) // if it's an independent town return 0; //--- only surrender when there is no own camps, but has enemy camps linked to this town ---// if( has_linked_own_camp || !has_linked_enemy_camp ) return 0; //--- surrender if 2/3 of the population think about surrender ---// int i, discontentedCount=0; for( i=0 ; ifirm_id == FIRM_CAMP && firmPtr->nation_recno != nation_recno && firmPtr->nation_recno && firmPtr->overseer_recno ) { curRating = camp_influence(firmPtr->overseer_recno); // see camp_influence() for details on how the rating is calculated if( curRating > bestRating ) { bestRating = curRating; bestNationRecno = firmPtr->nation_recno; } } } //------------------------------------// if( bestNationRecno ) { surrender( bestNationRecno ); return 1; } else return 0; } //------- End of function Town::think_surrender ---------// //------- Begin of function Town::surrender ---------// // // This town surrenders to another nation. // // toNationRecno - the recno of the nation this town surrenders to. // void Town::surrender(int toNationRecno) { err_when( !toNationRecno ); //--- if this is a rebel town and the mobile rebel count is > 0, don't surrender (this function can be called by update_resistance() when resistance drops to zero ---// if( rebel_recno ) { Rebel* rebelPtr = rebel_array[rebel_recno]; if( rebelPtr->mobile_rebel_count > 0 ) return; } //----------------------------------------// if( nation_recno == nation_array.player_recno || toNationRecno == nation_array.player_recno ) { news_array.town_surrendered(town_recno, toNationRecno); // ##### begin Gilbert 9/10 ######// // sound effect if( toNationRecno == nation_array.player_recno ) { se_ctrl.immediate_sound("GET_TOWN"); } // ##### end Gilbert 9/10 ######// } set_nation( toNationRecno ); } //------- End of function Town::surrender ---------// //------- Begin of function Town::think_rebel ---------// // void Town::think_rebel() { if( !nation_recno ) return; #define REBEL_INTERVAL_MONTH 3 // don't rebel twice in less than 3 months if( info.game_date < last_rebel_date + REBEL_INTERVAL_MONTH*30 ) return; if( town_defender_count > 0 || info.game_date < last_being_attacked_date + 10 ) // don't rebel within ten days after being attacked by a hostile unit return; //--- rebel if 2/3 of the population becomes discontented ---// int i, discontentedCount=0, rebelLeaderRaceId=0, largestRebelRace=0; for( i=0 ; i largestRebelRace ) { largestRebelRace = race_pop_array[i]; rebelLeaderRaceId = i+1; } } } if( population == 1 ) // if population is 1 only, handle otherwise { if( !rebelLeaderRaceId ) return; } else { if( discontentedCount < population * 2 / 3 ) return; } //----- if there was just one unit in the town and he rebels ----// int oneRebelOnly=0; if( population==1 ) { news_array.town_rebel(town_recno, 1); oneRebelOnly = 1; } //----- create the rebel leader and the rebel group ------// int rebelCount=1; int leaderUnitRecno = create_rebel_unit(rebelLeaderRaceId, 1); // 1-the unit is the rebel leader if( !leaderUnitRecno ) return; DWORD curGroupId = unit_array.cur_group_id++; Unit *unitPtr = unit_array[leaderUnitRecno]; unitPtr->unit_group_id = curGroupId; if( oneRebelOnly ) // if there was just one unit in the town and he rebels { rebel_array.create_rebel(leaderUnitRecno, nation_recno); return; } int rebelRecno = rebel_array.create_rebel(leaderUnitRecno, nation_recno, REBEL_ATTACK_TOWN, town_recno); // create a rebel group //------- create other rebel units in the rebel group -----// int j, unitRecno, raceRebelCount; for( i=0 ; i REBEL_LOYALTY ) continue; if( population==1 ) // if only one peasant left, break, so not all peasants will rebel break; raceRebelCount = (int) (race_pop_array[i]-race_spy_count_array[i]) * (30+m.random(30)) / 100; // 30% - 60% of the unit will rebel. err_when(raceRebelCount+1 > MAX_TOWN_POPULATION); // plus 1 for the leader, cannot excess MAX_TOWN_POPULATION, consider the case these units settle immediately for( j=0 ; junit_group_id = curGroupId; unitPtr->leader_unit_recno = leaderUnitRecno; rebel_array[rebelRecno]->join(unitRecno); rebelCount++; } //--- when disloyal units left, the average loyalty increases ---// change_loyalty( i+1, (float) 50 * j / race_pop_array[i] ); } //---------- add news -------------// last_rebel_date = info.game_date; news_array.town_rebel(town_recno, rebelCount); // add the news first as after callijng ai_spy_town_rebel, the town may disappear as all peasants are gone //--- tell the AI spies in the town that a rebellion is happening ---// spy_array.ai_spy_town_rebel(town_recno); } //------- End of function Town::think_rebel ---------// //-------- Begin of function Town::create_rebel_unit --------// // // Create a rebel unit from a town. // // raceId - race id. of the unit // isLeader - whether the unit is a rebel leader // // return: recno of the unit created. // int Town::create_rebel_unit(int raceId, int isLeader) { /* //--- do not mobilize spies as rebels ----// //---------------------------------------// // // If there are spies in this town, first mobilize // the spies whose actions are "Sow Dissent". // //---------------------------------------// int idleSpyCount=0; if( race_spy_count_array[raceId-1] > 0 ) { Spy* spyPtr; for( int i=spy_array.size() ; i>0 ; i-- ) { if( spy_array.is_deleted(i) ) continue; spyPtr = spy_array[i]; if( spyPtr->spy_place==SPY_TOWN && spyPtr->spy_place_para==town_recno && spyPtr->race_id==raceId ) { if( spyPtr->action_mode == SPY_SOW_DISSENT ) { int unitRecno = spyPtr->mobilize_town_spy(); if( isLeader ) unit_array[unitRecno]->set_rank(RANK_GENERAL); return unitRecno; } idleSpyCount++; } } } //---- if the remaining population are all sleep spy, no new rebels ----// if( race_pop_array[raceId-1] == idleSpyCount ) return 0; err_when( race_pop_array[raceId-1] < idleSpyCount ); */ //---- if no jobless people, make workers and overseers jobless ----// if( recruitable_race_pop(raceId, 0)==0 ) // 0-don't recruit spies as the above code should have handle spies already { if( !unjob_town_people(raceId, 0) ) // 0-don't unjob overseer return 0; if( recruitable_race_pop(raceId,0)==0 ) // if the unjob unit is a spy too, then don't rebel return 0; } //----look for an empty locatino for the unit to stand ----// //--- scan for the 5 rows right below the building ---// int unitId = race_res[raceId]->basic_unit_id; SpriteInfo* spriteInfo = sprite_res[unit_res[unitId]->sprite_id]; int xLoc=loc_x1, yLoc=loc_y1; // xLoc & yLoc are used for returning results if( !world.locate_space( xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height ) ) return 0; //---------- add the unit now -----------// int rankId; if( isLeader ) rankId = RANK_GENERAL; else rankId = RANK_SOLDIER; int unitRecno = unit_array.add_unit( unitId, 0, rankId, 0, xLoc, yLoc ); dec_pop(raceId, 0); // decrease the town's population //------- set the unit's parameters --------// Unit* unitPtr = unit_array[unitRecno]; if( isLeader ) { int combatLevel = 10 + population*2 + m.random(10); // the higher the population is, the higher the combat level will be int leadershipLevel = 10 + population + m.random(10); // the higher the population is, the higher the combat level will be unitPtr->set_combat_level( min(combatLevel, 100) ); unitPtr->skill.skill_id = SKILL_LEADING; unitPtr->skill.skill_level = min(leadershipLevel, 100); } else { unitPtr->set_combat_level(CITIZEN_COMBAT_LEVEL); // combat: 10 } return unitRecno; } //--------- End of function Town::create_rebel_unit ---------// //--------- Begin of function Town::assign_unit --------// // void Town::assign_unit(int unitRecno) { //-----------------------------------------// Unit* unitPtr = unit_array[unitRecno]; if(population>=MAX_TOWN_POPULATION) { unitPtr->stop2(); //----------------------------------------------------------------------// // codes for handle_blocked_move // set unit_group_id to a different value s.t. the members in this group // will not blocked by this unit. //----------------------------------------------------------------------// unitPtr->unit_group_id = unit_array.cur_group_id++; return; } //------ if the unit is a general, demote it first -------// if( unitPtr->rank_id == RANK_GENERAL ) unitPtr->set_rank(RANK_SOLDIER); //-------- increase population -------// inc_pop(unitPtr->race_id, 0, unitPtr->loyalty); //---- free the unit's name from the name database ----// race_res[unitPtr->race_id]->free_name_id( unitPtr->name_id ); //----- if it's a town defending unit -----// if( unitPtr->unit_mode == UNIT_MODE_DEFEND_TOWN ) { #define RESISTANCE_INCREASE 2 // if the defender defeat the attackers and return the town with victory, the resistance will further increase //---------------------------------------------// // // If this unit is a defender of the town, add back the // loyalty which was deducted from the defender left the // town. // //---------------------------------------------// if( unitPtr->nation_recno == nation_recno && unitPtr->unit_mode_para == town_recno ) { //-- if the unit is a town defender, skill.skill_level is temporary used for storing the loyalty that will be added back to the town if the defender returns to the town int loyaltyInc = unitPtr->skill.skill_level; if( nation_recno ) // set the loyalty later for nation_recno > 0 { change_loyalty( unitPtr->race_id, (float) loyaltyInc ); } else { for( int i=0 ; irace_id-1][i] + loyaltyInc + RESISTANCE_INCREASE; race_resistance_array[unitPtr->race_id-1][i] = min(newResistance, 100); } } } } //------ if the unit is a spy -------// if( unitPtr->spy_recno > 0 ) { spy_array[unitPtr->spy_recno]->set_place(SPY_TOWN, town_recno); unitPtr->spy_recno = 0; // reset it so Unit::deinit() won't delete the spy } //----- if this is an independent town -----// if( nation_recno==0 ) // update the town people's combat level with this unit's combat level { town_combat_level = ( (int)town_combat_level*(population-1) + (int)unitPtr->skill.combat_level ) / population; } //--------- delete the unit --------// unit_array.disappear_in_town(unitRecno, town_recno); // the unit disappear from the map because it has moved into a town } //---------- End of function Town::assign_unit --------// //------- Begin of function Town::think_migrate ---------// // // Let the town people (only those jobless) think if they want // to migrate or not. // // People who have jobs will think in Firm::think_worker_migrate() // // Migration Possibilities: // // Independent town people migrate to -> nation town // Nation town people migrate to -> nation town // // But nation town people will NOT migrate to independent towns. // void Town::think_migrate() { #define MIGRATE_PROCESS_CYCLE 90 #define MAX_MIGRATE_PER_DAY 4 // don't migrate more than 4 units per day if( jobless_population==0 ) return; int i, j, raceId, migratedCount, townDistance; int saveTownRecno = town_recno; int saveTownNationRecno = nation_recno; Town* townPtr; int cycleId = (info.game_date+town_recno)/MIGRATE_PROCESS_CYCLE; for( i=town_array.size() ; i>0 ; i-- ) { if( i%MIGRATE_PROCESS_CYCLE != cycleId ) // while this function is called every day, it only processes a certain number of towns (not all) once a day continue; if( town_array.is_deleted(i) ) continue; townPtr = town_array[i]; if( townPtr->population>=MAX_TOWN_POPULATION ) continue; townDistance = m.points_distance(center_x, center_y, townPtr->center_x, townPtr->center_y); //---- scan all jobless population, see if any of them want to migrate ----// raceId = m.random(MAX_RACE)+1; for( j=0 ; j MAX_RACE ) raceId = 1; err_when( race_spy_count_array[raceId-1] < 0 ); if( recruitable_race_pop(raceId, 0) <= race_spy_count_array[raceId-1] ) // only if there are peasants who are jobless and are not spies continue; //--- migrate a number of people of the same race at the same time ---// migratedCount=0; int loopCount=0; while( think_migrate_one(townPtr, raceId, townDistance) ) { err_when( ++loopCount > 100 ); migratedCount++; if( townDistance > EFFECTIVE_TOWN_TOWN_DISTANCE ) // don't migrate more than one unit at a time for migrating to non-linked towns break; if( migratedCount >= MAX_MIGRATE_PER_DAY ) break; } //------------- add news --------------// if( migratedCount > 0 ) { if( saveTownNationRecno==nation_array.player_recno || townPtr->nation_recno==nation_array.player_recno ) { news_array.migrate(saveTownRecno, townPtr->town_recno, raceId, migratedCount); } return; } } } } //-------- End of function Town::think_migrate -----------// //------- Begin of function Town::think_migrate_one ---------// // // Think about migrating one person of the given race to the // given town. // //------------------------------------------------// // // Calculate the attractive factor, it is based on: // // - the reputation of the target nation (+0 to 100) // - the racial harmony of the race in the target town (+0 to 100) // - distance between the current town and the target town (-0 to 100) // // Attractiveness level range: 0 to 200 // //------------------------------------------------// // int Town::think_migrate_one(Town* targetTown, int raceId, int townDistance) { //-- only if there are peasants who are jobless and are not spies --// if( recruitable_race_pop(raceId,0)==0 ) //0-don't recruit spies return 0; //---- if the target town's population has already reached its max ----// if( targetTown->population>=MAX_TOWN_POPULATION ) return 0 ; //-- do not migrate if the target town's population of that race is less than half of the population of the current town --// if( targetTown->race_pop_array[raceId-1] < race_pop_array[raceId-1]/2 ) return 0; //--- calculate the attractiveness rating of the current town ---// int curAttractLevel = race_harmony(raceId); //--- if the target town is not linked to the current town, reduce attractiveness ---// if( townDistance > EFFECTIVE_TOWN_TOWN_DISTANCE ) { curAttractLevel -= 20 + townDistance/2; // 20 to 70 negative } //------- loyalty/resistance affecting the attractivness ------// if( nation_recno ) { curAttractLevel += (int) nation_array[nation_recno]->reputation + (int) (race_loyalty_array[raceId-1] - 40); // loyalty > 40 is considered as positive force, < 40 is considered as negative force } else { if( targetTown->nation_recno ) curAttractLevel += (int) race_resistance_array[raceId-1][targetTown->nation_recno-1]; } //--- calculate the attractiveness rating of the target town ---// int targetAttractLevel = targetTown->race_harmony(raceId); if( targetTown->nation_recno ) targetAttractLevel += (int) nation_array[targetTown->nation_recno]->reputation; //--------- compare the attractiveness ratings ---------// if( targetAttractLevel > curAttractLevel && targetAttractLevel > 0 ) { //--- if this is non-linked town, there are 50% chance that the migrating units will get lost on their way and never reach the destination ---// if( townDistance > EFFECTIVE_TOWN_TOWN_DISTANCE ) { if( m.random(2)==0 ) { dec_pop(raceId, 0); return 1; } } //---------- migrate now ----------// int newLoyalty = max( targetAttractLevel/2, 40 ); migrate(raceId, targetTown->town_recno, newLoyalty); return 1; } return 0; } //-------- End of function Town::think_migrate_one -----------// //------- Begin of function Town::migrate ---------// // // People migrate from one town to another. // // raceId - id. of the race that migrates // destTownRecno - recno of the destination town. // newLoyalty - loyalty of the unit in the target town. // // return: 1 - migrated successfully // 0 - no building space in the target town for that race // void Town::migrate(int raceId, int destTownRecno, int newLoyalty) { Town* destTown = town_array[destTownRecno]; if(destTown->population>=MAX_TOWN_POPULATION) return; //------- decrease the population of this town ------// dec_pop(raceId, 0); //--------- increase the population of the target town ------// destTown->inc_pop(raceId, 0, newLoyalty); } //-------- End of function Town::migrate -----------// //------- Begin of function Town::migrate_to ---------// int Town::migrate_to(int destTownRecno, char remoteAction, int raceId) { if( !raceId ) { raceId = browse_selected_race_id(); if( !raceId ) return 0; } if( !remoteAction && remote.is_enable() ) { // packet structure : short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_MIGRATE, 3*sizeof(short)); shortPtr[0] = town_recno; shortPtr[1] = destTownRecno; shortPtr[2] = raceId; return 0; } return can_migrate(destTownRecno, 1, raceId); // 1- migrate now, 1-allow migrate spy } //-------- End of function Town::migrate_to -----------// //------- Begin of function Town::can_migrate ---------// // // Check if it is okay for migrating one person from // the current town to the given town. // // destTownRecno - the recno of the town the people // will migrate to. // // [int] migrateNow - migrate now or not if the result is true // (default: 0) // // [int] raceId - race to check migrate // (default: 0, to find from the selected_race_id() ) // // return: 1 - migration allowed // 0 - migration not allowed // int Town::can_migrate(int destTownRecno, int migrateNow, int raceId) { if(!raceId) { raceId = browse_selected_race_id(); if( !raceId ) return 0; } Town* destTown = town_array[destTownRecno]; if( destTown->population>=MAX_TOWN_POPULATION ) return 0; //---- if there are still jobless units ----// if( recruitable_race_pop(raceId, 1) > 0 ) // 1-allow migrate spy { if( migrateNow ) move_pop(destTown, raceId, 0); // 0-doesn't have job return 1; } //--- if there is no jobless units left -----// int i, j; Firm* firmPtr; Worker* workerPtr; if( race_pop_array[raceId-1] > 0 ) { //---- scan for firms that are linked to this town ----// for( i=linked_firm_count-1 ; i>=0 ; i-- ) { firmPtr = firm_array[linked_firm_array[i]]; //---- only for firms whose workers live in towns ----// if( !firm_res[firmPtr->firm_id]->live_in_town ) continue; //---- if the target town is within the effective range of this firm ----// if( m.points_distance( destTown->center_x, destTown->center_y, firmPtr->center_x, firmPtr->center_y ) > EFFECTIVE_FIRM_TOWN_DISTANCE ) { continue; } //------- scan for workers -----------// workerPtr=firmPtr->worker_array; for( j=firmPtr->worker_count-1 ; j>=0 ; j--, workerPtr++ ) { //--- if the worker lives in this town ----// if( workerPtr->race_id == raceId && workerPtr->town_recno == town_recno ) { if( migrateNow ) { if( firm_res[firmPtr->firm_id]->live_in_town ) workerPtr->town_recno = destTownRecno; else workerPtr->town_recno = 0; move_pop(destTown, raceId, 1); // 1-has job } return 1; } } } } return 0; } //-------- End of function Town::can_migrate -----------// //------- Begin of function Town::move_pop ---------// // // This function is called by Town::can_migrate() only to move a unit // from one town to another. // void Town::move_pop(Town* destTown, int raceId, int hasJob) { //--- if the only pop of this race in the source town are spies ---// if( !hasJob ) // only for peasant, for job unit, spy_place==SPY_FIRM and it isn't related to race_spy_count_array[] { err_when( race_spy_count_array[raceId-1] > jobless_race_pop_array[raceId-1] ); if( race_spy_count_array[raceId-1] == jobless_race_pop_array[raceId-1] ) { int spySeqId = m.random( race_spy_count_array[raceId-1] ) + 1; // randomly pick one of the spies int spyRecno = spy_array.find_town_spy(town_recno, raceId, spySeqId); err_when( !spyRecno ); spy_array[spyRecno]->spy_place_para = destTown->town_recno; // set the place_para of the spy race_spy_count_array[raceId-1]--; destTown->race_spy_count_array[raceId-1]++; } } //------------------------------------------// err_when( destTown->population>MAX_TOWN_POPULATION ); destTown->inc_pop( raceId, hasJob, (int) race_loyalty_array[raceId-1] ); dec_pop( raceId, hasJob ); // the unit doesn't have a job - this must be called finally as dec_pop() will have the whole town deleted if there is only one pop left err_when( race_spy_count_array[raceId-1] > jobless_race_pop_array[raceId-1] ); err_when( destTown->race_spy_count_array[raceId-1] > destTown->jobless_race_pop_array[raceId-1] ); } //-------- End of function Town::move_pop -----------// //-------- Begin of function Town::mobilize_town_people --------// // // Call out a citizen of the town population and make it // as an unit. // // raceId - race id. of the unit // decPop - whether decrease the population or not, // if 0, only a unit will be created and no population will // be reduced. // mobileSpyFlag - whether spies will be mobilized // // return: recno of the unit created. // int Town::mobilize_town_people(int raceId, int decPop, int mobileSpyFlag) { //---- if no jobless people, make workers and overseers jobless ----// if( recruitable_race_pop(raceId, mobileSpyFlag)==0 ) { if( !unjob_town_people(raceId, 0) ) // 0-don't unjob overseer return 0; err_when( recruitable_race_pop(raceId, mobileSpyFlag)==0 ); } //----look for an empty locatino for the unit to stand ----// //--- scan for the 5 rows right below the building ---// int unitId = race_res[raceId]->basic_unit_id; SpriteInfo* spriteInfo = sprite_res[unit_res[unitId]->sprite_id]; int xLoc=loc_x1, yLoc=loc_y1; // xLoc & yLoc are used for returning results if( !world.locate_space( xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height ) ) return 0; //---------- add the unit now -----------// int unitRecno = unit_array.add_unit( unitId, nation_recno, RANK_SOLDIER, (int) race_loyalty_array[raceId-1], xLoc, yLoc ); //------- set the unit's parameters --------// Unit* unitPtr = unit_array[unitRecno]; unitPtr->set_combat_level(CITIZEN_COMBAT_LEVEL); //-------- decrease the town's population ------// if( decPop ) dec_pop(raceId, 0); return unitRecno; } //--------- End of function Town::mobilize_town_people ---------// //--------- Begin of function Town::being_attacked -------// // // This function is called by Unit::hit_town() // // attackerUnitRecno - recno of the unit attacking this town. // attackDamage - damage caused by the attack // void Town::being_attacked(int attackerUnitRecno, float attackDamage) { if( rebel_recno ) // if this town is controlled by a rebel group rebel_array[rebel_recno]->town_being_attacked(attackerUnitRecno); if( population==0 ) return; defend_target_recno = attackerUnitRecno; // store the target recno Unit* attackerUnit = unit_array[attackerUnitRecno]; if( attackerUnit->nation_recno == nation_recno ) // this can happen when the unit has just changed nation return; int attackerNationRecno = attackerUnit->nation_recno; last_being_attacked_date = info.game_date; //--------- store attacker nation recno -----------// err_when(attackerNationRecno<0 || attackerNationRecno>MAX_NATION); set_hostile_nation(attackerNationRecno); //----------- call out defender -----------// // only call out defender when the attacking unit is within the effective defending distance if( m.points_distance( attackerUnit->cur_x_loc(), attackerUnit->cur_y_loc(), center_x, center_y ) <= EFFECTIVE_DEFEND_TOWN_DISTANCE ) { int loopCount=0; while(1) { if( !mobilize_defender(attackerNationRecno) ) break; err_when( loopCount++ > 1000 ); } } auto_defense(attackerUnitRecno); //----- pick a race to be attacked by the attacker randomly -----// int raceId = pick_random_race(1, 1); // 1-pick has job people, 1-pick spies err_when( !raceId ); //-------- town people get killed ---------// received_hit_count += attackDamage; if( received_hit_count >= RECEIVED_HIT_PER_KILL ) { received_hit_count = (float) 0; int townRecno = town_recno; kill_town_people(raceId, attackerNationRecno); // kill a town people if( town_array.is_deleted(townRecno) ) // the town may have been deleted when all pop are killed return; } //---- decrease resistance if this is an independent town ----// if( town_defender_count==0 ) { //--- Resistance/loyalty of the town people decrease if the attacking continues ---// // // Resistance/Loyalty decreases faster: // // -when there are few people in the town // -when there is no defender // //---------------------------------------// float loyaltyDec; if( nation_recno ) // if the town belongs to a nation { //---- decrease loyalty of all races in the town ----// for( raceId=1 ; raceId<=MAX_RACE ; raceId++ ) { if( race_pop_array[raceId-1] == 0 ) continue; if( has_linked_own_camp ) // if it is linked to one of its camp, the loyalty will decrease slower loyaltyDec = (float) 5 / race_pop_array[raceId-1]; else loyaltyDec = (float) 10 / race_pop_array[raceId-1]; loyaltyDec = min( loyaltyDec, (float) 1 ); change_loyalty( raceId, -loyaltyDec * attackDamage / (20/ATTACK_SLOW_DOWN) ); } //--- if the resistance of all the races are zero, think_change_nation() ---// int i; for( i=0 ; i= (float) 1 ) // values between 0 and 1 are considered as 0 break; } if( i==MAX_RACE ) // if resistance of all races drop to zero think_surrender(); } else // if the town is an independent town { if( !attackerNationRecno ) // if independent units do not attack independent towns return; //---- decrease resistance of all races in the town ----// for( raceId=1 ; raceId<=MAX_RACE ; raceId++ ) { if( race_pop_array[raceId-1] == 0 ) continue; loyaltyDec = (float) 10 / race_pop_array[raceId-1]; // decrease faster for independent towns than towns belonging to nations loyaltyDec = min( loyaltyDec, (float) 1 ); race_resistance_array[raceId-1][attackerNationRecno-1] -= loyaltyDec * attackDamage / (20/ATTACK_SLOW_DOWN); if( race_resistance_array[raceId-1][attackerNationRecno-1] < 0 ) race_resistance_array[raceId-1][attackerNationRecno-1] = (float) 0; } //--- if the resistance of all the races are zero, think_change_nation() ---// int i; for( i=0 ; i= (float) 1 ) break; } if( i==MAX_RACE ) // if resistance of all races drop to zero surrender(attackerNationRecno); } } //------ reinforce troops to defend against the attack ------// if( town_defender_count==0 && nation_recno ) { if( attackerUnit->nation_recno != nation_recno ) // they may become the same when the town has been captured nation_array[nation_recno]->ai_defend(attackerUnitRecno); } } //---------- End of function Town::being_attacked -----// //--------- Begin of function Town::clear_defense_mode -------// void Town::clear_defense_mode() { //------------------------------------------------------------------// // change defense unit's to non-defense mode //------------------------------------------------------------------// Unit *unitPtr; for(int i=unit_array.size(); i>=1; --i) { if(unit_array.is_deleted(i)) continue; unitPtr = unit_array[i]; if(!unitPtr) continue; err_when(unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE || unitPtr->hit_points<=0); if(unitPtr->in_defend_town_mode() && unitPtr->action_misc==ACTION_MISC_DEFEND_TOWN_RECNO && unitPtr->action_misc_para==town_recno) unitPtr->clear_town_defend_mode(); // note: maybe, unitPtr->nation_recno != nation_recno } } //---------- End of function Town::clear_defense_mode -----// //--------- Begin of function Town::mobilize_defender -------// // int Town::mobilize_defender(int attackerNationRecno) { if( population==1 ) // do not call out defenders any more if there is only one person left in the town, otherwise the town will be gone. return 0; //------- pick a race to mobilize randomly --------// int randomPersonId = m.random(population)+1; int popSum=0, raceId=0; int i; for( i=0 ; iset_mode( UNIT_MODE_DEFEND_TOWN, town_recno ); unitPtr->skill.skill_level = (char) loyaltyDec; // if the unit is a town defender, this var is temporary used for storing the loyalty that will be added back to the town if the defender returns to the town int combatLevel = town_combat_level + m.random(20) - 10; // -10 to +10 random difference combatLevel = min(combatLevel, 100); combatLevel = max(combatLevel, 10); unitPtr->set_combat_level(combatLevel); //-----------------------------------------------------// // enable unit defend_town mode //-----------------------------------------------------// unitPtr->stop2(); unitPtr->action_mode2 = ACTION_DEFEND_TOWN_DETECT_TARGET; unitPtr->action_para2 = UNIT_DEFEND_TOWN_DETECT_COUNT; unitPtr->action_misc = ACTION_MISC_DEFEND_TOWN_RECNO; unitPtr->action_misc_para = town_recno; town_defender_count++; //------- if this town is controlled by rebels --------// if( rebel_recno ) rebel_array[rebel_recno]->mobile_rebel_count++; // increase the no. of mobile rebel units return unitRecno; } //---------- End of function Town::mobilize_defender -----// //--------- Begin of function Town::reduce_defender_count -------// void Town::reduce_defender_count() { if( --town_defender_count==0 ) independ_town_nation_relation = 0; //------- if this town is controlled by rebels --------// if( rebel_recno ) rebel_array[rebel_recno]->mobile_rebel_count--; // decrease the no. of mobile rebel units } //---------- End of function Town::reduce_defender_count -----// //--------- Begin of function Town::kill_town_people -------// // void Town::kill_town_people(int raceId, int attackerNationRecno) { if( !raceId ) raceId = pick_random_race(1, 1); // 1-pick has job unit, 1-pick spies if( !raceId ) return ; //---- jobless town people get killed first, if all jobless are killed, then kill workers ----// if( recruitable_race_pop(raceId,1)==0 ) { if( !unjob_town_people(raceId, 1) ) // unjob overseer if the only person left is a overseer return; err_when( recruitable_race_pop(raceId,1)==0 ); } //------ the killed unit can be a spy -----// if( m.random(recruitable_race_pop(raceId,1)) < race_spy_count_array[raceId-1] ) { int spyRecno = spy_array.find_town_spy(town_recno, raceId, m.random(race_spy_count_array[raceId-1])+1 ); spy_array.del_spy(spyRecno); } //---- killing civilian people decreases loyalty -----// if( nation_recno && attackerNationRecno ) // your people's loyalty decreases because you cannot protect them. nation_array[nation_recno]->civilian_killed(raceId, 0); // but only when your units are killed by enemies, neutral disasters are not counted if( attackerNationRecno ) // the attacker's people's loyalty decreases because of the killing actions. nation_array[attackerNationRecno]->civilian_killed(raceId, 1); // the nation is the attacking one // -------- sound effect ---------// se_res.sound( center_x, center_y, 1, 'R', raceId, "DIE" ); //-------- decrease population now --------// dec_pop( raceId, 0 ); // 0-doesn't have a job } //---------- End of function Town::kill_town_people -----// //--------- Begin of function Town::unjob_town_people -------// // // Make one town people of the specific race jobless. // Workers are processed first, overseers are processed next. // // raceId - race id. // unjobOverseer - whether unjob overseer or not // killOverseer - kill the overseer if possible // // return: a town person has been made jobless // int Town::unjob_town_people(int raceId, int unjobOverseer, int killOverseer) { //---- if no jobless people, workers will then get killed -----// int i, workerId; Firm* firmPtr; Worker* workerPtr; int racePop = jobless_race_pop_array[raceId-1]; for( i=linked_firm_count-1 ; i>=0 ; i-- ) { firmPtr = firm_array[linked_firm_array[i]]; //------- scan for workers -----------// workerPtr=firmPtr->worker_array; for( workerId=1 ; workerId<=firmPtr->worker_count ; workerId++, workerPtr++ ) { //--- if the worker lives in this town ----// if( workerPtr->race_id == raceId && workerPtr->town_recno == town_recno ) { if(!firmPtr->resign_worker(workerId)) return 0; err_when(population>MAX_TOWN_POPULATION); err_when( jobless_race_pop_array[raceId-1] != racePop+1 ); return 1; } } } //----- if no worker killed, try to kill overseers ------// if( unjobOverseer ) { Unit* overseerUnit; for( i=linked_firm_count-1 ; i>=0 ; i-- ) { firmPtr = firm_array[linked_firm_array[i]]; //------- scan for overseer -----------// if( firmPtr->overseer_recno ) { //--- if the overseer lives in this town ----// overseerUnit = unit_array[firmPtr->overseer_recno]; if( overseerUnit->race_id == raceId && firmPtr->overseer_town_recno == town_recno ) { if(killOverseer) firmPtr->kill_overseer(); else { int overseerUnitRecno = firmPtr->overseer_recno; Unit *unitPtr = unit_array[overseerUnitRecno]; firmPtr->assign_overseer(0); if(!unit_array.is_deleted(overseerUnitRecno) && unitPtr->is_visible()) unit_array.disappear_in_town(overseerUnitRecno, town_recno); } err_when( jobless_race_pop_array[raceId-1] != racePop+1 ); return 1; } } } } return 0; } //---------- End of function Town::unjob_town_people -----// //--------- Begin of function Town::distribute_demand ---------// // // Distribute demands among // void Town::distribute_demand() { #define MAX_ACTIVE_MARKET_COUNT 20 //------------ define struct MarketInfo --------------// struct MarketGoodsInfo { FirmMarket* market_ptr[MAX_ACTIVE_MARKET_COUNT]; float total_supply; float total_own_supply; short market_count; }; //------ scan for a firm to input raw materials --------// int i, j; Firm* firmPtr; MarketGoodsInfo marketGoodsInfoArray[MAX_PRODUCT]; MarketGoodsInfo* marketGoodsInfo; float thisSupply; MarketGoods* marketGoods; memset( marketGoodsInfoArray, 0, sizeof(marketGoodsInfoArray) ); //------- count the no. of market place that are near to this town ----// for( int linkedFirmId=0 ; linkedFirmIdfirm_id != FIRM_MARKET ) continue; if( linked_firm_enable_array[linkedFirmId] != LINK_EE ) continue; firmPtr = firm_array[linked_firm_array[linkedFirmId]]; //---------- process market -------------// for( i=0 ; imarket_product_array[i]; marketGoodsInfo = marketGoodsInfoArray+i; if( marketGoods && marketGoodsInfo->market_count < MAX_ACTIVE_MARKET_COUNT ) { thisSupply = marketGoods->stock_qty; marketGoodsInfo->market_ptr[marketGoodsInfo->market_count] = (FirmMarket*) firmPtr; marketGoodsInfo->total_supply += thisSupply; if( firmPtr->nation_recno == nation_recno ) // vars for later use, so that towns will always try to buy goods from their own markets first. marketGoodsInfo->total_own_supply += thisSupply; marketGoodsInfo->market_count++; } } } //-- set the monthly demand of the town on each product --// float townDemand = (float) jobless_population * (float) PEASANT_GOODS_MONTH_DEMAND + (float) worker_population() * (float) WORKER_GOODS_MONTH_DEMAND; float ownShareDemand; // the share of demand for own markets //---------- sell goods now -----------// FirmMarket* firmMarket; for( i=0 ; imarket_count ; j++ ) { //----------------------------------// // // If the totalSupply < town demand: // a market's demand = its_supply + (town_demand-totalSupply) / market_count // // If the totalSupply > town demand: // a market's demand = town_demand * its_supply / totalSupply // //----------------------------------// firmMarket = marketGoodsInfo->market_ptr[j]; marketGoods = firmMarket->market_product_array[i]; if( marketGoods ) { //---- if the demand is larger than the supply -----// if( marketGoodsInfo->total_supply < townDemand ) { marketGoods->month_demand += marketGoods->stock_qty + (townDemand - marketGoodsInfo->total_supply) / marketGoodsInfo->market_count; // evenly distribute the excessive demand on all markets } else //---- if the supply is larger than the demand -----// { //--- towns always try to buy goods from their own markets first ---// ownShareDemand = min(townDemand, marketGoodsInfo->total_own_supply); if( firmMarket->nation_recno == nation_recno ) { marketGoods->month_demand += ownShareDemand * marketGoods->stock_qty / marketGoodsInfo->total_own_supply; } else { marketGoods->month_demand += (townDemand-ownShareDemand) * marketGoods->stock_qty / marketGoodsInfo->total_supply; } } } } } } //----------- End of function Town::distribute_demand -----------// //------- Begin of function Town::setup_link ---------// // void Town::setup_link() { //-----------------------------------------------------------------------------// // check the connected firms location and structure if ai_link_checked is true //-----------------------------------------------------------------------------// if(ai_town) ai_link_checked = 0; //----- build town-to-firm link relationship -------// int firmRecno, defaultLinkStatus; Firm* firmPtr; FirmInfo* firmInfo; linked_firm_count = 0; for( firmRecno=firm_array.size() ; firmRecno>0 ; firmRecno-- ) { if( firm_array.is_deleted(firmRecno) ) continue; firmPtr = firm_array[firmRecno]; firmInfo = firm_res[firmPtr->firm_id]; if( !firmInfo->is_linkable_to_town ) continue; //---------- check if the firm is close enough to this firm -------// if( m.points_distance( firmPtr->center_x, firmPtr->center_y, center_x, center_y ) > EFFECTIVE_FIRM_TOWN_DISTANCE ) { continue; } //------ check if both are on the same terrain type ------// if( (world.get_loc(firmPtr->center_x, firmPtr->center_y)->is_plateau()==1) != (world.get_loc(center_x, center_y)->is_plateau()==1) ) { continue; } //------- determine the default link status ------// if( firmPtr->nation_recno == nation_recno ) // if the two firms are of the same nation, get the default link status which is based on the types of the firms defaultLinkStatus = LINK_EE; else defaultLinkStatus = LINK_DD; // if the two firms are of different nations, default link status is both side disabled //----- a town cannot disable a camp's link to it ----// if( firmPtr->firm_id==FIRM_CAMP ) // for capturing the town defaultLinkStatus = LINK_EE; //-------- add the link now -------// if( linked_firm_count < MAX_LINKED_FIRM_TOWN ) { linked_firm_array[linked_firm_count] = firmRecno; linked_firm_enable_array[linked_firm_count] = defaultLinkStatus; linked_firm_count++; } else { err_here(); } if( firmPtr->linked_town_count < MAX_LINKED_TOWN_TOWN ) { if( defaultLinkStatus==LINK_ED ) // Reverse the link status for the opposite linker defaultLinkStatus=LINK_DE; else if( defaultLinkStatus==LINK_DE ) defaultLinkStatus=LINK_ED; firmPtr->linked_town_array[firmPtr->linked_town_count] = town_recno; firmPtr->linked_town_enable_array[firmPtr->linked_town_count] = defaultLinkStatus; firmPtr->linked_town_count++; if(firmPtr->firm_ai) firmPtr->ai_link_checked = 0; } else { err_here(); } } //----- build town-to-town link relationship -------// linked_town_count = 0; int townRecno; Town* townPtr; for( townRecno=town_array.size() ; townRecno>0 ; townRecno-- ) { if( town_array.is_deleted(townRecno) || townRecno==town_recno ) continue; townPtr = town_array[townRecno]; //------ check if the town is close enough to this firm -------// if( m.points_distance( townPtr->center_x, townPtr->center_y, center_x, center_y ) > EFFECTIVE_TOWN_TOWN_DISTANCE ) { continue; } //------ check if both are on the same terrain type ------// if( (world.get_loc(townPtr->center_x, townPtr->center_y)->is_plateau()==1) != (world.get_loc(center_x, center_y)->is_plateau()==1) ) { continue; } //------- determine the default link status ------// defaultLinkStatus = LINK_EE; //-------- add the link now -------// if( linked_town_count < MAX_LINKED_TOWN_TOWN ) { linked_town_array[linked_town_count] = townRecno; linked_town_enable_array[linked_town_count] = defaultLinkStatus; linked_town_count++; } else { err_here(); } if( townPtr->linked_town_count < MAX_LINKED_TOWN_TOWN ) { if( defaultLinkStatus==LINK_ED ) // Reverse the link status for the opposite linker defaultLinkStatus=LINK_DE; else if( defaultLinkStatus==LINK_DE ) defaultLinkStatus=LINK_ED; townPtr->linked_town_array[townPtr->linked_town_count] = town_recno; townPtr->linked_town_enable_array[townPtr->linked_town_count] = defaultLinkStatus; townPtr->linked_town_count++; if(townPtr->ai_town) townPtr->ai_link_checked = 0; } else { err_here(); } } } //-------- End of function Town::setup_link -----------// //------- Begin of function Town::release_link ---------// // void Town::release_link() { int i; Firm *firmPtr; Town *townPtr; //------ release linked firms ------// for( i=0 ; irelease_town_link(town_recno); if(firmPtr->firm_ai) firmPtr->ai_link_checked = 0; } //------ release linked towns ------// for( i=0 ; irelease_town_link(town_recno); if(townPtr->ai_town) townPtr->ai_link_checked = 0; } } //-------- End of function Town::release_link -----------// //------- Begin of function Town::release_firm_link ---------// // void Town::release_firm_link(int releaseFirmRecno) { //-----------------------------------------------------------------------------// // check the connected firms location and structure if ai_link_checked is true //-----------------------------------------------------------------------------// if(ai_town) ai_link_checked = 0; for( int i=0 ; i MAX_LINKED_FIRM_TOWN ); m.del_array_rec( linked_firm_array , linked_firm_count, sizeof(linked_firm_array[0]), i+1 ); m.del_array_rec( linked_firm_enable_array, linked_firm_count, sizeof(linked_firm_enable_array[0]), i+1 ); linked_firm_count--; return; } } err_here(); } //------- End of function Town::release_firm_link ---------// //------- Begin of function Town::release_town_link ---------// // void Town::release_town_link(int releaseTownRecno) { //-----------------------------------------------------------------------------// // check the connected firms location and structure if ai_link_checked is true //-----------------------------------------------------------------------------// if(ai_town) ai_link_checked = 0; for( int i=0 ; i MAX_LINKED_TOWN_TOWN ); m.del_array_rec( linked_town_array , linked_town_count, sizeof(linked_town_array[0]), i+1 ); m.del_array_rec( linked_town_enable_array, linked_town_count, sizeof(linked_town_enable_array[0]), i+1 ); linked_town_count--; return; } } err_here(); } //------- End of function Town::release_town_link ---------// //------- Begin of function Town::toggle_firm_link ---------// // // Toggle the firm link of the current firm. // // linkId - id. of the link // toggleFlag - 1-enable, 0-disable // remoteAction - remote action type // [int] setBoth - if this is 1, it will set the link to either LINK_EE or LINK_DD (and no LINK_ED or LINK_DD) // if this is -1, the only one side will be set even though the nation recno of the firm and town are the same // (default: 0) // void Town::toggle_firm_link(int linkId, int toggleFlag, char remoteAction, int setBoth) { if( !remoteAction && remote.is_enable() ) { // packet structure : short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_TOGGLE_LINK_FIRM, 3*sizeof(short)); shortPtr[0] = town_recno; shortPtr[1] = linkId; shortPtr[2] = toggleFlag; return; } Firm* linkedFirm = firm_array[linked_firm_array[linkId-1]]; int linkedNationRecno = linkedFirm->nation_recno; int sameNation = linkedNationRecno == nation_recno || // if one of the linked end is an indepdendent firm/nation, consider this link as a single nation link linkedNationRecno == 0 || nation_recno == 0; if( toggleFlag ) { if( (sameNation && setBoth==0) || setBoth==1 ) // 0 if setBoth == -1 linked_firm_enable_array[linkId-1] = LINK_EE; else linked_firm_enable_array[linkId-1] |= LINK_ED; } else { if( (sameNation && setBoth==0) || setBoth==1 ) linked_firm_enable_array[linkId-1] = LINK_DD; else linked_firm_enable_array[linkId-1] &= ~LINK_ED; } //------ set the linked flag of the opposite firm -----// Firm* firmPtr = firm_array[ linked_firm_array[linkId-1] ]; int i; for(i=firmPtr->linked_town_count-1; i>=0; i--) { if( firmPtr->linked_town_array[i] == town_recno ) { if( toggleFlag ) { if( (sameNation && setBoth==0) || setBoth==1 ) firmPtr->linked_town_enable_array[i] = LINK_EE; else firmPtr->linked_town_enable_array[i] |= LINK_DE; } else { if( (sameNation && setBoth==0) || setBoth==1 ) firmPtr->linked_town_enable_array[i] = LINK_DD; else firmPtr->linked_town_enable_array[i] &= ~LINK_DE; } break; } } //-------- update the town's influence --------// if( nation_recno==0 ) update_target_resistance(); //--- redistribute demand if a link to market place has been toggled ---// if( linkedFirm->firm_id == FIRM_MARKET ) town_array.distribute_demand(); } //-------- End of function Town::toggle_firm_link ---------// //------- Begin of function Town::toggle_town_link ---------// // // Toggle the town link of the current firm. // // linkId - id. of the link // toggleFlag - 1-enable, 0-disable // [int] setBoth - if this is 1, it will set the link to either LINK_EE or LINK_DD (and no LINK_ED or LINK_DD) // if this is -1, the only one side will be set even though the nation recno of the firm and town are the same // (default: 0) // void Town::toggle_town_link(int linkId, int toggleFlag, char remoteAction, int setBoth) { if( !remoteAction && remote.is_enable() ) { // packet structure : short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_TOGGLE_LINK_TOWN, 3*sizeof(short)); shortPtr[0] = town_recno; shortPtr[1] = linkId; shortPtr[2] = toggleFlag; return; } int linkedNationRecno = town_array[linked_town_array[linkId-1]]->nation_recno == nation_recno; int sameNation = linkedNationRecno == nation_recno || // if one of the linked end is an indepdendent firm/nation, consider this link as a single nation link linkedNationRecno == 0 || nation_recno == 0; if( toggleFlag ) { if( (sameNation && setBoth==0) || setBoth==1 ) linked_town_enable_array[linkId-1] = LINK_EE; else linked_town_enable_array[linkId-1] |= LINK_ED; } else { if( (sameNation && setBoth==0) || setBoth==1 ) linked_town_enable_array[linkId-1] = LINK_DD; else linked_town_enable_array[linkId-1] &= ~LINK_ED; } //------ set the linked flag of the opposite town -----// Town* townPtr = town_array[ linked_town_array[linkId-1] ]; int i; for(i=townPtr->linked_town_count-1; i>=0; i--) { if( townPtr->linked_town_array[i] == town_recno ) { if( toggleFlag ) { if( (sameNation && setBoth==0) || setBoth==1 ) townPtr->linked_town_enable_array[i] = LINK_EE; else townPtr->linked_town_enable_array[i] |= LINK_DE; } else { if( (sameNation && setBoth==0) || setBoth==1 ) townPtr->linked_town_enable_array[i] = LINK_DD; else townPtr->linked_town_enable_array[i] &= ~LINK_DE; } break; } } } //-------- End of function Town::toggle_town_link ---------// //-------- Begin of function Town::linked_active_camp_count ------// // // No. of linked military camp to this town which has a general in it. // int Town::linked_active_camp_count() { int i, linkedCount=0; Firm* firmPtr; for( i=0 ; ifirm_id == FIRM_CAMP && firmPtr->overseer_recno ) { linkedCount++; } } } return linkedCount; } //---------- End of function Town::linked_active_camp_count --------// //------- Begin of function Town::auto_defense ---------// // void Town::auto_defense(short targetRecno) { Firm *firmPtr; FirmCamp *campPtr; short townRecno = town_recno; for(int i=linked_firm_count-1; i>=0; i--) { err_when(!linked_firm_array[i] || firm_array.is_deleted(linked_firm_array[i])); firmPtr = firm_array[linked_firm_array[i]]; if(firmPtr->nation_recno!=nation_recno || firmPtr->firm_id!=FIRM_CAMP) continue; //-------------------------------------------------------// // the firm is a military camp of our nation //-------------------------------------------------------// campPtr = firmPtr->cast_to_FirmCamp(); campPtr->defense(targetRecno); if(town_array.is_deleted(townRecno)) break; // the last unit in the town has be mobilized } } //-------- End of function Town::auto_defense ---------// //-------- Begin of function Town::cancel_train_unit ------// void Town::cancel_train_unit() { if( train_unit_recno ) { //### begin alex 17/3 ###// //unit_array.disappear_in_town(train_unit_recno, town_recno); //train_unit_recno = 0; err_when(train_unit_recno==0); Unit *unitPtr = unit_array[train_unit_recno]; if(unitPtr->spy_recno && unitPtr->skill.skill_id) // check whether the unit is already a spy before training { spy_array[unitPtr->spy_recno]->set_place(SPY_TOWN, town_recno); unitPtr->spy_recno = 0; // reset it so Unit::deinit() won't delete the spy } unit_array.disappear_in_town(train_unit_recno, town_recno); train_unit_recno = 0; //#### end alex 17/3 ####// } } //----------- End of function Town::cancel_train_unit -----------// //-------- Begin of function Town::auto_set_layout ------// // void Town::auto_set_layout() { /* //------ debugging code -----// static int lastLayoutId=0; if( ++lastLayoutId > town_res.town_layout_count ) lastLayoutId=1; layout_id = lastLayoutId; */ //------------------// layout_id = think_layout_id(); err_when( !layout_id ); TownLayout* townLayout = town_res.get_layout(layout_id); TownSlot* firstTownSlot = town_res.get_slot(townLayout->first_slot_recno); short raceNeedBuildCount[MAX_RACE]; memset( slot_object_id_array, 0, sizeof(slot_object_id_array) ); memset( max_race_pop_array , 0, sizeof(max_race_pop_array) ); memset( raceNeedBuildCount, 0, sizeof(raceNeedBuildCount) ); int i; for( i=0 ; i 0 ) raceNeedBuildCount[i] += (race_pop_array[i]-1)/POPULATION_PER_HOUSE+1; } //--- assign the first house to each race, each present race will at least have one house ---// int firstRaceId = m.random(MAX_RACE)+1; // random match int raceId = firstRaceId; for( i=0 ; islot_count ; i++ ) { if( firstTownSlot[i].build_type == TOWN_OBJECT_HOUSE ) { int loopCount=0; while(1) // next race { if( ++raceId > MAX_RACE ) raceId = 1; if( raceId == (firstRaceId==MAX_RACE)?1:(firstRaceId+1) ) // finished the first house for all races goto label_distribute_house; if( raceNeedBuildCount[raceId-1] > 0 ) // if this race need buildings, skip all races that do not need buildings break; err_when( loopCount++ > 1000 ); } slot_object_id_array[i] = town_res.scan_build( townLayout->first_slot_recno+i, raceId); raceNeedBuildCount[raceId-1]--; max_race_pop_array[raceId-1] += POPULATION_PER_HOUSE; } } err_when( raceId != firstRaceId ); // some races are not assigned with a house //------- distribute the remaining houses -------// label_distribute_house: int bestRaceId, maxNeedBuildCount; for( i=0 ; islot_count ; i++ ) { if( firstTownSlot[i].build_type == TOWN_OBJECT_HOUSE && !slot_object_id_array[i] ) { bestRaceId=0; maxNeedBuildCount=0; for( raceId=1 ; raceId<=MAX_RACE ; raceId++ ) { if( raceNeedBuildCount[raceId-1] > maxNeedBuildCount ) { bestRaceId = raceId; maxNeedBuildCount = raceNeedBuildCount[raceId-1]; } } if( !bestRaceId ) // all races have assigned with their needed houses break; slot_object_id_array[i] = town_res.scan_build( townLayout->first_slot_recno+i, bestRaceId); raceNeedBuildCount[bestRaceId-1]--; max_race_pop_array[bestRaceId-1] += POPULATION_PER_HOUSE; } } //------- set plants in the town layout -------// for( i=0 ; islot_count ; i++ ) { switch(firstTownSlot[i].build_type) { case TOWN_OBJECT_PLANT: slot_object_id_array[i] = plant_res.scan(0, 'T', 0); // 'T'-town only, 1st 0-any zone area, 2nd 0-any terain type, 3rd-age level break; case TOWN_OBJECT_FARM: slot_object_id_array[i] = firstTownSlot[i].build_code; err_when( slot_object_id_array[i] < 1 || slot_object_id_array[i] > 9 ); break; case TOWN_OBJECT_HOUSE: if( !slot_object_id_array[i] ) slot_object_id_array[i] = town_res.scan_build( townLayout->first_slot_recno+i, m.random(MAX_RACE)+1 ); break; } } } //---------- End of function Town::auto_set_layout --------// //-------- Begin of function Town::think_layout_id ------// // int Town::think_layout_id() { int i, countDiff; int needBuildCount=0; // basic buildings needed int extraBuildCount=0; // extra buildings needed beside the basic one //---- count the needed buildings of each race ----// for( i=0 ; i POPULATION_PER_HOUSE ) // extra buildings, which are not necessary, but will look better if the layout plan fits with this number extraBuildCount += (race_pop_array[i]-POPULATION_PER_HOUSE-1)/POPULATION_PER_HOUSE+1; } //---------- scan the town layout ---------// int layoutId; TownLayout* townLayout; for( layoutId=town_res.town_layout_count ; layoutId>0 ; layoutId-- ) // scan from the most densed layout to the least densed layout { townLayout = town_res.get_layout(layoutId); //--- if this plan has less than the essential need ---// countDiff = townLayout->build_count - (needBuildCount+extraBuildCount); if( countDiff==0 ) // the match is perfect, return now break; if( countDiff < 0 ) // since we scan from the most densed town layout to the least densed one, if cannot find anyone matched now, there won't be any in the lower positions of the array { layoutId = town_res.town_layout_count; break; } } err_when( layoutId==0 ); //--- if there are more than one layout with the same number of building, pick one randomly ---// int layoutBuildCount = town_res.get_layout(layoutId)->build_count; int layoutId2; for( layoutId2=layoutId-1 ; layoutId2>0 ; layoutId2-- ) { townLayout = town_res.get_layout(layoutId2); if( layoutBuildCount != townLayout->build_count ) break; } layoutId2++; // the lowest layout id. that has the same no. of buildings err_when( layoutId2<1 || layoutId2>town_res.town_layout_count ); //------- return the result layout id -------// return layoutId2 + m.random(layoutId-layoutId2+1); } //---------- End of function Town::think_layout_id --------// //-------- Begin of function Town::average_loyalty ------// // int Town::average_loyalty() { int i, totalLoyalty=0; for( i=0 ; i 0 ) totalResistance += race_resistance_array[i][nationRecno-1] * thisPop; } return int(totalResistance / population); } //-------- End of function Town::average_resistance ---------// //------- Begin of function Town::average_target_resistance --------// // // Return the average target resistance of all the races in the town // against a specific nation. // int Town::average_target_resistance(int nationRecno) { int thisPop, t, totalResistance=0; for( int i=0 ; i 0 ) { t = race_target_resistance_array[i][nationRecno-1]; if( t >= 0 ) // -1 means no target totalResistance += t * thisPop; else totalResistance += (int) race_resistance_array[i][nationRecno-1] * thisPop; } } return int(totalResistance / population); } //-------- End of function Town::average_target_resistance ---------// //-------- Begin of function Town::can_recruit ------// // int Town::can_recruit(int raceId) { //----------------------------------------------------// // Cannot recruit when you have none of your own camps // linked to this town, but your enemies have camps // linked to it. //----------------------------------------------------// if( !has_linked_own_camp && has_linked_enemy_camp ) return 0; if( recruitable_race_pop(raceId,1)==0 ) return 0; err_when( recruitable_race_pop(raceId,1) < 0 ); //---------------------------------// int minRecruitLoyalty = MIN_RECRUIT_LOYALTY; //--- for the AI, only recruit if the loyalty still stay at 30 after recruiting the unit ---// if(ai_town && nation_recno) minRecruitLoyalty += 3+recruit_dec_loyalty(raceId, 0); // 0-don't actually decrease it, just return the loyalty to be decreased. return race_loyalty_array[raceId-1] >= minRecruitLoyalty; } //---------- End of function Town::can_recruit --------// //-------- Begin of function Town::can_train ------// // int Town::can_train(int raceId) { int recruitableCount = jobless_race_pop_array[raceId-1]; return has_linked_own_camp && recruitableCount > 0 && nation_array[nation_recno]->cash > TRAIN_SKILL_COST; } //---------- End of function Town::can_train --------// //-------- Begin of function Town::pick_random_race ------// // // Randonly pick a race of town people who live in the town. // // pickNonRecruitableAlso - whether also pick units that have jobs. // pickSpyFlag - whether will pick spies or not. // // return: id. of the race picked. // 0 - no race picked. // int Town::pick_random_race(int pickNonRecruitableAlso, int pickSpyFlag) { int totalPop; if( pickNonRecruitableAlso ) totalPop = population; else { totalPop = jobless_population - (train_unit_recno>0); if( !pickSpyFlag ) // if don't pick spies { for( int i=0 ; i raceId1, raceId2 - return the id. of the most and // 2nd most populated races. // void Town::get_most_populated_race(int& mostRaceId1, int& mostRaceId2) { //--- find the two races with most population in the town ---// int racePop; int mostRacePop1=0, mostRacePop2=0; mostRaceId1=0; mostRaceId2=0; if( population==0 ) return; for( int i=0 ; i= mostRacePop1 ) { mostRacePop2 = mostRacePop1; mostRacePop1 = racePop; mostRaceId2 = mostRaceId1; mostRaceId1 = i+1; } else if( racePop >= mostRaceId2 ) { mostRacePop2 = racePop; mostRaceId2 = i+1; } } } //---------- End of function Town::get_most_populated_race --------// //-------- Begin of function Town::majority_race ------// // int Town::majority_race() { int mostRaceCount=0, mostRaceId=0; for( int i=0 ; i mostRaceCount ) { mostRaceCount = race_pop_array[i]; mostRaceId = i+1; } } return mostRaceId; } //---------- End of function Town::majority_race --------// //-------- Begin of function Town::recruitable_race_pop ------// // // Return the number of units can be recruited from this town. // // raceId - id. of the race to recruit // // recruitSpy - whether spies will be recruited or not. // if no, spies are not counted in the // total no. of units that can be recruited. // int Town::recruitable_race_pop(int raceId, int recruitSpy) { err_when( raceId<1 || raceId>MAX_RACE ); short recruitableCount = jobless_race_pop_array[raceId-1]; if( train_unit_recno && unit_array[train_unit_recno]->race_id==raceId ) recruitableCount--; if( !recruitSpy ) { recruitableCount -= race_spy_count_array[raceId-1]; if( recruitableCount == -1 ) // it may have been reduced twice if the unit being trained is a spy recruitableCount = 0; } err_when( recruitableCount < 0 ); return recruitableCount; } //---------- End of function Town::recruitable_race_pop --------// //------ Begin of function Town::verify_slot_object_id_array ------// // // This function is for debugging only. // void Town::verify_slot_object_id_array() { TownLayout* townLayout = town_res.get_layout(layout_id); TownSlot* townSlot = town_res.get_slot(townLayout->first_slot_recno); for( int i=0 ; islot_count ; i++, townSlot++ ) { //----- build_type==0 if plants -----// switch(townSlot->build_type) { //----- build_type>0 if town buildings -----// case TOWN_OBJECT_HOUSE: town_res.get_build( slot_object_id_array[i] ); break; case TOWN_OBJECT_PLANT: plant_res.get_bitmap( slot_object_id_array[i] ); break; case TOWN_OBJECT_FARM: err_when( slot_object_id_array[i]<1 || slot_object_id_array[i]>9 ); break; } } } //-------- End of function Town::verify_slot_object_id_array ------// //----- Begin of function Town::set_auto_collect_tax_loyalty -----// // // Note: // // Auto collect tax loyalty must always be higher than the auto grant // loyalty. If the player has set it incorrectly, the program // will automatically adjust it. e.g. If the player sets the auto // grant level to 80 while the auto tax level is currently 60, // the program will adjust auto tax level to 90. And if the player // sets the auto grant level to 100, auto tax will be disabled. // void Town::set_auto_collect_tax_loyalty(int loyaltyLevel) { auto_collect_tax_loyalty = loyaltyLevel; if( loyaltyLevel && auto_grant_loyalty >= auto_collect_tax_loyalty ) { auto_grant_loyalty = auto_collect_tax_loyalty-10; } } //------ End of function Town::set_auto_collect_tax_loyalty -----// //----- Begin of function Town::set_auto_grant_loyalty -----// // void Town::set_auto_grant_loyalty(int loyaltyLevel) { auto_grant_loyalty = loyaltyLevel; if( loyaltyLevel && auto_grant_loyalty >= auto_collect_tax_loyalty ) { auto_collect_tax_loyalty = auto_grant_loyalty+10; if( auto_collect_tax_loyalty > 100 ) auto_collect_tax_loyalty = 0; // disable auto collect tax if it's over 100 } } //------ End of function Town::set_auto_grant_loyalty -----// //------ Begin of function Town::update_quality_of_life -------// // // Quality of life is determined by: // // - The provision of goods to the villagers. A more constant // supply and a bigger variety of goods give to high quality of life. // void Town::update_quality_of_life() { Firm* firmPtr; FirmMarket* firmMarket; //--- calculate the estimated total purchase from this town ----// float townDemand = (float) jobless_population * (float) PEASANT_GOODS_MONTH_DEMAND + (float) worker_population() * (float) WORKER_GOODS_MONTH_DEMAND; float totalPurchase = (float) 0; for( int i=0 ; ifirm_id != FIRM_MARKET ) continue; firmMarket = (FirmMarket*) firmPtr; //-------------------------------------// MarketGoods* marketGoods = firmMarket->market_goods_array; for( int j=0 ; jproduct_raw_id || marketGoods->month_demand==0 ) continue; float monthSaleQty = marketGoods->sale_qty_30days(); if( monthSaleQty > marketGoods->month_demand ) { totalPurchase += townDemand; } else if( marketGoods->month_demand > townDemand ) { totalPurchase += monthSaleQty * townDemand / marketGoods->month_demand; } else totalPurchase += monthSaleQty; } } //------ return the quality of life ------// quality_of_life = int( (float)100 * totalPurchase / (townDemand * MAX_PRODUCT) ); } //----------- End of function Town::update_quality_of_life ---------// //----- Begin of function Town::has_linked_camp -----// // // Return whether there is a camp of the specific nation // linked to this town. // // nationRecno - recno of the nation. // needOverseer - whether only count camps with overseers or not. // int Town::has_linked_camp(int nationRecno, int needOverseer) { Firm* firmPtr; for( int i=0 ; ifirm_id == FIRM_CAMP && firmPtr->nation_recno == nationRecno ) { if( !needOverseer || firmPtr->overseer_recno ) return 1; } } return 0; } //------ End of function Town::has_linked_camp -----// //----- Begin of function Town::can_grant_to_non_own_town -----// // // Return whether the given nation is allowed to grant to // this independent town. Only when the nation has a camp (with // an overseer) linked to the town, the nation will be able // to grant the independent village. // // grantNationRecno - the recno of the nation that // is going to grant this town. // int Town::can_grant_to_non_own_town(int grantNationRecno) { if( nation_recno == grantNationRecno ) // only for independent town return 0; if( nation_recno == 0 ) // independent town { return has_linked_camp( grantNationRecno, 1 ); // 1-only count camps with overseers } else // for nation town, when the enemy doesn't have camps linked to it and the granting nation has camps linked to it { return has_linked_camp( nation_recno, 0 )==0 && // 0-count camps regardless of the presence of overseers has_linked_camp( grantNationRecno, 1 ); // 1-only count camps with overseers } } //------ End of function Town::can_grant_to_non_own_town -----// //----- Begin of function Town::grant_to_non_own_town -----// // // grantNationRecno - the recno of the nation that // is going to grant this town. // int Town::grant_to_non_own_town(int grantNationRecno, int remoteAction) { if( !can_grant_to_non_own_town(grantNationRecno) ) return 0; Nation* grantNation = nation_array[grantNationRecno]; if( grantNation->cash < 0 ) return 0; if( !remoteAction && remote.is_enable() ) { short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_GRANT_INDEPENDENT, 2*sizeof(short) ); shortPtr[0] = town_recno; shortPtr[1] = grantNationRecno; return 1; } //---- calculate the resistance to be decreased -----// int resistanceDec = IND_TOWN_GRANT_RESISTANCE_DECREASE - accumulated_enemy_grant_penalty/5; resistanceDec = max(3, resistanceDec); accumulated_enemy_grant_penalty += 10; //------ decrease the resistance of the independent villagers ------// for( int i=0 ; iadd_expense(EXPENSE_GRANT_OTHER_TOWN, (float)population * IND_TOWN_GRANT_PER_PERSON ); return 1; } //------ End of function Town::grant_to_non_own_town -----// //----- Begin of function Town::update_camp_link -----// // // Update the status of links from this town to camps. // void Town::update_camp_link() { //--- enable the link of the town's side to all linked camps ---// Firm* firmPtr; int i; for( i=0 ; ifirm_id != FIRM_CAMP ) continue; //--- don't set it if the town and camp both belong to a human player, the player will set it himself ---// if( firmPtr->nation_recno == nation_recno && nation_recno && !nation_array[nation_recno]->is_ai() ) { continue; } //--------------------------------------------// toggle_firm_link( i+1, 1, COMMAND_AUTO ); } //------- update camp link status -------// has_linked_own_camp = 0; has_linked_enemy_camp = 0; for( i=0 ; ifirm_id!=FIRM_CAMP || !firmPtr->overseer_recno ) continue; if( firmPtr->nation_recno == nation_recno ) has_linked_own_camp = 1; else has_linked_enemy_camp = 1; } } //------ End of function Town::update_camp_link -----// //------- Begin of function Town::closest_own_camp -------// // // Return the firm recno of the camp that is closest to this town. // int Town::closest_own_camp() { Firm *firmPtr; int curDistance, minDistance=1000, closestFirmRecno=0; for( int i=linked_firm_count-1 ; i>=0 ; i-- ) { firmPtr = firm_array[ linked_firm_array[i] ]; if( firmPtr->firm_id != FIRM_CAMP || firmPtr->nation_recno != nation_recno ) { continue; } curDistance = m.points_distance( center_x, center_y, firmPtr->center_x, firmPtr->center_y ); if( curDistance < minDistance ) { minDistance = curDistance; closestFirmRecno = firmPtr->firm_recno; } } return closestFirmRecno; } //-------- End of function Town::closest_own_camp ---------//