UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ui_node_baseinventory.cpp
Go to the documentation of this file.
1 
8 /*
9 Copyright (C) 2002-2020 UFO: Alien Invasion.
10 
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 
20 See the GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 
26 */
27 
28 #include "../ui_main.h"
29 #include "../ui_parse.h"
30 #include "../ui_behaviour.h"
31 #include "../ui_actions.h"
32 #include "../ui_dragndrop.h"
33 #include "../ui_tooltip.h"
34 #include "../ui_nodes.h"
35 #include "../ui_input.h"
36 #include "../ui_render.h"
37 #include "../ui_lua.h"
38 
39 #include "ui_node_baseinventory.h"
40 #include "ui_node_model.h"
41 #include "ui_node_container.h"
42 #include "ui_node_abstractnode.h"
44 
45 #include "../../cl_shared.h"
46 #include "../../cgame/cl_game.h"
47 #include "../../input/cl_keys.h"
48 #include "../../cl_inventory.h"
49 
50 #include "../../../common/scripts_lua.h"
51 
52 #define EXTRADATA_TYPE baseInventoryExtraData_t
53 #define EXTRADATA(node) UI_EXTRADATA(node, EXTRADATA_TYPE)
54 #define EXTRADATACONST(node) UI_EXTRADATACONST(node, EXTRADATA_TYPE)
55 
56 extern bool CL_BattlescapeRunning(void);
57 extern cvar_t* cl_selected;
58 
63 static int dragInfoFromX = -1;
64 static int dragInfoFromY = -1;
65 
70 static const Item* dragInfoIC;
71 
82 static Item* UI_ContainerNodeGetExistingItem (const uiNode_t* node, const objDef_t* item, const itemFilterTypes_t filterType)
83 {
84  if (ui_inventory == nullptr) {
85  Com_Printf("ERROR: UI Inventory is not initialized in UI_ContainerNodeGetExistingItem!\n");
86  return nullptr;
87  }
88  return INV_SearchInInventoryWithFilter(ui_inventory, EXTRADATACONST(node).super.container, item, filterType);
89 }
90 
94 #define CII_AMMOONLY 0x01
95 #define CII_WEAPONONLY 0x02
96 #define CII_AVAILABLEONLY 0x04
97 #define CII_NOTAVAILABLEONLY 0x08
98 #define CII_IMPLANTONLY 0x10
99 #define CII_END 0x80
100 
101 typedef struct {
102  const uiNode_t* node;
103  byte groupSteps[6];
104  int groupID;
106 
107  int itemID;
110 
118 {
119  assert(iterator->groupSteps[iterator->groupID] != CII_END);
120 
121  /* iterate each groups */
122  for (; iterator->groupSteps[iterator->groupID] != CII_END; iterator->groupID++) {
123  int filter = iterator->groupSteps[iterator->groupID];
124  /* next */
125  iterator->itemID++;
126 
127  /* iterate all item type*/
128  for (;iterator->itemID < csi.numODs; iterator->itemID++) {
129  const objDef_t* obj = INVSH_GetItemByIDX(iterator->itemID);
130 
131  /* gameplay filter */
132  if (!GAME_ItemIsUseable(obj))
133  continue;
134 
135  /* type filter */
137  const bool isArmour = obj->isArmour();
138  const bool isAmmo = obj->numWeapons != 0 && obj->isAmmo();
139  const bool isWeapon = obj->weapon || obj->isMisc || isArmour;
140  const bool isImplant = obj->implant;
141 
142  if ((filter & CII_WEAPONONLY) && !isWeapon)
143  continue;
144  if ((filter & CII_AMMOONLY) && !isAmmo)
145  continue;
146  if ((filter & CII_IMPLANTONLY) && !isImplant)
147  continue;
148  if (!INV_ItemMatchesFilter(obj, iterator->filterEquipType))
149  continue;
150 
151  /* exists in inventory filter */
152  iterator->itemFound = UI_ContainerNodeGetExistingItem(iterator->node, obj, iterator->filterEquipType);
153  if ((filter & CII_AVAILABLEONLY) && iterator->itemFound == nullptr)
154  continue;
155  if ((filter & CII_NOTAVAILABLEONLY) && iterator->itemFound != nullptr)
156  continue;
157 
158  /* we found something */
159  return;
160  }
161 
162  /* can we search into another group? */
163  if (iterator->groupSteps[iterator->groupID + 1] != CII_END)
164  iterator->itemID = -1;
165  }
166 
167  /* clean up */
168  iterator->itemFound = nullptr;
169 }
170 
174 static void UI_ContainerItemIteratorInit (containerItemIterator_t* iterator, const uiNode_t* const node)
175 {
176  int groupID = 0;
177  iterator->itemID = -1;
178  iterator->groupID = 0;
179  iterator->node = node;
180  iterator->filterEquipType = (itemFilterTypes_t) EXTRADATACONST(node).filterEquipType;
181 
182  if (EXTRADATACONST(node).displayAvailableOnTop) {
183  /* available items */
184  if (EXTRADATACONST(node).displayWeapon)
185  iterator->groupSteps[groupID++] = CII_WEAPONONLY | CII_AVAILABLEONLY;
186  if (EXTRADATACONST(node).displayAmmo)
187  iterator->groupSteps[groupID++] = CII_AMMOONLY | CII_AVAILABLEONLY;
188  if (EXTRADATACONST(node).displayImplant)
189  iterator->groupSteps[groupID++] = CII_IMPLANTONLY | CII_AVAILABLEONLY;
190  /* unavailable items */
191  if (EXTRADATACONST(node).displayUnavailableItem) {
192  if (EXTRADATACONST(node).displayWeapon)
193  iterator->groupSteps[groupID++] = CII_WEAPONONLY | CII_NOTAVAILABLEONLY;
194  if (EXTRADATACONST(node).displayAmmo)
195  iterator->groupSteps[groupID++] = CII_AMMOONLY | CII_NOTAVAILABLEONLY;
196  if (EXTRADATACONST(node).displayImplant)
197  iterator->groupSteps[groupID++] = CII_IMPLANTONLY | CII_NOTAVAILABLEONLY;
198  }
199  } else {
200  const int filter = (EXTRADATACONST(node).displayUnavailableItem) ? 0 : CII_AVAILABLEONLY;
201  if (EXTRADATACONST(node).displayWeapon)
202  iterator->groupSteps[groupID++] = CII_WEAPONONLY | filter;
203  if (EXTRADATACONST(node).displayAmmo)
204  iterator->groupSteps[groupID++] = CII_AMMOONLY | filter;
205  if (EXTRADATACONST(node).displayImplant)
206  iterator->groupSteps[groupID++] = CII_IMPLANTONLY | filter;
207  }
208  iterator->groupSteps[groupID++] = CII_END;
209 
210  /* find the first item */
212 }
213 
219 {
220  if (EXTRADATA(node).onViewChange) {
221  UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange);
222  }
223  else if (EXTRADATA(node).lua_onViewChange != LUA_NOREF) {
224  UI_ExecuteLuaEventScript (node, EXTRADATA(node).lua_onViewChange);
225  }
226 }
227 
234 {
235  EXTRADATA(node).super.container = INVSH_GetInventoryDefinitionByID("equip");
236 }
237 
238 static const vec3_t scale = {3.5, 3.5, 3.5};
240 static const vec4_t colorDefault = {1, 1, 1, 1};
241 static const vec4_t colorLoadable = {0.5, 1, 0.5, 1};
242 static const vec4_t colorDisabledHiden = {0.5, 0.5, 0.5, 0.5};
243 static const vec4_t colorDisabledLoadable = {0.5, 0.25, 0.25, 1.0};
244 
249 static int UI_BaseInventoryNodeDrawItems (uiNode_t* node, const objDef_t* highlightType)
250 {
251  bool outOfNode = false;
252  vec2_t nodepos;
253  int items = 0;
254  int rowHeight = 0;
255  const int cellWidth = node->box.size[0] / EXTRADATA(node).columns;
256  containerItemIterator_t iterator;
257  int currentHeight = 0;
258  UI_GetNodeAbsPos(node, nodepos);
259 
260  UI_ContainerItemIteratorInit(&iterator, node);
261  for (; iterator.itemID < csi.numODs; UI_ContainerItemIteratorNext(&iterator)) {
262  const int id = iterator.itemID;
263  const objDef_t* obj = INVSH_GetItemByIDX(id);
264  Item tempItem(obj, nullptr, 1);
265  vec3_t pos;
266  vec3_t ammopos;
267  const float* color;
268  bool isHighlight = false;
269  int amount;
270  const int col = items % EXTRADATA(node).columns;
271  int cellHeight = 0;
272  const Item* icItem = iterator.itemFound;
273 
274  /* skip items over and bellow the node view */
275  if (outOfNode || currentHeight < EXTRADATA(node).scrollY.viewPos) {
276  int height;
277  R_FontTextSize("f_verysmall", _(obj->name),
278  cellWidth - 5, LONGLINES_WRAP, nullptr, &height, nullptr, nullptr);
279  height += obj->sy * C_UNIT + 10;
280  if (height > rowHeight)
281  rowHeight = height;
282 
283  if (outOfNode || currentHeight + rowHeight < EXTRADATA(node).scrollY.viewPos) {
284  if (col == EXTRADATA(node).columns - 1) {
285  currentHeight += rowHeight;
286  rowHeight = 0;
287  }
288  items++;
289  continue;
290  }
291  }
292 
293  Vector2Copy(nodepos, pos);
294  pos[0] += cellWidth * col;
295  pos[1] += currentHeight - EXTRADATA(node).scrollY.viewPos;
296  pos[2] = 0;
297 
298  if (highlightType) {
299  if (obj->isAmmo())
300  isHighlight = obj->isLoadableInWeapon(highlightType);
301  else
302  isHighlight = highlightType->isLoadableInWeapon(obj);
303  }
304 
305  if (icItem != nullptr) {
306  if (isHighlight)
307  color = colorLoadable;
308  else
309  color = colorDefault;
310  } else {
311  if (isHighlight)
312  color = colorDisabledLoadable;
313  else
314  color = colorDisabledHiden;
315  }
316 
317  if (icItem)
318  amount = icItem->getAmount();
319  else
320  amount = 0;
321 
322  /* draw item */
323  pos[0] += obj->sx * C_UNIT / 2.0;
324  pos[1] += obj->sy * C_UNIT / 2.0;
325  UI_DrawItem(node, pos, &tempItem, -1, -1, scale, color);
326  UI_DrawString("f_verysmall", ALIGN_LC,
327  pos[0] + obj->sx * C_UNIT / 2.0, pos[1] + obj->sy * C_UNIT / 2.0,
328  pos[0] + obj->sx * C_UNIT / 2.0, cellWidth - 5, /* maxWidth */
329  0, va("x%i", amount));
330  pos[0] -= obj->sx * C_UNIT / 2.0;
331  pos[1] += obj->sy * C_UNIT / 2.0;
332  cellHeight += obj->sy * C_UNIT;
333 
334  /* save position for ammo */
335  Vector2Copy(pos, ammopos);
336  ammopos[2] = 0;
337  ammopos[0] += obj->sx * C_UNIT + 10;
338 
339  /* draw the item name. */
340  cellHeight += UI_DrawString("f_verysmall", ALIGN_UL,
341  pos[0], pos[1],
342  pos[0], cellWidth - 5, /* max width */
343  0, _(obj->name));
344 
345  /* draw ammos of weapon */
346  if (obj->weapon && EXTRADATA(node).displayAmmoOfWeapon) {
347  for (int ammoIdx = 0; ammoIdx < obj->numAmmos; ammoIdx++) {
348  tempItem.setDef(obj->ammos[ammoIdx]);
349 
350  /* skip weapos that are their own ammo -- oneshot and such */
351  if (obj == tempItem.def())
352  continue;
353 
354  /* skip unusable ammo */
355  if (!GAME_ItemIsUseable(tempItem.def()))
356  continue;
357 
358  /* find and skip none existing ammo */
359  icItem = UI_ContainerNodeGetExistingItem(node, tempItem.def(), (itemFilterTypes_t) EXTRADATA(node).filterEquipType);
360  if (!icItem)
361  continue;
362 
363  /* Calculate the center of the item model/image. */
364  ammopos[0] += icItem->def()->sx * C_UNIT / 2.0;
365  ammopos[1] -= icItem->def()->sy * C_UNIT / 2.0;
366  UI_DrawItem(node, ammopos, &tempItem, -1, -1, scale, colorDefault);
367  UI_DrawString("f_verysmall", ALIGN_LC,
368  ammopos[0] + icItem->def()->sx * C_UNIT / 2.0, ammopos[1] + icItem->def()->sy * C_UNIT / 2.0,
369  ammopos[0] + icItem->def()->sx * C_UNIT / 2.0, cellWidth - 5 - ammopos[0], /* maxWidth */
370  0, va("x%i", icItem->getAmount()));
371  ammopos[0] += icItem->def()->sx * C_UNIT / 2.0;
372  ammopos[1] += icItem->def()->sy * C_UNIT / 2.0;
373  }
374  }
375  cellHeight += 10;
376 
377  if (cellHeight > rowHeight) {
378  rowHeight = cellHeight;
379  }
380 
381  /* add a marge between rows */
382  if (col == EXTRADATA(node).columns - 1) {
383  currentHeight += rowHeight;
384  rowHeight = 0;
385  if (currentHeight - EXTRADATA(node).scrollY.viewPos >= node->box.size[1])
386  outOfNode = true;
387  }
388 
389  /* count items */
390  items++;
391  }
392 
393  if (rowHeight != 0) {
394  currentHeight += rowHeight;
395  }
396  return currentHeight;
397 }
398 
402 static void UI_BaseInventoryNodeDraw2 (uiNode_t* node, const objDef_t* highlightType)
403 {
404  bool updateScroll = false;
405  int visibleHeight = 0;
406  int needHeight = 0;
407  vec2_t screenPos;
408 
409  UI_GetNodeScreenPos(node, screenPos);
410  UI_PushClipRect(screenPos[0], screenPos[1], node->box.size[0], node->box.size[1]);
411 
412  needHeight = UI_BaseInventoryNodeDrawItems(node, highlightType);
413 
414  UI_PopClipRect();
415  visibleHeight = node->box.size[1];
416 
417 #if 0
418  R_FontDrawString("f_verysmall", ALIGN_UL,
419  node->box.pos[0], node->box.pos[1], node->box.pos[0], node->box.pos[1],
420  0, 0, /* maxWidth/maxHeight */
421  0, va("%i %i/%i", EXTRADATA(node).scrollCur, visibleRows, totalRows), 0, 0, nullptr, false, 0);
422 #endif
423 
424  /* Update display of scroll buttons if something changed. */
425  if (visibleHeight != EXTRADATA(node).scrollY.viewSize || needHeight != EXTRADATA(node).scrollY.fullSize) {
426  EXTRADATA(node).scrollY.fullSize = needHeight;
427  EXTRADATA(node).scrollY.viewSize = visibleHeight;
428  updateScroll = true;
429  }
430  if (EXTRADATA(node).scrollY.viewPos > needHeight - visibleHeight) {
431  EXTRADATA(node).scrollY.viewPos = needHeight - visibleHeight;
432  updateScroll = true;
433  }
434  if (EXTRADATA(node).scrollY.viewPos < 0) {
435  EXTRADATA(node).scrollY.viewPos = 0;
436  updateScroll = true;
437  }
438 
439  if (updateScroll)
441 }
442 
445  EXTRADATA(node).lua_onViewChange = LUA_NOREF;
446 }
447 
452 {
453  const objDef_t* highlightType = nullptr;
454 
455  if (!EXTRADATA(node).super.container)
456  return;
457  if (!ui_inventory)
458  return;
459  /* is container invisible */
460  if (node->color[3] < 0.001)
461  return;
462 
463  /* Highlight weapons that the dragged ammo (if it is one) can be loaded into. */
464  if (UI_DNDIsDragging() && UI_DNDGetType() == DND_ITEM) {
465  highlightType = UI_DNDGetItem()->def();
466  }
467 
468  UI_BaseInventoryNodeDraw2(node, highlightType);
469 }
470 
474 static Item* UI_BaseInventoryNodeGetItem (const uiNode_t* const node, int mouseX, int mouseY, int* contX, int* contY)
475 {
476  bool outOfNode = false;
477  vec2_t nodepos;
478  int items = 0;
479  int rowHeight = 0;
480  const int cellWidth = node->box.size[0] / EXTRADATACONST(node).columns;
481  int tempX, tempY;
482  containerItemIterator_t iterator;
483  int currentHeight = 0;
484 
485  if (!contX)
486  contX = &tempX;
487  if (!contY)
488  contY = &tempY;
489 
490  UI_GetNodeAbsPos(node, nodepos);
491 
492  UI_ContainerItemIteratorInit(&iterator, node);
493  for (; iterator.itemID < csi.numODs; UI_ContainerItemIteratorNext(&iterator)) {
494  const int id = iterator.itemID;
495  const objDef_t* obj = INVSH_GetItemByIDX(id);
496  vec2_t pos;
497  vec2_t ammopos;
498  const int col = items % EXTRADATACONST(node).columns;
499  int cellHeight = 0;
500  Item* icItem = iterator.itemFound;
501  int height;
502 
503  /* skip items over and bellow the node view */
504  if (outOfNode || currentHeight < EXTRADATACONST(node).scrollY.viewPos) {
505  int outHeight;
506  R_FontTextSize("f_verysmall", _(obj->name),
507  cellWidth - 5, LONGLINES_WRAP, nullptr, &outHeight, nullptr, nullptr);
508  outHeight += obj->sy * C_UNIT + 10;
509  if (outHeight > rowHeight)
510  rowHeight = outHeight;
511 
512  if (outOfNode || currentHeight + rowHeight < EXTRADATACONST(node).scrollY.viewPos) {
513  if (col == EXTRADATACONST(node).columns - 1) {
514  currentHeight += rowHeight;
515  rowHeight = 0;
516  }
517  items++;
518  continue;
519  }
520  }
521 
522  Vector2Copy(nodepos, pos);
523  pos[0] += cellWidth * col;
524  pos[1] += currentHeight - EXTRADATACONST(node).scrollY.viewPos;
525 
526  /* check item */
527  if (mouseY < pos[1])
528  break;
529  if (mouseX >= pos[0] && mouseX < pos[0] + obj->sx * C_UNIT
530  && mouseY >= pos[1] && mouseY < pos[1] + obj->sy * C_UNIT) {
531  if (icItem) {
532  *contX = icItem->getX();
533  *contY = icItem->getY();
534  return icItem;
535  }
536  return nullptr;
537  }
538  pos[1] += obj->sy * C_UNIT;
539  cellHeight += obj->sy * C_UNIT;
540 
541  /* save position for ammo */
542  Vector2Copy(pos, ammopos);
543  ammopos[0] += obj->sx * C_UNIT + 10;
544 
545  /* draw the item name. */
546  R_FontTextSize("f_verysmall", _(obj->name),
547  cellWidth - 5, LONGLINES_WRAP, nullptr, &height, nullptr, nullptr);
548  cellHeight += height;
549 
550  /* draw ammos of weapon */
551  if (obj->weapon && EXTRADATACONST(node).displayAmmoOfWeapon) {
552  for (int ammoIdx = 0; ammoIdx < obj->numAmmos; ammoIdx++) {
553  const objDef_t* objammo = obj->ammos[ammoIdx];
554 
555  /* skip unusable ammo */
556  if (!GAME_ItemIsUseable(objammo))
557  continue;
558 
559  /* find and skip none existing ammo */
560  icItem = UI_ContainerNodeGetExistingItem(node, objammo, (itemFilterTypes_t) EXTRADATACONST(node).filterEquipType);
561  if (!icItem)
562  continue;
563 
564  /* check ammo (ammopos in on the left-lower corner) */
565  if (mouseX < ammopos[0] || mouseY >= ammopos[1])
566  break;
567  if (mouseX >= ammopos[0] && mouseX < ammopos[0] + objammo->sx * C_UNIT
568  && mouseY >= ammopos[1] - objammo->sy * C_UNIT && mouseY < ammopos[1]) {
569  *contX = icItem->getX();
570  *contY = icItem->getY();
571  return icItem;
572  }
573  ammopos[0] += objammo->sx * C_UNIT;
574  }
575  }
576  cellHeight += 10;
577 
578  if (cellHeight > rowHeight) {
579  rowHeight = cellHeight;
580  }
581 
582  /* add a margin between rows */
583  if (col == EXTRADATACONST(node).columns - 1) {
584  currentHeight += rowHeight;
585  rowHeight = 0;
586  if (currentHeight - EXTRADATACONST(node).scrollY.viewPos >= node->box.size[1])
587  return nullptr;
588  }
589 
590  /* count items */
591  items++;
592  }
593 
594  *contX = NONE;
595  *contY = NONE;
596  return nullptr;
597 }
598 
604 void uiBaseInventoryNode::drawTooltip (const uiNode_t* node, int x, int y) const
605 {
606  /* Find out where the mouse is. */
607  const Item* itemHover = UI_BaseInventoryNodeGetItem(node, x, y, nullptr, nullptr);
608  if (!itemHover)
609  return;
610 
611  static char tooltiptext[MAX_VAR * 2];
612  const int itemToolTipWidth = 250;
613 
614  /* Get name and info about item */
615  UI_GetItemTooltip(*itemHover, tooltiptext, sizeof(tooltiptext));
616 #ifdef DEBUG
617  /* Display stored container-coordinates of the item. */
618  Q_strcat(tooltiptext, sizeof(tooltiptext), "\n%i/%i", itemHover->getX(), itemHover->getY());
619 #endif
620  UI_DrawTooltip(tooltiptext, x, y, itemToolTipWidth);
621 }
622 
630 static void UI_ContainerNodeAutoPlace (uiNode_t* node, int mouseX, int mouseY)
631 {
632  if (!ui_inventory)
633  return;
634 
635  /* don't allow this in tactical missions */
636  if (CL_BattlescapeRunning())
637  return;
638 
639  const int sel = cl_selected->integer;
640  if (sel < 0)
641  return;
642 
643  assert(EXTRADATA(node).super.container);
644 
645  int fromX, fromY;
646  Item* ic = UI_BaseInventoryNodeGetItem(node, mouseX, mouseY, &fromX, &fromY);
647  Com_DPrintf(DEBUG_CLIENT, "UI_ContainerNodeAutoPlace: item %i/%i selected from scrollable container.\n", fromX, fromY);
648  if (!ic)
649  return;
651 
652  /* Update display of scroll buttons. */
654 }
655 
656 static int oldMouseX = 0;
657 static int oldMouseY = 0;
658 
660 {
661  const int delta = abs(oldMouseX - x) + abs(oldMouseY - y);
662  if (delta > 15) {
663  UI_DNDDragItem(node, dragInfoIC);
664  UI_MouseRelease();
665  }
666 }
667 
668 void uiBaseInventoryNode::onMouseDown (uiNode_t* node, int x, int y, int button)
669 {
670  switch (button) {
671  case K_MOUSE1:
672  {
673  /* start drag and drop */
674  int fromX, fromY;
675  dragInfoIC = UI_BaseInventoryNodeGetItem(node, x, y, &fromX, &fromY);
676  if (dragInfoIC) {
677  dragInfoFromX = fromX;
678  dragInfoFromY = fromY;
679  oldMouseX = x;
680  oldMouseY = y;
681  UI_SetMouseCapture(node);
682  EXTRADATA(node).super.lastSelectedId = dragInfoIC->def()->idx;
683  if (EXTRADATA(node).super.onSelect) {
684  UI_ExecuteEventActions(node, EXTRADATA(node).super.onSelect);
685  }
686  if (EXTRADATA(node).super.lua_onSelect != LUA_NOREF) {
687  UI_ExecuteLuaEventScript(node, EXTRADATA(node).super.lua_onSelect);
688  }
689  }
690  break;
691  }
692  case K_MOUSE2:
693  if (UI_DNDIsDragging()) {
694  UI_DNDAbort();
695  } else {
696  /* auto place */
697  UI_ContainerNodeAutoPlace(node, x, y);
698  }
699  break;
700  default:
701  break;
702  }
703 }
704 
705 void uiBaseInventoryNode::onMouseUp (uiNode_t* node, int x, int y, int button)
706 {
707  if (button != K_MOUSE1)
708  return;
709  if (UI_GetMouseCapture() == node) {
710  UI_MouseRelease();
711  }
712  if (UI_DNDIsDragging()) {
713  UI_DNDDrop();
714  }
715 }
716 
717 bool uiBaseInventoryNode::onScroll (uiNode_t* node, int deltaX, int deltaY)
718 {
719  if (deltaY == 0)
720  return false;
721 
722  if (EXTRADATA(node).scrollY.moveDelta(deltaY * 20)) {
724  return true;
725  }
726  return false;
727 }
728 
730 {
731  EXTRADATA(node).super.container = nullptr;
732  EXTRADATA(node).columns = 1;
733  node->color[3] = 1.0;
734 }
735 
740 {
741  /* The node is invalid */
742  if (EXTRADATA(target).super.container == nullptr)
743  return false;
744  /* accept items only, if we have a container */
745  return UI_DNDGetType() == DND_ITEM && UI_DNDGetSourceNode() != target;
746 }
747 
752 bool uiBaseInventoryNode::onDndMove (uiNode_t* target, int x, int y)
753 {
754  return true;
755 }
756 
761 {
762 }
763 
768 {
769 }
770 
772 {
773  behaviour->name = "baseinventory";
774  behaviour->extends = "container";
775  behaviour->manager = UINodePtr(new uiBaseInventoryNode());
776  behaviour->extraDataSize = sizeof(EXTRADATA_TYPE);
777  behaviour->lua_SWIG_typeinfo = UI_SWIG_TypeQuery("uiBaseInventoryNode_t *");
778 
779  /* Display/hide weapons. */
780  UI_RegisterExtradataNodeProperty(behaviour, "displayweapon", V_BOOL, baseInventoryExtraData_t, displayWeapon);
781  /* Display/hide ammo. */
782  UI_RegisterExtradataNodeProperty(behaviour, "displayammo", V_BOOL, baseInventoryExtraData_t, displayAmmo);
783  /* Display/hide implants. */
784  UI_RegisterExtradataNodeProperty(behaviour, "displayimplant", V_BOOL, baseInventoryExtraData_t, displayImplant);
785  /* Display/hide out of stock items. */
786  UI_RegisterExtradataNodeProperty(behaviour, "displayunavailableitem", V_BOOL, baseInventoryExtraData_t, displayUnavailableItem);
787  /* Sort the list to display in stock items on top of the list. */
788  UI_RegisterExtradataNodeProperty(behaviour, "displayavailableontop", V_BOOL, baseInventoryExtraData_t, displayAvailableOnTop);
789  /* Display/hide ammo near weapons. */
790  UI_RegisterExtradataNodeProperty(behaviour, "displayammoofweapon", V_BOOL, baseInventoryExtraData_t, displayAmmoOfWeapon);
791  /* Display/hide out of stock ammo near weapons. <code>displayammoofweapon</code> must be activated first. */
792  UI_RegisterExtradataNodeProperty(behaviour, "displayunavailableammoofweapon", V_BOOL, baseInventoryExtraData_t, displayUnavailableAmmoOfWeapon);
793  /* Custom the number of column we must use to display items. */
794  UI_RegisterExtradataNodeProperty(behaviour, "columns", V_INT, baseInventoryExtraData_t, columns);
795  /* Filter items by a category. */
796  UI_RegisterExtradataNodeProperty(behaviour, "filter", V_INT, baseInventoryExtraData_t, filterEquipType);
797 
798  /* Position of the vertical view (into the full number of elements the node contain) */
799  UI_RegisterExtradataNodeProperty(behaviour, "viewpos", V_INT, baseInventoryExtraData_t, scrollY.viewPos);
800  /* Size of the vertical view (proportional to the number of elements the node can display without moving) */
801  UI_RegisterExtradataNodeProperty(behaviour, "viewsize", V_INT, baseInventoryExtraData_t, scrollY.viewSize);
802  /* Full vertical size (proportional to the number of elements the node contain) */
803  UI_RegisterExtradataNodeProperty(behaviour, "fullsize", V_INT, baseInventoryExtraData_t, scrollY.fullSize);
804  /* Called when one of the properties viewpos/viewsize/fullsize change */
805  UI_RegisterExtradataNodeProperty(behaviour, "onviewchange", V_UI_ACTION, baseInventoryExtraData_t, onViewChange);
806 
807  Com_RegisterConstInt("FILTER_S_PRIMARY", FILTER_S_PRIMARY);
808  Com_RegisterConstInt("FILTER_S_SECONDARY", FILTER_S_SECONDARY);
809  Com_RegisterConstInt("FILTER_S_HEAVY", FILTER_S_HEAVY);
810  Com_RegisterConstInt("FILTER_S_IMPLANT", FILTER_S_IMPLANT);
811  Com_RegisterConstInt("FILTER_S_MISC", FILTER_S_MISC);
812  Com_RegisterConstInt("FILTER_S_ARMOUR", FILTER_S_ARMOUR);
813  Com_RegisterConstInt("FILTER_CRAFTITEM", FILTER_CRAFTITEM);
814  Com_RegisterConstInt("FILTER_UGVITEM", FILTER_UGVITEM);
815  Com_RegisterConstInt("FILTER_AIRCRAFT", FILTER_AIRCRAFT);
816  Com_RegisterConstInt("FILTER_DUMMY", FILTER_DUMMY);
817  Com_RegisterConstInt("FILTER_DISASSEMBLY", FILTER_DISASSEMBLY);
818 }
#define EXTRADATACONST(node)
vec2_t size
Definition: ui_nodes.h:52
byte sx
Definition: inv_shared.h:326
static const Item * dragInfoIC
int UI_DNDGetType(void)
Return the current type of the dragging object, else DND_NOTHING.
void UI_PopClipRect(void)
Definition: ui_render.cpp:52
void initNode(uiNode_t *node) override
bool implant
Definition: inv_shared.h:282
bool INV_ItemMatchesFilter(const objDef_t *obj, const itemFilterTypes_t filterType)
Checks if the given object/item matched the given filter type.
static Item * UI_ContainerNodeGetExistingItem(const uiNode_t *node, const objDef_t *item, const itemFilterTypes_t filterType)
Searches if there is an item at location (x/y) in a scrollable container. You can also provide an ite...
Item * UI_DNDGetItem(void)
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition: shared.cpp:410
const char * name
Definition: ui_behaviour.h:41
static int dragInfoFromX
int R_FontDrawString(const char *fontId, align_t align, int x, int y, int absX, int maxWidth, int lineHeight, const char *c, int boxHeight, int scrollPos, int *curLine, longlines_t method)
Definition: r_font.cpp:687
static const vec3_t scale
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
#define _(String)
Definition: cl_shared.h:43
void draw(uiNode_t *node) override
Main function to draw a container node.
static void UI_ContainerItemIteratorInit(containerItemIterator_t *iterator, const uiNode_t *const node)
Use a container node to init an item iterator.
void UI_DNDDragItem(uiNode_t *node, const Item *item)
Start to drag an item.
#define EXTRADATA(node)
static int oldMouseY
static void UI_ContainerNodeAutoPlace(uiNode_t *node, int mouseX, int mouseY)
Try to autoplace an item at a position when right-click was used in the inventory.
csi_t csi
Definition: common.cpp:39
void UI_DNDAbort(void)
Drop the object at the current position.
static const vec4_t colorDefault
void onCapturedMouseMove(uiNode_t *node, int x, int y) override
bool isMisc
Definition: inv_shared.h:288
#define CII_AMMOONLY
Flag for containerItemIterator_t (CII) groupSteps.
void onMouseDown(uiNode_t *node, int x, int y, int button) override
itemFilterTypes_t
A list of filter types in the market and production view.
Definition: cl_inventory.h:35
UINodePtr manager
Definition: ui_behaviour.h:43
bool UI_ExecuteLuaEventScript(uiNode_t *node, LUA_EVENT event)
Executes a lua event handler.
Definition: ui_lua.cpp:71
const objDef_t * def(void) const
Definition: inv_shared.h:469
void initNode(uiNode_t *node) override
static int oldMouseX
void onLoading(uiNode_t *node) override
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
int numODs
Definition: q_shared.h:518
void setDef(const objDef_t *objDef)
Definition: inv_shared.h:444
const struct objDef_s * ammos[MAX_AMMOS_PER_OBJDEF]
Definition: inv_shared.h:307
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
void onWindowOpened(uiNode_t *node, linkedList_t *params) override
Call when we open the window containing the node.
int integer
Definition: cvar.h:81
static const vec4_t colorDisabledHiden
void UI_MouseRelease(void)
Release the captured node.
Definition: ui_input.cpp:526
#define CII_NOTAVAILABLEONLY
uiNode_t * UI_DNDGetSourceNode(void)
Return source of the DND.
#define UI_RegisterExtradataNodeProperty(BEHAVIOUR, NAME, TYPE, EXTRADATATYPE, ATTRIBUTE)
Initialize a property from extradata of node.
Definition: ui_behaviour.h:109
item instance data, with linked list capability
Definition: inv_shared.h:402
void onMouseUp(uiNode_t *node, int x, int y, int button) override
void R_FontTextSize(const char *fontId, const char *text, int maxWidth, longlines_t method, int *width, int *height, int *lines, bool *isTruncated)
Supply information about the size of the text when it is linewrapped and rendered, without actually rendering it. Any of the output parameters may be nullptr.
Definition: r_font.cpp:524
#define C_UNIT
One unit in the containers is 25x25.
#define DEBUG_CLIENT
Definition: defines.h:59
#define MAX_VAR
Definition: shared.h:36
int numWeapons
Definition: inv_shared.h:317
SharedPtr< uiNode > UINodePtr
const invDef_t * INVSH_GetInventoryDefinitionByID(const char *id)
Definition: inv_shared.cpp:340
bool isAmmo() const
Definition: inv_shared.h:343
int UI_DrawTooltip(const char *string, int x, int y, int maxWidth)
Generic tooltip function.
Definition: ui_tooltip.cpp:40
#define EXTRADATA_TYPE
void * lua_SWIG_typeinfo
Definition: ui_behaviour.h:57
void onDndLeave(uiNode_t *node) override
Call when a DND enter into the node.
void UI_SetMouseCapture(uiNode_t *node)
Captured the mouse into a node.
Definition: ui_input.cpp:516
static void UI_ContainerItemIteratorNext(containerItemIterator_t *iterator)
Compute the next itemID.
bool onScroll(uiNode_t *node, int deltaX, int deltaY) override
#define CII_WEAPONONLY
bool weapon
Definition: inv_shared.h:277
void UI_ExecuteEventActions(uiNode_t *source, const uiAction_t *firstAction)
Definition: ui_actions.cpp:726
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
uiNode_t * UI_GetMouseCapture(void)
Return the captured node.
Definition: ui_input.cpp:508
int getAmount() const
Definition: inv_shared.h:463
static const vec4_t colorDisabledLoadable
bool CL_BattlescapeRunning(void)
Check whether we already have actors spawned on the battlefield.
Atomic structure used to define most of the UI.
Definition: ui_nodes.h:80
base code for scrollable node
void * UI_SWIG_TypeQuery(const char *name)
This function queries the SWIG type table for a type information structure. It is used in combination...
void Com_RegisterConstInt(const char *name, int value)
Register mappings between script strings and enum values for values of the type V_INT.
Definition: scripts.cpp:198
const char * name
Definition: inv_shared.h:267
void UI_GetNodeAbsPos(const uiNode_t *node, vec2_t pos)
Returns the absolute position of a node.
Definition: ui_node.cpp:514
bool onDndEnter(uiNode_t *node) override
Call when a DND enter into the node.
void UI_ContainerNodeAutoPlaceItem(uiNode_t *node, Item *ic)
Try to autoplace an item from a container.
bool isLoadableInWeapon(const objDef_s *weapon) const
Checks if an item can be used to reload a weapon.
Definition: inv_shared.cpp:356
void onLoaded(uiNode_t *node) override
Calculates the size of a container node and links the container into the node (uses the invDef_t shap...
static const vec4_t colorLoadable
uiBehaviour_t * super
Definition: ui_behaviour.h:55
Inventory * ui_inventory
void UI_GetItemTooltip(const Item &item, char *tooltipText, size_t stringMaxLength)
Generate tooltip text for an item.
intptr_t extraDataSize
Definition: ui_behaviour.h:54
Definition: scripts.h:50
void UI_RegisterBaseInventoryNode(uiBehaviour_t *behaviour)
node behaviour, how a node work
Definition: ui_behaviour.h:39
cvar_t * cl_selected
Definition: cl_main.cpp:73
static int dragInfoFromY
vec4_t color
Definition: ui_nodes.h:127
#define CII_AVAILABLEONLY
const char * extends
Definition: ui_behaviour.h:42
bool onDndMove(uiNode_t *node, int x, int y) override
Call into the target when the DND hover it.
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition: shared.cpp:475
bool isArmour() const
Definition: inv_shared.h:346
#define CII_END
vec_t vec3_t[3]
Definition: ufotypes.h:39
#define Vector2Copy(src, dest)
Definition: vector.h:52
vec_t vec2_t[2]
Definition: ufotypes.h:38
void UI_PushClipRect(int x, int y, int width, int height)
Definition: ui_render.cpp:47
Definition: scripts.h:52
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
Definition: inv_shared.cpp:266
int UI_DrawString(const char *fontID, align_t align, int x, int y, int absX, int maxWidth, int lineHeight, const char *c, int boxHeight, int scrollPos, int *curLine, bool increaseLine, longlines_t method)
Definition: ui_render.cpp:371
int getX() const
Definition: inv_shared.h:454
#define CII_IMPLANTONLY
static Item * UI_BaseInventoryNodeGetItem(const uiNode_t *const node, int mouseX, int mouseY, int *contX, int *contY)
static void UI_BaseInventoryNodeUpdateScroll(uiNode_t *node)
Update display of scroll buttons.
#define V_UI_ACTION
Definition: ui_parse.h:54
#define NONE
Definition: defines.h:68
int numAmmos
Definition: inv_shared.h:308
uiBox_t box
Definition: ui_nodes.h:96
byte sy
Definition: inv_shared.h:326
bool GAME_ItemIsUseable(const objDef_t *od)
Definition: cl_game.cpp:1295
bool UI_DNDIsDragging(void)
Return true if we are dragging something.
static void UI_BaseInventoryNodeDraw2(uiNode_t *node, const objDef_t *highlightType)
Draw the inventory of the base.
Item * INV_SearchInInventoryWithFilter(const Inventory *const inv, const invDef_t *container, const objDef_t *itemType, const itemFilterTypes_t filterType)
Searches if there is an item at location (x/y) in a scrollable container. You can also provide an ite...
uint8_t byte
Definition: ufotypes.h:34
void UI_DrawItem(uiNode_t *node, const vec3_t org, const Item *item, int x, int y, const vec3_t scale, const vec4_t color)
Draws an item to the screen.
void UI_DNDDrop(void)
Drop the object at the current position.
void drawTooltip(const uiNode_t *node, int x, int y) const override
Custom tooltip for container node.
int getY() const
Definition: inv_shared.h:457
void UI_GetNodeScreenPos(const uiNode_t *node, vec2_t pos)
Returns the absolute position of a node in the screen. Screen position is not used for the node rende...
Definition: ui_node.cpp:542
vec_t vec4_t[4]
Definition: ufotypes.h:40
static int UI_BaseInventoryNodeDrawItems(uiNode_t *node, const objDef_t *highlightType)
Draw the base inventory.
vec2_t pos
Definition: ui_nodes.h:51