CraftingStorage.cpp 14 KB

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