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.

item.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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 "item.h"
  23. #include "thingtypemanager.h"
  24. #include "spritemanager.h"
  25. #include "thing.h"
  26. #include "tile.h"
  27. #include "shadermanager.h"
  28. #include "container.h"
  29. #include "map.h"
  30. #include "houses.h"
  31. #include "game.h"
  32. #include <framework/core/clock.h>
  33. #include <framework/core/eventdispatcher.h>
  34. #include <framework/graphics/graphics.h>
  35. #include <framework/core/filestream.h>
  36. #include <framework/core/binarytree.h>
  37. Item::Item() :
  38. m_clientId(0),
  39. m_serverId(0),
  40. m_countOrSubType(1)
  41. {
  42. }
  43. ItemPtr Item::create(int id)
  44. {
  45. ItemPtr item(new Item);
  46. item->setId(id);
  47. return item;
  48. }
  49. ItemPtr Item::createFromOtb(int id)
  50. {
  51. ItemPtr item(new Item);
  52. item->setOtbId(id);
  53. return item;
  54. }
  55. void Item::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
  56. {
  57. if(m_clientId == 0)
  58. return;
  59. // determine animation phase
  60. int animationPhase = calculateAnimationPhase(animate);
  61. if(getAnimationPhases() > 1) {
  62. if(animate)
  63. animationPhase = (g_clock.millis() % (Otc::ITEM_TICKS_PER_FRAME * getAnimationPhases())) / Otc::ITEM_TICKS_PER_FRAME;
  64. else
  65. animationPhase = getAnimationPhases()-1;
  66. }
  67. // determine x,y,z patterns
  68. int xPattern = 0, yPattern = 0, zPattern = 0;
  69. calculatePatterns(xPattern, yPattern, zPattern);
  70. rawGetThingType()->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase, lightView);
  71. }
  72. void Item::setId(uint32 id)
  73. {
  74. if(!g_things.isValidDatId(id, ThingCategoryItem))
  75. id = 0;
  76. m_serverId = g_things.findItemTypeByClientId(id)->getServerId();
  77. m_clientId = id;
  78. }
  79. void Item::setOtbId(uint16 id)
  80. {
  81. if(!g_things.isValidOtbId(id))
  82. id = 0;
  83. auto itemType = g_things.getItemType(id);
  84. m_serverId = id;
  85. id = itemType->getClientId();
  86. if(!g_things.isValidDatId(id, ThingCategoryItem))
  87. id = 0;
  88. m_clientId = id;
  89. }
  90. bool Item::isValid()
  91. {
  92. return g_things.isValidDatId(m_clientId, ThingCategoryItem);
  93. }
  94. void Item::unserializeItem(const BinaryTreePtr &in)
  95. {
  96. try {
  97. while(in->canRead()) {
  98. int attrib = in->getU8();
  99. if(attrib == 0)
  100. break;
  101. switch(attrib) {
  102. case ATTR_COUNT:
  103. case ATTR_RUNE_CHARGES:
  104. setCount(in->getU8());
  105. break;
  106. case ATTR_CHARGES:
  107. setCount(in->getU16());
  108. break;
  109. case ATTR_HOUSEDOORID:
  110. case ATTR_SCRIPTPROTECTED:
  111. case ATTR_DUALWIELD:
  112. case ATTR_DECAYING_STATE:
  113. m_attribs.set(attrib, in->getU8());
  114. break;
  115. case ATTR_ACTION_ID:
  116. case ATTR_UNIQUE_ID:
  117. case ATTR_DEPOT_ID:
  118. m_attribs.set(attrib, in->getU16());
  119. break;
  120. case ATTR_CONTAINER_ITEMS:
  121. case ATTR_ATTACK:
  122. case ATTR_EXTRAATTACK:
  123. case ATTR_DEFENSE:
  124. case ATTR_EXTRADEFENSE:
  125. case ATTR_ARMOR:
  126. case ATTR_ATTACKSPEED:
  127. case ATTR_HITCHANCE:
  128. case ATTR_DURATION:
  129. case ATTR_WRITTENDATE:
  130. case ATTR_SLEEPERGUID:
  131. case ATTR_SLEEPSTART:
  132. case ATTR_ATTRIBUTE_MAP:
  133. m_attribs.set(attrib, in->getU32());
  134. break;
  135. case ATTR_TELE_DEST: {
  136. Position pos;
  137. pos.x = in->getU16();
  138. pos.y = in->getU16();
  139. pos.z = in->getU8();
  140. m_attribs.set(attrib, pos);
  141. break;
  142. }
  143. case ATTR_NAME:
  144. case ATTR_TEXT:
  145. case ATTR_DESC:
  146. case ATTR_ARTICLE:
  147. case ATTR_WRITTENBY:
  148. m_attribs.set(attrib, in->getString());
  149. break;
  150. default:
  151. stdext::throw_exception(stdext::format("invalid item attribute %d", attrib));
  152. }
  153. }
  154. } catch(stdext::exception& e) {
  155. g_logger.error(stdext::format("Failed to unserialize OTBM item: %s", e.what()));
  156. }
  157. }
  158. void Item::serializeItem(const OutputBinaryTreePtr& out)
  159. {
  160. out->startNode(OTBM_ITEM);
  161. out->addU16(getServerId());
  162. out->addU8(ATTR_COUNT);
  163. out->addU8(getCount());
  164. out->addU8(ATTR_CHARGES);
  165. out->addU16(getCountOrSubType());
  166. Position dest = m_attribs.get<Position>(ATTR_TELE_DEST);
  167. if(dest.isValid()) {
  168. out->addU8(ATTR_TELE_DEST);
  169. out->addPos(dest);
  170. }
  171. if(isDepot()) {
  172. out->addU8(ATTR_DEPOT_ID);
  173. out->addU16(getDepotId());
  174. }
  175. uint16 aid = m_attribs.get<uint16>(ATTR_ACTION_ID);
  176. uint16 uid = m_attribs.get<uint16>(ATTR_UNIQUE_ID);
  177. if(aid) {
  178. out->addU8(ATTR_ACTION_ID);
  179. out->addU16(aid);
  180. }
  181. if(uid) {
  182. out->addU8(ATTR_UNIQUE_ID);
  183. out->addU16(uid);
  184. }
  185. out->endNode();
  186. if(!m_containerItems.empty()) {
  187. for(auto c : m_containerItems)
  188. c->serializeItem(out);
  189. }
  190. }
  191. int Item::getSubType()
  192. {
  193. if(isSplash() || isFluidContainer())
  194. return m_countOrSubType;
  195. if(g_game.getProtocolVersion() >= 900)
  196. return 0;
  197. return 1;
  198. }
  199. int Item::getCount()
  200. {
  201. if(isStackable())
  202. return m_countOrSubType;
  203. return 1;
  204. }
  205. bool Item::isMoveable()
  206. {
  207. return !rawGetThingType()->isNotMoveable();
  208. }
  209. bool Item::isGround()
  210. {
  211. return rawGetThingType()->isGround();
  212. }
  213. ItemPtr Item::clone()
  214. {
  215. ItemPtr item = ItemPtr(new Item);
  216. *(item.get()) = *this;
  217. return item;
  218. }
  219. void Item::calculatePatterns(int& xPattern, int& yPattern, int& zPattern)
  220. {
  221. if(isStackable() && getNumPatternX() == 4 && getNumPatternY() == 2) {
  222. if(m_countOrSubType <= 0) {
  223. xPattern = 0;
  224. yPattern = 0;
  225. } else if(m_countOrSubType < 5) {
  226. xPattern = m_countOrSubType-1;
  227. yPattern = 0;
  228. } else if(m_countOrSubType < 10) {
  229. xPattern = 0;
  230. yPattern = 1;
  231. } else if(m_countOrSubType < 25) {
  232. xPattern = 1;
  233. yPattern = 1;
  234. } else if(m_countOrSubType < 50) {
  235. xPattern = 2;
  236. yPattern = 1;
  237. } else {
  238. xPattern = 3;
  239. yPattern = 1;
  240. }
  241. } else if(isHangable()) {
  242. const TilePtr& tile = getTile();
  243. if(tile) {
  244. if(tile->mustHookSouth())
  245. xPattern = getNumPatternX() >= 2 ? 1 : 0;
  246. else if(tile->mustHookEast())
  247. xPattern = getNumPatternX() >= 3 ? 2 : 0;
  248. }
  249. } else if(isSplash() || isFluidContainer()) {
  250. int color = Otc::FluidTransparent;
  251. switch(m_countOrSubType) {
  252. case Otc::FluidNone:
  253. color = Otc::FluidTransparent;
  254. break;
  255. case Otc::FluidWater:
  256. color = Otc::FluidBlue;
  257. break;
  258. case Otc::FluidMana:
  259. color = Otc::FluidPurple;
  260. break;
  261. case Otc::FluidBeer:
  262. color = Otc::FluidBrown;
  263. break;
  264. case Otc::FluidOil:
  265. color = Otc::FluidBrown;
  266. break;
  267. case Otc::FluidBlood:
  268. color = Otc::FluidRed;
  269. break;
  270. case Otc::FluidSlime:
  271. color = Otc::FluidGreen;
  272. break;
  273. case Otc::FluidMud:
  274. color = Otc::FluidBrown;
  275. break;
  276. case Otc::FluidLemonade:
  277. color = Otc::FluidYellow;
  278. break;
  279. case Otc::FluidMilk:
  280. color = Otc::FluidWhite;
  281. break;
  282. case Otc::FluidWine:
  283. color = Otc::FluidPurple;
  284. break;
  285. case Otc::FluidHealth:
  286. color = Otc::FluidRed;
  287. break;
  288. case Otc::FluidUrine:
  289. color = Otc::FluidYellow;
  290. break;
  291. case Otc::FluidRum:
  292. color = Otc::FluidBrown;
  293. break;
  294. case Otc::FluidFruidJuice:
  295. color = Otc::FluidYellow;
  296. break;
  297. case Otc::FluidCoconutMilk:
  298. color = Otc::FluidWhite;
  299. break;
  300. case Otc::FluidTea:
  301. color = Otc::FluidBrown;
  302. break;
  303. case Otc::FluidMead:
  304. color = Otc::FluidBrown;
  305. break;
  306. default:
  307. color = Otc::FluidTransparent;
  308. break;
  309. }
  310. xPattern = (color % 4) % getNumPatternX();
  311. yPattern = (color / 4) % getNumPatternY();
  312. } else if(isGround() || isOnBottom()) {
  313. xPattern = m_position.x % getNumPatternX();
  314. yPattern = m_position.y % getNumPatternY();
  315. zPattern = m_position.z % getNumPatternZ();
  316. }
  317. }
  318. int Item::calculateAnimationPhase(bool animate)
  319. {
  320. if(getAnimationPhases() > 1) {
  321. if(animate)
  322. return (g_clock.millis() % (Otc::ITEM_TICKS_PER_FRAME * getAnimationPhases())) / Otc::ITEM_TICKS_PER_FRAME;
  323. else
  324. return getAnimationPhases()-1;
  325. }
  326. return 0;
  327. }
  328. int Item::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
  329. {
  330. int exactSize = 0;
  331. calculatePatterns(xPattern, yPattern, zPattern);
  332. animationPhase = calculateAnimationPhase(true);
  333. for(layer = 0; layer < getLayers(); ++layer)
  334. exactSize = std::max(exactSize, Thing::getExactSize(layer, xPattern, yPattern, zPattern, animationPhase));
  335. return exactSize;
  336. }
  337. const ThingTypePtr& Item::getThingType()
  338. {
  339. return g_things.getThingType(m_clientId, ThingCategoryItem);
  340. }
  341. ThingType* Item::rawGetThingType()
  342. {
  343. return g_things.rawGetThingType(m_clientId, ThingCategoryItem);
  344. }