Inventory.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  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. bool Inventory::allowPullStack(ItemSlot* zSlot, Direction dir) const
  309. {
  310. return pullSlotsOrder;
  311. }
  312. bool Inventory::allowPushStack(
  313. ItemSlot* zSlot, Direction dir, const Item* zItem, int& count) const
  314. {
  315. return pushSlotsOrder;
  316. }
  317. void Inventory::afterPullStack(
  318. ItemSlot* zSlot, Direction dir, const Item* zItem, int count)
  319. {
  320. NetworkMessage* msg = new NetworkMessage();
  321. char* message = new char[9];
  322. message[0] = 1; // set count of items
  323. *(int*)(message + 1) = zSlot->getId();
  324. *(int*)(message + 5) = zSlot->getNumberOfItems();
  325. msg->setMessage(message, 9);
  326. notifyObservers(msg);
  327. for (auto call : afterPullStackCalls)
  328. call(zSlot, dir, zItem, count);
  329. }
  330. void Inventory::afterPushStack(
  331. ItemSlot* zSlot, Direction dir, const Item* zItem, int count)
  332. {
  333. updateSlot(zSlot);
  334. for (auto call : afterPushStackCalls)
  335. call(zSlot, dir, zItem, count);
  336. }
  337. void Inventory::updateSlot(ItemSlot* zSlot)
  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) = 0;
  344. msg->setMessage(message, 9);
  345. notifyObservers(msg);
  346. if (zSlot->getNumberOfItems() > 0)
  347. {
  348. const Item* zItem = zSlot->zStack()->zItem();
  349. NetworkMessage* msg = new NetworkMessage();
  350. char* message = new char[30 + zItem->getName().getLength()];
  351. message[0] = 2; // add new stack
  352. *(int*)(message + 1) = zSlot->getId();
  353. *(int*)(message + 5) = zSlot->getNumberOfItems();
  354. *(float*)(message + 9) = zItem->getHp();
  355. *(float*)(message + 13) = zItem->getMaxHp();
  356. *(float*)(message + 17) = zItem->getDurability();
  357. *(float*)(message + 21) = zItem->getMaxDurability();
  358. *(int*)(message + 25) = zItem->zItemType()->getId();
  359. *(message + 29) = (char)zItem->getName().getLength();
  360. memcpy(message + 30,
  361. zItem->getName().getText(),
  362. zItem->getName().getLength());
  363. msg->setMessage(message, 30 + zItem->getName().getLength());
  364. notifyObservers(msg);
  365. }
  366. }
  367. void Inventory::loadInventory(Framework::StreamReader* zReader)
  368. {
  369. if (itemCache)
  370. {
  371. for (auto stack : *pushSlotsOrder)
  372. {
  373. int size = 0;
  374. zReader->lese((char*)&size, 4);
  375. if (size != 0)
  376. {
  377. int id = 0;
  378. zReader->lese((char*)&id, 4);
  379. Item* item = Game::INSTANCE->zItemType(id)->loadItem(zReader);
  380. stack->addItems(new ItemStack(item, size), NO_DIRECTION);
  381. }
  382. }
  383. }
  384. }
  385. void Inventory::saveInventory(Framework::StreamWriter* zWriter)
  386. {
  387. if (itemCache)
  388. {
  389. for (auto slot : *pushSlotsOrder)
  390. {
  391. const ItemStack* stack = slot->zStack();
  392. int value = 0;
  393. if (!stack || !stack->zItem())
  394. {
  395. zWriter->schreibe((char*)&value, 4);
  396. }
  397. else
  398. {
  399. value = stack->getSize();
  400. zWriter->schreibe((char*)&value, 4);
  401. value = stack->zItem()->zItemType()->getId();
  402. zWriter->schreibe((char*)&value, 4);
  403. stack->zItem()->zItemType()->saveItem(stack->zItem(), zWriter);
  404. }
  405. }
  406. }
  407. }
  408. void Inventory::notifyObservers(NetworkMessage* msg)
  409. {
  410. observable.notifyObservers(msg);
  411. }
  412. void Inventory::lock()
  413. {
  414. cs.lock();
  415. }
  416. void Inventory::unlock()
  417. {
  418. cs.unlock();
  419. }
  420. const ItemSlot* Inventory::zSlot(int id) const
  421. {
  422. if (itemCache)
  423. {
  424. for (auto slot : *pushSlotsOrder)
  425. {
  426. if (slot->getId() == id) return slot;
  427. }
  428. }
  429. return 0;
  430. }
  431. void Inventory::localTransaction(Array<ItemSlot*>* zSourceSlots,
  432. Array<ItemSlot*>* zTargetSlots,
  433. ItemFilter* zFilter,
  434. int count,
  435. Direction outDir,
  436. Direction inDir)
  437. {
  438. if (itemCache)
  439. {
  440. cs.lock();
  441. auto sourceSlot
  442. = zSourceSlots ? zSourceSlots->begin() : pullSlotsOrder->begin();
  443. while (true)
  444. {
  445. while (sourceSlot
  446. && (sourceSlot->getNumberOfItems() == 0
  447. || (zFilter && !zFilter->matchSourceSlot(sourceSlot))))
  448. sourceSlot++;
  449. if (!sourceSlot)
  450. {
  451. cs.unlock();
  452. return;
  453. }
  454. bool needNext = 1;
  455. for (auto targetSlot = zTargetSlots->begin(); targetSlot;)
  456. {
  457. while (
  458. targetSlot
  459. && (targetSlot->isFull()
  460. || (zFilter && !zFilter->matchTargetSlot(targetSlot))))
  461. targetSlot++;
  462. if (!targetSlot) break;
  463. needNext &= !Inventory::unsafeMove(
  464. this, this, sourceSlot, targetSlot, outDir, inDir, count);
  465. if (count == 0)
  466. {
  467. cs.unlock();
  468. return;
  469. }
  470. if (sourceSlot->getNumberOfItems() == 0) break;
  471. }
  472. if (needNext) sourceSlot++;
  473. }
  474. cs.unlock();
  475. }
  476. }
  477. void Inventory::addItems(ItemStack* zItems, Direction dir, ItemFilter* zFilter)
  478. {
  479. if (itemCache && zItems && zItems->getSize() > 0)
  480. {
  481. cs.lock();
  482. for (auto targetSlot = pushSlotsOrder->begin(); targetSlot;
  483. targetSlot++)
  484. {
  485. if (!targetSlot->isFull()
  486. && (!zFilter || zFilter->matchTargetSlot(targetSlot)))
  487. {
  488. if (targetSlot->zStack())
  489. {
  490. if (targetSlot->zStack()->zItem()->canBeStackedWith(
  491. zItems->zItem()))
  492. {
  493. int number = MIN(targetSlot->numberOfAddableItems(
  494. zItems->zItem(), dir),
  495. zItems->getSize());
  496. int tmp = number;
  497. if (number > 0
  498. && allowPushStack(
  499. targetSlot, dir, zItems->zItem(), tmp))
  500. {
  501. number = MIN(number, tmp);
  502. ItemStack* stack = zItems->split(number);
  503. if (stack)
  504. {
  505. targetSlot->addItems(stack, dir);
  506. afterPushStack(targetSlot,
  507. dir,
  508. targetSlot->zStack()->zItem(),
  509. number);
  510. if (stack->getSize()) throw stack;
  511. stack->release();
  512. if (!zItems->getSize()) break;
  513. }
  514. }
  515. }
  516. }
  517. else
  518. {
  519. int number = MIN(
  520. targetSlot->numberOfAddableItems(zItems->zItem(), dir),
  521. zItems->getSize());
  522. int tmp = number;
  523. if (number > 0
  524. && allowPushStack(
  525. targetSlot, dir, zItems->zItem(), tmp))
  526. {
  527. number = MIN(number, tmp);
  528. ItemStack* stack = zItems->split(number);
  529. if (stack)
  530. {
  531. targetSlot->addItems(stack, dir);
  532. updateCache(targetSlot, -1);
  533. afterPushStack(targetSlot,
  534. dir,
  535. targetSlot->zStack()->zItem(),
  536. number);
  537. if (stack->getSize()) throw stack;
  538. stack->release();
  539. if (!zItems->getSize()) break;
  540. }
  541. }
  542. }
  543. }
  544. }
  545. cs.unlock();
  546. }
  547. }
  548. void Inventory::addItems(ItemSlot* zSlot, ItemStack* zItems, Direction dir)
  549. {
  550. if (zSlot->zStack()
  551. && !zSlot->zStack()->zItem()->canBeStackedWith(zItems->zItem()))
  552. return;
  553. bool needUpdate = !zSlot->zStack();
  554. int number = MIN(
  555. zSlot->numberOfAddableItems(zItems->zItem(), dir), zItems->getSize());
  556. int tmp = number;
  557. if (number > 0 && allowPushStack(zSlot, dir, zItems->zItem(), tmp))
  558. {
  559. number = MIN(number, tmp);
  560. ItemStack* stack = zItems->split(number);
  561. if (stack)
  562. {
  563. zSlot->addItems(stack, dir);
  564. if (needUpdate) updateCache(zSlot, -1);
  565. afterPushStack(zSlot, dir, zSlot->zStack()->zItem(), number);
  566. if (stack->getSize()) throw stack;
  567. stack->release();
  568. }
  569. }
  570. }
  571. ItemStack* Inventory::takeItemsOut(ItemSlot* zSlot, int count, Direction dir)
  572. {
  573. if (allowPullStack(zSlot, dir))
  574. {
  575. ItemStack* stack = zSlot->takeItemsOut(count, dir);
  576. if (stack)
  577. {
  578. updateCache(zSlot, stack->zItem()->zItemType()->getId());
  579. if (stack->getSize() > 0)
  580. afterPullStack(zSlot, dir, stack->zItem(), stack->getSize());
  581. }
  582. return stack;
  583. }
  584. return 0;
  585. }
  586. InventoryInteraction Inventory::interactWith(
  587. Inventory* zInventory, Direction dir)
  588. {
  589. return InventoryInteraction(this, zInventory, dir);
  590. }
  591. void Inventory::unsaveAddItem(
  592. ItemStack* zStack, Direction dir, ItemFilter* zFilter)
  593. {
  594. addItems(zStack, dir, zFilter);
  595. }
  596. int Inventory::numberOfAddableItems(const Item* zItem, Direction dir) const
  597. {
  598. int count = 0;
  599. for (auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++)
  600. {
  601. int maxCount = targetSlot->numberOfAddableItems(zItem, dir);
  602. int allowed = maxCount;
  603. if (allowPushStack(targetSlot, dir, zItem, allowed))
  604. count += MIN(maxCount, allowed);
  605. }
  606. return count;
  607. }
  608. int Inventory::numberOfAddableItems(
  609. const Item* zItem, Direction dir, const Framework::Text& slotName) const
  610. {
  611. int count = 0;
  612. for (auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++)
  613. {
  614. if (targetSlot->getName().istGleich(slotName))
  615. {
  616. int maxCount = targetSlot->numberOfAddableItems(zItem, dir);
  617. int allowed = maxCount;
  618. if (allowPushStack(targetSlot, dir, zItem, allowed))
  619. count += MIN(maxCount, allowed);
  620. }
  621. }
  622. return count;
  623. }
  624. bool Inventory::isAllAvailable(Framework::RCArray<RecipieInput>& inputs,
  625. const Framework::Text& slotName) const
  626. {
  627. int* used = new int[pullSlotsOrder->getEintragAnzahl()];
  628. memset(used, 0, sizeof(int) * pullSlotsOrder->getEintragAnzahl());
  629. for (RecipieInput* input : inputs)
  630. {
  631. int found = 0;
  632. for (int i = 0; i < pullSlotsOrder->getEintragAnzahl(); i++)
  633. {
  634. ItemSlot* slot = pullSlotsOrder->get(i);
  635. if (slot && slot->zStack() && slot->zStack()->zItem()
  636. && slot->getNumberOfItems() > used[i]
  637. && slot->getName().istGleich(slotName)
  638. && input->zFilter()->matchItem(slot->zStack()->zItem()))
  639. {
  640. int usable = slot->getNumberOfItems() - used[i];
  641. if (found + usable >= input->getAmount())
  642. {
  643. used[i] += input->getAmount() - found;
  644. found = input->getAmount();
  645. break;
  646. }
  647. else
  648. {
  649. used[i] += usable;
  650. found += usable;
  651. }
  652. }
  653. }
  654. if (found < input->getAmount())
  655. {
  656. delete[] used;
  657. return 0;
  658. }
  659. }
  660. delete[] used;
  661. return 1;
  662. }
  663. void Inventory::consume(
  664. Framework::RCArray<RecipieInput>& inputs, const Framework::Text& slotName)
  665. {
  666. for (RecipieInput* input : inputs)
  667. {
  668. int consumed = 0;
  669. for (int i = 0; i < pullSlotsOrder->getEintragAnzahl(); i++)
  670. {
  671. ItemSlot* slot = pullSlotsOrder->get(i);
  672. if (slot && slot->zStack() && slot->zStack()->zItem()
  673. && slot->getName().istGleich(slotName)
  674. && input->zFilter()->matchItem(slot->zStack()->zItem()))
  675. {
  676. if (consumed + slot->getNumberOfItems() >= input->getAmount())
  677. {
  678. takeItemsOut(
  679. slot, input->getAmount() - consumed, NO_DIRECTION)
  680. ->release();
  681. consumed = input->getAmount();
  682. break;
  683. }
  684. else
  685. {
  686. consumed += slot->getNumberOfItems();
  687. takeItemsOut(slot, slot->getNumberOfItems(), NO_DIRECTION)
  688. ->release();
  689. }
  690. }
  691. }
  692. }
  693. }
  694. Framework::ArrayIterator<ItemSlot*> Inventory::begin()
  695. {
  696. return pullSlotsOrder->begin();
  697. }
  698. Framework::ArrayIterator<ItemSlot*> Inventory::end()
  699. {
  700. return pullSlotsOrder->end();
  701. }
  702. void Inventory::inventoryApi(Framework::StreamReader* zRequest,
  703. NetworkMessage* zResponse,
  704. Entity* zSource)
  705. {
  706. char type;
  707. zRequest->lese(&type, 1);
  708. switch (type)
  709. {
  710. case 0: // request inventory
  711. {
  712. char idLen;
  713. zRequest->lese(&idLen, 1);
  714. char* id = new char[idLen + 1];
  715. zRequest->lese(id, idLen);
  716. id[(int)idLen] = 0;
  717. int processor;
  718. zRequest->lese((char*)&processor, 4);
  719. zResponse->addressUIElement(id, processor);
  720. observable.addObserver(zSource, id, processor);
  721. delete[] id;
  722. char filterLen;
  723. zRequest->lese(&filterLen, 1);
  724. char* filter = new char[filterLen + 1];
  725. if (filterLen) zRequest->lese(filter, filterLen);
  726. filter[(int)filterLen] = 0;
  727. InMemoryBuffer buffer;
  728. int count = 0;
  729. for (ItemSlot* slot : *this)
  730. {
  731. if (filterLen == 0 || slot->getName().istGleich(filter))
  732. {
  733. count++;
  734. int id = slot->getId();
  735. buffer.schreibe((char*)&id, 4);
  736. int itemCount = slot->getNumberOfItems();
  737. buffer.schreibe((char*)&itemCount, 4);
  738. if (itemCount > 0)
  739. {
  740. float f = slot->zStack()->zItem()->getHp();
  741. buffer.schreibe((char*)&f, 4);
  742. f = slot->zStack()->zItem()->getMaxHp();
  743. buffer.schreibe((char*)&f, 4);
  744. f = slot->zStack()->zItem()->getDurability();
  745. buffer.schreibe((char*)&f, 4);
  746. f = slot->zStack()->zItem()->getMaxDurability();
  747. buffer.schreibe((char*)&f, 4);
  748. int id = slot->zStack()->zItem()->zItemType()->getId();
  749. buffer.schreibe((char*)&id, 4);
  750. char len = (char)slot->zStack()
  751. ->zItem()
  752. ->getName()
  753. .getLength();
  754. buffer.schreibe((char*)&len, 1);
  755. buffer.schreibe(
  756. slot->zStack()->zItem()->getName().getText(),
  757. slot->zStack()->zItem()->getName().getLength());
  758. }
  759. }
  760. }
  761. delete[] filter;
  762. char* msg = new char[5 + buffer.getSize()];
  763. msg[0] = 0;
  764. *(int*)(msg + 1) = count;
  765. buffer.lese(msg + 5, (int)buffer.getSize());
  766. zResponse->setMessage(msg, 5 + (int)buffer.getSize());
  767. break;
  768. }
  769. case 1: // remove Observer
  770. {
  771. char idLen;
  772. zRequest->lese(&idLen, 1);
  773. char* id = new char[idLen + 1];
  774. zRequest->lese(id, idLen);
  775. id[(int)idLen] = 0;
  776. int processor;
  777. zRequest->lese((char*)&processor, 4);
  778. observable.removeObserver(zSource, id, processor);
  779. delete[] id;
  780. break;
  781. }
  782. case 2: // request item tooltip
  783. {
  784. char idLen;
  785. zRequest->lese(&idLen, 1);
  786. char* id = new char[idLen + 1];
  787. zRequest->lese(id, idLen);
  788. id[(int)idLen] = 0;
  789. int processor;
  790. zRequest->lese((char*)&processor, 4);
  791. zResponse->addressUIElement(id, processor);
  792. delete[] id;
  793. int slotId;
  794. zRequest->lese((char*)&slotId, 4);
  795. Text uiml;
  796. for (ItemSlot* slot : *pullSlotsOrder)
  797. {
  798. if (slot->getId() == slotId)
  799. {
  800. if (slot->zStack() && slot->zStack()->zItem())
  801. uiml = slot->zStack()->zItem()->getTooltipUIML();
  802. }
  803. }
  804. short len = (short)uiml.getLength();
  805. char* buffer = new char[uiml.getLength() + 7];
  806. buffer[0] = 3;
  807. *(int*)(buffer + 1) = slotId;
  808. *(short*)(buffer + 5) = len;
  809. memcpy(buffer + 7, uiml, len);
  810. zResponse->setMessage(buffer, len + 7);
  811. break;
  812. }
  813. }
  814. }
  815. void Inventory::registerAfterPullStackCall(std::function<void(
  816. ItemSlot* zSlot, Direction dir, const Item* zItem, int count)> call)
  817. {
  818. afterPullStackCalls.add(call);
  819. }
  820. void Inventory::registerAfterPushStackCall(std::function<void(
  821. ItemSlot* zSlot, Direction dir, const Item* zItem, int count)> call)
  822. {
  823. afterPushStackCalls.add(call);
  824. }
  825. void Inventory::registerObserverAddedCall(
  826. std::function<void(Entity* zSource, Framework::Text id, int processor)>
  827. call)
  828. {
  829. observable.registerOnObserverAddedCall(call);
  830. }
  831. int Inventory::getDimensionId() const
  832. {
  833. return dimensionId;
  834. }
  835. Framework::Vec3<float> Inventory::getLocation() const
  836. {
  837. return location;
  838. }
  839. bool Inventory::unsafeMove(Inventory* zSource,
  840. Inventory* zTarget,
  841. ArrayIterator<ItemSlot*>& sourceSlot,
  842. ArrayIterator<ItemSlot*>& targetSlot,
  843. Direction outDir,
  844. Direction inDir,
  845. int& count)
  846. {
  847. if (targetSlot->zStack())
  848. {
  849. if (sourceSlot->zStack()->zItem()->canBeStackedWith(
  850. targetSlot->zStack()->zItem()))
  851. {
  852. int number = MIN(targetSlot->numberOfAddableItems(
  853. sourceSlot->zStack()->zItem(), outDir),
  854. count);
  855. int tmp = number;
  856. if (number > 0 && zSource->allowPullStack(sourceSlot, outDir)
  857. && zTarget->allowPushStack(
  858. targetSlot, inDir, sourceSlot->zStack()->zItem(), tmp))
  859. {
  860. number = MIN(number, tmp);
  861. ItemStack* stack = sourceSlot->takeItemsOut(number, outDir);
  862. if (stack)
  863. {
  864. targetSlot->addItems(stack, inDir);
  865. zSource->updateCache(sourceSlot,
  866. targetSlot->zStack()->zItem()->zItemType()->getId());
  867. zSource->afterPullStack(sourceSlot,
  868. outDir,
  869. targetSlot->zStack()->zItem(),
  870. number);
  871. zTarget->afterPushStack(targetSlot,
  872. inDir,
  873. targetSlot->zStack()->zItem(),
  874. number);
  875. if (stack->getSize()) throw stack;
  876. stack->release();
  877. count -= number;
  878. return 1;
  879. }
  880. else
  881. targetSlot++;
  882. }
  883. else
  884. targetSlot++;
  885. }
  886. else
  887. targetSlot++;
  888. }
  889. else
  890. {
  891. int number = MIN(targetSlot->numberOfAddableItems(
  892. sourceSlot->zStack()->zItem(), outDir),
  893. count);
  894. int tmp = number;
  895. if (number > 0 && zSource->allowPullStack(sourceSlot, outDir)
  896. && zTarget->allowPushStack(
  897. targetSlot, inDir, sourceSlot->zStack()->zItem(), tmp))
  898. {
  899. number = MIN(number, tmp);
  900. if (number > 0)
  901. {
  902. ItemStack* stack = sourceSlot->takeItemsOut(number, outDir);
  903. if (stack)
  904. {
  905. targetSlot->addItems(stack, inDir);
  906. zSource->updateCache(sourceSlot,
  907. targetSlot->zStack()->zItem()->zItemType()->getId());
  908. zTarget->updateCache(targetSlot, -1);
  909. zSource->afterPullStack(sourceSlot,
  910. outDir,
  911. targetSlot->zStack()->zItem(),
  912. number);
  913. zTarget->afterPushStack(targetSlot,
  914. inDir,
  915. targetSlot->zStack()->zItem(),
  916. number);
  917. if (stack->getSize()) throw stack;
  918. stack->release();
  919. count -= number;
  920. return 1;
  921. }
  922. else
  923. targetSlot++;
  924. }
  925. else
  926. targetSlot++;
  927. }
  928. else
  929. targetSlot++;
  930. }
  931. return 0;
  932. }