CBattleObstacleController.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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. auto animation = std::make_shared<CAnimation>(spellObstacle->appearAnimation);
  78. animation->preload();
  79. auto first = animation->getImage(0, 0);
  80. if(!first)
  81. {
  82. obstaclesBeingPlaced.erase(obstaclesBeingPlaced.begin());
  83. continue;
  84. }
  85. //TODO: sound
  86. //soundBase::QUIKSAND
  87. //soundBase::LANDMINE
  88. //we assume here that effect graphics have the same size as the usual obstacle image
  89. // -> if we know how to blit obstacle, let's blit the effect in the same place
  90. Point whereTo = getObstaclePosition(first, *oi);
  91. owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::invalid, spellObstacle->appearAnimation, whereTo, oi->pos, CPointEffectAnimation::WAIT_FOR_SOUND));
  92. //so when multiple obstacles are added, they show up one after another
  93. owner->waitForAnims();
  94. obstaclesBeingPlaced.erase(obstaclesBeingPlaced.begin());
  95. loadObstacleImage(*spellObstacle);
  96. }
  97. }
  98. void CBattleObstacleController::showAbsoluteObstacles(std::shared_ptr<CCanvas> canvas, const Point & offset)
  99. {
  100. //Blit absolute obstacles
  101. for(auto & oi : owner->curInt->cb->battleGetAllObstacles())
  102. {
  103. if(oi->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
  104. {
  105. auto img = getObstacleImage(*oi);
  106. if(img)
  107. canvas->draw(img, Point(offset.x + oi->getInfo().width, offset.y + oi->getInfo().height));
  108. }
  109. }
  110. }
  111. void CBattleObstacleController::collectRenderableObjects(CBattleFieldRenderer & renderer)
  112. {
  113. for (auto obstacle : owner->curInt->cb->battleGetAllObstacles())
  114. {
  115. if (obstacle->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
  116. continue;
  117. if (obstacle->obstacleType == CObstacleInstance::MOAT)
  118. continue;
  119. renderer.insert(EBattleFieldLayer::OBSTACLES, obstacle->pos, [this, obstacle]( CBattleFieldRenderer::RendererPtr canvas ){
  120. auto img = getObstacleImage(*obstacle);
  121. if(img)
  122. {
  123. Point p = getObstaclePosition(img, *obstacle);
  124. canvas->draw(img, p);
  125. }
  126. });
  127. }
  128. }
  129. std::shared_ptr<IImage> CBattleObstacleController::getObstacleImage(const CObstacleInstance & oi)
  130. {
  131. int frameIndex = (owner->animCount+1) *25 / owner->getAnimSpeed();
  132. std::shared_ptr<CAnimation> animation;
  133. if (obstacleAnimations.count(oi.uniqueID) == 0)
  134. {
  135. if (boost::range::find(obstaclesBeingPlaced, oi.uniqueID) != obstaclesBeingPlaced.end())
  136. {
  137. // obstacle is not loaded yet, don't show anything
  138. return nullptr;
  139. }
  140. else
  141. {
  142. assert(0); // how?
  143. loadObstacleImage(oi);
  144. }
  145. }
  146. animation = obstacleAnimations[oi.uniqueID];
  147. assert(animation);
  148. if(animation)
  149. {
  150. frameIndex %= animation->size(0);
  151. return animation->getImage(frameIndex, 0);
  152. }
  153. return nullptr;
  154. }
  155. Point CBattleObstacleController::getObstaclePosition(std::shared_ptr<IImage> image, const CObstacleInstance & obstacle)
  156. {
  157. int offset = obstacle.getAnimationYOffset(image->height());
  158. Rect r = owner->fieldController->hexPosition(obstacle.pos);
  159. r.y += 42 - image->height() + offset;
  160. return r.topLeft();
  161. }