/** @file /ai/Strategizer/expansion.cpp @brief Zdrojovy kod modulu expanze AI. Zdrojovy kod modulu expanze AI. @author PZ @version 0.1 */ #include "ai/Strategizer/expansion.h" using namespace World; namespace ai_ns { namespace strategizer_ns { bool type_building_statitics::operator<(const struct type_building_statitics& tbs) { return (build_orderSS=SS; BuildingTemplateNumbers.clear(); BuildingStatistics.clear(); BuildOrder=0; loadExpansionCoefs(); } CStrategyExpansionEngine::~CStrategyExpansionEngine() { if (BuildOrder) KMemFree(BuildOrder); BuildOrder=0; BuildingTemplateNumbers.clear(); BuildingStatistics.clear(); } void CStrategyExpansionEngine::setPlayer(int passed_player_ID) { playerID=passed_player_ID; } void CStrategyExpansionEngine::loadExpansionCoefs() { ai_ns::CAIScriptCaller* sc=new ai_ns::CAIScriptCaller(); ai_ns::CTCLAIVar* varsout=sc->countScript(ID_SCRIPT_STRATEGY_COEFS,0); MoneyRatioAttack=varsout->getReal("DEFAULT_ATTACK_INCOME_RATIO"); MoneyRatioDefence=varsout->getReal("DEFAULT_DEFENCE_INCOME_RATIO"); MoneyRatioExpansion=varsout->getReal("DEFAULT_EXPANSION_INCOME_RATIO"); char* tmpbo=varsout->getString("BUILD_ORDER"); int bolen=(int) (strlen(tmpbo)); if (BuildOrder) KMemFree(BuildOrder); BuildOrder=(char*) KMemAlloc((bolen+1)*sizeof(char)); memcpy(BuildOrder,tmpbo,bolen); BuildOrder[bolen]='\0'; TBuildingStatistic bs; bs.building_type=1; bs.build_order=getBuildingOrder(bs.building_type); bs.building_num=varsout->getInt("CASTLE_TEMPLATE_NUMBER"); BuildingTemplateNumbers.push_back(bs); bs.building_type=2; bs.build_order=getBuildingOrder(bs.building_type); bs.building_num=varsout->getInt("FORTRESS_TEMPLATE_NUMBER"); BuildingTemplateNumbers.push_back(bs); bs.building_type=3; bs.build_order=getBuildingOrder(bs.building_type); bs.building_num=varsout->getInt("MAGIC_TOWER_TEMPLATE_NUMBER"); BuildingTemplateNumbers.push_back(bs); bs.building_type=4; bs.build_order=getBuildingOrder(bs.building_type); bs.building_num=varsout->getInt("WEAPONRY_TEMPLATE_NUMBER"); BuildingTemplateNumbers.push_back(bs); bs.building_type=5; bs.build_order=getBuildingOrder(bs.building_type); bs.building_num=varsout->getInt("BARRACKS_TEMPLATE_NUMBER"); BuildingTemplateNumbers.push_back(bs); BuildingTemplateNumbers.sort(); SecondBuilderBorder=varsout->getInt("SECOND_BUILDER_BORDER"); BuildingsPerBuilder=varsout->getInt("BUILDINGS_PER_BUILDER"); MaxProductionBuildingsPerKingdom=varsout->getInt("MAX_PRODUCTION_BUILDINGS_PER_KINGDOM"); delete varsout; delete sc; } // najde nejblizsiho nezaukolovaneho stavitele (vrati jeho World ID), nebo vrati (-1) pokud zadneho nenalezne int CStrategyExpansionEngine::getNearestAccessibleFreeBuilderFromHex(int hexid) { int rv=-1; int best_value=-1; int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 104 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_UNIT_ON_HEXID(SIP->map,i)) { if ((UNIT_ON_HEXID(SIP->map,SIP->living_units,i).player==playerID) && (IS_BUILDER_UNIT_TYPE(UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).type))) { int current_builder_id=UNIT_ID_ON_HEXID(SIP->map,i); TAIUnitInfo* bi=SS->findUnitInfoByWorldID(current_builder_id); if (bi) { if (bi->global_desire==Expansion) { bool cbnf=true; std::BUILD_DESIRES_AI_INFO_CONTAINER::iterator bdIt; for(bdIt=SS->BuildDesiresInfo.begin();((bdIt!=SS->BuildDesiresInfo.end()) && (cbnf));bdIt++) { if ((bdIt->builder_assigned) && (bdIt->builder_id=current_builder_id) && (!(bdIt->done))) { cbnf=false; } } std::REPAIR_DESIRES_AI_INFO_CONTAINER::iterator rdIt; for(rdIt=SS->RepairDesiresInfo.begin();((rdIt!=SS->RepairDesiresInfo.end()) && (cbnf));rdIt++) { if ((rdIt->builder_assigned) && (rdIt->builder_id=current_builder_id) && (!(rdIt->done))) { cbnf=false; } } if (cbnf) // builder je volny - budu vyhledavat { PACKET_PATHFIND_REQUEST pfr; pfr.unit_id=current_builder_id; COORDS tmpcoords; tmpcoords.x=i%SIP->map->width(); tmpcoords.y=i/SIP->map->width(); pfr.from=tmpcoords; tmpcoords.x=hexid%SIP->map->width(); tmpcoords.y=hexid/SIP->map->width(); pfr.to=tmpcoords; pfr.pathfind_transparency=ai_ns::pathfind_ns::PFT_IgnoreMyUnits; pfr.points_of_movement=UNIT_ON_HEXID(SIP->map,SIP->living_units,i).points_of_movement; TPATH* dispPath=(TPATH*) KSendGlobalMessage(MSG_PATHFIND_REQUEST,MOD_STRATEGY,MOD_PATHFIND,&pfr); if (dispPath) { TPATH_ITERATOR dispPathIt=dispPath->begin(); int turn_count=0; int akt_pom=UNIT_ON_HEXID(SIP->map,SIP->living_units,i).points_of_movement; while (dispPathIt!=dispPath->end()) { if (akt_pomstep_cost) { akt_pom=UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).max_points_of_movement; turn_count++; } else { akt_pom-=dispPathIt->step_cost; } dispPathIt++; } if ((rv==-1) || (turn_countplayers))[playerID])->data()).game_data.money); if (whole_money<0) // dostal jsem nejakou pokutu a jsem v minusu - nemuzu nic { SS->MoneyAttack=0; SS->MoneyDefence=0; SS->MoneyExpansion=0; return; } int prev_money=SS->MoneyAttack+SS->MoneyDefence+SS->MoneyExpansion; int new_money=whole_money-prev_money; // mohou byt nepresnosti se zaokrouhlovanim, ale to nevadi - zaokrouhluji pouze dolu if (new_money>=0) // penize pribyly { SS->MoneyAttack+=((int) (MoneyRatioAttack*new_money)); SS->MoneyDefence+=((int) (MoneyRatioDefence*new_money)); SS->MoneyExpansion+=((int) (MoneyRatioExpansion*new_money)); } else { // penize ubyly, predchozi naakumulovane hodnoty pouze prislusne zkratim SS->MoneyAttack=(int) (SS->MoneyAttack*(((double) whole_money)/((double) prev_money))); SS->MoneyDefence=(int) (SS->MoneyDefence*(((double) whole_money)/((double) prev_money))); SS->MoneyExpansion=(int) (SS->MoneyExpansion*(((double) whole_money)/((double) prev_money))); // mam moc jednotek na mesta - dat pul branicich nahodne na AttackUnassigned std::UNIT_AI_INFO_CONTAINER::iterator uiIt; for(uiIt=SS->UnitsInfo.begin();uiIt!=SS->UnitsInfo.end();uiIt++) { if (uiIt->global_desire==Defence) { if ((rand())%2) uiIt->global_desire=Attack_Unassigned; } } } } int CStrategyExpansionEngine::countPlannedBuildsPrice() { int rv=0; std::BUILD_DESIRES_AI_INFO_CONTAINER::iterator bdIt; for(bdIt=SS->BuildDesiresInfo.begin();bdIt!=SS->BuildDesiresInfo.end();bdIt++) { if (!(bdIt->started_to_build)) { rv+=((SIP->rules->building_types)[bdIt->building_type])->data().base_cost; } } return rv; } int CStrategyExpansionEngine::countPlannedRepairsPrice() { int rv=0; std::REPAIR_DESIRES_AI_INFO_CONTAINER::iterator rdIt; for(rdIt=SS->RepairDesiresInfo.begin();rdIt!=SS->RepairDesiresInfo.end();rdIt++) { rv+=(((SIP->rules->building_types)[BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,rdIt->repair_target_point).type])->data().repair_cost)*(BUILDING_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_buildings,rdIt->repair_target_point).lives-BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,rdIt->repair_target_point).lives); } return rv; } void CStrategyExpansionEngine::processHealingWithUnits() { // leceni jednotek int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 256 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_UNIT_ON_HEXID(SIP->map,i)) { if (UNIT_ON_HEXID(SIP->map,SIP->living_units,i).player==playerID) { // TODO: kriteria na leceni? - mel by validovat Wlk? CPlan* temp_plan=new CPlan(playerID); CUnitPlanAction_HealWounded* upa_hw=new CUnitPlanAction_HealWounded(UNIT_ID_ON_HEXID(SIP->map,i)); temp_plan->addActionToBack(upa_hw,PERFORM_IMMEDIATELY); temp_plan->deleteAllDoneActions(); delete temp_plan; } } } } } void CStrategyExpansionEngine::processRecruitingWithUnits() { // elitni rekrutace jednotek int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 281 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_UNIT_ON_HEXID(SIP->map,i)) { if ((UNIT_ON_HEXID(SIP->map,SIP->living_units,i).player==playerID) && (UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).max_lives>UNIT_ON_HEXID(SIP->map,SIP->living_units,i).lives)) { // TODO: kriteria na rekrutaci? - mel by validovat Wlk? int money_amount=UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).cure_cost*(UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).max_lives-UNIT_ON_HEXID(SIP->map,SIP->living_units,i).lives); if (SS->MoneyExpansion>=money_amount) { CPlan* temp_plan=new CPlan(playerID); CUnitPlanAction_EliteRecruit* upa_er=new CUnitPlanAction_EliteRecruit(UNIT_ID_ON_HEXID(SIP->map,i)); temp_plan->addActionToBack(upa_er,PERFORM_IMMEDIATELY); temp_plan->deleteAllDoneActions(); delete temp_plan; if (UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).max_lives==UNIT_ON_HEXID(SIP->map,SIP->living_units,i).lives) // rekrutace se zdarila { SS->MoneyExpansion-=money_amount; } } } } } } // neelitni rekrutace jednotek GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 312 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_UNIT_ON_HEXID(SIP->map,i)) { if ((UNIT_ON_HEXID(SIP->map,SIP->living_units,i).player==playerID) && (UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).max_lives>UNIT_ON_HEXID(SIP->map,SIP->living_units,i).lives)) { // TODO: kriteria na rekrutaci? - mel by validovat Wlk? int money_amount=UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).cure_cost*(UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).max_lives-UNIT_ON_HEXID(SIP->map,SIP->living_units,i).lives); if (SS->MoneyExpansion>=money_amount) { CPlan* temp_plan=new CPlan(playerID); CUnitPlanAction_NonEliteRecruit* upa_ner=new CUnitPlanAction_NonEliteRecruit(UNIT_ID_ON_HEXID(SIP->map,i)); temp_plan->addActionToBack(upa_ner,PERFORM_IMMEDIATELY); temp_plan->deleteAllDoneActions(); delete temp_plan; if (UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).max_lives==UNIT_ON_HEXID(SIP->map,SIP->living_units,i).lives) // rekrutace se zdarila { SS->MoneyExpansion-=money_amount; } } } } } } } void CStrategyExpansionEngine::updateExpansion() { // pokud je treba, vytrenuju noveho stavitele if (needToRecruitBuilder()) recruitBuilder(); // naplanuji opravy svych poskozenych budov planRepairs(); // naplanuji stavby novych budov if (shouldBuildNewBuildings()) planNewBuildings(); // zpracuji vsechny procesy staveb a oprav processAllBuildsAndRepairs(); // zkusim postavit most, pokud je treba buildBridge(); // naverbuju jednotky na defenzivu recruitDefence(); } void CStrategyExpansionEngine::planRepairs() { int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 356 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_BUILDING_ON_HEXID(SIP->map,i)) { if ((BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).player==playerID) && (BUILDING_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_buildings,i).construction_duration==0) && (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).livesmap,SIP->rules,SIP->living_buildings,i).lives)) { // nasel jsem svou poskozenou dostavenou budovu - jeste se podivam, zdali jiz neni naplanovana na opravu bool rdnf=true; std::REPAIR_DESIRES_AI_INFO_CONTAINER::iterator rdIt; for(rdIt=SS->RepairDesiresInfo.begin();((rdnf) && (rdIt!=SS->RepairDesiresInfo.end()));rdIt++) { rdnf=(i!=rdIt->repair_target_point); } if (rdnf) { // budova neni naplanovana pro opravu - to ted udelam TAIRepairDesireInfo new_repair_desire; new_repair_desire.builder_assigned=false; new_repair_desire.builder_id=-1; new_repair_desire.done=false; new_repair_desire.repair_target_point=i; new_repair_desire.started_to_repair=false; SS->RepairDesiresInfo.push_back(new_repair_desire); #ifdef AI_LOGGING LogAIDesires.LogMsg("AI player %d new repair desire - {Repair Target ID: %d }\n",playerID,new_repair_desire.repair_target_point); #endif } } } } } } void CStrategyExpansionEngine::planNewBuildings() { int mnbt=getMostNeededBuilding(); TPacket_MapAnalyzer_BestProductionBuildingPlace pmabpbp; pmabpbp.building_type=mnbt; pmabpbp.assigned_builder_position=-1; pmabpbp.planned_buildings_coordinates.clear(); std::BUILD_DESIRES_AI_INFO_CONTAINER::iterator bdIt2; for(bdIt2=SS->BuildDesiresInfo.begin();bdIt2!=SS->BuildDesiresInfo.end();bdIt2++) pmabpbp.planned_buildings_coordinates.push_back(bdIt2->build_target_point); pmabpbp.player_id=playerID; int* best_place=(int*) KSendGlobalMessage(MSG_MAPANALYZER_GET_BEST_PRODUCTION_BUILDING_PLACE,MOD_STRATEGY,MOD_MAPANALYZER,&pmabpbp); int placement=*best_place; KMemFree(best_place); if (placement!=-1) { // naplanuji stavbu dalsi budovy TAIBuildDesireInfo new_build_desire; new_build_desire.builder_assigned=false; new_build_desire.builder_id=-1; new_build_desire.building_type=mnbt; new_build_desire.done=false; new_build_desire.build_target_point=placement; new_build_desire.bridge_placement=-1; new_build_desire.building_orientation=(rand())%6; new_build_desire.started_to_build=false; SS->BuildDesiresInfo.push_back(new_build_desire); #ifdef AI_LOGGING LogAIDesires.LogMsg("AI player %d new build desire - {Building Type: %d },{Building Placement: %d }\n",playerID,new_build_desire.building_type,new_build_desire.build_target_point); #endif } } void CStrategyExpansionEngine::processAllBuildsAndRepairs() { // odmazu Done desires std::BUILD_DESIRES_AI_INFO_CONTAINER::iterator bdIt; for(bdIt=SS->BuildDesiresInfo.begin();bdIt!=SS->BuildDesiresInfo.end();) { if (bdIt->done) { #ifdef AI_LOGGING LogAIDesires.LogMsg("AI player %d - Build desire deleted - {Building Type: %d },{Building Placement: %d }\n",playerID,bdIt->building_type,bdIt->build_target_point); #endif bdIt=SS->BuildDesiresInfo.erase(bdIt); } else bdIt++; } std::REPAIR_DESIRES_AI_INFO_CONTAINER::iterator rdIt; for(rdIt=SS->RepairDesiresInfo.begin();rdIt!=SS->RepairDesiresInfo.end();) { if (rdIt->done) { #ifdef AI_LOGGING LogAIDesires.LogMsg("AI player %d - Repair desire deleted - {Repair Target: %d }\n",playerID,rdIt->repair_target_point); #endif rdIt=SS->RepairDesiresInfo.erase(rdIt); } else rdIt++; } bdIt=SS->BuildDesiresInfo.begin(); rdIt=SS->RepairDesiresInfo.begin(); while (!((bdIt==SS->BuildDesiresInfo.end()) && (rdIt==SS->RepairDesiresInfo.end()))) { if (rdIt!=SS->RepairDesiresInfo.end()) { processRepair(&(*rdIt)); rdIt++; } if(bdIt!=SS->BuildDesiresInfo.end()) { processBuild(&(*bdIt)); bdIt++; } } } void CStrategyExpansionEngine::getUnitsOutOfBuildings() { int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 475 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if ((IS_UNIT_ON_HEXID(SIP->map,i)) && (IS_BUILDING_ON_HEXID(SIP->map,i))) { if ((UNIT_ON_HEXID(SIP->map,SIP->living_units,i).player==playerID) && (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).player==playerID)) { // jeste testuji, zdali se nejedna o stavitele, jenz jeste stavi budovu nebo jednotku na moste if ((!((IS_BUILDER_UNIT_TYPE(UNIT_ON_HEXID(SIP->map,SIP->living_units,i).type)) && (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).construction_duration!=0))) && (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).type!=BRIDGE_BUILDING_TYPE_ID)) { int unit_id=UNIT_ID_ON_HEXID(SIP->map,i); TPacket_MapAnalyzer_GetActionRadius pmagar; pmagar.position=i; pmagar.radius_size=1; TPacket_MapAnalyzer_ActionRadiusResponse* ar=(TPacket_MapAnalyzer_ActionRadiusResponse*) KSendGlobalMessage(MSG_MAPANALYZER_GET_ACTION_RADIUS,MOD_STRATEGY,MOD_MAPANALYZER,&pmagar); std::list::iterator hIt; bool unm=true; for(hIt=(ar->radius_hexes).begin();((unm) && (hIt!=(ar->radius_hexes).end()));hIt++) { if ((*hIt!=i) && (!(IS_BUILDING_ON_HEXID(SIP->map,*hIt)))) { CPlan* temp_plan=new CPlan(playerID); CUnitPlanAction_Go* upag=new CUnitPlanAction_Go(unit_id); upag->path_target=*hIt; upag->transparency=ai_ns::pathfind_ns::PFT_UnitsNotTransparent; // tady testuji transparenci na vsechny okolni hexy temp_plan->addActionToBack(upag,PERFORM_IMMEDIATELY); temp_plan->deleteAllDoneActions(); delete temp_plan; // test, zdali jednotka opravdu vysla z budovy if (IS_UNIT_ON_HEXID(SIP->map,*hIt)) { if (unit_id==UNIT_ID_ON_HEXID(SIP->map,*hIt)) { unm=false; } } } } delete ar; } } } } } } void CStrategyExpansionEngine::processBuild(TAIBuildDesireInfo* build_desire) { // ukoncene stavby neresim - ty odmazavam explicitne if (build_desire->done) return; if (build_desire->builder_assigned) { // desiru je jiz prirazen stavitel if (build_desire->started_to_build) { // stavitel je jiz na cilovem hexu a zacal stavet - jenom zkontroluji, jestli je jiz dostaveno // pokud se jedna o most - musim kontrolovat jiny hex if (build_desire->building_type==BRIDGE_BUILDING_TYPE_ID) { if (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,build_desire->bridge_placement).construction_duration==0) { build_desire->done=true; build_desire->builder_id=-1; build_desire->builder_assigned=false; } } else if (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,build_desire->build_target_point).construction_duration==0) { build_desire->done=true; build_desire->builder_id=-1; build_desire->builder_assigned=false; } } else { // stavitel jeste nezacal stavet if (UNIT_ID_ON_HEXID(SIP->map,build_desire->build_target_point)==build_desire->builder_id) { // stavitel jiz dorazil na cilovy hex if (SS->MoneyExpansion>=((SIP->rules->building_types)[build_desire->building_type])->data().base_cost) { CPlan* build_building_plan=new CPlan(playerID); CUnitPlanAction_Build* build_action=new CUnitPlanAction_Build(build_desire->builder_id); build_action->build_target=((build_desire->building_type==BRIDGE_BUILDING_TYPE_ID)?(build_desire->bridge_placement):(build_desire->build_target_point)); build_action->building_type=build_desire->building_type; build_action->building_orientation=build_desire->building_orientation; build_building_plan->addActionToBack(build_action,PERFORM_IMMEDIATELY); build_building_plan->processPlan(); delete build_building_plan; // jeste otestuji, zdali se zacalo opravdu stavet // musim rozlisit pripad s mostem int builder_position=((build_desire->building_type==BRIDGE_BUILDING_TYPE_ID)?(build_desire->bridge_placement):(build_desire->build_target_point)); if (IS_UNIT_ON_HEXID(SIP->map,builder_position)) { if ((UNIT_ON_HEXID(SIP->map,SIP->living_units,builder_position).state==US_BUILDING) || (UNIT_ON_HEXID(SIP->map,SIP->living_units,builder_position).state==US_HAS_STARTED_BUILDING)) { build_desire->started_to_build=true; SS->MoneyExpansion-=((SIP->rules->building_types)[build_desire->building_type])->data().base_cost; } } } } else { TPacket_MapAnalyzer_FindUnitPosition pmafup; pmafup.unit_world_id=build_desire->builder_id; int* uprv=(int*) KSendGlobalMessage(MSG_MAPANALYZER_FIND_UNIT_POSITION,MOD_STRATEGY,MOD_MAPANALYZER,&pmafup); int bp=*uprv; KMemFree(uprv); // zkusim zkontrolovat, zdali se na hex mohu vubec dostat PACKET_PATHFIND_REQUEST pathfr; pathfr.unit_id=build_desire->builder_id; COORDS sh,th; sh.x=bp%SIP->map->width(); sh.y=bp/SIP->map->width(); th.x=(build_desire->build_target_point)%(SIP->map->width()); th.y=(build_desire->build_target_point)/(SIP->map->width()); pathfr.from=sh; pathfr.to=th; pathfr.pathfind_transparency=ai_ns::pathfind_ns::PFT_IgnoreMyUnits; pathfr.points_of_movement=UNIT_ON_HEX(SIP->map,SIP->living_units,sh.x,sh.y).points_of_movement; TPATH* dispPath=(TPATH*) KSendGlobalMessage(MSG_PATHFIND_REQUEST,MOD_STRATEGY,MOD_PATHFIND,&pathfr); if (dispPath) { delete dispPath; } else { // cesta nenalezena - preplanuji cil stavby pro stavitele if (build_desire->building_type!=BRIDGE_BUILDING_TYPE_ID) // otestuji, zdali se nejedna o most - ten nepreplanovavam { TPacket_MapAnalyzer_BestProductionBuildingPlace pmabpbp; pmabpbp.building_type=build_desire->building_type; pmabpbp.assigned_builder_position=bp; pmabpbp.planned_buildings_coordinates.clear(); std::BUILD_DESIRES_AI_INFO_CONTAINER::iterator bdIt2; for(bdIt2=SS->BuildDesiresInfo.begin();bdIt2!=SS->BuildDesiresInfo.end();bdIt2++) pmabpbp.planned_buildings_coordinates.push_back(bdIt2->build_target_point); pmabpbp.player_id=playerID; int* best_place=(int*) KSendGlobalMessage(MSG_MAPANALYZER_GET_BEST_PRODUCTION_BUILDING_PLACE,MOD_STRATEGY,MOD_MAPANALYZER,&pmabpbp); #ifdef AI_LOGGING LogAIDesires.LogMsg("AI player %d build desire target replanned - {Building Type: %d },{Old Building Desired Placement: %d },{New Building Desired Placement: %d }\n",playerID,build_desire->building_type,build_desire->build_target_point,*best_place); #endif build_desire->build_target_point=*best_place; KMemFree(best_place); } } if (build_desire->build_target_point==-1) { // preplanovani se nepovedlo - stavitel nenalezl moznou pozici - tento build desire zrusim (dam mu Done priznak) a stavitele odregistruji build_desire->builder_assigned=false; build_desire->done=true; } else { // preplanovani se povedlo - nalezena nova pozice // stavitel jeste nedorazil na cilovy hex CPlan* temp_plan=new CPlan(playerID); CUnitPlanAction_Go* dia=new CUnitPlanAction_Go(build_desire->builder_id); dia->path_target=build_desire->build_target_point; dia->transparency=ai_ns::pathfind_ns::PFT_IgnoreTargetUnit; temp_plan->addActionToBack(dia,PERFORM_IMMEDIATELY); temp_plan->deleteAllDoneActions(); // posilam jeste jednou s jinou transparenci - to je pokud by cesta neexistovala pres me jednotky CUnitPlanAction_Go* dia2=new CUnitPlanAction_Go(build_desire->builder_id); dia2->path_target=build_desire->build_target_point; dia2->transparency=ai_ns::pathfind_ns::PFT_IgnoreMyUnitsAndTargetUnit; temp_plan->addActionToBack(dia2,PERFORM_IMMEDIATELY); temp_plan->deleteAllDoneActions(); delete temp_plan; // pustim processing tohoto build desiru to znovu, pokud jiz stavitel dorazil na misto stavby if (UNIT_ID_ON_HEXID(SIP->map,build_desire->build_target_point)==build_desire->builder_id) processBuild(build_desire); } } } } else { // desiru jeste neni prirazen stavitel int fbID=getNearestAccessibleFreeBuilderFromHex(build_desire->build_target_point); if (fbID!=-1) { // nasel jsem nezaukolovaneho stavitele build_desire->builder_id=fbID; build_desire->builder_assigned=true; build_desire->started_to_build=false; // pustim processing tohoto build desiru to znovu processBuild(build_desire); } } } void CStrategyExpansionEngine::processRepair(TAIRepairDesireInfo* repair_desire) { // ukoncene opravy neresim - ty odmazavam explicitne if (repair_desire->done) return; if (repair_desire->builder_assigned) { // desiru je jiz prirazen stavitel if (repair_desire->started_to_repair) { // stavitel je jiz na cilovem hexu a zacal opravovat - jenom zkontroluji, jestli je jiz doopraveno if (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,repair_desire->repair_target_point).lives==BUILDING_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_buildings,repair_desire->repair_target_point).lives) { repair_desire->done=true; repair_desire->builder_id=-1; repair_desire->builder_assigned=false; } } else { // stavitel je prirazen, ale jeste opravovat nezacal - zkontroluji, zdali je jiz na cilovem hexu if (UNIT_ID_ON_HEXID(SIP->map,repair_desire->repair_target_point)==repair_desire->builder_id) { // stavitel jiz dorazil na cilovy hex if (SS->MoneyExpansion>=(((BUILDING_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_buildings,repair_desire->repair_target_point).lives-BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,repair_desire->repair_target_point).lives))*(((SIP->rules->building_types)[BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,repair_desire->repair_target_point).type])->data().repair_cost))) { CPlan* repair_building_plan=new CPlan(playerID); CUnitPlanAction_Repair* repair_action=new CUnitPlanAction_Repair(repair_desire->builder_id); repair_action->building_id=BUILDING_ID_ON_HEXID(SIP->map,repair_desire->repair_target_point); repair_building_plan->addActionToBack(repair_action,PERFORM_IMMEDIATELY); repair_building_plan->processPlan(); delete repair_building_plan; // jeste otestuji, zdali se zacalo opravdu opravovat if ((UNIT_ON_HEXID(SIP->map,SIP->living_units,repair_desire->repair_target_point).state==US_BUILDING) || (UNIT_ON_HEXID(SIP->map,SIP->living_units,repair_desire->repair_target_point).state==US_HAS_STARTED_BUILDING)) { repair_desire->started_to_repair=true; SS->MoneyExpansion-=(((BUILDING_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_buildings,repair_desire->repair_target_point).lives-BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,repair_desire->repair_target_point).lives))*(((SIP->rules->building_types)[BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,repair_desire->repair_target_point).type])->data().repair_cost)); } } } else { // stavitel jeste nedorazil na cilovy hex CPlan* temp_plan=new CPlan(playerID); CUnitPlanAction_Go* dia=new CUnitPlanAction_Go(repair_desire->builder_id); dia->path_target=repair_desire->repair_target_point; dia->transparency=ai_ns::pathfind_ns::PFT_IgnoreTargetUnit; temp_plan->addActionToBack(dia,PERFORM_IMMEDIATELY); temp_plan->deleteAllDoneActions(); // posilam jeste jednou s jinou transparenci - to je pokud by cesta neexistovala pres me jednotky CUnitPlanAction_Go* dia2=new CUnitPlanAction_Go(repair_desire->builder_id); dia2->path_target=repair_desire->repair_target_point; dia2->transparency=ai_ns::pathfind_ns::PFT_IgnoreMyUnitsAndTargetUnit; temp_plan->addActionToBack(dia2,PERFORM_IMMEDIATELY); temp_plan->deleteAllDoneActions(); delete temp_plan; // pustim processing tohoto repair desiru znovu, pokud jiz stavitel dorazil na misto stavby if (UNIT_ID_ON_HEXID(SIP->map,repair_desire->repair_target_point)==repair_desire->builder_id) processRepair(repair_desire); } } } else { // desiru jeste neni prirazen stavitel int fbID=getNearestAccessibleFreeBuilderFromHex(repair_desire->repair_target_point); if (fbID!=-1) { // nasel jsem nezaukolovaneho stavitele repair_desire->builder_id=fbID; repair_desire->builder_assigned=true; repair_desire->started_to_repair=false; // pustim processing tohoto repair desiru to znovu processRepair(repair_desire); } } } void CStrategyExpansionEngine::recruitDefence() { int PlayerEmpireCenter; TPacket_MapAnalyzer_FindPlayerEmpireCenter pmafpec; pmafpec.player_id=playerID; int* pec_result=(int*) KSendGlobalMessage(MSG_MAPANALYZER_FIND_PLAYER_EMPIRE_CENTER,MOD_STRATEGY,MOD_MAPANALYZER,&pmafpec); PlayerEmpireCenter=*pec_result; KMemFree(pec_result); int oldDefenceMoney=-1; while(oldDefenceMoney!=SS->MoneyDefence) // tato podminka znamena, ze uz na vice nemam { oldDefenceMoney=SS->MoneyDefence; int some_unit_type=selectToProduceRandomPossibleUnitForDefence(); TPacket_MapAnalyzer_NearestFreeProductionBuildingForUnitTrain pmanfpbfut; pmanfpbfut.player_id=playerID; pmanfpbfut.start_hex=PlayerEmpireCenter; pmanfpbfut.unit_type=some_unit_type; int* bbp=(int*) KSendGlobalMessage(MSG_MAPANALYZER_GET_NEAREST_FREE_PRODUCTION_BUILDING_FOR_UNIT_TRAIN,MOD_STRATEGY,MOD_MAPANALYZER,&pmanfpbfut); if ((*bbp!=-1) && (((SIP->rules->unit_types)[some_unit_type])->data().costMoneyDefence)) { CPlan* build_unit_plan=new CPlan(playerID); CBuildingPlanAction_TrainUnit* bua=new CBuildingPlanAction_TrainUnit(BUILDING_ID_ON_HEXID(SIP->map,*bbp)); bua->trained_unit_type=some_unit_type; build_unit_plan->addActionToBack(bua,PERFORM_IMMEDIATELY); build_unit_plan->processPlan(); delete build_unit_plan; // test, zdali se jednotka opravdu vytvorila if (IS_UNIT_ON_HEXID(SIP->map,*bbp)) { if (UNIT_ON_HEXID(SIP->map,SIP->living_units,*bbp).type==some_unit_type) { // jednotka se skutecne vytvorila -> zaradim ji do struktur a odectu penize SS->MoneyDefence-=((SIP->rules->unit_types)[some_unit_type])->data().cost; TAIUnitInfo new_ui; new_ui.global_desire=Defence; new_ui.unit_type=some_unit_type; new_ui.world_id=UNIT_ID_ON_HEXID(SIP->map,*bbp); SS->UnitsInfo.push_back(new_ui); } } } KMemFree(bbp); } } int CStrategyExpansionEngine::selectToProduceRandomPossibleUnitForDefence() { std::list possible_producing; possible_producing.clear(); int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 815 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_BUILDING_ON_HEXID(SIP->map,i)) { if ((BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).player==playerID) && (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).construction_duration==0)) { TUnitsIterator uIt; for(uIt=SIP->rules->unit_types.begin();uIt!=SIP->rules->unit_types.end();uIt++) { TPacket_MapAnalyzer_UnitTrainableInBuilding pmautib; pmautib.building_placement=i; pmautib.unit_type=uIt->first; bool* ut_msg_res=(bool*) KSendGlobalMessage(MSG_MAPANALYZER_UNIT_TRAINABLE_IN_BUILDING,MOD_STRATEGY,MOD_MAPANALYZER,&pmautib); bool upttib=*ut_msg_res; KMemFree(ut_msg_res); if ((UNIT_FOR_DEFENCE_UNIT_TYPE(uIt->first)) && (upttib) && (((SIP->rules->unit_types)[uIt->first])->data().attack_range>=1)) { possible_producing.push_back(uIt->first); } } } } } } if (possible_producing.empty()) return -1; else { int prod_choices_rand_pos=((rand())%((int) (possible_producing.size()))); std::list::iterator ppIt=possible_producing.begin(); int pccntr; for(pccntr=0;pccntrmap->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_BUILDING_ON_HEXID(SIP->map,i)) { // spocitam vsechny sve budovy, i rozestavene if (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).player==playerID) { int found_building_type=BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).type; bool btnf=true; std::list::iterator bsIt; for(bsIt=BuildingStatistics.begin();((btnf) && (bsIt!=BuildingStatistics.end()));) { if (bsIt->building_type==found_building_type) btnf=false; else bsIt++; } if (!btnf) { (bsIt->building_num)++; } } } } } // pripoctu jeste planovane budovy std::BUILD_DESIRES_AI_INFO_CONTAINER::iterator bdIt; for(bdIt=SS->BuildDesiresInfo.begin();bdIt!=SS->BuildDesiresInfo.end();bdIt++) { if ((!(bdIt->done)) && (!(bdIt->started_to_build))) { bool btnf=true; std::list::iterator bsIt; for(bsIt=BuildingStatistics.begin();((btnf) && (bsIt!=BuildingStatistics.end()));) { if (bsIt->building_type==bdIt->building_type) btnf=false; else bsIt++; } if (!btnf) { (bsIt->building_num)++; } } } // TODO: uplne odmazat, az nebude treba /* #ifdef AI_LOGGING LogAIDesires.LogMsg("Player %d Building statistics:\n",playerID); std::list::iterator DbsIt; for(DbsIt=BuildingStatistics.begin();DbsIt!=BuildingStatistics.end();DbsIt++) { LogAIDesires.LogMsg("Building type: %d,Building number: %d\n",DbsIt->building_type,DbsIt->building_num); } #endif */ } int CStrategyExpansionEngine::getMostNeededBuilding() throw(E_8K_AI_Strategy_InvalidBuildingStatistics) { // spocitam aktualni pocty mych budov vcetne planovanych countBuildingStatistics(); if (BuildingStatistics.size()==0) THROW(E_8K_AI_Strategy_InvalidBuildingStatistics,"Invalidni zaznamy o poctu budov."); if (BuildingStatistics.size()!=BuildingTemplateNumbers.size()) THROW(E_8K_AI_Strategy_InvalidBuildingStatistics,"Invalidni zaznamy o poctu budov."); // spocitam koeficienty pomeru vuci templatam a vezmu nejmensi nenulovy std::list::iterator bsIt; std::list::iterator btnIt=BuildingTemplateNumbers.begin(); int best_type=-1; double lowest_ratio=0.0; for(bsIt=BuildingStatistics.begin();(bsIt!=BuildingStatistics.end());bsIt++) { if (bsIt->building_type!=btnIt->building_type) THROW(E_8K_AI_Strategy_InvalidBuildingStatistics,"Neodpovidajici zaznamy typu budov."); // budovu tohoto typu jeste vubec nemam a stavet ji mam postupne v planu - protoze beru podle prioritnich poradi, budu stavet prave ji if ((bsIt->building_num==0) && (btnIt->building_type>0)) return (btnIt->building_type); if (btnIt->building_num!=0) { if ((best_type==-1) || (lowest_ratio>(((double) (bsIt->building_num))/((double) (btnIt->building_num))))) { best_type=bsIt->building_type; lowest_ratio=(((double) (bsIt->building_num))/((double) (btnIt->building_num))); } } btnIt++; } return best_type; } bool CStrategyExpansionEngine::needToRecruitBuilder() { int builder_count=0; // spocitam stavitele std::UNIT_AI_INFO_CONTAINER::iterator uiIt; for(uiIt=SS->UnitsInfo.begin();uiIt!=SS->UnitsInfo.end();uiIt++) { if (uiIt->unit_type==BUILDER_UNIT_TYPE_ID) builder_count++; } if (builder_count==0) return true; // spocitam pocty budov ve statistikach - to je kriterium k doporucenemu mnozstvi stavitelu int whole_buildings_num=0; countBuildingStatistics(); BuildingStatistics.sort(); std::list::iterator bsIt; for(bsIt=BuildingStatistics.begin();(bsIt!=BuildingStatistics.end());bsIt++) whole_buildings_num+=bsIt->building_num; return (builder_count<(1+((whole_buildings_num+BuildingsPerBuilder-SecondBuilderBorder-1)/BuildingsPerBuilder))); } bool CStrategyExpansionEngine::recruitBuilder() { int PlayerEmpireCenter; TPacket_MapAnalyzer_FindPlayerEmpireCenter pmafpec; pmafpec.player_id=playerID; int* pec_result=(int*) KSendGlobalMessage(MSG_MAPANALYZER_FIND_PLAYER_EMPIRE_CENTER,MOD_STRATEGY,MOD_MAPANALYZER,&pmafpec); PlayerEmpireCenter=*pec_result; KMemFree(pec_result); TPacket_MapAnalyzer_NearestFreeProductionBuildingForUnitTrain pmanfpbfut; pmanfpbfut.player_id=playerID; pmanfpbfut.start_hex=PlayerEmpireCenter; pmanfpbfut.unit_type=BUILDER_UNIT_TYPE_ID; int* bbp=(int*) KSendGlobalMessage(MSG_MAPANALYZER_GET_NEAREST_FREE_PRODUCTION_BUILDING_FOR_UNIT_TRAIN,MOD_STRATEGY,MOD_MAPANALYZER,&pmanfpbfut); int pbh=*bbp; KMemFree(bbp); if (pbh!=-1) { // nasel jsem budovu, ktera mi muze stavitele vytvorit - jeste zkontroluju, jestli na nej mam penize if (SS->MoneyExpansion>=((SIP->rules->unit_types)[BUILDER_UNIT_TYPE_ID])->data().cost) { CPlan* build_builder_plan=new CPlan(playerID); CBuildingPlanAction_TrainUnit* bua=new CBuildingPlanAction_TrainUnit(BUILDING_ID_ON_HEXID(SIP->map,pbh)); bua->trained_unit_type=BUILDER_UNIT_TYPE_ID; build_builder_plan->addActionToBack(bua,PERFORM_IMMEDIATELY); build_builder_plan->processPlan(); delete build_builder_plan; // test, zdali se jednotka opravdu vytvorila if (IS_UNIT_ON_HEXID(SIP->map,pbh)) { if (UNIT_ON_HEXID(SIP->map,SIP->living_units,pbh).type==BUILDER_UNIT_TYPE_ID) { // jednotka se skutecne vytvorila -> zaradim ji do struktur a odectu penize SS->MoneyExpansion-=((SIP->rules->unit_types)[BUILDER_UNIT_TYPE_ID])->data().cost; TAIUnitInfo new_ui; new_ui.global_desire=Expansion; new_ui.unit_type=BUILDER_UNIT_TYPE_ID; new_ui.world_id=UNIT_ID_ON_HEXID(SIP->map,pbh); SS->UnitsInfo.push_back(new_ui); return true; } } } } return false; } void CStrategyExpansionEngine::buildBridge() { // pokud nemam stavitele, nebudu ani resit if (!(hasBuilder())) return; // projedu Build desires, zdali uz nahodou most nestavim std::BUILD_DESIRES_AI_INFO_CONTAINER::iterator bdIt; for(bdIt=SS->BuildDesiresInfo.begin();bdIt!=SS->BuildDesiresInfo.end();bdIt++) { if (bdIt->building_type==BRIDGE_BUILDING_TYPE_ID) return; } TPacket_MapAnalyzer_BridgeBuildingAnalysis pmabba; pmabba.player_id=playerID; TPacket_MapAnalyzer_BridgeBuildingResponse* bbp_result=(TPacket_MapAnalyzer_BridgeBuildingResponse*) KSendGlobalMessage(MSG_MAPANALYZER_BRIDGE_BUILDING_ANALYSIS,MOD_STRATEGY,MOD_MAPANALYZER,&pmabba); if (bbp_result) { // naplanuji stavbu mostu TAIBuildDesireInfo new_build_desire; new_build_desire.builder_assigned=false; new_build_desire.builder_id=-1; new_build_desire.building_type=BRIDGE_BUILDING_TYPE_ID; new_build_desire.done=false; new_build_desire.build_target_point=bbp_result->builder_position; new_build_desire.bridge_placement=bbp_result->bridge_placement; new_build_desire.building_orientation=bbp_result->bridge_orientation; new_build_desire.started_to_build=false; SS->BuildDesiresInfo.push_back(new_build_desire); #ifdef AI_LOGGING LogAIDesires.LogMsg("AI player %d new build desire - {Building Type: Bridge },{Bridge Placement: %d },{Builder Position: %d }\n",playerID,new_build_desire.bridge_placement,new_build_desire.build_target_point); #endif delete bbp_result; } } void CStrategyExpansionEngine::processOnlyExpansionUnitsState() throw(E_8K_AI_Strategy_CantFindSelectedExpansionUnit) { // nemam zadne mesta a utocne jednotky - zkusim najit nejaky neutralni cil // najdu expanzni jednotku, se kterou budu obsazovat neutralni entity int feu_id=-1; std::UNIT_AI_INFO_CONTAINER::iterator uiIt; for(uiIt=SS->UnitsInfo.begin();((feu_id==-1) && (uiIt!=SS->UnitsInfo.end()));uiIt++) { if ((uiIt->global_desire==Expansion) && (EXPANSION_ONLY_UNIT_TYPE(uiIt->unit_type))) feu_id=uiIt->world_id; } if (feu_id==-1) return; // nenasel jsem zadnou expanzni jednotku // naleznu jeste pozici teto expanzni jednotky int eup=-1; int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 1099 expansion"); for(i=0;((eup==-1) && (i<(SIP->map->width()*SIP->map->height())));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_UNIT_ON_HEXID(SIP->map,i)) { if (UNIT_ID_ON_HEXID(SIP->map,i)==feu_id) eup=i; } } } if (eup==-1) THROW(E_8K_AI_Strategy_CantFindSelectedExpansionUnit,"Zvolena expanzni jednotka nebyla nalezena."); // nepodarilo se mi nalez zvolenou jednotku - toto je chybovy stav // prvne zkousim mesta GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 1114 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if ((SIP->map->getHexById(i)->data()).terrain==TT_TOWN) { TPacket_MapAnalyzer_FindCityByPosition pfcbp; pfcbp.position=i; TOWN* str_city=(TOWN*) KSendGlobalMessage(MSG_MAPANALYZER_FIND_CITY_BY_POSITION,MOD_STRATEGY,MOD_MAPANALYZER,&pfcbp); if (str_city->owner==0) { // nasel jsem neutralni mesto // zkusim k nemu najit natvrdo cestu PACKET_PATHFIND_REQUEST pathfr; pathfr.unit_id=feu_id; COORDS sh,th; sh.x=eup%SIP->map->width(); sh.y=eup/SIP->map->width(); th.x=(str_city->position[0])%(SIP->map->width()); th.y=(str_city->position[0])/(SIP->map->width()); pathfr.from=sh; pathfr.to=th; pathfr.pathfind_transparency=ai_ns::pathfind_ns::PFT_UnitsNotTransparent; pathfr.points_of_movement=UNIT_ON_HEX(SIP->map,SIP->living_units,sh.x,sh.y).points_of_movement; TPATH* dispPath=(TPATH*) KSendGlobalMessage(MSG_PATHFIND_REQUEST,MOD_STRATEGY,MOD_PATHFIND,&pathfr); if (dispPath) { // cesta existuje - expanzni jednotku po ni poslu CPlan* temp_plan=new CPlan(playerID); CUnitPlanAction_Go* dia=new CUnitPlanAction_Go(feu_id); dia->path_target=str_city->position[0]; dia->transparency=ai_ns::pathfind_ns::PFT_UnitsNotTransparent; temp_plan->addActionToBack(dia,PERFORM_IMMEDIATELY); temp_plan->deleteAllDoneActions(); delete temp_plan; delete dispPath; return; } } } } } // pak zkousim budovy GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 1160 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_BUILDING_ON_HEXID(SIP->map,i)) { if (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).player==0) { // nasel jsem neutralni budovu // zkusim k ni najit natvrdo cestu PACKET_PATHFIND_REQUEST pathfr; pathfr.unit_id=feu_id; COORDS sh,th; sh.x=eup%SIP->map->width(); sh.y=eup/SIP->map->width(); th.x=i%(SIP->map->width()); th.y=i/(SIP->map->width()); pathfr.from=sh; pathfr.to=th; pathfr.pathfind_transparency=ai_ns::pathfind_ns::PFT_UnitsNotTransparent; pathfr.points_of_movement=UNIT_ON_HEX(SIP->map,SIP->living_units,sh.x,sh.y).points_of_movement; TPATH* dispPath=(TPATH*) KSendGlobalMessage(MSG_PATHFIND_REQUEST,MOD_STRATEGY,MOD_PATHFIND,&pathfr); if (dispPath) { // cesta existuje - expanzni jednotku po ni poslu CPlan* temp_plan=new CPlan(playerID); CUnitPlanAction_Go* dia=new CUnitPlanAction_Go(feu_id); dia->path_target=i; dia->transparency=ai_ns::pathfind_ns::PFT_UnitsNotTransparent; temp_plan->addActionToBack(dia,PERFORM_IMMEDIATELY); temp_plan->deleteAllDoneActions(); delete temp_plan; delete dispPath; return; } } } } } } bool CStrategyExpansionEngine::hasCities() { int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 1206 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if ((SIP->map->getHexById(i)->data()).terrain==TT_TOWN) { TPacket_MapAnalyzer_FindCityByPosition pfcbp; pfcbp.position=i; TOWN* str_city=(TOWN*) KSendGlobalMessage(MSG_MAPANALYZER_FIND_CITY_BY_POSITION,MOD_STRATEGY,MOD_MAPANALYZER,&pfcbp); if (str_city->owner==playerID) return true; } } } return false; } bool CStrategyExpansionEngine::hasProductionBuildings() { int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 1227 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_BUILDING_ON_HEXID(SIP->map,i)) { if ((BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).player==playerID) && (IS_PRODUCTION_BUILDING(BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).type))) { return true; } } } } return false; } bool CStrategyExpansionEngine::hasAttackableUnits() { int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 1247 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_UNIT_ON_HEXID(SIP->map,i)) { if ((UNIT_ON_HEXID(SIP->map,SIP->living_units,i).player==playerID) && (!(EXPANSION_ONLY_UNIT_TYPE(UNIT_ON_HEXID(SIP->map,SIP->living_units,i).type)))) { return true; } } } } return false; } bool CStrategyExpansionEngine::hasBuilder() { int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 1267 expansion"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if (IS_UNIT_ON_HEXID(SIP->map,i)) { if ((UNIT_ON_HEXID(SIP->map,SIP->living_units,i).player==playerID) && (IS_BUILDER_UNIT_TYPE(UNIT_ON_HEXID(SIP->map,SIP->living_units,i).type))) { return true; } } } } return false; } int CStrategyExpansionEngine::getBuildingOrder(int building_type) throw(E_8K_AI_Strategy_InvalidBuildOrder) { if (!BuildOrder) THROW(E_8K_AI_Strategy_InvalidBuildOrder,"Neinicializovane poradi stavby."); if (building_type>((int) (strlen(BuildOrder)))) THROW(E_8K_AI_Strategy_InvalidBuildOrder,"Invalidni poradi stavby nebo typ budovy."); if ((BuildOrder[building_type-1]>='0') && (BuildOrder[building_type-1]<='9')) { return ((BuildOrder[building_type-1])-'0'); } else { THROW(E_8K_AI_Strategy_InvalidBuildOrder,"Invalidni hodnoty v poradi stavby."); } } bool CStrategyExpansionEngine::shouldBuildNewBuildings() throw(E_8K_AI_Strategy_InvalidBuildingStatistics) { // zkusim zdali mam vubec nejakeho stavitele - pokud ne, neni co resit if (!(hasBuilder())) return false; // podivam se, jestli je naplanovana a neprirazena nejaka stavba produkcni budovy, pokud ano, tak koncim std::BUILD_DESIRES_AI_INFO_CONTAINER::iterator bdIt; for(bdIt=SS->BuildDesiresInfo.begin();bdIt!=SS->BuildDesiresInfo.end();bdIt++) { if ((IS_PRODUCTION_BUILDING(bdIt->building_type)) && (!(bdIt->done)) && (!(bdIt->builder_assigned))) return false; } // spocitam si statistiky budov countBuildingStatistics(); std::list::iterator bsIt; std::list::iterator btnIt=BuildingTemplateNumbers.begin(); // podivam se, zdali mi nejaka budova uplne nechybi for(bsIt=BuildingStatistics.begin();(bsIt!=BuildingStatistics.end());bsIt++) { if (bsIt->building_type!=btnIt->building_type) THROW(E_8K_AI_Strategy_InvalidBuildingStatistics,"Neodpovidajici zaznamy typu budov."); if ((bsIt->building_num==0) && (btnIt->building_num>0)) return true; btnIt++; } // pokud ne, spocitam horni hranici poctu budov vzhledem k poctu mych kralovstvi int BuildingNumBorder=MaxProductionBuildingsPerKingdom*MAX(1,countMyKingdoms()); int bn=0; for(bsIt=BuildingStatistics.begin();(bsIt!=BuildingStatistics.end());bsIt++) { bn+=bsIt->building_num; } return (bnkingdoms->begin();kIt!=SIP->kingdoms->end();kIt++) { if (KINGDOM_FROM_ITERATOR(kIt).roleid==playerID) kingdoms_num++; } return kingdoms_num; } } }