Recipie.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. #include "Recipie.h"
  2. #include <Logging.h>
  3. #include "CraftingStorage.h"
  4. #include "Game.h"
  5. #include "Item.h"
  6. #include "RecipieGroupConfig.h"
  7. #include "UIElement.h"
  8. RecipieInput::RecipieInput()
  9. : ReferenceCounter(),
  10. filter(0),
  11. modifier(0),
  12. amount(0)
  13. {}
  14. RecipieInput::~RecipieInput()
  15. {
  16. if (filter) filter->release();
  17. if (modifier) modifier->release();
  18. }
  19. void RecipieInput::setFilter(ItemFilter* filter)
  20. {
  21. if (this->filter) this->filter->release();
  22. this->filter = filter;
  23. }
  24. ItemFilter* RecipieInput::zFilter() const
  25. {
  26. return filter;
  27. }
  28. void RecipieInput::setModifier(ItemModifier* modifier)
  29. {
  30. if (this->modifier) this->modifier->release();
  31. this->modifier = modifier;
  32. }
  33. ItemModifier* RecipieInput::zModifier() const
  34. {
  35. return modifier;
  36. }
  37. void RecipieInput::setAmount(int amount)
  38. {
  39. this->amount = amount;
  40. }
  41. int RecipieInput::getAmount() const
  42. {
  43. return amount;
  44. }
  45. RecipieInputFactory::RecipieInputFactory()
  46. : ObjectTypeFactory()
  47. {}
  48. RecipieInput* RecipieInputFactory::fromJson(
  49. Framework::JSON::JSONObject* zJson) const
  50. {
  51. RecipieInput* result = new RecipieInput();
  52. result->setFilter(Game::INSTANCE->zTypeRegistry()->fromJson<ItemFilter>(
  53. zJson->asObject()->zValue("filter")));
  54. result->setModifier(Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(
  55. zJson->asObject()->zValue("modifier")));
  56. result->setAmount(
  57. (int)zJson->asObject()->zValue("amount")->asNumber()->getNumber());
  58. return result;
  59. }
  60. Framework::JSON::JSONObject* RecipieInputFactory::toJsonObject(
  61. RecipieInput* zObject) const
  62. {
  63. Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
  64. result->addValue(
  65. "filter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zFilter()));
  66. result->addValue("modifier",
  67. Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModifier()));
  68. result->addValue("amount",
  69. new Framework::JSON::JSONNumber((double)zObject->getAmount()));
  70. return result;
  71. }
  72. JSONObjectValidationBuilder* RecipieInputFactory::addToValidator(
  73. JSONObjectValidationBuilder* builder) const
  74. {
  75. Framework::JSON::JSONObject* defaultModifier
  76. = new Framework::JSON::JSONObject();
  77. defaultModifier->addValue(
  78. "type", new Framework::JSON::JSONString("consume"));
  79. return builder
  80. ->withRequiredAttribute("filter",
  81. Game::INSTANCE->zTypeRegistry()->getValidator<ItemFilter>())
  82. ->withRequiredAttribute("modifier",
  83. Game::INSTANCE->zTypeRegistry()->getValidator<ItemModifier>())
  84. ->withRequiredObject("modifier")
  85. ->withRequiredString("type")
  86. ->withExactMatch("consume")
  87. ->finishString()
  88. ->withDefault(defaultModifier)
  89. ->finishObject()
  90. ->withRequiredNumber("amount")
  91. ->whichIsGreaterOrEqual(1.0)
  92. ->withDefault(1.0)
  93. ->finishNumber();
  94. }
  95. RecipieOutput::RecipieOutput()
  96. : ReferenceCounter(),
  97. itemTypeId(0),
  98. amount(0),
  99. modifier(0)
  100. {}
  101. RecipieOutput::~RecipieOutput()
  102. {
  103. modifier->release();
  104. }
  105. void RecipieOutput::setItemTypeId(int itemTypeId)
  106. {
  107. this->itemTypeId = itemTypeId;
  108. }
  109. int RecipieOutput::getItemTypeId() const
  110. {
  111. return itemTypeId;
  112. }
  113. void RecipieOutput::setAmount(int amount)
  114. {
  115. this->amount = amount;
  116. }
  117. int RecipieOutput::getAmount() const
  118. {
  119. return amount;
  120. }
  121. void RecipieOutput::setModifier(ItemModifier* modifier)
  122. {
  123. if (this->modifier) this->modifier->release();
  124. this->modifier = modifier;
  125. }
  126. ItemModifier* RecipieOutput::zModifier() const
  127. {
  128. return modifier;
  129. }
  130. Item* RecipieOutput::createItem() const
  131. {
  132. Item* result = Game::INSTANCE->zItemType(itemTypeId)->createItem();
  133. if (result)
  134. {
  135. modifier->applyOn(result);
  136. }
  137. return result;
  138. }
  139. RecipieOutputFactory::RecipieOutputFactory()
  140. : ObjectTypeFactory()
  141. {}
  142. RecipieOutput* RecipieOutputFactory::fromJson(
  143. Framework::JSON::JSONObject* zJson) const
  144. {
  145. RecipieOutput* result = new RecipieOutput();
  146. result->setItemTypeId(Game::INSTANCE->getItemTypeId(
  147. zJson->asObject()->zValue("itemType")->asString()->getString()));
  148. result->setAmount(
  149. (int)zJson->asObject()->zValue("amount")->asNumber()->getNumber());
  150. result->setModifier(Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(
  151. zJson->asObject()->zValue("modifier")));
  152. return result;
  153. }
  154. Framework::JSON::JSONObject* RecipieOutputFactory::toJsonObject(
  155. RecipieOutput* zObject) const
  156. {
  157. Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
  158. result->addValue("itemType",
  159. new Framework::JSON::JSONString(
  160. Game::INSTANCE->zItemType(zObject->getItemTypeId())->getName()));
  161. result->addValue("amount",
  162. new Framework::JSON::JSONNumber((double)zObject->getAmount()));
  163. result->addValue("modifier",
  164. Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModifier()));
  165. return result;
  166. }
  167. JSONObjectValidationBuilder* RecipieOutputFactory::addToValidator(
  168. JSONObjectValidationBuilder* builder) const
  169. {
  170. Framework::JSON::JSONObject* defaultModifier
  171. = new Framework::JSON::JSONObject();
  172. defaultModifier->addValue(
  173. "type", new Framework::JSON::JSONString("doNothing"));
  174. return builder
  175. ->withRequiredAttribute("itemType",
  176. Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
  177. ItemTypeNameFactory::TYPE_ID))
  178. ->withRequiredAttribute("modifier",
  179. Game::INSTANCE->zTypeRegistry()->getValidator<ItemModifier>())
  180. ->withRequiredObject("modifier")
  181. ->withRequiredString("type")
  182. ->withExactMatch("doNothing")
  183. ->finishString()
  184. ->withDefault(defaultModifier)
  185. ->finishObject()
  186. ->withRequiredNumber("amount")
  187. ->whichIsGreaterOrEqual(1.0)
  188. ->withDefault(1.0)
  189. ->finishNumber();
  190. }
  191. Recipie::Recipie()
  192. : ReferenceCounter()
  193. {}
  194. void Recipie::apply(CraftingStorage* zStorage)
  195. {
  196. consumeInputs(zStorage);
  197. produceOutputs(zStorage);
  198. }
  199. void Recipie::addOutput(RecipieOutput* outputs)
  200. {
  201. this->outputs.add(outputs);
  202. }
  203. Framework::Array<ItemInfo> Recipie::getOutput() const
  204. {
  205. Framework::Array<ItemInfo> result;
  206. for (const RecipieOutput* output : outputs)
  207. {
  208. Item* item = output->createItem();
  209. if (item)
  210. {
  211. result.add({item->zItemType()->getId(),
  212. output->getAmount(),
  213. item->getHp(),
  214. item->getMaxHp(),
  215. item->getDurability(),
  216. item->getMaxDurability()});
  217. item->release();
  218. }
  219. }
  220. return result;
  221. }
  222. bool Recipie::createsOutput(int itemTypeId)
  223. {
  224. for (RecipieOutput* output : outputs)
  225. {
  226. if (output->getItemTypeId() == itemTypeId)
  227. {
  228. return 1;
  229. }
  230. }
  231. return 0;
  232. }
  233. void Recipie::setGroupName(Framework::Text groupName)
  234. {
  235. this->groupName = groupName;
  236. }
  237. const Framework::RCArray<RecipieOutput>& Recipie::getOutputs() const
  238. {
  239. return outputs;
  240. }
  241. Framework::Text Recipie::getGroupName() const
  242. {
  243. return groupName;
  244. }
  245. int Recipie::getTicksNeeded() const
  246. {
  247. return 1;
  248. }
  249. int Recipie::getFuelPerTickNeeded() const
  250. {
  251. return 0;
  252. }
  253. UnshapedRecipie::UnshapedRecipie()
  254. : Recipie()
  255. {}
  256. bool UnshapedRecipie::testApplicability(CraftingStorage* zStorage)
  257. {
  258. for (RecipieOutput* output : outputs)
  259. {
  260. Item* item = output->createItem();
  261. if (item)
  262. {
  263. if (!zStorage->hasFreeSpace(item, output->getAmount()))
  264. {
  265. item->release();
  266. return 0;
  267. }
  268. item->release();
  269. }
  270. }
  271. return zStorage->isAllAvailable(inputs);
  272. }
  273. void UnshapedRecipie::consumeInputs(CraftingStorage* zStorage)
  274. {
  275. zStorage->consume(inputs);
  276. }
  277. void UnshapedRecipie::produceOutputs(CraftingStorage* zStorage)
  278. {
  279. for (RecipieOutput* output : outputs)
  280. {
  281. Item* item = output->createItem();
  282. if (item)
  283. {
  284. ItemStack* stack = new ItemStack(item, output->getAmount());
  285. zStorage->addCraftingResult(stack);
  286. if (stack->getSize() > 0)
  287. {
  288. Game::INSTANCE->spawnItem(zStorage->getStorageLocation(),
  289. zStorage->getStorageDimensionId(),
  290. stack);
  291. }
  292. else
  293. {
  294. stack->release();
  295. }
  296. }
  297. }
  298. }
  299. Framework::Text UnshapedRecipie::getRecipieUIML()
  300. {
  301. Framework::Text result = "<recipie type=\"unshaped\"><ingredients>";
  302. for (RecipieInput* input : inputs)
  303. {
  304. result.append() << "<ingredient amount=\"" << input->getAmount()
  305. << "\">";
  306. if (input->zFilter())
  307. {
  308. result.append()
  309. << "<logic>" << input->zFilter()->getLogicUIML() << "</logic>";
  310. }
  311. result += "</ingredient>";
  312. // TODO: add modifiers
  313. }
  314. result += "</ingredients><outputs>";
  315. for (RecipieOutput* output : outputs)
  316. {
  317. Item* item = output->createItem();
  318. if (item)
  319. {
  320. result.append()
  321. << "<output amount=\"" << output->getAmount()
  322. << "\" itemType=\"" << item->zItemType()->getId() << "\" hp=\""
  323. << item->getHp() << "\" durability=\"" << item->getDurability()
  324. << "\" maxHp=\"" << item->getMaxHp() << "\" maxDurability=\""
  325. << item->getMaxDurability() << "\">" << item->getTooltipUIML()
  326. << "</output>";
  327. item->release();
  328. }
  329. }
  330. result += "</outputs></recipie>";
  331. return result;
  332. }
  333. void UnshapedRecipie::addInput(RecipieInput* input)
  334. {
  335. inputs.add(input);
  336. }
  337. const Framework::RCArray<RecipieInput>& UnshapedRecipie::getInputs() const
  338. {
  339. return inputs;
  340. }
  341. ShapedRecipie::ShapedRecipie()
  342. : Recipie(),
  343. width(0),
  344. height(0)
  345. {}
  346. bool ShapedRecipie::testApplicability(CraftingStorage* zStorage)
  347. {
  348. ShapedCraftingStorage* zShapedStorage
  349. = dynamic_cast<ShapedCraftingStorage*>(zStorage);
  350. if (!zShapedStorage) return 0;
  351. for (RecipieOutput* output : outputs)
  352. {
  353. Item* item = output->createItem();
  354. if (item)
  355. {
  356. if (!zShapedStorage->hasFreeSpace(item, output->getAmount()))
  357. {
  358. item->release();
  359. return 0;
  360. }
  361. item->release();
  362. }
  363. }
  364. return zShapedStorage->isAllAvailable(inputs, width, height);
  365. }
  366. void ShapedRecipie::consumeInputs(CraftingStorage* zStorage)
  367. {
  368. ShapedCraftingStorage* zShapedStorage
  369. = dynamic_cast<ShapedCraftingStorage*>(zStorage);
  370. zShapedStorage->consume(inputs, width, height);
  371. }
  372. void ShapedRecipie::produceOutputs(CraftingStorage* zStorage)
  373. {
  374. for (RecipieOutput* output : outputs)
  375. {
  376. Item* item = output->createItem();
  377. if (item)
  378. {
  379. ItemStack* stack = new ItemStack(item, output->getAmount());
  380. zStorage->addCraftingResult(stack);
  381. if (stack->getSize() > 0)
  382. {
  383. Game::INSTANCE->spawnItem(zStorage->getStorageLocation(),
  384. zStorage->getStorageDimensionId(),
  385. stack);
  386. }
  387. else
  388. {
  389. stack->release();
  390. }
  391. }
  392. }
  393. }
  394. Framework::Text ShapedRecipie::getRecipieUIML()
  395. {
  396. Framework::Text result = "<recipie type=\"shaped\" width=\"";
  397. result.append() << width << "\" height=\"" << height << "\"><ingredients>";
  398. for (RecipieInput* input : inputs)
  399. {
  400. result.append() << "<ingredient amount=\"" << input->getAmount()
  401. << "\">";
  402. if (input->zFilter())
  403. {
  404. result.append()
  405. << "<logic>" << input->zFilter()->getLogicUIML() << "</logic>";
  406. }
  407. result += "</ingredient>";
  408. // TODO: add modifiers
  409. }
  410. result += "</ingredients><outputs>";
  411. for (RecipieOutput* output : outputs)
  412. {
  413. Item* item = output->createItem();
  414. if (item)
  415. {
  416. result.append()
  417. << "<output amount=\"" << output->getAmount()
  418. << "\" itemType=\"" << item->zItemType()->getId() << "\" hp=\""
  419. << item->getHp() << "\" durability=\"" << item->getDurability()
  420. << "\" maxHp=\"" << item->getMaxHp() << "\" maxDurability=\""
  421. << item->getMaxDurability() << "\">" << item->getTooltipUIML()
  422. << "</output>";
  423. item->release();
  424. }
  425. }
  426. result += "</outputs></recipie>";
  427. return result;
  428. }
  429. void ShapedRecipie::setWidth(int width)
  430. {
  431. this->width = width;
  432. }
  433. int ShapedRecipie::getWidth() const
  434. {
  435. return width;
  436. }
  437. void ShapedRecipie::setHeight(int height)
  438. {
  439. this->height = height;
  440. }
  441. int ShapedRecipie::getHeight() const
  442. {
  443. return height;
  444. }
  445. void ShapedRecipie::addInput(RecipieInput* input)
  446. {
  447. inputs.add(input);
  448. }
  449. void ShapedRecipie::setInput(int index, RecipieInput* input)
  450. {
  451. inputs.set(input, index);
  452. }
  453. const Framework::RCArray<RecipieInput>& ShapedRecipie::getInputs() const
  454. {
  455. return inputs;
  456. }
  457. ShapedRecipieFactory::ShapedRecipieFactory()
  458. : RecipieFactory()
  459. {}
  460. ShapedRecipie* ShapedRecipieFactory::createValue(
  461. Framework::JSON::JSONObject* zJson) const
  462. {
  463. return new ShapedRecipie();
  464. }
  465. ShapedRecipie* ShapedRecipieFactory::fromJson(
  466. Framework::JSON::JSONObject* zJson) const
  467. {
  468. ShapedRecipie* result = RecipieFactory::fromJson(zJson);
  469. int width = (int)zJson->zValue("width")->asNumber()->getNumber();
  470. int height = (int)zJson->zValue("height")->asNumber()->getNumber();
  471. for (int i = 0; i < width * height; i++)
  472. {
  473. result->addInput(new RecipieInput());
  474. }
  475. for (Framework::JSON::JSONValue* input :
  476. *zJson->zValue("inputs")->asArray())
  477. {
  478. int x = (int)input->asObject()->zValue("x")->asNumber()->getNumber();
  479. int y = (int)input->asObject()->zValue("y")->asNumber()->getNumber();
  480. if (x >= width || y >= height)
  481. {
  482. Framework::Logging::warning()
  483. << "Invalid input position in shaped recipie with width="
  484. << width << ", height=" << height << ", x=" << x << ", y=" << y
  485. << " input " << input->toString() << " will be ignored.";
  486. continue;
  487. }
  488. result->setInput(y * width + x,
  489. Game::INSTANCE->zTypeRegistry()->fromJson<RecipieInput>(
  490. input->asObject()->zValue("input")));
  491. }
  492. result->setWidth((int)zJson->zValue("width")->asNumber()->getNumber());
  493. result->setHeight((int)zJson->zValue("height")->asNumber()->getNumber());
  494. return result;
  495. }
  496. Framework::JSON::JSONObject* ShapedRecipieFactory::toJsonObject(
  497. ShapedRecipie* zObject) const
  498. {
  499. Framework::JSON::JSONObject* result = RecipieFactory::toJsonObject(zObject);
  500. result->addValue(
  501. "width", new Framework::JSON::JSONNumber(zObject->getWidth()));
  502. result->addValue(
  503. "height", new Framework::JSON::JSONNumber(zObject->getHeight()));
  504. Framework::JSON::JSONArray* inputs = new Framework::JSON::JSONArray();
  505. for (int i = 0; i < zObject->getWidth() * zObject->getHeight(); i++)
  506. {
  507. Framework::JSON::JSONObject* input = new Framework::JSON::JSONObject();
  508. input->addValue(
  509. "x", new Framework::JSON::JSONNumber(i % zObject->getHeight()));
  510. input->addValue(
  511. "y", new Framework::JSON::JSONNumber(i / zObject->getHeight()));
  512. input->addValue("input",
  513. Game::INSTANCE->zTypeRegistry()->toJson(zObject->getInputs().z(i)));
  514. inputs->addValue(input);
  515. }
  516. result->addValue("inputs", inputs);
  517. return result;
  518. }
  519. JSONObjectValidationBuilder* ShapedRecipieFactory::addToValidator(
  520. JSONObjectValidationBuilder* builder) const
  521. {
  522. return RecipieFactory::addToValidator(builder->withRequiredArray("inputs")
  523. ->addAcceptedObjectInArray()
  524. ->withRequiredNumber("x")
  525. ->whichIsGreaterOrEqual(0.0)
  526. ->finishNumber()
  527. ->withRequiredNumber("y")
  528. ->whichIsGreaterOrEqual(0.0)
  529. ->finishNumber()
  530. ->withRequiredAttribute("input",
  531. Game::INSTANCE->zTypeRegistry()->getValidator<RecipieInput>())
  532. ->finishObject()
  533. ->finishArray()
  534. ->withRequiredNumber("width")
  535. ->whichIsGreaterOrEqual(1.0)
  536. ->finishNumber()
  537. ->withRequiredNumber("height")
  538. ->whichIsGreaterOrEqual(1.0)
  539. ->finishNumber());
  540. }
  541. const char* ShapedRecipieFactory::getTypeToken() const
  542. {
  543. return "shaped";
  544. }
  545. MachineRecipie::MachineRecipie()
  546. : UnshapedRecipie(),
  547. neededTicks(1),
  548. neededFuelPerTick(0)
  549. {}
  550. void MachineRecipie::setTicksNeeded(int ticks)
  551. {
  552. neededTicks = ticks;
  553. }
  554. int MachineRecipie::getTicksNeeded() const
  555. {
  556. return neededTicks;
  557. }
  558. void MachineRecipie::setFuelPerTickNeeded(int fuel)
  559. {
  560. neededFuelPerTick = fuel;
  561. }
  562. int MachineRecipie::getFuelPerTickNeeded() const
  563. {
  564. return neededFuelPerTick;
  565. }
  566. MachineRecipieFactory::MachineRecipieFactory()
  567. : UnshapedRecipieFactory()
  568. {}
  569. MachineRecipie* MachineRecipieFactory::createValue(
  570. Framework::JSON::JSONObject* zJson) const
  571. {
  572. return new MachineRecipie();
  573. }
  574. MachineRecipie* MachineRecipieFactory::fromJson(
  575. Framework::JSON::JSONObject* zJson) const
  576. {
  577. MachineRecipie* result = UnshapedRecipieFactory::fromJson(zJson);
  578. result->setTicksNeeded(
  579. (int)zJson->zValue("ticksNeeded")->asNumber()->getNumber());
  580. result->setFuelPerTickNeeded(
  581. (int)zJson->zValue("fuelPerTickNeeded")->asNumber()->getNumber());
  582. return result;
  583. }
  584. Framework::JSON::JSONObject* MachineRecipieFactory::toJsonObject(
  585. MachineRecipie* zObject) const
  586. {
  587. Framework::JSON::JSONObject* result
  588. = UnshapedRecipieFactory::toJsonObject(zObject);
  589. result->addValue("ticksNeeded",
  590. new Framework::JSON::JSONNumber(zObject->getTicksNeeded()));
  591. result->addValue("fuelPerTickNeeded",
  592. new Framework::JSON::JSONNumber(zObject->getFuelPerTickNeeded()));
  593. return result;
  594. }
  595. JSONObjectValidationBuilder* MachineRecipieFactory::addToValidator(
  596. JSONObjectValidationBuilder* builder) const
  597. {
  598. return UnshapedRecipieFactory::addToValidator(builder)
  599. ->withRequiredNumber("ticksNeeded")
  600. ->whichIsGreaterOrEqual(1.0)
  601. ->withDefault(1.0)
  602. ->finishNumber()
  603. ->withRequiredNumber("fuelPerTickNeeded")
  604. ->whichIsGreaterOrEqual(0.0)
  605. ->withDefault(0.0)
  606. ->finishNumber();
  607. }
  608. const char* MachineRecipieFactory::getTypeToken() const
  609. {
  610. return "machine";
  611. }