CraftingGrid.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. #include "CraftingGrid.h"
  2. #include <FileSystem.h>
  3. #include <XML.h>
  4. #include "DragController.h"
  5. #include "FactoryClient.h"
  6. #include "Game.h"
  7. #include "Globals.h"
  8. #include "ItemType.h"
  9. #include "UIMLToolTip.h"
  10. #include "UIMLUtils.h"
  11. #include "World.h"
  12. using namespace Framework;
  13. CraftingGridElement::CraftingGridElement()
  14. : UIMLElement()
  15. {}
  16. //! prüft, ob dieses UIML Element für ein bestimmtes xml Element zuständig ist
  17. bool CraftingGridElement::isApplicableFor(Framework::XML::Element& element)
  18. {
  19. return element.getName().isEqual("craftingGrid");
  20. }
  21. //! erstellt eine neue Drawable zu einem gegebenen xml Element
  22. Framework::Drawable* CraftingGridElement::parseElement(
  23. Framework::XML::Element& element, Framework::UIMLContainer& generalFactory)
  24. {
  25. Text targetValue = element.getAttributeValue("target");
  26. int addressLength = 0;
  27. int* address = getUIMLTargetAddress(targetValue, addressLength);
  28. return new CraftingGridView(element.getAttributeValue("id"),
  29. (int)element.getAttributeValue("rowSize"),
  30. (int)element.getAttributeValue("colSize"),
  31. (int)element.getAttributeValue("numOutputSlots"),
  32. address,
  33. addressLength);
  34. }
  35. bool CraftingGridElement::updateElement(Framework::XML::Element& element,
  36. Framework::Drawable& z,
  37. Framework::UIMLContainer& generalFactory)
  38. {
  39. return false;
  40. }
  41. //! wendet die layout parameter zu einer Drawable an
  42. void CraftingGridElement::layout(Framework::XML::Element& element,
  43. Framework::Drawable& z,
  44. int pWidth,
  45. int pHeight,
  46. Framework::UIMLContainer& generalLayouter)
  47. {
  48. z.setSize(500, 500); // TODO: calculate size
  49. UIMLElement::layout(element, z, pWidth, pHeight, generalLayouter);
  50. }
  51. CraftingGridView::CraftingGridView(Text id,
  52. int rowSize,
  53. int colSize,
  54. int numOutputSlots,
  55. int* address,
  56. int addressLength)
  57. : DrawableBackground(),
  58. NetworkAPIProcessor(),
  59. rowSize(rowSize),
  60. colSize(colSize),
  61. numOutputSlots(numOutputSlots),
  62. address(address),
  63. addressLength(addressLength),
  64. slots(0),
  65. outputs(0),
  66. id(id),
  67. dragStartId(-1),
  68. dragStopId(-1),
  69. currentTooltipSlot(-1),
  70. requestetTooltipSlot(-1)
  71. {
  72. craft = uiFactory.createButton(uiFactory.initParam);
  73. craft->setPosition(rowSize * 60, 0);
  74. craft->setSize(40, 20);
  75. craft->setText("Craft");
  76. craft->setMouseEvent([this](void* p, void* o, MouseEvent me) {
  77. if (me.id == ME_RLeft)
  78. {
  79. char* msg = new char[2 + 4 * this->addressLength];
  80. msg[0] = 7; // request crafting
  81. msg[1] = this->addressLength < 4;
  82. for (int i = 0; i < this->addressLength; i++)
  83. {
  84. *(int*)(msg + 2 + i * 4)
  85. = this->address[i]; // copy address to message
  86. }
  87. World::INSTANCE->zClient()->sendPlayerAction(
  88. msg, 2 + 4 * this->addressLength);
  89. delete[] msg;
  90. }
  91. return 1;
  92. });
  93. recipies = uiFactory.createButton(uiFactory.initParam);
  94. recipies->setPosition(rowSize * 60, colSize * 60 - 49);
  95. recipies->setSize(40, 40);
  96. recipies->addStyle(Button::Style::BImage | Button::Style::BAlpha
  97. | Button::Style::Background);
  98. recipies->removeStyle(Button::Style::Buffered);
  99. recipies->setBorderWidth(1);
  100. Framework::LTDBFile file;
  101. file.setFile(new Framework::Text("data/images/gui_icons.ltdb"));
  102. file.readData(0);
  103. recipies->setBackgroundImageZ(file.load(0, new Text("recipies.png")));
  104. recipies->setMouseEvent([this](void* p, void* o, MouseEvent me) {
  105. if (me.id == ME_RLeft)
  106. {
  107. ((Game*)(Menu*)menuRegister->get("game"))->showItemList();
  108. }
  109. return 1;
  110. });
  111. recipies->setToolTipText(
  112. "Recipies", uiFactory.initParam.bildschirm, uiFactory.initParam.font);
  113. setStyle(DrawableBackground::Style::Visible
  114. | DrawableBackground::Style::Allowed);
  115. char* msg = new char[id.getLength() + 12 + 3 + 4];
  116. msg[0] = 0; // request inventory tooltip
  117. msg[1] = (char)id.getLength();
  118. memcpy(msg + 2, id.getText(), id.getLength());
  119. *(int*)(msg + 2 + id.getLength()) = NetworkAPIProcessor::getId();
  120. msg[6 + id.getLength()] = (char)12;
  121. memcpy(msg + 7 + id.getLength(), "CraftingGrid", 12);
  122. World::INSTANCE->zClient()->inventoryAPIRequest(
  123. addressLength < 4
  124. ? Framework::Either<int, Framework::VecN<int, 4>>(address[0])
  125. : Framework::Either<int, Framework::VecN<int, 4>>(
  126. Framework::VecN<int, 4>{
  127. address[0], address[1], address[2], address[3]}),
  128. msg,
  129. id.getLength() + 12 + 3 + 4);
  130. delete[] msg;
  131. setNeedToolTipEvent([this](Drawable* z, Point p) {
  132. int slot = getSlotByLocalPos(p);
  133. if (currentTooltipSlot != slot && currentTooltipSlot != -1)
  134. {
  135. std::cout << "closing tooltip\n";
  136. this->setToolTipZ(0);
  137. currentTooltipSlot = -1;
  138. }
  139. if (requestetTooltipSlot != slot && slot != -1)
  140. {
  141. std::cout << "requesting tooltip for slot " << slot << "\n";
  142. requestetTooltipSlot = slot;
  143. char* msg = new char[this->id.getLength() + 10];
  144. msg[0] = 2; // request inventory tooltip
  145. msg[1] = (char)this->id.getLength();
  146. memcpy(msg + 2, this->id.getText(), this->id.getLength());
  147. *(int*)(msg + 2 + this->id.getLength())
  148. = NetworkAPIProcessor::getId();
  149. *(int*)(msg + 6 + this->id.getLength()) = slot;
  150. World::INSTANCE->zClient()->inventoryAPIRequest(
  151. this->addressLength < 4
  152. ? Framework::Either<int, Framework::VecN<int, 4>>(
  153. this->address[0])
  154. : Framework::Either<int, Framework::VecN<int, 4>>(
  155. Framework::VecN<int, 4>{this->address[0],
  156. this->address[1],
  157. this->address[2],
  158. this->address[3]}),
  159. msg,
  160. this->id.getLength() + 10);
  161. return 1;
  162. }
  163. return 0;
  164. });
  165. }
  166. CraftingGridView::~CraftingGridView()
  167. {
  168. DragController<InventoryDragSource, int>* controller
  169. = menuRegister ? ((Game*)(Menu*)menuRegister->get("game"))
  170. ->zInventoryDragController()
  171. : 0;
  172. if (menuRegister && controller->getCurrentDragContainer() == this)
  173. controller->stopDrag();
  174. if (slots) slots->release();
  175. if (outputs) outputs->release();
  176. char* msg = new char[id.getLength() + 6];
  177. msg[0] = 1;
  178. msg[1] = (char)id.getLength();
  179. memcpy(msg + 2, id.getText(), id.getLength());
  180. *(int*)(msg + 2 + id.getLength()) = NetworkAPIProcessor::getId();
  181. World::INSTANCE->zClient()->inventoryAPIRequest(
  182. addressLength < 4
  183. ? Framework::Either<int, Framework::VecN<int, 4>>(address[0])
  184. : Framework::Either<int, Framework::VecN<int, 4>>(
  185. Framework::VecN<int, 4>{
  186. address[0], address[1], address[2], address[3]}),
  187. msg,
  188. id.getLength() + 6);
  189. delete[] msg;
  190. craft->release();
  191. recipies->release();
  192. }
  193. int CraftingGridView::getSlotByLocalPos(Point pos)
  194. {
  195. int x = 0;
  196. int y = 0;
  197. int rowCount = 0;
  198. int slot = 0;
  199. dragStopId = -1;
  200. if (slots)
  201. {
  202. for (SlotInfo info : *slots)
  203. {
  204. if (pos.x >= x && pos.x < x + 50 && pos.y >= y && pos.y < y + 50)
  205. return info.id;
  206. x += 60;
  207. if (++rowCount >= rowSize)
  208. {
  209. y += 60;
  210. x = 0;
  211. rowCount = 0;
  212. }
  213. slot++;
  214. }
  215. }
  216. return -1;
  217. }
  218. void CraftingGridView::api(char* message)
  219. {
  220. switch (message[0])
  221. {
  222. case 0:
  223. // send inventory content
  224. {
  225. Array<SlotInfo>* slots = new Array<SlotInfo>();
  226. int count = *(int*)(++message);
  227. for (int i = 0; i < count; i++)
  228. {
  229. SlotInfo info;
  230. info.id = *(int*)(message += 4);
  231. info.itemCount = *(int*)(message += 4);
  232. if (info.itemCount > 0)
  233. {
  234. info.hp = *(float*)(message += 4);
  235. info.maxHp = *(float*)(message += 4);
  236. info.durability = *(float*)(message += 4);
  237. info.maxDurability = *(float*)(message += 4);
  238. info.zItem = zItemType(*(int*)(message += 4))->zIcon();
  239. char len = *(message += 4);
  240. char* name = new char[len + 1];
  241. memcpy(name, message += 1, len);
  242. name[len] = 0;
  243. info.name = name;
  244. delete[] name;
  245. message += len - 4;
  246. }
  247. slots->add(info);
  248. }
  249. window->zScreen()->postAction([this, slots]() {
  250. if (this->slots) this->slots->release();
  251. this->slots = slots;
  252. });
  253. break;
  254. }
  255. case 1: // set count of items
  256. {
  257. if (!slots) return;
  258. int id = *(int*)(message + 1);
  259. int count = *(int*)(message + 5);
  260. for (int i = 0; i < slots->getEntryCount(); i++)
  261. {
  262. if (slots->get(i).id == id)
  263. {
  264. SlotInfo info = slots->get(i);
  265. info.itemCount = count;
  266. if (info.itemCount == 0)
  267. {
  268. DragController<InventoryDragSource, int>* controller
  269. = ((Game*)(Menu*)menuRegister->get("game"))
  270. ->zInventoryDragController();
  271. if (controller
  272. && controller->getCurrentDragContainer() == this
  273. && controller->getCurrentDaragElement() == info.id)
  274. {
  275. controller->stopDrag();
  276. }
  277. }
  278. slots->set(info, i);
  279. break;
  280. }
  281. }
  282. break;
  283. }
  284. case 2: // add new stack
  285. {
  286. if (!slots) return;
  287. int id = *(int*)(message + 1);
  288. for (int i = 0; i < slots->getEntryCount(); i++)
  289. {
  290. if (slots->get(i).id == id)
  291. {
  292. SlotInfo info = slots->get(i);
  293. info.itemCount = *(int*)(message + 5);
  294. info.hp = *(float*)(message + 9);
  295. info.maxHp = *(float*)(message + 13);
  296. info.durability = *(float*)(message + 17);
  297. info.maxDurability = *(float*)(message + 21);
  298. info.zItem = zItemType(*(int*)(message + 25))->zIcon();
  299. char len = *(message + 29);
  300. char* name = new char[len + 1];
  301. memcpy(name, message + 30, len);
  302. name[len] = 0;
  303. info.name = name;
  304. delete[] name;
  305. slots->set(info, i);
  306. break;
  307. }
  308. }
  309. break;
  310. }
  311. case 3: // receive tooltip uiml
  312. {
  313. int slotId = *(int*)(message + 1);
  314. if (slotId == requestetTooltipSlot)
  315. {
  316. std::cout << "tooltip loaded for slot " << slotId << "\n";
  317. short len = *(short*)(message + 5);
  318. if (len > 0)
  319. {
  320. char* uiml = new char[len + 1];
  321. memcpy(uiml, message + 7, len);
  322. uiml[len] = 0;
  323. UIMLToolTip* tip = new UIMLToolTip();
  324. tip->setUIML(uiml);
  325. tip->setWarten(0);
  326. tip->setPosition(mausPos.x, mausPos.y + 15);
  327. setToolTipZ(tip);
  328. delete[] uiml;
  329. currentTooltipSlot = slotId;
  330. requestetTooltipSlot = -1;
  331. }
  332. else
  333. toolTipRequested = 0;
  334. }
  335. break;
  336. }
  337. case 100: // set crafting result
  338. {
  339. Array<SlotInfo>* outputs = new Array<SlotInfo>();
  340. int count = *(int*)(++message);
  341. for (int i = 0; i < count; i++)
  342. {
  343. SlotInfo info;
  344. info.id = i;
  345. info.itemCount = *(int*)(message += 4);
  346. if (info.itemCount > 0)
  347. {
  348. info.hp = *(float*)(message += 4);
  349. info.maxHp = *(float*)(message += 4);
  350. info.durability = *(float*)(message += 4);
  351. info.maxDurability = *(float*)(message += 4);
  352. info.zItem = zItemType(*(int*)(message += 4))->zIcon();
  353. }
  354. outputs->add(info);
  355. }
  356. window->zScreen()->postAction([this, outputs]() {
  357. if (this->outputs) this->outputs->release();
  358. this->outputs = outputs;
  359. });
  360. break;
  361. }
  362. }
  363. }
  364. bool CraftingGridView::tick(double tickVal)
  365. {
  366. return DrawableBackground::tick(tickVal);
  367. }
  368. void CraftingGridView::render(Image& rObj)
  369. {
  370. DrawableBackground::render(rObj);
  371. if (!rObj.setDrawOptions(pos.x, pos.y, gr.x, gr.y)) return;
  372. int numRows = 1;
  373. if (slots)
  374. {
  375. int x = 0;
  376. int y = 0;
  377. int rowCount = 0;
  378. int index = 0;
  379. for (SlotInfo info : *slots)
  380. {
  381. info.render(
  382. x, y, rObj, dragStartId == info.id, dragStopId == info.id);
  383. x += 60;
  384. if (++rowCount >= rowSize)
  385. {
  386. y += 60;
  387. x = 0;
  388. rowCount = 0;
  389. if (index < slots->getEntryCount() - 1) numRows++;
  390. }
  391. index++;
  392. }
  393. }
  394. craft->render(rObj);
  395. recipies->setStyle(Button::Style::Visible,
  396. !((Game*)(Menu*)menuRegister->get("game"))->isItemListVisible());
  397. recipies->render(rObj);
  398. rObj.fillRegion(rowSize * 60, gr.y / 2 - 5, 25, 10, 0xFF52525E);
  399. rObj.drawTriangle(Point(rowSize * 60 + 25, gr.y / 2 - 15),
  400. Point(rowSize * 60 + 40, gr.y / 2),
  401. Point(rowSize * 60 + 25, gr.y / 2 + 15),
  402. 0xFF52525E);
  403. if (outputs)
  404. {
  405. int x = rowSize * 60 + 50;
  406. int y = 0;
  407. int colCount = 0;
  408. for (SlotInfo info : *outputs)
  409. {
  410. info.render(
  411. x, y, rObj, dragStartId == info.id, dragStopId == info.id);
  412. y += 60;
  413. if (++colCount >= numRows)
  414. {
  415. x += 60;
  416. y = 0;
  417. colCount = 0;
  418. }
  419. }
  420. }
  421. rObj.releaseDrawOptions();
  422. }
  423. void CraftingGridView::doMouseEvent(MouseEvent& me, bool userRet)
  424. {
  425. mausPos.x = me.originalX;
  426. mausPos.y = me.originalY;
  427. if (!slots) return;
  428. if (me.id == ME_Move)
  429. {
  430. if (getSlotByLocalPos(Point(me.mx, me.my)) != currentTooltipSlot)
  431. {
  432. if (currentTooltipSlot != -1)
  433. {
  434. std::cout << "closing tooltip\n";
  435. setToolTipZ(0);
  436. }
  437. else
  438. toolTipRequested = 0;
  439. currentTooltipSlot = -1;
  440. }
  441. }
  442. craft->doPublicMouseEvent(me);
  443. recipies->doPublicMouseEvent(me);
  444. DragController<InventoryDragSource, int>* controller
  445. = ((Game*)(Menu*)menuRegister->get("game"))->zInventoryDragController();
  446. int x = 0;
  447. int y = 0;
  448. int rowCount = 0;
  449. int slot = 0;
  450. dragStopId = -1;
  451. for (SlotInfo info : *slots)
  452. {
  453. if (me.mx >= x && me.mx < x + 50 && me.my >= y && me.my < y + 50)
  454. {
  455. if (me.id == ME_RLeft)
  456. {
  457. if (!controller->getCurrentDragContainer()
  458. && info.itemCount > 0)
  459. {
  460. controller->beginDrag(this, info.id, info.zItem, [this]() {
  461. dragStartId = -1;
  462. });
  463. dragStartId = info.id;
  464. }
  465. else if (controller->getCurrentDragContainer())
  466. {
  467. // request to transfer items from source to target slot
  468. Framework::Either<int, Framework::VecN<int, 4>> source
  469. = controller->getCurrentDragContainer()
  470. ->getInventoryTarget();
  471. int len = 2 + (source.isA() ? 4 : 16) + 5
  472. + (addressLength < 4 ? 4 : 16) + 4;
  473. char* msg = new char[len];
  474. int index = 0;
  475. msg[index++] = 6;
  476. msg[index++] = (char)source.isA();
  477. if (source.isA())
  478. {
  479. *(int*)(msg + index) = source.getA();
  480. index += 4;
  481. }
  482. else
  483. {
  484. *(int*)(msg + index) = source.getB()[0];
  485. *(int*)(msg + index + 4) = source.getB()[1];
  486. *(int*)(msg + index + 8) = source.getB()[2];
  487. *(int*)(msg + index + 12) = source.getB()[3];
  488. index += 16;
  489. }
  490. *(int*)(msg + index) = controller->getCurrentDaragElement();
  491. index += 4;
  492. msg[index++] = addressLength < 4;
  493. if (addressLength < 4)
  494. {
  495. *(int*)(msg + index) = address[0];
  496. index += 4;
  497. }
  498. else
  499. {
  500. *(int*)(msg + index) = address[0];
  501. *(int*)(msg + index + 4) = address[1];
  502. *(int*)(msg + index + 8) = address[2];
  503. *(int*)(msg + index + 12) = address[3];
  504. index += 16;
  505. }
  506. *(int*)(msg + index) = info.id;
  507. World::INSTANCE->zClient()->sendPlayerAction(msg, len);
  508. delete[] msg;
  509. }
  510. }
  511. else
  512. {
  513. if (controller->getCurrentDragContainer()
  514. && (controller->getCurrentDragContainer() != this
  515. || controller->getCurrentDaragElement() != info.id))
  516. {
  517. dragStopId = info.id;
  518. }
  519. }
  520. break;
  521. }
  522. x += 60;
  523. if (++rowCount >= rowSize)
  524. {
  525. y += 60;
  526. x = 0;
  527. rowCount = 0;
  528. }
  529. slot++;
  530. }
  531. DrawableBackground::doMouseEvent(me, userRet);
  532. }
  533. Framework::Either<int, Framework::VecN<int, 4>>
  534. CraftingGridView::getInventoryTarget() const
  535. {
  536. return addressLength < 4
  537. ? Framework::Either<int, Framework::VecN<int, 4>>(address[0])
  538. : Framework::Either<int, Framework::VecN<int, 4>>(
  539. Framework::VecN<int, 4>{
  540. address[0], address[1], address[2], address[3]});
  541. }