CBattleObstacleController.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * CBattleObstacleController.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 "CBattleObstacleController.h"
  12. #include "CBattleInterface.h"
  13. #include "CBattleFieldController.h"
  14. #include "CBattleAnimations.h"
  15. #include "CBattleStacksController.h"
  16. #include "../CPlayerInterface.h"
  17. #include "../gui/CAnimation.h"
  18. #include "../gui/CCanvas.h"
  19. #include "../../CCallback.h"
  20. #include "../../lib/battle/CObstacleInstance.h"
  21. #include "../../lib/ObstacleHandler.h"
  22. CBattleObstacleController::CBattleObstacleController(CBattleInterface * owner):
  23. owner(owner)
  24. {
  25. auto obst = owner->curInt->cb->battleGetAllObstacles();
  26. for(auto & elem : obst)
  27. {
  28. if ( elem->obstacleType == CObstacleInstance::MOAT )
  29. continue; // handled by siege controller;
  30. loadObstacleImage(*elem);
  31. }
  32. }
  33. void CBattleObstacleController::loadObstacleImage(const CObstacleInstance & oi)
  34. {
  35. std::string animationName;
  36. if (auto spellObstacle = dynamic_cast<const SpellCreatedObstacle*>(&oi))
  37. {
  38. animationName = spellObstacle->animation;
  39. }
  40. else
  41. {
  42. assert( oi.obstacleType == CObstacleInstance::USUAL || oi.obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE);
  43. animationName = oi.getInfo().animation;
  44. }
  45. if (animationsCache.count(animationName) == 0)
  46. {
  47. if (oi.obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
  48. {
  49. // obstacle use single bitmap image for animations
  50. auto animation = std::make_shared<CAnimation>();
  51. animation->setCustom(animationName, 0, 0);
  52. animationsCache[animationName] = animation;
  53. }
  54. else
  55. {
  56. auto animation = std::make_shared<CAnimation>(animationName);
  57. animationsCache[animationName] = animation;
  58. animation->preload();
  59. }
  60. }
  61. obstacleAnimations[oi.uniqueID] = animationsCache[animationName];
  62. }
  63. void CBattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> & obstacles)
  64. {
  65. assert(obstaclesBeingPlaced.empty());
  66. for (auto const & oi : obstacles)
  67. obstaclesBeingPlaced.push_back(oi->uniqueID);
  68. for (auto const & oi : obstacles)
  69. {
  70. auto spellObstacle = dynamic_cast<const SpellCreatedObstacle*>(oi.get());
  71. if (!spellObstacle)
  72. {
  73. logGlobal->error("I don't know how to animate appearing obstacle of type %d", (int)oi->obstacleType);
  74. obstaclesBeingPlaced.erase(obstaclesBeingPlaced.begin());
  75. continue;
  76. }
  77. std::string defname = spellObstacle->appearAnimation;
  78. //TODO: sound
  79. //soundBase::QUIKSAND
  80. //soundBase::LANDMINE
  81. //soundBase::FORCEFLD
  82. //soundBase::fireWall
  83. auto animation = std::make_shared<CAnimation>(defname);
  84. animation->preload();
  85. auto first = animation->getImage(0, 0);
  86. if(!first)
  87. {
  88. obstaclesBeingPlaced.erase(obstaclesBeingPlaced.begin());
  89. continue;
  90. }
  91. //we assume here that effect graphics have the same size as the usual obstacle image
  92. // -> if we know how to blit obstacle, let's blit the effect in the same place
  93. Point whereTo = getObstaclePosition(first, *oi);
  94. owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::QUIKSAND, defname, whereTo, CPointEffectAnimation::WAIT_FOR_SOUND));
  95. //so when multiple obstacles are added, they show up one after another
  96. owner->waitForAnims();
  97. obstaclesBeingPlaced.erase(obstaclesBeingPlaced.begin());
  98. loadObstacleImage(*spellObstacle);
  99. }
  100. }
  101. void CBattleObstacleController::showAbsoluteObstacles(std::shared_ptr<CCanvas> canvas, const Point & offset)
  102. {
  103. //Blit absolute obstacles
  104. for(auto & oi : owner->curInt->cb->battleGetAllObstacles())
  105. {
  106. if(oi->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
  107. {
  108. auto img = getObstacleImage(*oi);
  109. if(img)
  110. canvas->draw(img, Point(offset.x + oi->getInfo().width, offset.y + oi->getInfo().height));
  111. }
  112. }
  113. }
  114. void CBattleObstacleController::showBattlefieldObjects(std::shared_ptr<CCanvas> canvas, const BattleHex & location )
  115. {
  116. for (auto &obstacle : owner->curInt->cb->battleGetAllObstacles())
  117. {
  118. if (obstacle->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
  119. continue;
  120. if (obstacle->obstacleType == CObstacleInstance::MOAT)
  121. continue;
  122. if ( obstacle->pos != location)
  123. continue;
  124. auto img = getObstacleImage(*obstacle);
  125. if(img)
  126. {
  127. Point p = getObstaclePosition(img, *obstacle);
  128. canvas->draw(img, p);
  129. }
  130. }
  131. }
  132. std::shared_ptr<IImage> CBattleObstacleController::getObstacleImage(const CObstacleInstance & oi)
  133. {
  134. int frameIndex = (owner->animCount+1) *25 / owner->getAnimSpeed();
  135. std::shared_ptr<CAnimation> animation;
  136. if (obstacleAnimations.count(oi.uniqueID) == 0)
  137. {
  138. if (boost::range::find(obstaclesBeingPlaced, oi.uniqueID) != obstaclesBeingPlaced.end())
  139. {
  140. // obstacle is not loaded yet, don't show anything
  141. return nullptr;
  142. }
  143. else
  144. {
  145. assert(0); // how?
  146. loadObstacleImage(oi);
  147. }
  148. }
  149. animation = obstacleAnimations[oi.uniqueID];
  150. assert(animation);
  151. if(animation)
  152. {
  153. frameIndex %= animation->size(0);
  154. return animation->getImage(frameIndex, 0);
  155. }
  156. return nullptr;
  157. }
  158. Point CBattleObstacleController::getObstaclePosition(std::shared_ptr<IImage> image, const CObstacleInstance & obstacle)
  159. {
  160. int offset = obstacle.getAnimationYOffset(image->height());
  161. Rect r = owner->fieldController->hexPosition(obstacle.pos);
  162. r.y += 42 - image->height() + offset;
  163. return r.topLeft();
  164. }