/** @file /ai/MapAnalyzer/mapanalyzer.cpp @brief Zdrojovy kod modulu analyzy mapy. Zdrojovy kod modulu analyzy mapy. @author PZ @version 0.1 */ #include "ai/MapAnalyzer/mapanalyzer.h" using namespace World; namespace ai_ns { namespace mapanalyzer_ns { CMapAnalyzerEngine::CMapAnalyzerEngine() { SIP=0; } CMapAnalyzerEngine::~CMapAnalyzerEngine() { if (SIP) delete SIP; } void CMapAnalyzerEngine::initMapAnalyzer(TPacket_AI_LetsGo* initPackage) { 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; } int CMapAnalyzerEngine::hexDistance(int hexid1,int hexid2) { COORDS start; COORDS target; start.x=hexid1%SIP->map->width(); start.y=hexid1/SIP->map->width(); target.x=hexid2%SIP->map->width(); target.y=hexid2/SIP->map->width(); bool sxlcol=(start.y%2)==1; bool txlcol=(target.y%2)==1; int xdif=2*ABS(target.x-start.x); int uyt=start.y; int dyt=start.y; if (xdif==0) // stejny dvoujsloupec { xdif=(ABS(target.y-start.y))%2; } else { if (!((sxlcol && txlcol) || ((!sxlcol) && (!txlcol)))) // ruzne umisteni ve dvojsloupci { if (target.x>start.x) { if (sxlcol) { xdif++; } else { xdif--; } } else { if (sxlcol) { xdif--; } else { xdif++; } } } } uyt+=xdif; dyt-=xdif; if (target.yuyt) { return (xdif+((target.y-uyt)/2)); } else { return xdif; } } COORDS_ARRAY CMapAnalyzerEngine::getAdjacentHexes(int hexid) { COORDS_ARRAY rnl; rnl.clear(); COORDS tempsou; tempsou.x=hexid%SIP->map->width(); tempsou.y=hexid/SIP->map->width(); tempsou.y+=2; if (SIP->map->insideBorders((tempsou.y*SIP->map->width())+tempsou.x)) rnl.push_front(tempsou); tempsou.y-=4; if (SIP->map->insideBorders((tempsou.y*SIP->map->width())+tempsou.x)) rnl.push_front(tempsou); tempsou.y++; if ((hexid/SIP->map->width())%2) tempsou.x--; if (SIP->map->insideBorders((tempsou.y*SIP->map->width())+tempsou.x)) rnl.push_front(tempsou); tempsou.x++; if (SIP->map->insideBorders((tempsou.y*SIP->map->width())+tempsou.x)) rnl.push_front(tempsou); tempsou.y+=2; if (SIP->map->insideBorders((tempsou.y*SIP->map->width())+tempsou.x)) rnl.push_front(tempsou); tempsou.x--; if (SIP->map->insideBorders((tempsou.y*SIP->map->width())+tempsou.x)) rnl.push_front(tempsou); return rnl; } bool CMapAnalyzerEngine::hexAdjacentToStatic(int hexid) { if ((SIP->map->getHexById(hexid)->data()).terrain==TT_TOWN) return true; if (IS_BUILDING_ON_HEXID(SIP->map,hexid)) return true; COORDS_ARRAY ah=getAdjacentHexes(hexid); COORDS_ARRAY::iterator ahIt; for(ahIt=ah.begin();ahIt!=ah.end();ahIt++) { if ((SIP->map->getHexAt(ahIt->x,ahIt->y)->data()).terrain==TT_TOWN) return true; if (IS_BUILDING_ON_HEX(SIP->map,ahIt->x,ahIt->y)) return true; } return false; } bool CMapAnalyzerEngine::hexAdjacentToPlannedBuildings(std::list* planned_buildings_coordinates,int hexid) { // predam sve planovane budovy std::list::iterator pbIt; for(pbIt=planned_buildings_coordinates->begin();pbIt!=planned_buildings_coordinates->end();pbIt++) { if (hexid==*pbIt) return true; COORDS_ARRAY ah=getAdjacentHexes(*pbIt); COORDS_ARRAY::iterator ahIt; for(ahIt=ah.begin();ahIt!=ah.end();ahIt++) { if (hexid==((ahIt->y*SIP->map->width())+ahIt->x)) return true; } ah.clear(); } return false; } int CMapAnalyzerEngine::getBestProductionBuildingPlace(int playerID,int building_type,std::list* planned_buildings_coordinates,int assigned_builder_position) { std::list EnemyStList; std::list MyStList; MyStList.clear(); EnemyStList.clear(); // predam sve planovane budovy std::list::iterator pbIt; for(pbIt=planned_buildings_coordinates->begin();pbIt!=planned_buildings_coordinates->end();pbIt++) { MyStList.push_back(*pbIt); } int* mamask=(int*) KMemAlloc((SIP->map->width()*SIP->map->height())*sizeof(int)); GLOBALLOGID(PRIORITY_AI_ALLOC, "mamask ln 193 mapanalyzer"); GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 193 mapanalyzer"); int i; // nastrkam budovy do prislusnych kontajneru 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) // moje budova { MyStList.push_back(i); } else // cizi budova { EnemyStList.push_back(i); } } } } TTownsIterator citIt; // nastrkam mesta do prislusnych kontajneru for(citIt=SIP->towns->begin();citIt!=SIP->towns->end();citIt++) { bool found_visible_piece=false; 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 (!found_visible_piece) { found_visible_piece=true; if (TOWN_FROM_ITERATOR(citIt).owner==playerID) // moje mesto { MyStList.push_back(TOWN_FROM_ITERATOR(citIt).position[cpc]); } else // cizi budova { EnemyStList.push_back(TOWN_FROM_ITERATOR(citIt).position[cpc]); } } } } } GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 242 mapanalyzer"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { mamask[i]=INT_MIN; if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { if ((!hexAdjacentToStatic(i)) && (!hexAdjacentToPlannedBuildings(planned_buildings_coordinates,i)) && (canBuildBuildingOnHex(building_type,i))) { std::list::iterator liIt; int tmpvalue=0; for(liIt=MyStList.begin();liIt!=MyStList.end();liIt++) tmpvalue+=hexDistance(i,*liIt); int tmpvalue2=0; for(liIt=EnemyStList.begin();liIt!=EnemyStList.end();liIt++) tmpvalue2+=hexDistance(i,*liIt); mamask[i]=tmpvalue2-tmpvalue; mamask[i]+=(UNIT_OCCURENCE_BONUS*((SIP->map->getHexById(i)->data()).unit_occurrence.length)); } } } if (assigned_builder_position!=-1) // preplanovavam stavbu pro urciteho stavitele { ai_ns::pathfind_ns::FLOOD_MASK AllocatedFloodMaskForBuilder=(int*) KMemAlloc((SIP->map->width()*SIP->map->height())*sizeof(int)); ai_ns::pathfind_ns::PF_MARKMAP AllocatedMarkMap=(bool*) KMemAlloc((SIP->map->width()*SIP->map->height())*sizeof(bool)); GLOBALLOGID(PRIORITY_AI_ALLOC, "AllocatedFloodMaskForBuilder ln 226 mapanalyzer"); GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 270 mapanalyzer"); 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)==VI_NEVER_SEEN)) { AllocatedMarkMap[i]=true; } else { AllocatedMarkMap[i]=false; } } COORDS sh; sh.x=assigned_builder_position%SIP->map->width(); sh.y=assigned_builder_position/SIP->map->width(); PACKET_FLOODFILL_REQUEST pfr; pfr.unit_id=UNIT_ID_ON_HEXID(SIP->map,assigned_builder_position); pfr.start_hex=sh; pfr.mark_map=AllocatedMarkMap; pfr.flood_mask=AllocatedFloodMaskForBuilder; // TODO: mozne dat primo bez transparence - pak to bude mozna mene efektivni, ale jiste se to nezasekne pfr.flooding_transparency=ai_ns::pathfind_ns::PFT_IgnoreMyUnits; KSendGlobalMessage(MSG_FLOODFILL_REQUEST,MOD_MAPANALYZER,MOD_PATHFIND,&pfr); // pro nedostupne hexy pro stavitele nastavim nejhorsi vyber GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 296 mapanalyzer"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if ((AllocatedFloodMaskForBuilder[i]==FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskForBuilder[i]==FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { mamask[i]=INT_MIN; } } KMemFree(AllocatedMarkMap); KMemFree(AllocatedFloodMaskForBuilder); } int bi=-1; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 309 mapanalyzer"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if (SIP->map->insideBorders(i)) { if (mamask[i]!=INT_MIN) { if (bi==-1) { bi=i; } else { if (mamask[i]>mamask[bi]) { bi=i; } } } } } MyStList.clear(); EnemyStList.clear(); //if (bi==-1) THROW(E_8K_AI_MapAnalyzer_InvalidProductionBuildingPlacement,"Invalidni optimalni pozice pro staveni produkcni budovy."); KMemFree(mamask); return bi; } // vrati pomyslne centrum hracova uzemi int CMapAnalyzerEngine::findPlayerEmpireCenter(int playerID) throw(E_8K_AI_MapAnalyzer_InvalidPlayerEmpireCenter) { std::list StList; StList.clear(); int* mamask=(int*) KMemAlloc((SIP->map->width()*SIP->map->height())*sizeof(int)); GLOBALLOGID(PRIORITY_AI_ALLOC, "mamask ln 341 mapanalyzer"); int i; // nastrkam budovy do kontajneru GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 350 mapanalyzer"); 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) // moje budova { StList.push_back(i); } } } } TTownsIterator citIt; // nastrkam mesta do kontajneru for(citIt=SIP->towns->begin();citIt!=SIP->towns->end();citIt++) { bool found_visible_piece=false; int cpc; for(cpc=0;((!found_visible_piece) && (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 (!found_visible_piece) { found_visible_piece=true; if (TOWN_FROM_ITERATOR(citIt).owner==playerID) // moje mesto { StList.push_back(TOWN_FROM_ITERATOR(citIt).position[cpc]); } } } } } if (StList.empty()) // hrac nema staticke entity - urcim centrum z jednotek { int i; // nastrkam jednotky do kontajneru GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 391 mapanalyzer"); 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) // moje jendotka { StList.push_back(i); } } } } } GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 407 mapanalyzer"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { mamask[i]=INT_MAX; if ((SIP->map->insideBorders(i)) && (VISIBILITY_FOR_PLAYER_ON_HEXID(SIP->visibility_maps,playerID,i)!=World::VI_NEVER_SEEN)) { std::list::iterator liIt; int tmpvalue=0; for(liIt=StList.begin();liIt!=StList.end();liIt++) tmpvalue+=hexDistance(i,*liIt); mamask[i]=tmpvalue; } } int bi=-1; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 422 mapanalyzer"); 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 (bi==-1) { bi=i; } else { if (mamask[i]towns->begin();citIt!=SIP->towns->end();citIt++) { for(cpc=0;cpc<(TOWN_FROM_ITERATOR(citIt)).citysize;cpc++) { if (city_position==TOWN_FROM_ITERATOR(citIt).position[cpc]) { return (&(TOWN_FROM_ITERATOR(citIt))); } } } THROW(E_8K_AI_MapAnalyzer_CityNotFound,"Mesto nenalezeno."); } bool CMapAnalyzerEngine::canBuildBuildingOnHex(int building_type,int hexid) { // je mozne zde stavet if ((((SIP->rules->building_types)[building_type])->data()).terrain[(SIP->map->getHexById(hexid)->data()).terrain]!=1) return false; // jsou okolni hexy ve stejne vysce? World::ELEVATION_TYPE th_elev=(SIP->map->getHexById(hexid)->data()).elevation; COORDS_ARRAY ah=getAdjacentHexes(hexid); COORDS_ARRAY::iterator ahIt; for(ahIt=ah.begin();ahIt!=ah.end();ahIt++) { if ((SIP->map->getHexAt(ahIt->x,ahIt->y)->data()).elevation!=th_elev) return false; } return true; } // najde nejblizsi produkcni budovu, ktera umi vytrenovat jednotku daneho typu int CMapAnalyzerEngine::getNearestFreeProductionBuildingForUnitTrain(int playerID,int hexid,int unit_type) { if (unit_type==-1) return (-1); int rv=-1; int best_dist=-1; int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 493 mapanalyzer"); 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)) && (!(IS_UNIT_ON_HEXID(SIP->map,i)))) // v budove nesmi byt jednotka { if ((BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).construction_duration==0) && (BUILDING_ON_HEXID(SIP->map,SIP->living_buildings,i).player==playerID) && (isUnitPossibleToTrainInBuildingOnHex(i,unit_type))) { int dist=hexDistance(i,hexid); if ((rv==-1) || (dist invisible_hexes; int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 520 mapanalyzer"); 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)) { // vynechavam hexy s obecne nedostupnymi tereny (reka, more, hluboky les) if ((SIP->map->getHexById(i)->data().terrain!=TT_DEEP_FOREST) && (SIP->map->getHexById(i)->data().terrain!=TT_RIVER) && (SIP->map->getHexById(i)->data().terrain!=TT_SEA)) { invisible_hexes.push_back(i); } } } if (invisible_hexes.empty()) return (-1); srand((unsigned) (time(NULL))); std::list::iterator ihIt=invisible_hexes.begin(); int random_position=(rand())%((int) (invisible_hexes.size())); for (i=0;iradius_hexes.clear(); if (radius_size>=0) { rv->radius_hexes.push_back(hexid); } if (radius_size==1) { COORDS_ARRAY ah=getAdjacentHexes(hexid); COORDS_ARRAY::iterator ahIt; for(ahIt=ah.begin();ahIt!=ah.end();ahIt++) rv->radius_hexes.push_back((ahIt->y*SIP->map->width())+ahIt->x); } else if (radius_size>1) { int sx=hexid%SIP->map->width(); int sy=hexid/SIP->map->width(); int cy,cxup,cxdown,cxcount; COORDS tempcoords; if (sy%2) { for(cy=sy+(2*radius_size);cy>(sy+radius_size);cy--) { cxdown=sx-((sy+(2*radius_size)-cy+1)/2); cxup=sx+((sy+(2*radius_size)-cy)/2)+1; for(cxcount=cxdown;cxcountmap->insideBorders((tempcoords.y*SIP->map->width())+tempcoords.x)) { rv->radius_hexes.push_back((tempcoords.y*SIP->map->width())+tempcoords.x); } } } for(cy=sy-radius_size;cy<=(sy+radius_size);cy++) { if (radius_size%2) { cxdown=sx-(radius_size/2)-((cy+1)%2); cxup=sx+(radius_size/2)+1; } else { cxdown=sx-(radius_size/2); cxup=sx+(radius_size/2)+(cy%2); } for(cxcount=cxdown;cxcountmap->insideBorders((tempcoords.y*SIP->map->width())+tempcoords.x)) { rv->radius_hexes.push_back((tempcoords.y*SIP->map->width())+tempcoords.x); } } } for(cy=sy-(2*radius_size);cy<(sy-radius_size);cy++) { cxdown=sx-((cy-sy+(2*radius_size)+1)/2); cxup=sx+((cy-sy+(2*radius_size))/2)+1; for(cxcount=cxdown;cxcountmap->insideBorders((tempcoords.y*SIP->map->width())+tempcoords.x)) { rv->radius_hexes.push_back((tempcoords.y*SIP->map->width())+tempcoords.x); } } } } else { for(cy=sy+(2*radius_size);cy>(sy+radius_size);cy--) { cxdown=sx-((sy+(2*radius_size)-cy+1)/2)+(cy%2); cxup=sx+((sy+(2*radius_size)-cy)/2)+(cy%2)+1; for(cxcount=cxdown;cxcountmap->insideBorders((tempcoords.y*SIP->map->width())+tempcoords.x)) { rv->radius_hexes.push_back((tempcoords.y*SIP->map->width())+tempcoords.x); } } } for(cy=sy-radius_size;cy<=(sy+radius_size);cy++) { if (radius_size%2) { cxdown=sx-(radius_size/2); cxup=sx+(radius_size/2)+(cy%2)+1; } else { cxdown=sx-(radius_size/2)+(cy%2); cxup=sx+(radius_size/2)+1; } for(cxcount=cxdown;cxcountmap->insideBorders((tempcoords.y*SIP->map->width())+tempcoords.x)) { rv->radius_hexes.push_back((tempcoords.y*SIP->map->width())+tempcoords.x); } } } for(cy=sy-(2*radius_size);cy<(sy-radius_size);cy++) { cxdown=sx-((cy-sy+(2*radius_size)+1)/2)+(cy%2); cxup=sx+((cy-sy+(2*radius_size))/2)+(cy%2)+1; for(cxcount=cxdown;cxcountmap->insideBorders((tempcoords.y*SIP->map->width())+tempcoords.x)) { rv->radius_hexes.push_back((tempcoords.y*SIP->map->width())+tempcoords.x); } } } } } return rv; } bool CMapAnalyzerEngine::isUnitPossibleToTrainInBuildingOnHex(int building_placement,int unit_type) throw(E_8K_AI_MapAnalyzer_InvalidProductionBuildingPlacement) { if (!(IS_BUILDING_ON_HEXID(SIP->map,building_placement))) THROW(E_8K_AI_MapAnalyzer_InvalidProductionBuildingPlacement,"Na zadanem hexu neni produkcni budova."); // prvne zjistim, co lze v budove normalne vyrobit za jednotky bool utf=false; World::BUILDING b=BUILDING_TYPE_ON_HEXID(SIP->map,SIP->rules,SIP->living_buildings,building_placement); int bpIt; for(bpIt=0;((!utf) && (bpItrules->unit_types)[unit_type])->data().default_occurrence==1) return true; World::HEX h; h=SIP->map->getHexById(building_placement)->data(); int huoIt; bool hof=false; for(huoIt=0;((!hof) && (huoItmap->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_SUITABLE_FOR_PATHFIND_TESTING(UNIT_ON_HEXID(SIP->map,SIP->living_units,i).type))) { pf_unit_id=UNIT_ID_ON_HEXID(SIP->map,i); } } } } if (pf_unit_id==-1) return ((TPacket_MapAnalyzer_BridgeBuildingResponse*) 0); int pec=findPlayerEmpireCenter(playerID); ai_ns::pathfind_ns::FLOOD_MASK AllocatedFloodMaskCountRivers=(int*) KMemAlloc((SIP->map->width()*SIP->map->height())*sizeof(int)); ai_ns::pathfind_ns::FLOOD_MASK AllocatedFloodMaskNotCountRivers=(int*) KMemAlloc((SIP->map->width()*SIP->map->height())*sizeof(int)); ai_ns::pathfind_ns::PF_MARKMAP AllocatedMarkMap=(bool*) KMemAlloc((SIP->map->width()*SIP->map->height())*sizeof(bool)); GLOBALLOGID(PRIORITY_AI_ALLOC, "AllocatedFloodMaskCountRivers ln 723 mapanalyzer"); GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 736 mapanalyzer"); 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)==VI_NEVER_SEEN)) { AllocatedMarkMap[i]=true; } else { AllocatedMarkMap[i]=false; } } COORDS sh; sh.x=pec%SIP->map->width(); sh.y=pec/SIP->map->width(); PACKET_FLOODFILL_REQUEST pfr; pfr.unit_id=pf_unit_id; pfr.start_hex=sh; pfr.mark_map=AllocatedMarkMap; pfr.flood_mask=AllocatedFloodMaskCountRivers; pfr.flooding_transparency=ai_ns::pathfind_ns::PFT_IgnoreAllUnits; KSendGlobalMessage(MSG_FLOODFILL_REQUEST,MOD_MAPANALYZER,MOD_PATHFIND,&pfr); GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 761 mapanalyzer"); 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)==VI_NEVER_SEEN)) { AllocatedMarkMap[i]=true; } else { AllocatedMarkMap[i]=false; } } pfr.mark_map=AllocatedMarkMap; pfr.flood_mask=AllocatedFloodMaskNotCountRivers; pfr.flooding_transparency=ai_ns::pathfind_ns::PFT_BridgeAnalysis; KSendGlobalMessage(MSG_FLOODFILL_REQUEST,MOD_MAPANALYZER,MOD_PATHFIND,&pfr); KMemFree(AllocatedMarkMap); // naskladam do kontajneru vsechny mozne vystavby mostu std::list bbi; bbi.clear(); GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 784 mapanalyzer"); 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)!=VI_NEVER_SEEN)) { if ((((SIP->map->getHexById(i)->data()).terrain==TT_RIVER) || ((SIP->map->getHexById(i)->data()).terrain==TT_SEA)) && (!(IS_BUILDING_ON_HEXID(SIP->map,i)))) { TBridgeBuildInfo new_bbi; new_bbi.bridge_position=i; int N_hex=N(i,SIP->map->width()); int S_hex=S(i,SIP->map->width()); int NW_hex=NW(i,SIP->map->width()); int NE_hex=NE(i,SIP->map->width()); int SW_hex=SW(i,SIP->map->width()); int SE_hex=SE(i,SIP->map->width()); if ((SIP->map->insideBorders(N_hex)) && (SIP->map->insideBorders(S_hex))) { // hexy maji spravny teren a prevyseni if ( (((SIP->map->getHexById(N_hex)->data()).terrain!=World::TT_RIVER) && ((SIP->map->getHexById(N_hex)->data()).terrain!=World::TT_SEA) && ((SIP->map->getHexById(N_hex)->data()).terrain!=World::TT_SHALLOW)) && (((SIP->map->getHexById(S_hex)->data()).terrain!=World::TT_RIVER) && ((SIP->map->getHexById(S_hex)->data()).terrain!=World::TT_SEA) && ((SIP->map->getHexById(S_hex)->data()).terrain!=World::TT_SHALLOW)) && ((TERRAIN_FOR_BRIDGE_OUPUTS((SIP->map->getHexById(N_hex)->data()).terrain)) && (TERRAIN_FOR_BRIDGE_OUPUTS((SIP->map->getHexById(S_hex)->data()).terrain))) && ((SIP->map->getHexById(N_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(S_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(NW_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(NE_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(SW_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(SE_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) ) { // N --> S if ((AllocatedFloodMaskCountRivers[N_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskCountRivers[N_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vstupni hex se lze dostat if (AllocatedFloodMaskCountRivers[S_hex]!=FLOOD_MASK_VALUE_CANT_SEE) { // vystupni hex vidim if ((AllocatedFloodMaskNotCountRivers[S_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskNotCountRivers[S_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vystupni hex se lze dostat po postaveni mostu new_bbi.bridge_input=N_hex; new_bbi.bridge_output=S_hex; new_bbi.orientation=0; bbi.push_back(new_bbi); } } } // S --> N if ((AllocatedFloodMaskCountRivers[S_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskCountRivers[S_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vstupni hex se lze dostat if (AllocatedFloodMaskCountRivers[N_hex]!=FLOOD_MASK_VALUE_CANT_SEE) { // vystupni hex vidim if ((AllocatedFloodMaskNotCountRivers[N_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskNotCountRivers[N_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vystupni hex se lze dostat po postaveni mostu new_bbi.bridge_input=S_hex; new_bbi.bridge_output=N_hex; new_bbi.orientation=6; bbi.push_back(new_bbi); } } } } } if ((SIP->map->insideBorders(NW_hex)) && (SIP->map->insideBorders(SE_hex))) { // hexy maji spravny teren a prevyseni if ( (((SIP->map->getHexById(NW_hex)->data()).terrain!=World::TT_RIVER) && ((SIP->map->getHexById(NW_hex)->data()).terrain!=World::TT_SEA) && ((SIP->map->getHexById(NW_hex)->data()).terrain!=World::TT_SHALLOW)) && (((SIP->map->getHexById(SE_hex)->data()).terrain!=World::TT_RIVER) && ((SIP->map->getHexById(SE_hex)->data()).terrain!=World::TT_SEA) && ((SIP->map->getHexById(SE_hex)->data()).terrain!=World::TT_SHALLOW)) && ((TERRAIN_FOR_BRIDGE_OUPUTS((SIP->map->getHexById(NW_hex)->data()).terrain)) && (TERRAIN_FOR_BRIDGE_OUPUTS((SIP->map->getHexById(SE_hex)->data()).terrain))) && ((SIP->map->getHexById(N_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(S_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(NW_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(NE_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(SW_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(SE_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) ) { // NW --> SE if ((AllocatedFloodMaskCountRivers[NW_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskCountRivers[NW_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vstupni hex se lze dostat if (AllocatedFloodMaskCountRivers[SE_hex]!=FLOOD_MASK_VALUE_CANT_SEE) { // vystupni hex vidim if ((AllocatedFloodMaskNotCountRivers[SE_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskNotCountRivers[SE_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vystupni hex se lze dostat po postaveni mostu new_bbi.bridge_input=NW_hex; new_bbi.bridge_output=SE_hex; new_bbi.orientation=10; bbi.push_back(new_bbi); } } } // SE --> NW if ((AllocatedFloodMaskCountRivers[SE_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskCountRivers[SE_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vstupni hex se lze dostat if (AllocatedFloodMaskCountRivers[NW_hex]!=FLOOD_MASK_VALUE_CANT_SEE) { // vystupni hex vidim if ((AllocatedFloodMaskNotCountRivers[NW_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskNotCountRivers[NW_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vystupni hex se lze dostat po postaveni mostu new_bbi.bridge_input=SE_hex; new_bbi.bridge_output=NW_hex; new_bbi.orientation=4; bbi.push_back(new_bbi); } } } } } if ((SIP->map->insideBorders(NE_hex)) && (SIP->map->insideBorders(SW_hex))) { // hexy maji spravny teren a prevyseni if ( (((SIP->map->getHexById(NE_hex)->data()).terrain!=World::TT_RIVER) && ((SIP->map->getHexById(NE_hex)->data()).terrain!=World::TT_SEA) && ((SIP->map->getHexById(NE_hex)->data()).terrain!=World::TT_SHALLOW)) && (((SIP->map->getHexById(SW_hex)->data()).terrain!=World::TT_RIVER) && ((SIP->map->getHexById(SW_hex)->data()).terrain!=World::TT_SEA) && ((SIP->map->getHexById(SW_hex)->data()).terrain!=World::TT_SHALLOW)) && ((TERRAIN_FOR_BRIDGE_OUPUTS((SIP->map->getHexById(NE_hex)->data()).terrain)) && (TERRAIN_FOR_BRIDGE_OUPUTS((SIP->map->getHexById(SW_hex)->data()).terrain))) && ((SIP->map->getHexById(N_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(S_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(NW_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(NE_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(SW_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) && ((SIP->map->getHexById(SE_hex)->data()).elevation==(SIP->map->getHexById(i)->data()).elevation) ) { // NE --> SW if ((AllocatedFloodMaskCountRivers[NE_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskCountRivers[NE_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vstupni hex se lze dostat if (AllocatedFloodMaskCountRivers[SW_hex]!=FLOOD_MASK_VALUE_CANT_SEE) { // vystupni hex vidim if ((AllocatedFloodMaskNotCountRivers[SW_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskNotCountRivers[SW_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vystupni hex se lze dostat po postaveni mostu new_bbi.bridge_input=NE_hex; new_bbi.bridge_output=SW_hex; new_bbi.orientation=2; bbi.push_back(new_bbi); } } } // SW --> NE if ((AllocatedFloodMaskCountRivers[SW_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskCountRivers[SW_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vstupni hex se lze dostat if (AllocatedFloodMaskCountRivers[NE_hex]!=FLOOD_MASK_VALUE_CANT_SEE) { // vystupni hex vidim if ((AllocatedFloodMaskNotCountRivers[NE_hex]!=FLOOD_MASK_VALUE_CANT_SEE) && (AllocatedFloodMaskNotCountRivers[NE_hex]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE)) { // na vystupni hex se lze dostat po postaveni mostu new_bbi.bridge_input=SW_hex; new_bbi.bridge_output=NE_hex; new_bbi.orientation=8; bbi.push_back(new_bbi); } } } } } } } } // nenalezl jsem zadne moznosti stavby mostu if (bbi.empty()) { KMemFree(AllocatedFloodMaskCountRivers); KMemFree(AllocatedFloodMaskNotCountRivers); return ((TPacket_MapAnalyzer_BridgeBuildingResponse*) 0); } TPacket_MapAnalyzer_BridgeBuildingResponse* rv=new TPacket_MapAnalyzer_BridgeBuildingResponse(); // nejake moznosti stavby mostu existuji - vybereme z nich // prvne se podivame, jestli existuji nejake moznosti jez nam otevrou nedostupne oblasti bool naabnf=true; std::list::iterator bbiIt; for(bbiIt=bbi.begin();((naabnf) && (bbiIt!=bbi.end()));bbiIt++) { naabnf=(!((AllocatedFloodMaskCountRivers[bbiIt->bridge_output]==FLOOD_MASK_VALUE_NOT_ACCESSIBLE) && (AllocatedFloodMaskNotCountRivers[bbiIt->bridge_output]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE))); } if (!naabnf) { // nalezl jsem most, ktery by mi otviral nove oblasti => odmazu vsechny ostatni a vyberu ten s nejmensi hodnotou na vstupnim hexu for(bbiIt=bbi.begin();bbiIt!=bbi.end();) { if (AllocatedFloodMaskCountRivers[bbiIt->bridge_output]!=FLOOD_MASK_VALUE_NOT_ACCESSIBLE) bbiIt=bbi.erase(bbiIt); else bbiIt++; } if (bbi.empty()) THROW(E_8K_AI_MapAnalyzer_InvalidBridgeAnalysis,"Invalidni hodnoty v analyze stavby mostu."); rv->builder_position=(bbi.begin())->bridge_input; rv->bridge_placement=(bbi.begin())->bridge_position; rv->bridge_orientation=(bbi.begin())->orientation; for(bbiIt=bbi.begin();bbiIt!=bbi.end();bbiIt++) { if (AllocatedFloodMaskCountRivers[bbiIt->bridge_input]builder_position]) { rv->builder_position=bbiIt->bridge_input; rv->bridge_placement=bbiIt->bridge_position; rv->bridge_orientation=bbiIt->orientation; } } bbi.clear(); KMemFree(AllocatedFloodMaskCountRivers); KMemFree(AllocatedFloodMaskNotCountRivers); return rv; } else { // nalezl jsem pouze vylepsovaci mosty, ale dostanu se vsude i bez nich // odmazu ty, ktere mi moc chuze neusetri - bylo by zbytecne je stavet for(bbiIt=bbi.begin();bbiIt!=bbi.end();) { int accesibility_difference=(AllocatedFloodMaskCountRivers[bbiIt->bridge_output]-AllocatedFloodMaskNotCountRivers[bbiIt->bridge_output]); if (accesibility_difference<=BRIDGE_BUILDING_CRITERIUM) bbiIt=bbi.erase(bbiIt); else bbiIt++; } if (bbi.empty()) { delete rv; KMemFree(AllocatedFloodMaskCountRivers); KMemFree(AllocatedFloodMaskNotCountRivers); return ((TPacket_MapAnalyzer_BridgeBuildingResponse*) 0); } else { rv->builder_position=(bbi.begin())->bridge_input; rv->bridge_placement=(bbi.begin())->bridge_position; rv->bridge_orientation=(bbi.begin())->orientation; int rvbv=(AllocatedFloodMaskCountRivers[(bbi.begin())->bridge_output]-AllocatedFloodMaskNotCountRivers[(bbi.begin())->bridge_output]); for(bbiIt=bbi.begin();bbiIt!=bbi.end();bbiIt++) { if (rvbv<(AllocatedFloodMaskCountRivers[bbiIt->bridge_output]-AllocatedFloodMaskNotCountRivers[bbiIt->bridge_output])) { rv->builder_position=bbiIt->bridge_input; rv->bridge_placement=bbiIt->bridge_position; rv->bridge_orientation=bbiIt->orientation; rvbv=AllocatedFloodMaskCountRivers[bbiIt->bridge_output]-AllocatedFloodMaskNotCountRivers[bbiIt->bridge_output]; } } bbi.clear(); KMemFree(AllocatedFloodMaskCountRivers); KMemFree(AllocatedFloodMaskNotCountRivers); return rv; } } } int CMapAnalyzerEngine::findUnitPosition(int unit_world_id) throw(E_8K_AI_MapAnalyzer_UnitNotFoundOnMap) { int i; GLOBALLOGID(PRIORITY_AI_ALLOC, "for ln 1076 mapanalyzer"); for(i=0;(i<(SIP->map->width()*SIP->map->height()));i++) { if (SIP->map->insideBorders(i)) { if (IS_UNIT_ON_HEXID(SIP->map,i)) { if (UNIT_ID_ON_HEXID(SIP->map,i)==unit_world_id) return i; } } } THROW(E_8K_AI_MapAnalyzer_UnitNotFoundOnMap,"Jednotka s danym World ID nebyla nalezena."); } } }