Win.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Win.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "Goals.h"
  12. #include "../VCAI.h"
  13. #include "../AIUtility.h"
  14. #include "../AIhelper.h"
  15. #include "../FuzzyHelper.h"
  16. #include "../ResourceManager.h"
  17. #include "../BuildingManager.h"
  18. #include "../../../lib/mapping/CMapHeader.h" //for victory conditions
  19. #include "../../../lib/mapObjects/CGTownInstance.h"
  20. #include "../../../lib/CPathfinder.h"
  21. #include "../../../lib/StringConstants.h"
  22. extern boost::thread_specific_ptr<CCallback> cb;
  23. extern boost::thread_specific_ptr<VCAI> ai;
  24. extern FuzzyHelper * fh;
  25. using namespace Goals;
  26. TSubgoal Win::whatToDoToAchieve()
  27. {
  28. auto toBool = [=](const EventCondition &)
  29. {
  30. // TODO: proper implementation
  31. // Right now even already fulfilled goals will be included into generated list
  32. // Proper check should test if event condition is already fulfilled
  33. // Easiest way to do this is to call CGameState::checkForVictory but this function should not be
  34. // used on client side or in AI code
  35. return false;
  36. };
  37. std::vector<EventCondition> goals;
  38. for(const TriggeredEvent & event : cb->getMapHeader()->triggeredEvents)
  39. {
  40. //TODO: try to eliminate human player(s) using loss conditions that have isHuman element
  41. if(event.effect.type == EventEffect::VICTORY)
  42. {
  43. boost::range::copy(event.trigger.getFulfillmentCandidates(toBool), std::back_inserter(goals));
  44. }
  45. }
  46. //TODO: instead of returning first encountered goal AI should generate list of possible subgoals
  47. for(const EventCondition & goal : goals)
  48. {
  49. switch(goal.condition)
  50. {
  51. case EventCondition::HAVE_ARTIFACT:
  52. return sptr(GetArtOfType(goal.objectType));
  53. case EventCondition::DESTROY:
  54. {
  55. if(goal.object)
  56. {
  57. auto obj = cb->getObj(goal.object->id);
  58. if(obj)
  59. if(obj->getOwner() == ai->playerID) //we can't capture our own object
  60. return sptr(Conquer());
  61. return sptr(VisitObj(goal.object->id.getNum()));
  62. }
  63. else
  64. {
  65. // TODO: destroy all objects of type goal.objectType
  66. // This situation represents "kill all creatures" condition from H3
  67. break;
  68. }
  69. }
  70. case EventCondition::HAVE_BUILDING:
  71. {
  72. // TODO build other buildings apart from Grail
  73. // goal.objectType = buidingID to build
  74. // goal.object = optional, town in which building should be built
  75. // Represents "Improve town" condition from H3 (but unlike H3 it consists from 2 separate conditions)
  76. if(goal.objectType == BuildingID::GRAIL)
  77. {
  78. if(auto h = ai->getHeroWithGrail())
  79. {
  80. //hero is in a town that can host Grail
  81. if(h->visitedTown && !vstd::contains(h->visitedTown->forbiddenBuildings, BuildingID::GRAIL))
  82. {
  83. const CGTownInstance * t = h->visitedTown;
  84. return sptr(BuildThis(BuildingID::GRAIL, t).setpriority(10));
  85. }
  86. else
  87. {
  88. auto towns = cb->getTownsInfo();
  89. towns.erase(boost::remove_if(towns,
  90. [](const CGTownInstance * t) -> bool
  91. {
  92. return vstd::contains(t->forbiddenBuildings, BuildingID::GRAIL);
  93. }),
  94. towns.end());
  95. boost::sort(towns, CDistanceSorter(h.get()));
  96. if(towns.size())
  97. {
  98. return sptr(VisitTile(towns.front()->visitablePos()).sethero(h));
  99. }
  100. }
  101. }
  102. double ratio = 0;
  103. // maybe make this check a bit more complex? For example:
  104. // 0.75 -> dig randomly within 3 tiles radius
  105. // 0.85 -> radius now 2 tiles
  106. // 0.95 -> 1 tile radius, position is fully known
  107. // AFAIK H3 AI does something like this
  108. int3 grailPos = cb->getGrailPos(&ratio);
  109. if(ratio > 0.99)
  110. {
  111. return sptr(DigAtTile(grailPos));
  112. } //TODO: use FIND_OBJ
  113. else if(const CGObjectInstance * obj = ai->getUnvisitedObj(objWithID<Obj::OBELISK>)) //there are unvisited Obelisks
  114. return sptr(VisitObj(obj->id.getNum()));
  115. else
  116. return sptr(Explore());
  117. }
  118. break;
  119. }
  120. case EventCondition::CONTROL:
  121. {
  122. if(goal.object)
  123. {
  124. auto objRelations = cb->getPlayerRelations(ai->playerID, goal.object->tempOwner);
  125. if(objRelations == PlayerRelations::ENEMIES)
  126. {
  127. return sptr(VisitObj(goal.object->id.getNum()));
  128. }
  129. else
  130. {
  131. // TODO: Defance
  132. break;
  133. }
  134. }
  135. else
  136. {
  137. //TODO: control all objects of type "goal.objectType"
  138. // Represents H3 condition "Flag all mines"
  139. break;
  140. }
  141. }
  142. case EventCondition::HAVE_RESOURCES:
  143. //TODO mines? piles? marketplace?
  144. //save?
  145. return sptr(CollectRes(static_cast<EGameResID>(goal.objectType), goal.value));
  146. case EventCondition::HAVE_CREATURES:
  147. return sptr(GatherTroops(goal.objectType, goal.value));
  148. case EventCondition::TRANSPORT:
  149. {
  150. //TODO. merge with bring Grail to town? So AI will first dig grail, then transport it using this goal and builds it
  151. // Represents "transport artifact" condition:
  152. // goal.objectType = type of artifact
  153. // goal.object = destination-town where artifact should be transported
  154. break;
  155. }
  156. case EventCondition::STANDARD_WIN:
  157. return sptr(Conquer());
  158. // Conditions that likely don't need any implementation
  159. case EventCondition::DAYS_PASSED:
  160. break; // goal.value = number of days for condition to trigger
  161. case EventCondition::DAYS_WITHOUT_TOWN:
  162. break; // goal.value = number of days to trigger this
  163. case EventCondition::IS_HUMAN:
  164. break; // Should be only used in calculation of candidates (see toBool lambda)
  165. case EventCondition::CONST_VALUE:
  166. break;
  167. case EventCondition::HAVE_0:
  168. case EventCondition::HAVE_BUILDING_0:
  169. case EventCondition::DESTROY_0:
  170. //TODO: support new condition format
  171. return sptr(Conquer());
  172. default:
  173. assert(0);
  174. }
  175. }
  176. return sptr(Invalid());
  177. }