CraftingStorage.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. #include "CraftingStorage.h"
  2. #include <InMemoryBuffer.h>
  3. #include "Game.h"
  4. #include "Inventory.h"
  5. #include "Item.h"
  6. #include "ItemType.h"
  7. #include "RecipieList.h"
  8. #include "RecipieLoader.h"
  9. #undef min
  10. #undef max
  11. BasicShapedCrafter::BasicShapedCrafter(
  12. int width, int height, Inventory* zInventory, Framework::Text recipieList)
  13. : zInventory(zInventory),
  14. currentRecipie(0),
  15. recipieList(recipieList),
  16. width(width),
  17. height(height)
  18. {
  19. for (int i = 0; i < width * height; i++)
  20. {
  21. ItemSlot* slot = new ItemSlot("CraftingGrid",
  22. 1,
  23. std::numeric_limits<int>::max(),
  24. std::numeric_limits<int>::max(),
  25. INSIDE,
  26. INSIDE,
  27. 0);
  28. zInventory->addSlot(slot);
  29. craftingInput.add(slot);
  30. }
  31. std::function<void(
  32. ItemSlot * zSlot, Direction dir, const Item* zItem, int count)>
  33. onChange
  34. = [this, recipieList](
  35. ItemSlot* zSlot, Direction dir, const Item* zItem, int count) {
  36. if (!zSlot->getName().istGleich("CraftingGrid")) return;
  37. calculateOutputPreview();
  38. };
  39. zInventory->registerAfterPullStackCall(onChange);
  40. zInventory->registerAfterPushStackCall(onChange);
  41. zInventory->registerObserverAddedCall(
  42. [this](Entity* zSource, Framework::Text id, int processor) {
  43. Recipie* old = currentRecipie;
  44. calculateOutputPreview();
  45. if (old == currentRecipie)
  46. {
  47. NetworkMessage* message = new NetworkMessage();
  48. getOutputPreview(message);
  49. message->addressUIElement(id, processor);
  50. Game::INSTANCE->sendMessage(message, zSource);
  51. }
  52. });
  53. }
  54. void BasicShapedCrafter::getOutputPreview(NetworkMessage* zMessage)
  55. {
  56. if (currentRecipie)
  57. {
  58. Framework::Array<ItemInfo> output = currentRecipie->getOutput();
  59. Framework::InMemoryBuffer buffer;
  60. int count = 0;
  61. for (const ItemInfo& slot : output)
  62. {
  63. count++;
  64. int itemCount = slot.count;
  65. buffer.schreibe((char*)&itemCount, 4);
  66. if (itemCount > 0)
  67. {
  68. float f = slot.hp;
  69. buffer.schreibe((char*)&f, 4);
  70. f = slot.maxHp;
  71. buffer.schreibe((char*)&f, 4);
  72. f = slot.durability;
  73. buffer.schreibe((char*)&f, 4);
  74. f = slot.maxDurability;
  75. buffer.schreibe((char*)&f, 4);
  76. int id = slot.type;
  77. buffer.schreibe((char*)&id, 4);
  78. }
  79. }
  80. char* msg = new char[5 + buffer.getSize()];
  81. msg[0] = 100; // set crafting result
  82. *(int*)(msg + 1) = count;
  83. buffer.lese(msg + 5, (int)buffer.getSize());
  84. zMessage->setMessage(msg, 5 + (int)buffer.getSize());
  85. }
  86. else
  87. {
  88. char* msg = new char[5];
  89. msg[0] = 100; // set crafting result
  90. *(int*)(msg + 1) = 0;
  91. zMessage->setMessage(msg, 5);
  92. }
  93. }
  94. bool BasicShapedCrafter::isAllAvailable(
  95. Framework::RCArray<RecipieInput>& inputs, int width, int height)
  96. {
  97. for (int x = 0; x <= this->width - width; x++)
  98. {
  99. for (int y = 0; y <= this->height - height; y++)
  100. {
  101. bool wrong = 0;
  102. for (int w = 0; w < width; w++)
  103. {
  104. for (int h = 0; h < height; h++)
  105. {
  106. RecipieInput* i = inputs.z(h * width + w);
  107. ItemSlot* s
  108. = craftingInput.get((h + y) * this->width + (x + w));
  109. const Item* item = 0;
  110. if (s && s->zStack()
  111. && s->zStack()->getSize() >= i->getAmount())
  112. item = s->zStack()->zItem();
  113. wrong |= (item && !i->zFilter()) || (!item && i->zFilter());
  114. wrong |= item && i->zFilter()
  115. && !i->zFilter()->matchItem(item);
  116. if (wrong) break;
  117. }
  118. if (wrong) break;
  119. }
  120. if (!wrong)
  121. {
  122. int i = 0;
  123. for (ItemSlot* slot : craftingInput)
  124. {
  125. int w = i % this->width;
  126. int h = i / this->width;
  127. if ((w < x || w >= x + width || h < y || h >= y + height)
  128. && slot->zStack())
  129. return 0; // more items then needed are in crafting grid
  130. i++;
  131. }
  132. return 1;
  133. }
  134. }
  135. }
  136. return 0;
  137. }
  138. bool BasicShapedCrafter::isAllAvailable(
  139. Framework::RCArray<RecipieInput>& inputs)
  140. {
  141. return zInventory->isAllAvailable(inputs, "CraftingGrid");
  142. }
  143. bool BasicShapedCrafter::hasFreeSpace(const Item* zItem, int amount)
  144. {
  145. int addable = zInventory->numberOfAddableItems(zItem, NO_DIRECTION);
  146. return addable >= amount;
  147. }
  148. bool BasicShapedCrafter::consume(
  149. Framework::RCArray<RecipieInput>& inputs, int width, int height)
  150. {
  151. int beginX = this->width;
  152. int beginY = this->height;
  153. SourceSlotBlacklistFilter otherSlotsSource;
  154. TargetSlotBlacklistFilter otherSlotsTarget;
  155. for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
  156. {
  157. if (!craftingInput.get(i)->isEmpty())
  158. {
  159. int x = i % this->width;
  160. int y = i / this->width;
  161. beginX = MIN(beginX, x);
  162. beginY = MIN(beginY, y);
  163. }
  164. otherSlotsSource.addBlackListSlotId(craftingInput.get(i)->getId());
  165. otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId());
  166. }
  167. for (int x = 0; x < width; x++)
  168. {
  169. for (int y = 0; y < height; y++)
  170. {
  171. ItemSlot* target
  172. = craftingInput.get((y + beginY) * this->width + x + beginX);
  173. ItemStack* stack = zInventory->takeItemsOut(
  174. target, target->getNumberOfItems(), INSIDE);
  175. if (stack)
  176. {
  177. if (stack->getSize() > inputs.z(y * width + x)->getAmount())
  178. {
  179. ItemStack* overflow
  180. = stack->split(stack->getSize()
  181. - inputs.z(y * width + x)->getAmount());
  182. zInventory->unsaveAddItem(
  183. overflow, INSIDE, &otherSlotsTarget);
  184. if (overflow->getSize() > 0)
  185. {
  186. Game::INSTANCE->spawnItem(zInventory->getLocation(),
  187. zInventory->getDimensionId(),
  188. overflow);
  189. }
  190. else
  191. {
  192. overflow->release();
  193. }
  194. }
  195. if (stack->getSize() > 0 && stack->zItem())
  196. {
  197. ItemModifier* m = inputs.z(y * width + x)->zModifier();
  198. if (m) m->applyOn((Item*)stack->zItem());
  199. }
  200. if (stack->zItem()->getHp() == 0)
  201. stack->release();
  202. else if (stack->zItem()->getDurability() == 0)
  203. {
  204. Item* broken = stack->zItem()->zItemType()->breakItem(
  205. stack->zItem());
  206. if (broken)
  207. {
  208. ItemStack* brokenStack
  209. = new ItemStack(broken, stack->getSize());
  210. zInventory->unsaveAddItem(
  211. brokenStack, INSIDE, &otherSlotsTarget);
  212. if (brokenStack->getSize() > 0)
  213. {
  214. Game::INSTANCE->spawnItem(zInventory->getLocation(),
  215. zInventory->getDimensionId(),
  216. brokenStack);
  217. }
  218. else
  219. {
  220. brokenStack->release();
  221. }
  222. }
  223. stack->release();
  224. }
  225. else
  226. {
  227. zInventory->addItems(target, stack, INSIDE);
  228. if (stack->getSize() > 0)
  229. {
  230. Game::INSTANCE->spawnItem(zInventory->getLocation(),
  231. zInventory->getDimensionId(),
  232. stack);
  233. }
  234. else
  235. {
  236. stack->release();
  237. }
  238. }
  239. }
  240. ItemFilter* f = inputs.z(y * width + x)->zFilter();
  241. if (f)
  242. {
  243. if (target->isEmpty())
  244. {
  245. Framework::RCArray<ItemFilter> filters;
  246. filters.add(dynamic_cast<ItemFilter*>(f->getThis()));
  247. filters.add(
  248. dynamic_cast<ItemFilter*>(otherSlotsSource.getThis()));
  249. Framework::Array<ItemSlot*> tmp;
  250. tmp.add(target);
  251. CombinedItemFilter combinedFilter(
  252. filters, [](bool a, bool b) { return a && b; });
  253. zInventory->localTransaction(
  254. 0, &tmp, &combinedFilter, 1, NO_DIRECTION, INSIDE);
  255. }
  256. }
  257. }
  258. }
  259. return 1;
  260. }
  261. void BasicShapedCrafter::consume(Framework::RCArray<RecipieInput>& inputs)
  262. {
  263. SourceSlotBlacklistFilter otherSlotsSource;
  264. TargetSlotBlacklistFilter otherSlotsTarget;
  265. for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
  266. {
  267. otherSlotsSource.addBlackListSlotId(craftingInput.get(i)->getId());
  268. otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId());
  269. }
  270. bool* used = new bool[craftingInput.getEintragAnzahl()];
  271. memset(used, 0, sizeof(bool) * craftingInput.getEintragAnzahl());
  272. for (int i = 0; i < inputs.getEintragAnzahl(); i++)
  273. {
  274. for (int j = 0; j < craftingInput.getEintragAnzahl(); j++)
  275. {
  276. if (used[j]) continue;
  277. ItemSlot* target = craftingInput.get(j);
  278. if (target && target->zStack()
  279. && target->zStack()->getSize() >= inputs.z(i)->getAmount()
  280. && target->zStack()->zItem()
  281. && inputs.z(i)->zFilter()->matchItem(target->zStack()->zItem()))
  282. {
  283. used[i] = 1;
  284. ItemStack* stack = zInventory->takeItemsOut(
  285. target, target->getNumberOfItems(), INSIDE);
  286. if (stack)
  287. {
  288. if (stack->getSize() > inputs.z(i)->getAmount())
  289. {
  290. ItemStack* overflow = stack->split(
  291. stack->getSize() - inputs.z(i)->getAmount());
  292. zInventory->unsaveAddItem(
  293. overflow, INSIDE, &otherSlotsTarget);
  294. if (overflow->getSize() > 0)
  295. {
  296. Game::INSTANCE->spawnItem(zInventory->getLocation(),
  297. zInventory->getDimensionId(),
  298. overflow);
  299. }
  300. else
  301. {
  302. overflow->release();
  303. }
  304. }
  305. if (stack->getSize() > 0 && stack->zItem())
  306. {
  307. ItemModifier* m = inputs.z(i)->zModifier();
  308. if (m) m->applyOn((Item*)stack->zItem());
  309. }
  310. if (stack->zItem()->getHp() == 0)
  311. stack->release();
  312. else if (stack->zItem()->getDurability() == 0)
  313. {
  314. Item* broken = stack->zItem()->zItemType()->breakItem(
  315. stack->zItem());
  316. if (broken)
  317. {
  318. ItemStack* brokenStack
  319. = new ItemStack(broken, stack->getSize());
  320. zInventory->unsaveAddItem(
  321. brokenStack, INSIDE, &otherSlotsTarget);
  322. if (brokenStack->getSize() > 0)
  323. {
  324. Game::INSTANCE->spawnItem(
  325. zInventory->getLocation(),
  326. zInventory->getDimensionId(),
  327. brokenStack);
  328. }
  329. else
  330. {
  331. brokenStack->release();
  332. }
  333. }
  334. stack->release();
  335. }
  336. else
  337. {
  338. zInventory->addItems(target, stack, INSIDE);
  339. if (stack->getSize() > 0)
  340. {
  341. Game::INSTANCE->spawnItem(zInventory->getLocation(),
  342. zInventory->getDimensionId(),
  343. stack);
  344. }
  345. else
  346. {
  347. stack->release();
  348. }
  349. }
  350. }
  351. ItemFilter* f = inputs.z(i)->zFilter();
  352. if (f)
  353. {
  354. if (target->isEmpty())
  355. {
  356. Framework::RCArray<ItemFilter> filters;
  357. filters.add(dynamic_cast<ItemFilter*>(f->getThis()));
  358. filters.add(dynamic_cast<ItemFilter*>(
  359. otherSlotsSource.getThis()));
  360. Framework::Array<ItemSlot*> tmp;
  361. tmp.add(target);
  362. CombinedItemFilter combinedFilter(
  363. filters, [](bool a, bool b) { return a && b; });
  364. zInventory->localTransaction(
  365. 0, &tmp, &combinedFilter, 1, NO_DIRECTION, INSIDE);
  366. }
  367. }
  368. break;
  369. }
  370. }
  371. }
  372. delete[] used;
  373. }
  374. void BasicShapedCrafter::addCraftingResult(ItemStack* zStack)
  375. {
  376. TargetSlotBlacklistFilter otherSlotsTarget;
  377. for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
  378. otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId());
  379. zInventory->unsaveAddItem(zStack, NO_DIRECTION, &otherSlotsTarget);
  380. }
  381. void BasicShapedCrafter::applyCurrentRecipie()
  382. {
  383. if (currentRecipie && currentRecipie->testApplicability(this))
  384. currentRecipie->apply(this);
  385. }
  386. void BasicShapedCrafter::calculateOutputPreview()
  387. {
  388. RecipieList* recipies
  389. = Game::INSTANCE->zRecipies()->zRecipieList(recipieList);
  390. if (recipies)
  391. {
  392. Recipie* recipie = recipies->zFirstRecipie(this);
  393. if (recipie != currentRecipie)
  394. {
  395. currentRecipie = recipie;
  396. NetworkMessage* message = new NetworkMessage();
  397. getOutputPreview(message);
  398. zInventory->notifyObservers(message);
  399. }
  400. }
  401. }
  402. Framework::Vec3<float> BasicShapedCrafter::getStorageLocation() const
  403. {
  404. return zInventory->getLocation();
  405. }
  406. int BasicShapedCrafter::getStorageDimensionId() const
  407. {
  408. return zInventory->getDimensionId();
  409. }