BWAPI
|
00001 #pragma once 00002 #include "../PersistentUnitGroup.h" 00003 //#include "../UnitManager.h" 00004 //#include "../UnitData.h" 00005 #include "../Scheduler/SchedulerTask.h" 00006 #include "../Utils/Functors.hpp" 00007 #include "../Utils/Vector2.h" 00008 #include "../Utils/Utils.h" 00009 #include "../Utils/Event.h" 00010 #include "../Utils/UnitGroup.h" 00011 #include "../Utils/Resources.h" 00012 #include "Locations/Common.h" 00013 #include "InfluenceMap/InfluenceMap.h" 00014 #include "InfluenceMap/StructuralImportance.h" 00015 #include "InfluenceMap/Threat.h" 00016 #include "InfluenceMap/Visibility.h" 00017 #include "Tasks/UpdateInfluenceMapTask.h" 00018 #include "Tasks/UpdateBuildingsTask.h" 00019 #include "Tasks/UpdateUnitsTask.h" 00020 #include "Techs/Techs.h" 00021 #include <algorithm> 00022 00023 static const int SAFE_POSITION_RANGE = 3; 00024 static const int DODGE_DISTANCE = 90; 00025 00030 class PerceptualState : public Component 00031 { 00032 public: 00033 PerceptualState(); 00034 00035 ~PerceptualState(); 00036 00041 template <class LocationTypes, class TechTypes> 00042 void onStart() 00043 { 00044 m_map = LocationTypes::instantiateMap(); 00045 Techs::onStart<TechTypes>(m_map); 00046 activateTasks(); 00047 } 00048 00049 void onFrame() 00050 { 00051 #ifdef DRAW_ON_SCREEN 00052 if (Spar->getConfiguration().displayMap()) 00053 displayMap(); 00054 00055 if (Spar->getConfiguration().displayEnemyInfluenceMap()) 00056 m_enemyInfluenceMap.display(); 00057 if (Spar->getConfiguration().displaySelfInfluenceMap()) 00058 m_selfInfluenceMap.display(); 00059 if (Spar->getConfiguration().displayVisibilityInfluenceMap()) 00060 m_visibilityInfluenceMap.display(); 00061 if (Spar->getConfiguration().displayStructureInfluenceMap()) 00062 m_structureInfluenceMap.display(); 00063 #endif 00064 } 00065 00066 void onEnd() 00067 { 00068 Techs::onEnd(); 00069 } 00070 00071 void onUnitDiscover(BWAPI::Unit* unit); 00072 void onUnitEvade(BWAPI::Unit* unit); 00073 void onUnitShow(BWAPI::Unit* unit); 00074 void onUnitHide(BWAPI::Unit* unit); 00075 void onUnitCreate(BWAPI::Unit* unit); 00076 void onUnitDestroy(BWAPI::Unit* unit); 00077 void onUnitMorph(BWAPI::Unit* unit); 00078 void onUnitRenegade(BWAPI::Unit* unit); 00079 00080 class ResearchInProgress; 00081 ResearchInProgress* onResearchStarted(const Process* parent, TechTypeTech* m_tech, BWAPI::Unit* m_building); 00082 ResearchInProgress* onUpgradeStarted(const Process* parent, UpgradeTypeTech* m_upgrade, BWAPI::Unit* m_building); 00083 00084 // TODO: all this getUnits() stuff should go in Map, and should return enemy units in fog of war as well 00085 // (hence units should be kept on a per-tile basis, as in BWAPI) 00086 00087 template <class Predicate> 00088 UnitGroup getUnits(const CircularLocation& location, Predicate predicate) const 00089 { 00090 // TODO: this may crash before BWAPI is fixed! 00091 UnitGroup units(BWAPI::Broodwar->getUnitsInRadius(location.getCurrentCenter(), location.getRadius())); 00092 UnitGroup::iterator it = units.begin(); 00093 while (it != units.end()) 00094 { 00095 UnitGroup::iterator next = ++(UnitGroup::iterator(it)); 00096 if (!predicate(*it)) 00097 units.erase(it); 00098 it = next; 00099 } 00100 return units; 00101 } 00102 00103 template <class Location> 00104 UnitGroup getUnits(const Location& lcoation) 00105 { 00106 return getUnits(location, True()); 00107 } 00108 00109 template <class Predicate> 00110 UnitGroup getUnits(const RectangularLocation& location, Predicate predicate) const 00111 { 00112 // TODO: use this when BWAPI is fixed! 00113 //UnitGroup units(BWAPI::Broodwar->getUnitsInRectangle(location.getTopLeftCorner().makeValid(), location.getBottomRightCorner().makeValid())); 00114 //UnitGroup::iterator it = units.begin(); 00115 //while (it != units.end()) 00116 //{ 00117 // UnitGroup::iterator next = ++(UnitGroup::iterator(it)); 00118 // if (!predicate(*it)) 00119 // units.erase(it); 00120 // it = next; 00121 //} 00122 //return units; 00123 00124 const BWAPI::TilePosition topLeft(location.getTopLeftCorner().makeValid()); 00125 int tileLeft = topLeft.x(); 00126 int tileTop = topLeft.y(); 00127 const BWAPI::TilePosition bottomRight(location.getBottomRightCorner().makeValid()); 00128 int tileRight = bottomRight.x(); 00129 int tileBottom = bottomRight.y(); 00130 00131 UnitGroup allUnits; 00132 for (int x = tileLeft; x <= tileRight; ++x) 00133 { 00134 for (int y = tileTop; y <= tileBottom; ++y) 00135 { 00136 const std::set<BWAPI::Unit*>& units = BWAPI::Broodwar->getUnitsOnTile(x, y); 00137 for (std::set<BWAPI::Unit*>::const_iterator it = units.begin(); it != units.end(); ++it) 00138 { 00139 BWAPI::Unit* unit= *it; 00140 BWAPI::Position pos = unit->getPosition(); 00141 if (is_between<int, true>(location.getTopLeftCorner().x(), location.getBottomRightCorner().x())(pos.x()) && 00142 is_between<int, true>(location.getTopLeftCorner().y(), location.getBottomRightCorner().y())(pos.y()) && 00143 predicate(unit)) 00144 allUnits.insert(unit); 00145 } 00146 } 00147 } 00148 #ifdef _DEBUG 00149 for (UnitGroup::const_iterator it = allUnits.begin(); it != allUnits.end(); ++it) 00150 { 00151 BWAPI::Position pos = (*it)->getPosition(); 00152 bool isBetweenX = is_between<int, true>(location.getTopLeftCorner().x(), location.getBottomRightCorner().x())(pos.x()); 00153 bool isBetweenY = is_between<int, true>(location.getTopLeftCorner().y(), location.getBottomRightCorner().y())(pos.y()); 00154 assert(isBetweenX && isBetweenY); 00155 } 00156 #endif 00157 return allUnits; 00158 } 00159 template <class Predicate> 00160 UnitGroup getUnits(const CircularUnitDynamicLocation& location, Predicate predicate) const 00161 { 00162 return getUnits(location.getCircularLocation(), predicate); 00163 } 00164 template <class Predicate> 00165 UnitGroup getUnits(const RectangularGroupDynamicLocation& location, Predicate predicate) const 00166 { 00167 if (location.getGroup()->empty()) 00168 return UnitGroup(); 00169 else 00170 return getUnits(location.getExpandedRectangularLocation(), predicate); 00171 } 00172 00173 template <class LocationType> 00174 UnitGroup getOwnUnits(const LocationType& location) const 00175 { 00176 return getUnits(location, IsOwnUnit<BWAPI::Unit>()); 00177 } 00178 00179 template <class LocationType> 00180 UnitGroup getEnemyUnits(const LocationType& location) const 00181 { 00182 return getUnits(location, IsEnemyUnit<BWAPI::Unit>()); 00183 } 00184 00185 UnitGroup getEnemiesNearUnit(BWAPI::Unit* unit, int range) const 00186 { 00187 return getEnemyUnits(CircularLocation(unit->getPosition(), range)); 00188 } 00189 00190 bool unitInSight(BWAPI::Unit* unit) const 00191 { 00192 return tileInSight(unit->getTilePosition(), unit->getType()); 00193 } 00194 00195 bool tileInSight(BWAPI::TilePosition tile, BWAPI::UnitType unitType) const; 00196 00197 //This check if the position is reachable by a ground unit. 00198 //It checks if there is a static obstacle and if the position itself is obstructed (either by other units or by static obstacles) 00199 bool positionIsReachable( const BWAPI::Position& current_pos, const BWAPI::Position& destination) const; 00200 00201 std::set<BWAPI::Unit*> PerceptualState::getTargetingUnits(BWAPI::Unit* unit) const; 00202 bool isUnitTargeted(BWAPI::Unit* unit) const; 00203 00210 BWAPI::Position getGroundFrontier(const BWAPI::Position& position, const double angle) const; 00211 00212 BWAPI::Position getBorder(const BWAPI::Position& position) const; 00213 00214 BWAPI::Position getSafeDodgePosition(BWAPI::Unit* unit) const; 00215 00216 BWAPI::Position getSafeRetreatPosition(BWAPI::Unit* unit) const; 00217 00218 BWAPI::Position getSafeRetreatPosition(const PersistentUnitGroup* group, const UnitGroup& enemyUnits) const; 00219 00220 BWAPI::Position getScoutingLocation(BWAPI::Unit* unit, const BWTA::Region* const region) const; 00221 00222 Map* getMap() { return m_map; } 00223 const Map* getMap() const { return m_map; } 00224 00225 PrimitiveLocation* getHostLocation(BWAPI::UnitType unitType, bool isLifted, BWAPI::Position position, BWAPI::TilePosition tilePosition) const; 00226 PrimitiveLocation* getHostLocation(BWAPI::Unit* unit) const 00227 { 00228 return getHostLocation(unit->getType(), unit->isLifted(), unit->getPosition(), unit->getTilePosition()); 00229 } 00230 PrimitiveLocation* getHostLocation(const EnemyUnit::SavedState& state) const 00231 { 00232 return getHostLocation(state.getType(), state.isLifted(), state.getPosition(), state.getTilePosition()); 00233 } 00234 00235 // Dynamically creating static locations will require events if we allow them to be subsequently deleted 00236 00237 DECLARE_EVENT1(OnUnitDiscover, BWAPI::Unit*); 00238 OnUnitDiscover& getUnitDiscoverEvent() const { return m_unitDiscoverEvent; } 00239 DECLARE_EVENT1(OnUnitEvade, BWAPI::Unit*); 00240 OnUnitEvade& getUnitEvadeEvent() const { return m_unitEvadeEvent; } 00241 DECLARE_EVENT1(OnUnitShow, BWAPI::Unit*); 00242 OnUnitShow& getUnitShowEvent() const { return m_unitShowEvent; } 00243 DECLARE_EVENT1(OnUnitHide, BWAPI::Unit*); 00244 OnUnitHide& getUnitHideEvent() const { return m_unitHideEvent; } 00245 DECLARE_EVENT1(OnUnitCreate, BWAPI::Unit*); 00246 OnUnitCreate& getUnitCreateEvent() const { return m_unitCreateEvent; } 00247 DECLARE_EVENT1(OnUnitDestroy, BWAPI::Unit*); 00248 OnUnitDestroy& getUnitDestroyEvent() const { return m_unitDestroyEvent; } 00249 DECLARE_EVENT1(OnUnitMorph, BWAPI::Unit*); 00250 OnUnitMorph& getUnitMorphEvent() const { return m_unitMorphEvent; } 00251 DECLARE_EVENT1(OnUnitRenegade, BWAPI::Unit*); 00252 OnUnitRenegade& getUnitRenegadeEvent() const { return m_unitRenegadeEvent; } 00253 00254 typedef Map::OnUnitCompleted OnUnitCompleted; 00255 OnUnitCompleted& getUnitCompletedEvent() const 00256 { 00257 return m_map->getUnitCompletedEvent(); 00258 } 00259 00260 typedef Map::OnUnitMorphCompleted OnUnitMorphCompleted; 00261 OnUnitMorphCompleted& getUnitMorphCompletedEvent() const 00262 { 00263 return m_map->getUnitMorphCompletedEvent(); 00264 } 00265 00266 class ResearchInProgress : public Process 00267 { 00268 public: 00269 ResearchInProgress(const Process* parent, BWAPI::Unit* unit, TechTypeTech* tech); 00270 ResearchInProgress(const Process* parent, BWAPI::Unit* unit, UpgradeTypeTech* upgrade); 00271 void onTimeout(); 00272 void onUnitDestroyed(void* data); 00273 void cancel(); 00275 // GUI // 00277 virtual std::set<BWAPI::Unit*> getCommandedUnits() const 00278 { 00279 return std::set<BWAPI::Unit*>(&m_building, &m_building + 1); 00280 } 00281 static const TerminationMode ResearchCancelled; 00282 static const TerminationMode BuildingDestroyed; 00283 protected: 00284 virtual void output(std::ostream& out) const; 00285 virtual void executeImpl(); 00286 virtual void terminateImpl(); 00287 00288 BWAPI::Unit* const m_building; 00289 UpgradeTypeTech* const m_upgrade; 00290 TechTypeTech* const m_tech; 00291 SCHEDULER_EVENT(ResearchInProgress, onTimeout) m_timeoutEvent; 00292 Event<boost::tuples::tuple<>>::SubscriberID m_unitDestroyedSubscriberId; 00293 EVENT_HANDLER(ResearchInProgress, onUnitDestroyed) m_unitDestroyedEventHandler; 00294 }; 00295 00296 private: 00297 friend class ResearchInProgress; 00298 00299 // TODO: this should be a process 00300 class UnitInConstruction : public Component 00301 { 00302 public: 00303 UnitInConstruction(BWAPI::Unit* unit); 00304 UnitInConstruction(const UnitInConstruction& other); 00305 void setPosInContainer(stdext::hash_map<BWAPI::Unit*, UnitInConstruction>::iterator posInContainer) { m_posInContainer = posInContainer; } 00306 stdext::hash_map<BWAPI::Unit*, UnitInConstruction>::iterator getPosInContainer() const { return m_posInContainer; } 00307 void execute(); 00308 void onTimeout(); 00309 void onUnitDestroyed(void* data); 00310 void externalTerminate() 00311 { 00312 terminate(); 00313 } 00314 private: 00315 void terminate(); 00316 00317 BWAPI::Unit* const m_unitInConstruction; 00318 SCHEDULER_EVENT(UnitInConstruction, onTimeout) m_timeoutEvent; 00319 Event<boost::tuples::tuple<>>::SubscriberID m_unitDestroyedSubscriberId; 00320 EVENT_HANDLER(UnitInConstruction, onUnitDestroyed) m_unitDestroyedEventHandler; 00321 stdext::hash_map<BWAPI::Unit*, UnitInConstruction>::iterator m_posInContainer; 00322 }; 00323 friend class UnitInConstruction; 00324 00325 class UnitMorphing : public Component 00326 { 00327 public: 00328 UnitMorphing(BWAPI::Unit* unit); 00329 UnitMorphing(const UnitMorphing& other); 00330 void setPosInContainer(stdext::hash_map<BWAPI::Unit*, UnitMorphing>::iterator posInContainer) { m_posInContainer = posInContainer; } 00331 stdext::hash_map<BWAPI::Unit*, UnitMorphing>::iterator getPosInContainer() const { return m_posInContainer; } 00332 void execute(); 00333 void onTimeout(); 00334 void onUnitDestroyed(void* data); 00335 void externalTerminate() 00336 { 00337 terminate(); 00338 } 00339 private: 00340 void terminate(); 00341 00342 BWAPI::Unit* const m_unitMorphing; 00343 SCHEDULER_EVENT(UnitMorphing, onTimeout) m_timeoutEvent; 00344 Event<boost::tuples::tuple<>>::SubscriberID m_unitDestroyedSubscriberId; 00345 EVENT_HANDLER(UnitMorphing, onUnitDestroyed) m_unitDestroyedEventHandler; 00346 stdext::hash_map<BWAPI::Unit*, UnitMorphing>::iterator m_posInContainer; 00347 }; 00348 friend class UnitMorphing; 00349 00350 00351 void monitorUnitCompletion(BWAPI::Unit* unit); 00352 void activateTasks(); 00353 void displayMap(); 00354 00355 void onUnitInConstructionTerminate(UnitInConstruction* unitInConstruction) 00356 { 00357 m_unitsInConstruction.erase(unitInConstruction->getPosInContainer()); 00358 } 00359 00360 void onUnitMorphingTerminate(UnitMorphing* unitMorphing) 00361 { 00362 m_unitsMorphing.erase(unitMorphing->getPosInContainer()); 00363 } 00364 00365 stdext::hash_map<BWAPI::Unit*, UnitInConstruction> m_unitsInConstruction; 00366 stdext::hash_map<BWAPI::Unit*, UnitMorphing> m_unitsMorphing; 00367 00368 Map* m_map; 00369 00370 // Events 00371 EVENT(OnUnitDiscover) m_unitDiscoverEvent; 00372 EVENT(OnUnitEvade) m_unitEvadeEvent; 00373 EVENT(OnUnitShow) m_unitShowEvent; 00374 EVENT(OnUnitHide) m_unitHideEvent; 00375 EVENT(OnUnitCreate) m_unitCreateEvent; 00376 EVENT(OnUnitDestroy) m_unitDestroyEvent; 00377 EVENT(OnUnitMorph) m_unitMorphEvent; 00378 EVENT(OnUnitRenegade) m_unitRenegadeEvent; 00379 00380 // Influence maps 00381 InfluenceMap<Threat> m_enemyInfluenceMap; 00382 InfluenceMap<Threat> m_selfInfluenceMap; 00383 InfluenceMap<Visibility> m_visibilityInfluenceMap; 00384 InfluenceMap<StructuralImportance> m_structureInfluenceMap; 00385 00386 // Tasks 00387 UpdateInfluenceMapTask<Threat> m_updateEnemyThreatInfluenceMap; 00388 UpdateInfluenceMapTask<Threat> m_updateSelfThreatInfluenceMap; 00389 UpdateInfluenceMapTask<Visibility> m_updateVisibilityInfluenceMap; 00390 UpdateInfluenceMapTask<StructuralImportance> m_updateStructuralImportanceInfluenceMap; 00391 UpdateBuildingsTask* m_updateBuildings; 00392 UpdateUnitsTask* m_updateUnits; 00393 };