Inventory.cpp 30 KB

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