CraftingStorage.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  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(h * width + w))
  109. item = s->zStack()->zItem();
  110. wrong |= (item && !f) || (!item && f);
  111. wrong |= item && f && !f->matchItem(item);
  112. if (wrong) break;
  113. }
  114. if (wrong) break;
  115. }
  116. if (!wrong)
  117. {
  118. int i = 0;
  119. for (ItemSlot* slot : craftingInput)
  120. {
  121. int w = i % this->width;
  122. int h = i / this->width;
  123. if ((w < x || w >= x + width || h < y || h >= y + height)
  124. && slot->zStack())
  125. return 0; // more items then needed are in crafting grid
  126. i++;
  127. }
  128. return 1;
  129. }
  130. }
  131. }
  132. return 0;
  133. }
  134. bool BasicShapedCrafter::isAllAvailable(
  135. Framework::RCArray<ItemFilter>& filters, Framework::Array<int>& inputAmount)
  136. {
  137. bool* used = new bool[craftingInput.getEintragAnzahl()];
  138. memset(used, 0, sizeof(bool) * craftingInput.getEintragAnzahl());
  139. int index = 0;
  140. for (ItemFilter* filter : filters)
  141. {
  142. bool found = 0;
  143. for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
  144. {
  145. if (used[i]) continue;
  146. ItemSlot* slot = craftingInput.get(i);
  147. if (slot && slot->zStack()
  148. && slot->zStack()->getSize() >= inputAmount.get(index)
  149. && slot->zStack()->zItem()
  150. && filter->matchItem(slot->zStack()->zItem()))
  151. {
  152. found = 1;
  153. used[i] = 1;
  154. break;
  155. }
  156. }
  157. if (!found)
  158. {
  159. delete[] used;
  160. return 0;
  161. }
  162. index++;
  163. }
  164. delete[] used;
  165. return 1;
  166. }
  167. bool BasicShapedCrafter::hasFreeSpace(const Item* zItem, int amount)
  168. {
  169. ItemStack* stack
  170. = new ItemStack(zItem->zItemType()->cloneItem(zItem), amount);
  171. int addable = zInventory->numberOfAddableItems(stack, NO_DIRECTION);
  172. stack->release();
  173. return addable >= amount;
  174. }
  175. bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
  176. Framework::RCArray<ItemModifier>& modifiers,
  177. Framework::Array<int>& inputAmount,
  178. int width,
  179. int height)
  180. {
  181. int beginX = this->width;
  182. int beginY = this->height;
  183. SourceSlotBlacklistFilter otherSlotsSource;
  184. TargetSlotBlacklistFilter otherSlotsTarget;
  185. for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
  186. {
  187. if (!craftingInput.get(i)->isEmpty())
  188. {
  189. int x = i % this->width;
  190. int y = i / this->width;
  191. beginX = MIN(beginX, x);
  192. beginY = MIN(beginY, y);
  193. }
  194. otherSlotsSource.addBlackListSlotId(craftingInput.get(i)->getId());
  195. otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId());
  196. }
  197. for (int x = 0; x < width; x++)
  198. {
  199. for (int y = 0; y < height; y++)
  200. {
  201. ItemSlot* target
  202. = craftingInput.get((y + beginY) * this->width + x + beginX);
  203. ItemStack* stack = zInventory->takeItemsOut(
  204. target, target->getNumberOfItems(), INSIDE);
  205. if (stack)
  206. {
  207. if (stack->getSize()
  208. > inputAmount.get(y * width + x))
  209. {
  210. ItemStack* overflow = stack->split(
  211. stack->getSize()
  212. - inputAmount.get(y * width + x));
  213. zInventory->unsaveAddItem(
  214. overflow, INSIDE, &otherSlotsTarget);
  215. if (overflow->getSize() > 0)
  216. {
  217. // TODO: drop items
  218. }
  219. overflow->release();
  220. }
  221. if (stack->getSize() > 0 && stack->zItem())
  222. {
  223. ItemModifier* m = modifiers.z(y * width + x);
  224. if (m) m->applyOn((Item*)stack->zItem());
  225. }
  226. if (stack->zItem()->getHp() == 0)
  227. stack->release();
  228. else if (stack->zItem()->getDurability() == 0)
  229. {
  230. Item* broken = stack->zItem()->zItemType()->breakItem(
  231. stack->zItem());
  232. stack->release();
  233. if (broken)
  234. {
  235. ItemStack* brokenStack
  236. = new ItemStack(broken, stack->getSize());
  237. zInventory->unsaveAddItem(
  238. brokenStack, INSIDE, &otherSlotsTarget);
  239. // TODO: if brokenStack is not empty spawn an item
  240. // entity
  241. brokenStack->release();
  242. }
  243. }
  244. else
  245. {
  246. zInventory->addItems(target, stack, INSIDE);
  247. // TODO: if stack is not empty spawn an item entity
  248. }
  249. }
  250. ItemFilter* f = filters.z(y * width + x);
  251. if (f)
  252. {
  253. if (target->isEmpty())
  254. {
  255. Framework::Array<ItemSlot*> tmp;
  256. tmp.add(target);
  257. CombinedItemFilter combinedFilter(
  258. dynamic_cast<ItemFilter*>(f->getThis()),
  259. dynamic_cast<ItemFilter*>(otherSlotsSource.getThis()),
  260. [](bool a, bool b) { return a && b; });
  261. zInventory->localTransaction(
  262. 0, &tmp, &combinedFilter, 1, NO_DIRECTION, INSIDE);
  263. }
  264. }
  265. }
  266. }
  267. return 1;
  268. }
  269. bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
  270. Framework::RCArray<ItemModifier>& modifiers,
  271. Framework::Array<int>& inputAmount)
  272. {
  273. SourceSlotBlacklistFilter otherSlotsSource;
  274. TargetSlotBlacklistFilter otherSlotsTarget;
  275. for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
  276. {
  277. otherSlotsSource.addBlackListSlotId(craftingInput.get(i)->getId());
  278. otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId());
  279. }
  280. bool* used = new bool[craftingInput.getEintragAnzahl()];
  281. memset(used, 0, sizeof(bool) * craftingInput.getEintragAnzahl());
  282. for (int i = 0; i < filters.getEintragAnzahl(); i++)
  283. {
  284. for (int j = 0; j < craftingInput.getEintragAnzahl(); j++)
  285. {
  286. if (used[j]) continue;
  287. ItemSlot* target = craftingInput.get(j);
  288. if (target && target->zStack()
  289. && target->zStack()->getSize() >= inputAmount.get(i)
  290. && target->zStack()->zItem()
  291. && filters.z(i)->matchItem(target->zStack()->zItem()))
  292. {
  293. used[i] = 1;
  294. ItemStack* stack = zInventory->takeItemsOut(
  295. target, target->getNumberOfItems(), INSIDE);
  296. if (stack)
  297. {
  298. if (stack->getSize() > inputAmount.get(i))
  299. {
  300. ItemStack* overflow = stack->split(
  301. stack->getSize() - inputAmount.get(i));
  302. zInventory->unsaveAddItem(
  303. overflow, INSIDE, &otherSlotsTarget);
  304. if (overflow->getSize() > 0)
  305. {
  306. // TODO: drop items
  307. }
  308. overflow->release();
  309. }
  310. if (stack->getSize() > 0 && stack->zItem())
  311. {
  312. ItemModifier* m = modifiers.z(i);
  313. if (m) m->applyOn((Item*)stack->zItem());
  314. }
  315. if (stack->zItem()->getHp() == 0)
  316. stack->release();
  317. else if (stack->zItem()->getDurability() == 0)
  318. {
  319. Item* broken = stack->zItem()->zItemType()->breakItem(
  320. stack->zItem());
  321. stack->release();
  322. if (broken)
  323. {
  324. ItemStack* brokenStack
  325. = new ItemStack(broken, stack->getSize());
  326. zInventory->unsaveAddItem(
  327. brokenStack, INSIDE, &otherSlotsTarget);
  328. // TODO: if brokenStack is not empty spawn an item
  329. // entity
  330. brokenStack->release();
  331. }
  332. }
  333. else
  334. {
  335. zInventory->addItems(target, stack, INSIDE);
  336. // TODO: if stack is not empty spawn an item entity
  337. }
  338. }
  339. ItemFilter* f = filters.z(i);
  340. if (f)
  341. {
  342. if (target->isEmpty())
  343. {
  344. Framework::Array<ItemSlot*> tmp;
  345. tmp.add(target);
  346. CombinedItemFilter combinedFilter(
  347. dynamic_cast<ItemFilter*>(f->getThis()),
  348. dynamic_cast<ItemFilter*>(
  349. otherSlotsSource.getThis()),
  350. [](bool a, bool b) { return a && b; });
  351. zInventory->localTransaction(
  352. 0, &tmp, &combinedFilter, 1, NO_DIRECTION, INSIDE);
  353. }
  354. }
  355. break;
  356. }
  357. }
  358. }
  359. delete[] used;
  360. return 1;
  361. }
  362. void BasicShapedCrafter::addCraftingResult(ItemStack* stack)
  363. {
  364. TargetSlotBlacklistFilter otherSlotsTarget;
  365. for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
  366. otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId());
  367. zInventory->unsaveAddItem(stack, NO_DIRECTION, &otherSlotsTarget);
  368. }
  369. void BasicShapedCrafter::applyCurrentRecipie()
  370. {
  371. if (currentRecipie && currentRecipie->testApplicability(this))
  372. currentRecipie->apply(this);
  373. }
  374. void BasicShapedCrafter::calculateOutputPreview()
  375. {
  376. RecipieList* recipies
  377. = Game::INSTANCE->getRecipies().zRecipieList(recipieList);
  378. if (recipies)
  379. {
  380. Recipie* recipie = recipies->zFirstRecipie(this);
  381. if (recipie != currentRecipie)
  382. {
  383. currentRecipie = recipie;
  384. NetworkMessage* message = new NetworkMessage();
  385. getOutputPreview(message);
  386. zInventory->notifyObservers(message);
  387. }
  388. }
  389. }