Inventory.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. #include "Inventory.h"
  2. #include <InMemoryBuffer.h>
  3. #include "Area.h"
  4. #include "Constants.h"
  5. #include "Entity.h"
  6. #include "Game.h"
  7. #include "ItemFilter.h"
  8. #include "ItemSlot.h"
  9. #include "ItemStack.h"
  10. #include "ItemType.h"
  11. #include "NetworkMessage.h"
  12. using namespace Framework;
  13. InventoryInteraction::InventoryInteraction(
  14. Inventory* current, Inventory* other, Direction dir)
  15. : current(current),
  16. other(other),
  17. dir(dir)
  18. {
  19. lock();
  20. }
  21. InventoryInteraction::InventoryInteraction(
  22. const InventoryInteraction& interaction)
  23. : InventoryInteraction(
  24. interaction.current, interaction.other, interaction.dir)
  25. {}
  26. InventoryInteraction::~InventoryInteraction()
  27. {
  28. unlock();
  29. }
  30. void InventoryInteraction::lock()
  31. {
  32. if (!current || !other) return;
  33. if (current->location.x < other->location.x)
  34. {
  35. current->cs.lock();
  36. other->cs.lock();
  37. return;
  38. }
  39. else if (current->location.x == other->location.x)
  40. {
  41. if (current->location.y < other->location.y)
  42. {
  43. current->cs.lock();
  44. other->cs.lock();
  45. return;
  46. }
  47. else if (current->location.y == other->location.y)
  48. {
  49. if (current->location.z < other->location.z)
  50. {
  51. current->cs.lock();
  52. other->cs.lock();
  53. return;
  54. }
  55. }
  56. }
  57. other->cs.lock();
  58. current->cs.lock();
  59. }
  60. void InventoryInteraction::unlock()
  61. {
  62. if (!current || !other) return;
  63. if (current->location.x < other->location.x)
  64. {
  65. current->cs.unlock();
  66. other->cs.unlock();
  67. return;
  68. }
  69. else if (current->location.x == other->location.x)
  70. {
  71. if (current->location.y < other->location.y)
  72. {
  73. current->cs.unlock();
  74. other->cs.unlock();
  75. return;
  76. }
  77. else if (current->location.y == other->location.y)
  78. {
  79. if (current->location.z < other->location.z)
  80. {
  81. current->cs.unlock();
  82. other->cs.unlock();
  83. return;
  84. }
  85. }
  86. }
  87. other->cs.unlock();
  88. current->cs.unlock();
  89. }
  90. void InventoryInteraction::transaction(Inventory* zSource,
  91. Inventory* zTarget,
  92. ItemFilter* zFilter,
  93. Direction sourceView,
  94. Direction targetView,
  95. int count)
  96. {
  97. for (auto sourceSlot = zSource->pullSlotsOrder->begin(); sourceSlot;)
  98. {
  99. while (sourceSlot
  100. && (sourceSlot->getNumberOfItems() == 0
  101. || (zFilter && !zFilter->matchSourceSlot(sourceSlot))))
  102. sourceSlot++;
  103. if (!sourceSlot) break;
  104. // TODO: use target cache ot get list of slots that already contains the
  105. // source item
  106. bool needNext = 1;
  107. for (auto targetSlot = zTarget->pushSlotsOrder->begin(); targetSlot;)
  108. {
  109. while (targetSlot
  110. && (targetSlot->isFull()
  111. || (zFilter && !zFilter->matchTargetSlot(targetSlot))))
  112. targetSlot++;
  113. if (!targetSlot) break;
  114. needNext &= !Inventory::unsafeMove(zSource,
  115. zTarget,
  116. sourceSlot,
  117. targetSlot,
  118. sourceView,
  119. targetView,
  120. count);
  121. if (count == 0) return;
  122. if (sourceSlot->getNumberOfItems() == 0) break;
  123. }
  124. if (needNext) sourceSlot++;
  125. }
  126. }
  127. InventoryInteraction& InventoryInteraction::operator=(
  128. const InventoryInteraction& data)
  129. {
  130. if (&data == this) return *this;
  131. unlock();
  132. current = data.current;
  133. other = data.other;
  134. dir = data.dir;
  135. lock();
  136. return *this;
  137. }
  138. void InventoryInteraction::endInteraction()
  139. {
  140. unlock();
  141. current = 0;
  142. other = 0;
  143. }
  144. void InventoryInteraction::pullItems(int count, ItemFilter* zFilter)
  145. {
  146. if (!current || !other) return;
  147. transaction(other, current, zFilter, getOppositeDirection(dir), dir, count);
  148. }
  149. void InventoryInteraction::pushItems(int count, ItemFilter* zFilter)
  150. {
  151. if (!current || !other) return;
  152. transaction(current, other, zFilter, dir, getOppositeDirection(dir), count);
  153. }
  154. MultipleInventoryLock::MultipleInventoryLock(Inventory** inventories, int count)
  155. : inventories(new Inventory*[count]),
  156. count(count),
  157. locked(0)
  158. {
  159. // sort given inventories in locking order
  160. bool* used = new bool[count];
  161. memset(used, 0, count);
  162. // TODO: use a performant sorting algorithm
  163. for (int i = 0; i < count; i++)
  164. {
  165. Inventory* min = 0;
  166. int minJ = 0;
  167. for (int j = 0; j < count; j++)
  168. {
  169. if (!used[j])
  170. {
  171. if (!min)
  172. {
  173. min = inventories[j];
  174. minJ = j;
  175. continue;
  176. }
  177. if (inventories[j]->location.x < min->location.x)
  178. {
  179. min = inventories[j];
  180. minJ = j;
  181. continue;
  182. }
  183. if (inventories[j]->location.x == min->location.x)
  184. {
  185. if (inventories[j]->location.y < min->location.y)
  186. {
  187. min = inventories[j];
  188. minJ = j;
  189. continue;
  190. }
  191. if (inventories[j]->location.y == min->location.y)
  192. {
  193. if (inventories[j]->location.z < min->location.z)
  194. {
  195. min = inventories[j];
  196. minJ = j;
  197. continue;
  198. }
  199. }
  200. }
  201. }
  202. }
  203. this->inventories[i] = min;
  204. used[minJ] = 1;
  205. }
  206. lock();
  207. delete[] used;
  208. }
  209. MultipleInventoryLock::~MultipleInventoryLock()
  210. {
  211. unlock();
  212. delete[] inventories;
  213. }
  214. void MultipleInventoryLock::unlock()
  215. {
  216. if (locked)
  217. {
  218. locked = 0;
  219. for (int i = count - 1; i >= 0; i--)
  220. {
  221. inventories[i]->cs.unlock();
  222. }
  223. }
  224. }
  225. void MultipleInventoryLock::lock()
  226. {
  227. if (!locked)
  228. {
  229. locked = 1;
  230. for (int i = 0; i < count; i++)
  231. {
  232. inventories[i]->cs.lock();
  233. }
  234. }
  235. }
  236. Inventory::Inventory(
  237. const Framework::Vec3<float> location, int dimensionId, bool hasInventory)
  238. : ReferenceCounter(),
  239. nextSlotId(1),
  240. dimensionId(dimensionId),
  241. location(location)
  242. {
  243. if (hasInventory)
  244. {
  245. pullSlotsOrder = new Framework::RCArray<ItemSlot>();
  246. pushSlotsOrder = new Framework::RCArray<ItemSlot>();
  247. itemCache = new Framework::HashMap<int, Framework::Array<ItemSlot*>*>(
  248. ITEM_CACHE_SIZE, [](int key) { return key; });
  249. }
  250. else
  251. {
  252. pullSlotsOrder = 0;
  253. pushSlotsOrder = 0;
  254. itemCache = 0;
  255. }
  256. }
  257. Inventory::~Inventory()
  258. {
  259. if (pullSlotsOrder) pullSlotsOrder->release();
  260. if (pushSlotsOrder) pushSlotsOrder->release();
  261. if (itemCache) itemCache->release();
  262. }
  263. void Inventory::updateCache(ItemSlot* zSlot, int beforeKey)
  264. {
  265. if (!itemCache) return;
  266. int key
  267. = zSlot->zStack() ? zSlot->zStack()->zItem()->zItemType()->getId() : -1;
  268. if (key == beforeKey) return;
  269. if (beforeKey >= 0)
  270. {
  271. auto tmp = itemCache->safeGet(key, 0);
  272. if (tmp) tmp->removeValue(zSlot);
  273. }
  274. if (zSlot->zStack())
  275. {
  276. auto tmp = itemCache->safeGet(key, 0);
  277. if (!tmp)
  278. {
  279. tmp = new Array<ItemSlot*>();
  280. itemCache->put(key, tmp);
  281. }
  282. tmp->add(zSlot, 0);
  283. }
  284. }
  285. void Inventory::addSlot(ItemSlot* slot)
  286. {
  287. cs.lock();
  288. ((ItemSlotIDSetter*)slot)->setId(nextSlotId++);
  289. int pullPrio = slot->getPullPriority();
  290. int pushPrio = slot->getPushPriority();
  291. int index = 0;
  292. for (auto stack : *pullSlotsOrder)
  293. {
  294. if (stack->getPullPriority() > pullPrio) break;
  295. index++;
  296. }
  297. pullSlotsOrder->add(dynamic_cast<ItemSlot*>(slot->getThis()), index);
  298. index = 0;
  299. for (auto stack : *pushSlotsOrder)
  300. {
  301. if (stack->getPushPriority() > pushPrio) break;
  302. index++;
  303. }
  304. pushSlotsOrder->add(slot, index);
  305. updateCache(slot, -1);
  306. cs.unlock();
  307. }
  308. int Inventory::countAccessableItems(ItemFilter* zFilter, Direction dir) const
  309. {
  310. int count = 0;
  311. if (itemCache)
  312. {
  313. for (auto slot : *pullSlotsOrder)
  314. {
  315. if (slot->getNumberOfItems() > 0
  316. && (!zFilter || zFilter->matchSourceSlot(slot)))
  317. {
  318. if (allowPullStack(slot, dir))
  319. {
  320. count += slot->getNumberOfItems();
  321. }
  322. }
  323. }
  324. }
  325. return count;
  326. }
  327. bool Inventory::allowPullStack(ItemSlot* zSlot, Direction dir) const
  328. {
  329. return pullSlotsOrder != 0;
  330. }
  331. bool Inventory::allowPushStack(
  332. ItemSlot* zSlot, Direction dir, const Item* zItem, int& count) const
  333. {
  334. return pushSlotsOrder != 0;
  335. }
  336. void Inventory::afterPullStack(
  337. ItemSlot* zSlot, Direction dir, const Item* zItem, int count)
  338. {
  339. NetworkMessage* msg = new NetworkMessage();
  340. char* message = new char[9];
  341. message[0] = 1; // set count of items
  342. *(int*)(message + 1) = zSlot->getId();
  343. *(int*)(message + 5) = zSlot->getNumberOfItems();
  344. msg->setMessage(message, 9);
  345. notifyObservers(msg);
  346. for (auto call : afterPullStackCalls)
  347. call(zSlot, dir, zItem, count);
  348. }
  349. void Inventory::afterPushStack(
  350. ItemSlot* zSlot, Direction dir, const Item* zItem, int count)
  351. {
  352. updateSlot(zSlot);
  353. for (auto call : afterPushStackCalls)
  354. call(zSlot, dir, zItem, count);
  355. }
  356. void Inventory::updateSlot(ItemSlot* zSlot)
  357. {
  358. NetworkMessage* msg = new NetworkMessage();
  359. char* message = new char[9];
  360. message[0] = 1; // set count of items
  361. *(int*)(message + 1) = zSlot->getId();
  362. *(int*)(message + 5) = 0;
  363. msg->setMessage(message, 9);
  364. notifyObservers(msg);
  365. if (zSlot->getNumberOfItems() > 0)
  366. {
  367. const Item* zItem = zSlot->zStack()->zItem();
  368. NetworkMessage* msg = new NetworkMessage();
  369. char* message = new char[30 + zItem->getName().getLength()];
  370. message[0] = 2; // add new stack
  371. *(int*)(message + 1) = zSlot->getId();
  372. *(int*)(message + 5) = zSlot->getNumberOfItems();
  373. *(float*)(message + 9) = zItem->getHp();
  374. *(float*)(message + 13) = zItem->getMaxHp();
  375. *(float*)(message + 17) = zItem->getDurability();
  376. *(float*)(message + 21) = zItem->getMaxDurability();
  377. *(int*)(message + 25) = zItem->zItemType()->getId();
  378. *(message + 29) = (char)zItem->getName().getLength();
  379. memcpy(message + 30,
  380. zItem->getName().getText(),
  381. zItem->getName().getLength());
  382. msg->setMessage(message, 30 + zItem->getName().getLength());
  383. notifyObservers(msg);
  384. }
  385. }
  386. void Inventory::loadInventory(Framework::StreamReader* zReader)
  387. {
  388. if (itemCache)
  389. {
  390. for (auto stack : *pushSlotsOrder)
  391. {
  392. int size = 0;
  393. zReader->lese((char*)&size, 4);
  394. if (size != 0)
  395. {
  396. int id = 0;
  397. zReader->lese((char*)&id, 4);
  398. Item* item = Game::INSTANCE->zItemType(id)->loadItem(zReader);
  399. stack->addItems(new ItemStack(item, size), NO_DIRECTION);
  400. }
  401. }
  402. }
  403. }
  404. void Inventory::saveInventory(Framework::StreamWriter* zWriter)
  405. {
  406. if (itemCache)
  407. {
  408. for (auto slot : *pushSlotsOrder)
  409. {
  410. const ItemStack* stack = slot->zStack();
  411. int value = 0;
  412. if (!stack || !stack->zItem())
  413. {
  414. zWriter->schreibe((char*)&value, 4);
  415. }
  416. else
  417. {
  418. value = stack->getSize();
  419. zWriter->schreibe((char*)&value, 4);
  420. value = stack->zItem()->zItemType()->getId();
  421. zWriter->schreibe((char*)&value, 4);
  422. stack->zItem()->zItemType()->saveItem(stack->zItem(), zWriter);
  423. }
  424. }
  425. }
  426. }
  427. void Inventory::notifyObservers(NetworkMessage* msg)
  428. {
  429. observable.notifyObservers(msg);
  430. }
  431. void Inventory::lock()
  432. {
  433. cs.lock();
  434. }
  435. void Inventory::unlock()
  436. {
  437. cs.unlock();
  438. }
  439. const ItemSlot* Inventory::zSlot(int id) const
  440. {
  441. if (itemCache)
  442. {
  443. for (auto slot : *pushSlotsOrder)
  444. {
  445. if (slot->getId() == id) return slot;
  446. }
  447. }
  448. return 0;
  449. }
  450. void Inventory::localTransaction(Array<ItemSlot*>* zSourceSlots,
  451. Array<ItemSlot*>* zTargetSlots,
  452. ItemFilter* zFilter,
  453. int count,
  454. Direction outDir,
  455. Direction inDir)
  456. {
  457. if (itemCache)
  458. {
  459. cs.lock();
  460. auto sourceSlot
  461. = zSourceSlots ? zSourceSlots->begin() : pullSlotsOrder->begin();
  462. while (true)
  463. {
  464. while (sourceSlot
  465. && (sourceSlot->getNumberOfItems() == 0
  466. || (zFilter && !zFilter->matchSourceSlot(sourceSlot))))
  467. sourceSlot++;
  468. if (!sourceSlot)
  469. {
  470. cs.unlock();
  471. return;
  472. }
  473. bool needNext = 1;
  474. for (auto targetSlot = zTargetSlots->begin(); targetSlot;)
  475. {
  476. while (
  477. targetSlot
  478. && (targetSlot->isFull()
  479. || (zFilter && !zFilter->matchTargetSlot(targetSlot))))
  480. targetSlot++;
  481. if (!targetSlot) break;
  482. needNext &= !Inventory::unsafeMove(
  483. this, this, sourceSlot, targetSlot, outDir, inDir, count);
  484. if (count == 0)
  485. {
  486. cs.unlock();
  487. return;
  488. }
  489. if (sourceSlot->getNumberOfItems() == 0) break;
  490. }
  491. if (needNext) sourceSlot++;
  492. }
  493. cs.unlock();
  494. }
  495. }
  496. void Inventory::addItems(ItemStack* zItems, Direction dir, ItemFilter* zFilter)
  497. {
  498. if (itemCache && zItems && zItems->getSize() > 0)
  499. {
  500. cs.lock();
  501. for (auto targetSlot = pushSlotsOrder->begin(); targetSlot;
  502. targetSlot++)
  503. {
  504. if (!targetSlot->isFull()
  505. && (!zFilter || zFilter->matchTargetSlot(targetSlot)))
  506. {
  507. if (targetSlot->zStack())
  508. {
  509. if (targetSlot->zStack()->zItem()->canBeStackedWith(
  510. zItems->zItem()))
  511. {
  512. int number = MIN(targetSlot->numberOfAddableItems(
  513. zItems->zItem(), dir),
  514. zItems->getSize());
  515. int tmp = number;
  516. if (number > 0
  517. && allowPushStack(
  518. targetSlot, dir, zItems->zItem(), tmp))
  519. {
  520. number = MIN(number, tmp);
  521. ItemStack* stack = zItems->split(number);
  522. if (stack)
  523. {
  524. targetSlot->addItems(stack, dir);
  525. afterPushStack(targetSlot,
  526. dir,
  527. targetSlot->zStack()->zItem(),
  528. number);
  529. if (stack->getSize()) throw stack;
  530. stack->release();
  531. if (!zItems->getSize()) break;
  532. }
  533. }
  534. }
  535. }
  536. else
  537. {
  538. int number = MIN(
  539. targetSlot->numberOfAddableItems(zItems->zItem(), dir),
  540. zItems->getSize());
  541. int tmp = number;
  542. if (number > 0
  543. && allowPushStack(
  544. targetSlot, dir, zItems->zItem(), tmp))
  545. {
  546. number = MIN(number, tmp);
  547. ItemStack* stack = zItems->split(number);
  548. if (stack)
  549. {
  550. targetSlot->addItems(stack, dir);
  551. updateCache(targetSlot, -1);
  552. afterPushStack(targetSlot,
  553. dir,
  554. targetSlot->zStack()->zItem(),
  555. number);
  556. if (stack->getSize()) throw stack;
  557. stack->release();
  558. if (!zItems->getSize()) break;
  559. }
  560. }
  561. }
  562. }
  563. }
  564. cs.unlock();
  565. }
  566. }
  567. void Inventory::addItems(ItemSlot* zSlot, ItemStack* zItems, Direction dir)
  568. {
  569. if (zSlot->zStack()
  570. && !zSlot->zStack()->zItem()->canBeStackedWith(zItems->zItem()))
  571. return;
  572. bool needUpdate = !zSlot->zStack();
  573. int number = MIN(
  574. zSlot->numberOfAddableItems(zItems->zItem(), dir), zItems->getSize());
  575. int tmp = number;
  576. if (number > 0 && allowPushStack(zSlot, dir, zItems->zItem(), tmp))
  577. {
  578. number = MIN(number, tmp);
  579. ItemStack* stack = zItems->split(number);
  580. if (stack)
  581. {
  582. zSlot->addItems(stack, dir);
  583. if (needUpdate) updateCache(zSlot, -1);
  584. afterPushStack(zSlot, dir, zSlot->zStack()->zItem(), number);
  585. if (stack->getSize()) throw stack;
  586. stack->release();
  587. }
  588. }
  589. }
  590. ItemStack* Inventory::takeItemsOut(ItemSlot* zSlot, int count, Direction dir)
  591. {
  592. if (allowPullStack(zSlot, dir))
  593. {
  594. ItemStack* stack = zSlot->takeItemsOut(count, dir);
  595. if (stack)
  596. {
  597. updateCache(zSlot, stack->zItem()->zItemType()->getId());
  598. if (stack->getSize() > 0)
  599. afterPullStack(zSlot, dir, stack->zItem(), stack->getSize());
  600. }
  601. return stack;
  602. }
  603. return 0;
  604. }
  605. InventoryInteraction Inventory::interactWith(
  606. Inventory* zInventory, Direction dir)
  607. {
  608. return InventoryInteraction(this, zInventory, dir);
  609. }
  610. void Inventory::unsaveAddItem(
  611. ItemStack* zStack, Direction dir, ItemFilter* zFilter)
  612. {
  613. addItems(zStack, dir, zFilter);
  614. }
  615. int Inventory::numberOfAddableItems(const Item* zItem, Direction dir) const
  616. {
  617. int count = 0;
  618. for (auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++)
  619. {
  620. int maxCount = targetSlot->numberOfAddableItems(zItem, dir);
  621. int allowed = maxCount;
  622. if (allowPushStack(targetSlot, dir, zItem, allowed))
  623. count += MIN(maxCount, allowed);
  624. }
  625. return count;
  626. }
  627. int Inventory::numberOfAddableItems(
  628. const Item* zItem, Direction dir, const Framework::Text& slotName) const
  629. {
  630. int count = 0;
  631. for (auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++)
  632. {
  633. if (targetSlot->getName().istGleich(slotName))
  634. {
  635. int maxCount = targetSlot->numberOfAddableItems(zItem, dir);
  636. int allowed = maxCount;
  637. if (allowPushStack(targetSlot, dir, zItem, allowed))
  638. count += MIN(maxCount, allowed);
  639. }
  640. }
  641. return count;
  642. }
  643. bool Inventory::isAllAvailable(Framework::RCArray<RecipieInput>& inputs,
  644. const Framework::Text& slotName) const
  645. {
  646. int* used = new int[pullSlotsOrder->getEintragAnzahl()];
  647. memset(used, 0, sizeof(int) * pullSlotsOrder->getEintragAnzahl());
  648. for (RecipieInput* input : inputs)
  649. {
  650. int found = 0;
  651. for (int i = 0; i < pullSlotsOrder->getEintragAnzahl(); i++)
  652. {
  653. ItemSlot* slot = pullSlotsOrder->get(i);
  654. if (slot && slot->zStack() && slot->zStack()->zItem()
  655. && slot->getNumberOfItems() > used[i]
  656. && slot->getName().istGleich(slotName)
  657. && input->zFilter()->matchItem(slot->zStack()->zItem()))
  658. {
  659. int usable = slot->getNumberOfItems() - used[i];
  660. if (found + usable >= input->getAmount())
  661. {
  662. used[i] += input->getAmount() - found;
  663. found = input->getAmount();
  664. break;
  665. }
  666. else
  667. {
  668. used[i] += usable;
  669. found += usable;
  670. }
  671. }
  672. }
  673. if (found < input->getAmount())
  674. {
  675. delete[] used;
  676. return 0;
  677. }
  678. }
  679. delete[] used;
  680. return 1;
  681. }
  682. void Inventory::consume(
  683. Framework::RCArray<RecipieInput>& inputs, const Framework::Text& slotName)
  684. {
  685. for (RecipieInput* input : inputs)
  686. {
  687. int consumed = 0;
  688. for (int i = 0; i < pullSlotsOrder->getEintragAnzahl(); i++)
  689. {
  690. ItemSlot* slot = pullSlotsOrder->get(i);
  691. if (slot && slot->zStack() && slot->zStack()->zItem()
  692. && slot->getName().istGleich(slotName)
  693. && input->zFilter()->matchItem(slot->zStack()->zItem()))
  694. {
  695. if (consumed + slot->getNumberOfItems() >= input->getAmount())
  696. {
  697. takeItemsOut(
  698. slot, input->getAmount() - consumed, NO_DIRECTION)
  699. ->release();
  700. consumed = input->getAmount();
  701. break;
  702. }
  703. else
  704. {
  705. consumed += slot->getNumberOfItems();
  706. takeItemsOut(slot, slot->getNumberOfItems(), NO_DIRECTION)
  707. ->release();
  708. }
  709. }
  710. }
  711. }
  712. }
  713. Framework::ArrayIterator<ItemSlot*> Inventory::begin()
  714. {
  715. return pullSlotsOrder->begin();
  716. }
  717. Framework::ArrayIterator<ItemSlot*> Inventory::end()
  718. {
  719. return pullSlotsOrder->end();
  720. }
  721. void Inventory::inventoryApi(Framework::StreamReader* zRequest,
  722. NetworkMessage* zResponse,
  723. Entity* zSource)
  724. {
  725. char type;
  726. zRequest->lese(&type, 1);
  727. switch (type)
  728. {
  729. case 0: // request inventory
  730. {
  731. char idLen;
  732. zRequest->lese(&idLen, 1);
  733. char* id = new char[idLen + 1];
  734. zRequest->lese(id, idLen);
  735. id[(int)idLen] = 0;
  736. int processor;
  737. zRequest->lese((char*)&processor, 4);
  738. zResponse->addressUIElement(id, processor);
  739. observable.addObserver(zSource, id, processor);
  740. delete[] id;
  741. char filterLen;
  742. zRequest->lese(&filterLen, 1);
  743. char* filter = new char[filterLen + 1];
  744. if (filterLen) zRequest->lese(filter, filterLen);
  745. filter[(int)filterLen] = 0;
  746. InMemoryBuffer buffer;
  747. int count = 0;
  748. for (ItemSlot* slot : *this)
  749. {
  750. if (filterLen == 0 || slot->getName().istGleich(filter))
  751. {
  752. count++;
  753. int id = slot->getId();
  754. buffer.schreibe((char*)&id, 4);
  755. int itemCount = slot->getNumberOfItems();
  756. buffer.schreibe((char*)&itemCount, 4);
  757. if (itemCount > 0)
  758. {
  759. float f = slot->zStack()->zItem()->getHp();
  760. buffer.schreibe((char*)&f, 4);
  761. f = slot->zStack()->zItem()->getMaxHp();
  762. buffer.schreibe((char*)&f, 4);
  763. f = slot->zStack()->zItem()->getDurability();
  764. buffer.schreibe((char*)&f, 4);
  765. f = slot->zStack()->zItem()->getMaxDurability();
  766. buffer.schreibe((char*)&f, 4);
  767. int id = slot->zStack()->zItem()->zItemType()->getId();
  768. buffer.schreibe((char*)&id, 4);
  769. char len = (char)slot->zStack()
  770. ->zItem()
  771. ->getName()
  772. .getLength();
  773. buffer.schreibe((char*)&len, 1);
  774. buffer.schreibe(
  775. slot->zStack()->zItem()->getName().getText(),
  776. slot->zStack()->zItem()->getName().getLength());
  777. }
  778. }
  779. }
  780. delete[] filter;
  781. char* msg = new char[5 + buffer.getSize()];
  782. msg[0] = 0;
  783. *(int*)(msg + 1) = count;
  784. buffer.lese(msg + 5, (int)buffer.getSize());
  785. zResponse->setMessage(msg, 5 + (int)buffer.getSize());
  786. break;
  787. }
  788. case 1: // remove Observer
  789. {
  790. char idLen;
  791. zRequest->lese(&idLen, 1);
  792. char* id = new char[idLen + 1];
  793. zRequest->lese(id, idLen);
  794. id[(int)idLen] = 0;
  795. int processor;
  796. zRequest->lese((char*)&processor, 4);
  797. observable.removeObserver(zSource, id, processor);
  798. delete[] id;
  799. break;
  800. }
  801. case 2: // request item tooltip
  802. {
  803. char idLen;
  804. zRequest->lese(&idLen, 1);
  805. char* id = new char[idLen + 1];
  806. zRequest->lese(id, idLen);
  807. id[(int)idLen] = 0;
  808. int processor;
  809. zRequest->lese((char*)&processor, 4);
  810. zResponse->addressUIElement(id, processor);
  811. delete[] id;
  812. int slotId;
  813. zRequest->lese((char*)&slotId, 4);
  814. Text uiml;
  815. for (ItemSlot* slot : *pullSlotsOrder)
  816. {
  817. if (slot->getId() == slotId)
  818. {
  819. if (slot->zStack() && slot->zStack()->zItem())
  820. uiml = slot->zStack()->zItem()->getTooltipUIML();
  821. }
  822. }
  823. short len = (short)uiml.getLength();
  824. char* buffer = new char[uiml.getLength() + 7];
  825. buffer[0] = 3;
  826. *(int*)(buffer + 1) = slotId;
  827. *(short*)(buffer + 5) = len;
  828. memcpy(buffer + 7, uiml, len);
  829. zResponse->setMessage(buffer, len + 7);
  830. break;
  831. }
  832. }
  833. }
  834. void Inventory::registerAfterPullStackCall(std::function<void(
  835. ItemSlot* zSlot, Direction dir, const Item* zItem, int count)> call)
  836. {
  837. afterPullStackCalls.add(call);
  838. }
  839. void Inventory::registerAfterPushStackCall(std::function<void(
  840. ItemSlot* zSlot, Direction dir, const Item* zItem, int count)> call)
  841. {
  842. afterPushStackCalls.add(call);
  843. }
  844. void Inventory::registerObserverAddedCall(
  845. std::function<void(Entity* zSource, Framework::Text id, int processor)>
  846. call)
  847. {
  848. observable.registerOnObserverAddedCall(call);
  849. }
  850. int Inventory::getDimensionId() const
  851. {
  852. return dimensionId;
  853. }
  854. Framework::Vec3<float> Inventory::getLocation() const
  855. {
  856. return location;
  857. }
  858. bool Inventory::unsafeMove(Inventory* zSource,
  859. Inventory* zTarget,
  860. ArrayIterator<ItemSlot*>& sourceSlot,
  861. ArrayIterator<ItemSlot*>& targetSlot,
  862. Direction outDir,
  863. Direction inDir,
  864. int& count)
  865. {
  866. if (targetSlot->zStack())
  867. {
  868. if (sourceSlot->zStack()->zItem()->canBeStackedWith(
  869. targetSlot->zStack()->zItem()))
  870. {
  871. int number = MIN(targetSlot->numberOfAddableItems(
  872. sourceSlot->zStack()->zItem(), outDir),
  873. count);
  874. int tmp = number;
  875. if (number > 0 && zSource->allowPullStack(sourceSlot, outDir)
  876. && zTarget->allowPushStack(
  877. targetSlot, inDir, sourceSlot->zStack()->zItem(), tmp))
  878. {
  879. number = MIN(number, tmp);
  880. ItemStack* stack = sourceSlot->takeItemsOut(number, outDir);
  881. if (stack)
  882. {
  883. targetSlot->addItems(stack, inDir);
  884. zSource->updateCache(sourceSlot,
  885. targetSlot->zStack()->zItem()->zItemType()->getId());
  886. zSource->afterPullStack(sourceSlot,
  887. outDir,
  888. targetSlot->zStack()->zItem(),
  889. number);
  890. zTarget->afterPushStack(targetSlot,
  891. inDir,
  892. targetSlot->zStack()->zItem(),
  893. number);
  894. if (stack->getSize()) throw stack;
  895. stack->release();
  896. count -= number;
  897. return 1;
  898. }
  899. else
  900. targetSlot++;
  901. }
  902. else
  903. targetSlot++;
  904. }
  905. else
  906. targetSlot++;
  907. }
  908. else
  909. {
  910. int number = MIN(targetSlot->numberOfAddableItems(
  911. sourceSlot->zStack()->zItem(), outDir),
  912. count);
  913. int tmp = number;
  914. if (number > 0 && zSource->allowPullStack(sourceSlot, outDir)
  915. && zTarget->allowPushStack(
  916. targetSlot, inDir, sourceSlot->zStack()->zItem(), tmp))
  917. {
  918. number = MIN(number, tmp);
  919. if (number > 0)
  920. {
  921. ItemStack* stack = sourceSlot->takeItemsOut(number, outDir);
  922. if (stack)
  923. {
  924. targetSlot->addItems(stack, inDir);
  925. zSource->updateCache(sourceSlot,
  926. targetSlot->zStack()->zItem()->zItemType()->getId());
  927. zTarget->updateCache(targetSlot, -1);
  928. zSource->afterPullStack(sourceSlot,
  929. outDir,
  930. targetSlot->zStack()->zItem(),
  931. number);
  932. zTarget->afterPushStack(targetSlot,
  933. inDir,
  934. targetSlot->zStack()->zItem(),
  935. number);
  936. if (stack->getSize()) throw stack;
  937. stack->release();
  938. count -= number;
  939. return 1;
  940. }
  941. else
  942. targetSlot++;
  943. }
  944. else
  945. targetSlot++;
  946. }
  947. else
  948. targetSlot++;
  949. }
  950. return 0;
  951. }