No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tile.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*
  2. * Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.
  21. */
  22. #include "tile.h"
  23. #include "item.h"
  24. #include "thingstype.h"
  25. #include "map.h"
  26. #include "game.h"
  27. #include "localplayer.h"
  28. #include "effect.h"
  29. #include <otclient/net/protocolgame.h>
  30. #include <framework/graphics/fontmanager.h>
  31. Tile::Tile(const Position& position)
  32. {
  33. m_drawElevation = 0;
  34. m_position = position;
  35. }
  36. void Tile::draw(const Point& dest, float scaleFactor, int drawFlags)
  37. {
  38. bool animate = drawFlags & Otc::DrawAnimations;
  39. // first bottom items
  40. if(drawFlags & (Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawOnBottom)) {
  41. m_drawElevation = 0;
  42. for(const ThingPtr& thing : m_things) {
  43. if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
  44. break;
  45. if((thing->isGround() && drawFlags & Otc::DrawGround) ||
  46. (thing->isGroundBorder() && drawFlags & Otc::DrawGroundBorders) ||
  47. (thing->isOnBottom() && drawFlags & Otc::DrawOnBottom))
  48. thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate);
  49. m_drawElevation += thing->getElevation();
  50. if(m_drawElevation > Otc::MAX_ELEVATION)
  51. m_drawElevation = Otc::MAX_ELEVATION;
  52. }
  53. }
  54. int redrawPreviousTopW = 0;
  55. int redrawPreviousTopH = 0;
  56. if(drawFlags & Otc::DrawItems) {
  57. // now common items in reverse order
  58. for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
  59. const ThingPtr& thing = *it;
  60. if(thing->isOnTop() || thing->isOnBottom() || thing->isGroundBorder() || thing->isGround() || thing->asCreature())
  61. break;
  62. thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate);
  63. if(thing->isLyingCorpse()) {
  64. redrawPreviousTopW = std::max(thing->getDimensionWidth(), redrawPreviousTopW);
  65. redrawPreviousTopH = std::max(thing->getDimensionHeight(), redrawPreviousTopH);
  66. }
  67. m_drawElevation += thing->getElevation();
  68. if(m_drawElevation > Otc::MAX_ELEVATION)
  69. m_drawElevation = Otc::MAX_ELEVATION;
  70. }
  71. }
  72. // after we render 2x2 lying corpses, we must redraw previous creatures/ontop above them
  73. if(redrawPreviousTopH > 0 || redrawPreviousTopW > 0) {
  74. int topRedrawFlags = drawFlags & (Otc::DrawCreatures | Otc::DrawEffects | Otc::DrawOnTop | Otc::DrawAnimations);
  75. if(topRedrawFlags) {
  76. for(int x=-redrawPreviousTopW;x<=0;++x) {
  77. for(int y=-redrawPreviousTopH;y<=0;++y) {
  78. if(x == 0 && y == 0)
  79. continue;
  80. const TilePtr& tile = g_map.getTile(m_position.translated(x,y));
  81. if(tile)
  82. tile->draw(dest + Point(x*Otc::TILE_PIXELS, y*Otc::TILE_PIXELS)*scaleFactor, scaleFactor, topRedrawFlags);
  83. }
  84. }
  85. }
  86. }
  87. // creatures
  88. if(drawFlags & Otc::DrawCreatures) {
  89. if(animate) {
  90. for(const CreaturePtr& creature : m_walkingCreatures) {
  91. creature->draw(Point(dest.x + ((creature->getPosition().x - m_position.x)*Otc::TILE_PIXELS - m_drawElevation)*scaleFactor,
  92. dest.y + ((creature->getPosition().y - m_position.y)*Otc::TILE_PIXELS - m_drawElevation)*scaleFactor), scaleFactor, animate);
  93. }
  94. }
  95. for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
  96. CreaturePtr creature = (*it)->asCreature();
  97. if(creature && (!creature->isWalking() || !animate))
  98. creature->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate);
  99. }
  100. }
  101. // effects
  102. if(drawFlags & Otc::DrawEffects) {
  103. for(const EffectPtr& effect : m_effects)
  104. effect->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate);
  105. }
  106. // top items
  107. if(drawFlags & Otc::DrawOnTop) {
  108. for(const ThingPtr& thing : m_things) {
  109. if(thing->isOnTop())
  110. thing->draw(dest, scaleFactor, animate);
  111. }
  112. }
  113. }
  114. void Tile::clean()
  115. {
  116. while(!m_things.empty())
  117. removeThing(m_things.front());
  118. }
  119. void Tile::addWalkingCreature(const CreaturePtr& creature)
  120. {
  121. m_walkingCreatures.push_back(creature);
  122. }
  123. void Tile::removeWalkingCreature(const CreaturePtr& creature)
  124. {
  125. auto it = std::find(m_walkingCreatures.begin(), m_walkingCreatures.end(), creature);
  126. if(it != m_walkingCreatures.end())
  127. m_walkingCreatures.erase(it);
  128. }
  129. ThingPtr Tile::addThing(const ThingPtr& thing, int stackPos)
  130. {
  131. if(!thing)
  132. return nullptr;
  133. if(EffectPtr effect = thing->asEffect()) {
  134. m_effects.push_back(effect);
  135. return nullptr;
  136. }
  137. if(stackPos < 0) {
  138. stackPos = 0;
  139. int priority = thing->getStackPriority();
  140. for(stackPos = 0; stackPos < (int)m_things.size(); ++stackPos) {
  141. int otherPriority = m_things[stackPos]->getStackPriority();
  142. if(otherPriority > priority || (otherPriority == priority && otherPriority == 5))
  143. break;
  144. }
  145. } else if(stackPos > (int)m_things.size())
  146. stackPos = m_things.size();
  147. ThingPtr oldObject;
  148. if(stackPos < (int)m_things.size())
  149. oldObject = m_things[stackPos];
  150. m_things.insert(m_things.begin() + stackPos, thing);
  151. return oldObject;
  152. }
  153. bool Tile::removeThing(ThingPtr thing)
  154. {
  155. if(!thing)
  156. return false;
  157. bool removed = false;
  158. if(EffectPtr effect = thing->asEffect()) {
  159. auto it = std::find(m_effects.begin(), m_effects.end(), effect);
  160. if(it != m_effects.end()) {
  161. m_effects.erase(it);
  162. removed = true;
  163. }
  164. } else {
  165. auto it = std::find(m_things.begin(), m_things.end(), thing);
  166. if(it != m_things.end()) {
  167. m_things.erase(it);
  168. removed = true;
  169. }
  170. }
  171. // reset values managed by this tile
  172. if(removed) {
  173. //thing->setDrawOffset(0);
  174. //thing->setStackpos(0);
  175. }
  176. return removed;
  177. }
  178. ThingPtr Tile::getThing(int stackPos)
  179. {
  180. if(stackPos >= 0 && stackPos < (int)m_things.size())
  181. return m_things[stackPos];
  182. return nullptr;
  183. }
  184. int Tile::getThingStackpos(const ThingPtr& thing)
  185. {
  186. for(uint stackpos = 0; stackpos < m_things.size(); ++stackpos)
  187. if(thing == m_things[stackpos])
  188. return stackpos;
  189. return -1;
  190. }
  191. ThingPtr Tile::getTopThing()
  192. {
  193. if(isEmpty())
  194. return nullptr;
  195. return m_things[m_things.size() - 1];
  196. }
  197. std::vector<CreaturePtr> Tile::getCreatures()
  198. {
  199. std::vector<CreaturePtr> creatures;
  200. for(const ThingPtr& thing : m_things) {
  201. if(CreaturePtr creature = thing->asCreature())
  202. creatures.push_back(creature);
  203. }
  204. return creatures;
  205. }
  206. ItemPtr Tile::getGround()
  207. {
  208. ThingPtr firstObject = getThing(0);
  209. if(!firstObject)
  210. return nullptr;
  211. if(firstObject->isGround())
  212. return firstObject->asItem();
  213. return nullptr;
  214. }
  215. int Tile::getGroundSpeed()
  216. {
  217. int groundSpeed = 100;
  218. if(ItemPtr ground = getGround())
  219. groundSpeed = ground->getGroundSpeed();
  220. return groundSpeed;
  221. }
  222. ThingPtr Tile::getTopLookThing()
  223. {
  224. if(isEmpty())
  225. return nullptr;
  226. for(uint i = 0; i < m_things.size(); ++i) {
  227. ThingPtr thing = m_things[i];
  228. if(!thing->isIgnoreLook() && (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop()))
  229. return thing;
  230. }
  231. return m_things[0];
  232. }
  233. ThingPtr Tile::getTopUseThing()
  234. {
  235. if(isEmpty())
  236. return nullptr;
  237. for(uint i = 0; i < m_things.size(); ++i) {
  238. ThingPtr thing = m_things[i];
  239. if(thing->isForceUse() || (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop() && !thing->asCreature()))
  240. return thing;
  241. }
  242. return m_things[0];
  243. }
  244. CreaturePtr Tile::getTopCreature()
  245. {
  246. CreaturePtr creature;
  247. for(uint i = 0; i < m_things.size(); ++i) {
  248. ThingPtr thing = m_things[i];
  249. if(thing->asLocalPlayer()) // return local player if there is no other creature
  250. creature = thing->asCreature();
  251. else if(thing->asCreature() && !thing->asLocalPlayer())
  252. return thing->asCreature();
  253. }
  254. return creature;
  255. }
  256. ThingPtr Tile::getTopMoveThing()
  257. {
  258. if(isEmpty())
  259. return nullptr;
  260. for(uint i = 0; i < m_things.size(); ++i) {
  261. ThingPtr thing = m_things[i];
  262. if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop() && !thing->asCreature()) {
  263. if(i > 0 && thing->isNotMoveable())
  264. return m_things[i-1];
  265. return thing;
  266. }
  267. }
  268. return m_things[0];
  269. }
  270. ThingPtr Tile::getTopMultiUseThing()
  271. {
  272. // this is related to classic controls, getting top item, forceuse or creature
  273. if(isEmpty())
  274. return nullptr;
  275. for(uint i = 0; i < m_things.size(); ++i) {
  276. ThingPtr thing = m_things[i];
  277. if(thing->isForceUse() || (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop())) {
  278. if(i > 0 && thing->isFluid())
  279. return m_things[i-1];
  280. return thing;
  281. }
  282. }
  283. return m_things[0];
  284. }
  285. bool Tile::isWalkable()
  286. {
  287. if(!getGround())
  288. return false;
  289. for(const ThingPtr& thing : m_things) {
  290. if(thing->isNotWalkable())
  291. return false;
  292. if(CreaturePtr creature = thing->asCreature()) {
  293. if(!creature->getPassable())
  294. return false;
  295. }
  296. }
  297. return true;
  298. }
  299. bool Tile::isFullGround()
  300. {
  301. ItemPtr ground = getGround();
  302. if(ground && ground->isFullGround())
  303. return true;
  304. return false;
  305. }
  306. bool Tile::isFullyOpaque()
  307. {
  308. ThingPtr firstObject = getThing(0);
  309. return firstObject && firstObject->isFullGround();
  310. }
  311. bool Tile::isLookPossible()
  312. {
  313. for(const ThingPtr& thing : m_things) {
  314. if(thing->blocksProjectile())
  315. return false;
  316. }
  317. return true;
  318. }
  319. bool Tile::isClickable()
  320. {
  321. bool hasGround = false;
  322. bool hasOnBottom = false;
  323. bool hasIgnoreLook = false;
  324. for(const ThingPtr& thing : m_things) {
  325. if(thing->isGround())
  326. hasGround = true;
  327. if(thing->isOnBottom())
  328. hasOnBottom = true;
  329. if(thing->isIgnoreLook())
  330. hasIgnoreLook = true;
  331. if((hasGround || hasOnBottom) && !hasIgnoreLook)
  332. return true;
  333. }
  334. return false;
  335. }
  336. bool Tile::isEmpty()
  337. {
  338. return m_things.size() == 0;
  339. }
  340. bool Tile::mustHookEast()
  341. {
  342. for(const ThingPtr& thing : m_things)
  343. if(thing->isHookEast())
  344. return true;
  345. return false;
  346. }
  347. bool Tile::mustHookSouth()
  348. {
  349. for(const ThingPtr& thing : m_things)
  350. if(thing->isHookSouth())
  351. return true;
  352. return false;
  353. }
  354. bool Tile::hasCreature()
  355. {
  356. for(const ThingPtr& thing : m_things)
  357. if(thing->asCreature())
  358. return true;
  359. return false;
  360. }
  361. bool Tile::limitsFloorsView()
  362. {
  363. // ground and walls limits the view
  364. ThingPtr firstThing = getThing(0);
  365. if(firstThing && !firstThing->isDontHide() && (firstThing->isGround() || firstThing->isOnBottom()))
  366. return true;
  367. return false;
  368. }
  369. bool Tile::canErase()
  370. {
  371. return m_walkingCreatures.empty() && m_effects.empty() && m_things.empty();
  372. }