/** @file /ai/Strategizer/strategizer.cpp @brief Zdrojovy kod modulu strategickeho planovace. Zdrojovy kod modulu strategickeho planovace. @author PZ @version 0.1 */ #include "ai/Strategizer/strategizer.h" namespace ai_ns { namespace strategizer_ns { CStrategizerEngine::CStrategizerEngine() { SIP=0; StrategySerialization=0; StrategyAttackEngine=0; StrategyExpansionEngine=0; } CStrategizerEngine::~CStrategizerEngine() { if (SIP) delete SIP; SIP=0; if (StrategySerialization) delete StrategySerialization; StrategySerialization=0; if (StrategyAttackEngine) delete StrategyAttackEngine; StrategyAttackEngine=0; if (StrategyExpansionEngine) delete StrategyExpansionEngine; StrategyExpansionEngine=0; } void CStrategizerEngine::AITurnForPlayer(int playerID,int last_history_event_id,PLAYER_TYPE ai_level) { CHECK_AI_THREAD_STATE; // loads the information from MAP (xml) .. those separated with | StrategySerialization->loadDataToInnerStructure(AI_DATA_FOR_PLAYER(SIP->players,playerID)); CHECK_AI_THREAD_STATE; StrategyAttackEngine->setPlayer(playerID); StrategyExpansionEngine->setPlayer(playerID); CHECK_AI_THREAD_STATE; updateSerializationStructures(playerID); CHECK_AI_THREAD_STATE; StrategyExpansionEngine->updateDisponibleMoney(); CHECK_AI_THREAD_STATE; if ((!(StrategyExpansionEngine->hasAttackableUnits())) && (!(StrategyExpansionEngine->hasCities()))) StrategyExpansionEngine->processOnlyExpansionUnitsState(); CHECK_AI_THREAD_STATE; StrategyExpansionEngine->getUnitsOutOfBuildings(); CHECK_AI_THREAD_STATE; StrategyAttackEngine->updateAttacks(); CHECK_AI_THREAD_STATE; StrategyExpansionEngine->updateExpansion(); CHECK_AI_THREAD_STATE; CStrGraph* strGr=buildStrategyGraph(playerID,ai_level); CHECK_AI_THREAD_STATE; CPlan* def_plan=strGr->generateDefencePlan(playerID); CHECK_AI_THREAD_STATE; def_plan->processPlan(); delete strGr; strGr=0; delete def_plan; def_plan=0; CHECK_AI_THREAD_STATE; StrategyExpansionEngine->processHealingWithUnits(); CHECK_AI_THREAD_STATE; StrategyExpansionEngine->processRecruitingWithUnits(); CHECK_AI_THREAD_STATE; StrategyAttackEngine->processAttackingWithUnusedUnits(); CHECK_AI_THREAD_STATE; StrategyAttackEngine->processExploringWithUnassignedAttackers(); CHECK_AI_THREAD_STATE; if (AI_DATA_FOR_PLAYER(SIP->players,playerID)) KMemFree(AI_DATA_FOR_PLAYER(SIP->players,playerID)); AI_DATA_FOR_PLAYER(SIP->players,playerID)=StrategySerialization->saveDataFromInnerStructure(); CHECK_AI_THREAD_STATE; #ifdef AI_LOGGING LogAIActions.LogMsg("AI player %d END TURN\n",playerID); LogAIDesires.LogMsg("AI player %d END TURN\n",playerID); #endif CHECK_AI_THREAD_STATE; PACKET_WORLD_AI pwai; pwai.player_id=playerID; pwai.type=MSG_ACT_NEXT_TURN; KSendGlobalMessage(MSG_WORLD_AI,MOD_STRATEGY,MOD_WORLD_SERVER,&pwai); } void CStrategizerEngine::initStrategy(TPacket_AI_LetsGo* initPackage) { if (SIP) delete SIP; SIP=new TPacket_AI_LetsGo(); SIP->rules=initPackage->rules; SIP->map=initPackage->map; SIP->kingdoms=initPackage->kingdoms; SIP->towns=initPackage->towns; SIP->visibility_maps=initPackage->visibility_maps; SIP->living_units=initPackage->living_units; SIP->living_buildings=initPackage->living_buildings; SIP->players=initPackage->players; KSendGlobalMessage(MSG_MAPANALYZER_INIT,MOD_STRATEGY,MOD_MAPANALYZER,SIP); if (StrategySerialization) delete StrategySerialization; StrategySerialization=new CStrategySerialization(SIP); if (StrategyAttackEngine) delete StrategyAttackEngine; StrategyAttackEngine=new CStrategyAttackEngine(SIP,StrategySerialization); if (StrategyExpansionEngine) delete StrategyExpansionEngine; StrategyExpansionEngine=new CStrategyExpansionEngine(SIP,StrategySerialization); } CStrGraph* CStrategizerEngine::buildStrategyGraph(int playerID,PLAYER_TYPE ai_level) { CStrGraph* strGr=new CStrGraph(SIP,playerID,ai_level); int* ActionAreaForDefence=strGr->getLandForDefence(playerID); int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 155 strategizer"); 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) && (ActionAreaForDefence[i]==playerID))) { if (IS_BUILDING_ON_HEXID(SIP->map,i)) { if (BUILDING_NEED_TO_DEFEND(BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).type)) { CBuilding* sv=new CBuilding(); sv->setPosX(i%SIP->map->width()); sv->setPosY(i/SIP->map->width()); sv->setBuildingType(BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).type); sv->setBuildingCost(((SIP->rules->building_types)[BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).type])->data().base_cost); sv->setWorldID(BUILDING_ID_ON_HEXID(SIP->map,i)); sv->setFreeDefendingPlaces(1); sv->setGuardedIndicator(false); int bpid=BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).player; if (bpid==0) { sv->setDipOwnership(Neutral); } else if (bpid==playerID) { sv->setDipOwnership(My); } else { TPacket_Diplomacy_GetRelation grp; grp.source_diplomat_world_id=playerID; grp.target_diplomat_world_id=bpid; ai_ns::diplomacy_ns::TRelationship* msg_result=(ai_ns::diplomacy_ns::TRelationship*) KSendGlobalMessage(MSG_DIPLOMACY_GET_RELATION,MOD_STRATEGY,MOD_DIPLOMACY,&grp); switch (*msg_result) { case ai_ns::diplomacy_ns::RELATIONSHIP_ALLY:sv->setDipOwnership(Ally); break; case ai_ns::diplomacy_ns::RELATIONSHIP_TRUCE:sv->setDipOwnership(Truce); break; case ai_ns::diplomacy_ns::RELATIONSHIP_ENEMY:sv->setDipOwnership(Enemy); break; case ai_ns::diplomacy_ns::RELATIONSHIP_WAR:sv->setDipOwnership(War); break; default:sv->setDipOwnership(DoesntMatter); //break; } KMemFree(msg_result); } strGr->enlistVertex(sv); } } if (IS_UNIT_ON_HEXID(SIP->map,i)) { CUnit* sv=new CUnit(); TAIUnitInfo* ui=StrategySerialization->findUnitInfoByWorldID(UNIT_ID_ON_HEXID(SIP->map,i)); if ((ui) && (ui->global_desire!=Defence)) // ma jednotka, ale neurcena k obrane { delete sv; sv=0; } else // ma jednotka urcena pro obranu nebo cizi jednotka { sv->DefenceDesire=NoDefenceDesire; // nastavuji i pro cizi jednotky, ale nema vyznam sv->setPosX(i%SIP->map->width()); sv->setPosY(i/SIP->map->width()); sv->setFireRange(UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).attack_range); sv->setWorldID(UNIT_ID_ON_HEXID(SIP->map,i)); ai_ns::CAIScriptCaller* sc=new ai_ns::CAIScriptCaller(); ai_ns::CTCLAIVar* varsin=new ai_ns::CTCLAIVar(); // TODO: zahrnout bonusy // TODO: zahrnout zkusenosti if (sv->getFireRange()>1) varsin->addInt("IS_FIRING_UNIT",1); else varsin->addInt("IS_FIRING_UNIT",0); varsin->addInt("UNIT_ATTACK",UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).attack); varsin->addInt("UNIT_DEFENCE",UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).defense); varsin->addInt("UNIT_ACTUAL_MEN_COUNT",UNIT_ON_HEXID(SIP->map,SIP->living_units,i).lives); varsin->addInt("UNIT_MAX_MEN_NUMBER",UNIT_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_units,i).max_lives); ai_ns::CTCLAIVar* varsout=sc->countScript(ID_SCRIPT_UNIT_POWERS,varsin); sv->setAttackPower(varsout->getInt("ATTACKING_UNIT_POWER")); sv->setDefendPower(varsout->getInt("DEFENSIVE_UNIT_POWER")); sv->setOverallPower(varsout->getInt("OVERALL_UNIT_POWER")); delete varsin; delete varsout; delete sc; int upid=UNIT_ON_HEXID(SIP->map,SIP->living_units,i).player; if (upid==playerID) { sv->setDipOwnership(My); } else { TPacket_Diplomacy_GetRelation grp; grp.source_diplomat_world_id=playerID; grp.target_diplomat_world_id=upid; ai_ns::diplomacy_ns::TRelationship* msg_result=(ai_ns::diplomacy_ns::TRelationship*) KSendGlobalMessage(MSG_DIPLOMACY_GET_RELATION,MOD_STRATEGY,MOD_DIPLOMACY,&grp); switch (*msg_result) { case ai_ns::diplomacy_ns::RELATIONSHIP_ALLY:sv->setDipOwnership(Ally); break; case ai_ns::diplomacy_ns::RELATIONSHIP_TRUCE:sv->setDipOwnership(Truce); break; case ai_ns::diplomacy_ns::RELATIONSHIP_ENEMY:sv->setDipOwnership(Enemy); break; case ai_ns::diplomacy_ns::RELATIONSHIP_WAR:sv->setDipOwnership(War); break; default:sv->setDipOwnership(DoesntMatter); //break; } KMemFree(msg_result); } } if (sv) strGr->enlistVertex(sv); } } } int j; CCity* vc; TTownsIterator citIt; for(citIt=SIP->towns->begin();citIt!=SIP->towns->end();citIt++) { j=0; vc=0; if (TOWN_FROM_ITERATOR(citIt).owner==playerID) { int cpc; for(cpc=0;cpc<(TOWN_FROM_ITERATOR(citIt)).citysize;cpc++) { if (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,TOWN_FROM_ITERATOR(citIt).position[cpc])!=World::VI_NEVER_SEEN) { if (!j) { vc=new CCity(); // pozice neni u mesta relevantni vc->setPosX(i%SIP->map->width()); vc->setPosY(i/SIP->map->width()); int copid=TOWN_FROM_ITERATOR(citIt).owner; if (copid==0) { vc->setDipOwnership(Neutral); } else if (copid==playerID) { vc->setDipOwnership(My); } else { TPacket_Diplomacy_GetRelation grp; grp.source_diplomat_world_id=playerID; grp.target_diplomat_world_id=copid; ai_ns::diplomacy_ns::TRelationship* msg_result=(ai_ns::diplomacy_ns::TRelationship*) KSendGlobalMessage(MSG_DIPLOMACY_GET_RELATION,MOD_STRATEGY,MOD_DIPLOMACY,&grp); switch (*msg_result) { case ai_ns::diplomacy_ns::RELATIONSHIP_ALLY:vc->setDipOwnership(Ally);break; case ai_ns::diplomacy_ns::RELATIONSHIP_TRUCE:vc->setDipOwnership(Truce); break; case ai_ns::diplomacy_ns::RELATIONSHIP_ENEMY:vc->setDipOwnership(Enemy);break; case ai_ns::diplomacy_ns::RELATIONSHIP_WAR:vc->setDipOwnership(War);break; default:vc->setDipOwnership(DoesntMatter); //break; } KMemFree(msg_result); } } (vc->position)[j]=TOWN_FROM_ITERATOR(citIt).position[cpc]; j++; vc->setCitySize(j); } } vc->setFreeDefendingPlaces(vc->getCitySize()); vc->setGuardedIndicator(false); } if (vc) strGr->enlistVertex(vc); } int cities_count=strGr->countMyCities(); int all_my_cities_count=strGr->countMyCitiesPayment(); std::VERTEX_CONTAINER* vertices=strGr->getVertices(); std::VERTEX_CONTAINER::iterator vIt; for (vIt=(*vertices).begin();vIt!=(*vertices).end();vIt++) { if ((*vIt)->getDipOwnership()==My) { if (dynamic_cast(*vIt)) // utok na mou budovu { int building_type=(dynamic_cast(*vIt))->getBuildingType(); int building_cost=(dynamic_cast(*vIt))->getBuildingCost(); int same_buildings_count=strGr->countMyBuildingsByType(building_type); ai_ns::CAIScriptCaller* sc=new ai_ns::CAIScriptCaller(); ai_ns::CTCLAIVar* varsin=new ai_ns::CTCLAIVar(); varsin->addInt("BUILDINGS_COUNT",same_buildings_count); varsin->addInt("BUILDING_TYPE",building_type); varsin->addInt("BUILDING_COST",building_cost); ai_ns::CTCLAIVar* varsout=sc->countScript(ID_SCRIPT_BUILDING_PRICE,varsin); (dynamic_cast(*vIt))->setPrice(varsout->getInt("RESULT_PRICE")); delete varsin; delete varsout; delete sc; } else if (dynamic_cast(*vIt)) // utok na me mesto { int city_payment=(dynamic_cast(*vIt))->getCitySize()*TOWN_INCOME; ai_ns::CAIScriptCaller* sc=new ai_ns::CAIScriptCaller(); ai_ns::CTCLAIVar* varsin=new ai_ns::CTCLAIVar(); varsin->addInt("CITIES_COUNT",cities_count); varsin->addInt("ALL_MY_CITIES_PAYMENT",all_my_cities_count); varsin->addInt("CITY_PAYMENT",city_payment); ai_ns::CTCLAIVar* varsout=sc->countScript(ID_SCRIPT_CITY_PRICE,varsin); (dynamic_cast(*vIt))->setPrice(varsout->getInt("RESULT_PRICE")); delete varsin; delete varsout; delete sc; } } } strGr->setWholeWealthPrice(strGr->countWholeWealthPrice()); strGr->setWholePower(strGr->countWholePower()); strGr->computeRatios(); // could sort the verticles by AI's units?? strGr->createEdgesForAllVertices(); // THIS LINE TAKES LONG strGr->computeGraphEdgesValues(playerID); KMemFree(ActionAreaForDefence); return strGr; } void CStrategizerEngine::updateSerializationStructures(int playerID) { int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 398 strategizer"); 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) { TAIUnitInfo* ui=StrategySerialization->findUnitInfoByWorldID(UNIT_ID_ON_HEXID(SIP->map,i)); if (ui) { if (ui->global_desire==NoGlobalDesire) { // TODO: mozno zmenit kriterium if (EXPANSION_ONLY_UNIT_TYPE(ui->unit_type)) { ui->global_desire=Expansion; } else if ((ATTACK_ONLY_UNIT_TYPE(ui->unit_type)) && (ui->global_desire!=Attack_Assigned)) { ui->global_desire=Attack_Unassigned; } else if ((StrategyExpansionEngine->hasProductionBuildings()) || (StrategyExpansionEngine->hasCities())) { ui->global_desire=Defence; } else { ui->global_desire=Attack_Unassigned; } } } else { TAIUnitInfo new_unit_info; new_unit_info.world_id=UNIT_ID_ON_HEXID(SIP->map,i); new_unit_info.unit_type=UNIT_ON_HEXID(SIP->map,SIP->living_units,i).type; if (EXPANSION_ONLY_UNIT_TYPE(new_unit_info.unit_type)) { new_unit_info.global_desire=Expansion; } else if (ATTACK_ONLY_UNIT_TYPE(new_unit_info.unit_type)) { new_unit_info.global_desire=Attack_Unassigned; } else { // TODO: mozno zmenit kriterium if ((StrategyExpansionEngine->hasProductionBuildings()) || (StrategyExpansionEngine->hasCities())) new_unit_info.global_desire=Defence; else new_unit_info.global_desire=Attack_Unassigned; } StrategySerialization->UnitsInfo.push_back(new_unit_info); } } } } } // odstraneni mrtvych jendotek std::UNIT_AI_INFO_CONTAINER::iterator uiIt; for(uiIt=StrategySerialization->UnitsInfo.begin();uiIt!=StrategySerialization->UnitsInfo.end();) { bool unf=true; int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 468 strategizer"); for(i=0;((unf) && (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)==uiIt->world_id) { unf=false; } } } } if (unf) // jednotka nebyla nalezena uiIt=StrategySerialization->UnitsInfo.erase(uiIt); else uiIt++; } // podle informaci o jednotkach se updatuji jeste ostatni serializacni struktury // AttacksInfo - existuji prirazene jednotky? std::ATTACKS_AI_INFO_CONTAINER::iterator aiIt; for(aiIt=StrategySerialization->AttacksInfo.begin();aiIt!=StrategySerialization->AttacksInfo.end();aiIt++) { std::ATTACK_SLOTS_CONTAINER::iterator asIt; for(asIt=(aiIt->units_for_attack).begin();asIt!=(aiIt->units_for_attack).end();asIt++) { if (asIt->assigned) { if (!(StrategySerialization->findUnitInfoByWorldID(asIt->assigned_unit_id))) { asIt->assigned=false; asIt->assigned_unit_id=-1; asIt->synchronized=false; } } } } // AttacksInfo - existuji a jsou stale cizi cile utoku? bool delete_this_attack_info; for(aiIt=StrategySerialization->AttacksInfo.begin();aiIt!=StrategySerialization->AttacksInfo.end();) { delete_this_attack_info=false; switch (aiIt->attack_target_type) { case ATCity: { TPacket_MapAnalyzer_FindCityByPosition pfcbp; pfcbp.position=aiIt->target_point; TOWN* str_city=(TOWN*) KSendGlobalMessage(MSG_MAPANALYZER_FIND_CITY_BY_POSITION,MOD_STRATEGY,MOD_MAPANALYZER,&pfcbp); if (str_city->owner==playerID) delete_this_attack_info=true; } break; case ATBuilding: { if (IS_BUILDING_ON_HEXID(SIP->map,aiIt->target_point)) { if (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,aiIt->target_point).player==playerID) { delete_this_attack_info=true; } } else { delete_this_attack_info=true; } } break; case ATUnit: { } break; default:; } if (delete_this_attack_info) aiIt=StrategySerialization->AttacksInfo.erase(aiIt); else aiIt++; } // Build Desires - kontrola stavitele - zdali jeste existuje std::BUILD_DESIRES_AI_INFO_CONTAINER::iterator bdIt; for(bdIt=StrategySerialization->BuildDesiresInfo.begin();bdIt!=StrategySerialization->BuildDesiresInfo.end();bdIt++) { if (bdIt->builder_assigned) { if (!(StrategySerialization->findUnitInfoByWorldID(bdIt->builder_id))) { bdIt->builder_assigned=false; bdIt->builder_id=-1; bdIt->started_to_build=false; } } } // Build Desires - kontrola zdali mam prirazeneho stavitele jenz jeste nezacal stavet a cilovy hex je obsazen nejakou budovou for(bdIt=StrategySerialization->BuildDesiresInfo.begin();bdIt!=StrategySerialization->BuildDesiresInfo.end();) { if ((bdIt->builder_assigned) && (!(bdIt->started_to_build))) { int bp; if (bdIt->building_type==BRIDGE_BUILDING_TYPE_ID) bp=bdIt->bridge_placement; else bp=bdIt->build_target_point; if (IS_BUILDING_ON_HEXID(SIP->map,bp)) bdIt=StrategySerialization->BuildDesiresInfo.erase(bdIt); else bdIt++; } else { bdIt++; } } // Repair Desires - kontrola stavitele - zdali jeste existuje std::REPAIR_DESIRES_AI_INFO_CONTAINER::iterator rdIt; for(rdIt=StrategySerialization->RepairDesiresInfo.begin();rdIt!=StrategySerialization->RepairDesiresInfo.end();rdIt++) { if (rdIt->builder_assigned) { if (!(StrategySerialization->findUnitInfoByWorldID(rdIt->builder_id))) { rdIt->builder_assigned=false; rdIt->builder_id=-1; } } } // Repair desires - zdali budovy, ktere chci opravit jeste existuji a jsou moje a nejsou jiz opravene for(rdIt=StrategySerialization->RepairDesiresInfo.begin();rdIt!=StrategySerialization->RepairDesiresInfo.end();) { bool invalid_repair_desire_building=false; if (!(IS_BUILDING_ON_HEXID(SIP->map,rdIt->repair_target_point))) { invalid_repair_desire_building=true; } else if ((BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,rdIt->repair_target_point).player!=playerID) || (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,rdIt->repair_target_point).lives==BUILDING_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_buildings,rdIt->repair_target_point).lives)) { invalid_repair_desire_building=true; } if (invalid_repair_desire_building) rdIt=StrategySerialization->RepairDesiresInfo.erase(rdIt); else rdIt++; } } } }