UFO: Alien Invasion
Loading...
Searching...
No Matches
ui_node_container.cpp
Go to the documentation of this file.
1
13
14/*
15Copyright (C) 2002-2025 UFO: Alien Invasion.
16
17This program is free software; you can redistribute it and/or
18modify it under the terms of the GNU General Public License
19as published by the Free Software Foundation; either version 2
20of the License, or (at your option) any later version.
21
22This program is distributed in the hope that it will be useful,
23but WITHOUT ANY WARRANTY; without even the implied warranty of
24MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25
26See the GNU General Public License for more details.
27
28You should have received a copy of the GNU General Public License
29along with this program; if not, write to the Free Software
30Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31
32*/
33
34#include "../ui_main.h"
35#include "../ui_parse.h"
36#include "../ui_behaviour.h"
37#include "../ui_actions.h"
38#include "../ui_dragndrop.h"
39#include "../ui_tooltip.h"
40#include "../ui_nodes.h"
41#include "../ui_input.h"
42#include "../ui_render.h"
43#include "../ui_lua.h"
44
45#include "ui_node_model.h"
46#include "ui_node_container.h"
48
49#include "../../client.h"
52#include "../../cgame/cl_game.h"
54#include "../../cl_inventory.h"
55
57
63
64#define EXTRADATA_TYPE containerExtraData_t
65#define EXTRADATA(node) UI_EXTRADATA(node, EXTRADATA_TYPE)
66#define EXTRADATACONST(node) UI_EXTRADATACONST(node, EXTRADATA_TYPE)
67
72static int dragInfoFromX = -1;
73static int dragInfoFromY = -1;
74
79static int dragInfoToX = -1;
80static int dragInfoToY = -1;
81
86static const Item* dragInfoIC;
87
88static inline bool UI_IsScrollContainerNode (const uiNode_t* const node)
89{
90 return EXTRADATACONST(node).container && EXTRADATACONST(node).container->scroll;
91}
92
103{
104 /* make a copy, because we are not really using these items,
105 * but only putting them into a temp container */
106 int* const numItems = Mem_Dup(int, ed->numItems, lengthof(ed->numItems));
107
108 /* a 'tiny hack' to add the remaining equipment (not carried)
109 * correctly into buy categories, reloading at the same time;
110 * it is valid only due to the following property: */
112
113 for (int i = 0; i < csi.numODs; i++) {
114 const objDef_t* od = INVSH_GetItemByIDX(i);
115 /* Don't allow to show unuseable items. */
116 if (!GAME_ItemIsUseable(od))
117 continue;
118
119 while (numItems[i]) {
120 const Item item(od);
121 if (!cls.i.addToInventory(inv, &item, INVDEF(CID_EQUIP), NONE, NONE, 1)) {
122 /* no space left in the inventory */
123 break;
124 }
125 numItems[item.def()->idx]--;
126 }
127 }
128
129 Mem_Free(numItems);
130
131 /* First-time linking of ui_inventory. */
132 if (ui_inventory && !ui_inventory->getEquipContainer()) {
133 ui_inventory->setContainer(CID_EQUIP, inv->getEquipContainer());
134 }
135}
136
149void UI_DrawItem (uiNode_t* node, const vec3_t org, const Item* item, int x, int y, const vec3_t scale, const vec4_t color)
150{
151 const objDef_t* od = item->def();
152 vec4_t col;
154
155 assert(od);
156 assert(org[2] > -1000 && org[2] < 1000); /*< prevent use of vec2_t for org */
157
158 Vector4Copy(color, col);
159 /* no ammo in this weapon - highlight this item */
160 if (od->weapon && item->mustReload()) {
161 col[1] *= 0.5;
162 col[2] *= 0.5;
163 }
164
165 VectorCopy(org, origin);
166
167 /* Calculate correct location of the image or the model (depends on rotation) */
170 if (x >= 0 || y >= 0) {
171 /* Add offset of location in container. */
172 origin[0] += x * C_UNIT;
173 origin[1] += y * C_UNIT;
174
175 /* Add offset for item-center (depends on rotation). */
176 if (item->rotated) {
177 origin[0] += od->sy * C_UNIT / 2.0;
178 origin[1] += od->sx * C_UNIT / 2.0;
183 } else {
184 origin[0] += od->sx * C_UNIT / 2.0;
185 origin[1] += od->sy * C_UNIT / 2.0;
186 }
187 }
188
189 /* don't handle the od->tech->image here - it's very ufopedia specific in most cases */
190 if (od->image[0] != '\0') {
191 const int imgWidth = od->sx * C_UNIT;
192 const int imgHeight = od->sy * C_UNIT;
193 origin[0] -= od->sx * C_UNIT / 2.0;
194 origin[1] -= od->sy * C_UNIT / 2.0;
195
196 /* Draw the image. */
197 R_Color(color);
198 UI_DrawNormImageByName(false, origin[0], origin[1], imgWidth, imgHeight, 0, 0, 0, 0, od->image);
199 R_Color(nullptr);
200 } else {
201 uiModel_t* model = nullptr;
202 const char* modelName = GAME_GetModelForItem(od, &model);
203
204 /* no model definition in the tech struct, not in the fallback object definition */
205 if (Q_strnull(modelName)) {
206 Com_Printf("UI_DrawItem: No model given for item: '%s'\n", od->id);
207 return;
208 }
209
210 if (model && node) {
211 UI_DrawModelNode(node, modelName);
212 } else {
213 modelInfo_t mi;
214 vec3_t angles = {-10, 160, 70};
215 vec3_t size = {scale[0], scale[1], scale[2]};
216 vec3_t center;
217
218 if (item->rotated)
219 angles[0] -= 90;
220
221 if (od->scale)
222 VectorScale(size, od->scale, size);
223
224 VectorNegate(od->center, center);
225
226 OBJZERO(mi);
227 mi.origin = origin;
228 mi.angles = angles;
229 mi.center = center;
230 mi.scale = size;
231 mi.color = col;
232 mi.name = modelName;
233
234 /* draw the model */
235 R_DrawModelDirect(&mi, nullptr, nullptr);
236 }
237 }
238}
239
247void UI_GetItemTooltip (const Item& item, char* tooltipText, size_t stringMaxLength)
248{
249 assert(item.def());
250
251 if (item.getAmount() > 1)
252 Com_sprintf(tooltipText, stringMaxLength, "%i x %s\n", item.getAmount(), _(item.def()->name));
253 else
254 Com_sprintf(tooltipText, stringMaxLength, "%s\n", _(item.def()->name));
255
256 /* Only display further info if item.t is researched */
257 if (GAME_ItemIsUseable(item.def())) {
258 if (item.isWeapon()) {
259 /* Get info about used ammo (if there is any) */
260 if (item.def() == item.ammoDef()) {
261 /* Item has no ammo but might have shot-count */
262 if (item.getAmmoLeft()) {
263 Q_strcat(tooltipText, stringMaxLength, _("Ammo: %i\n"), item.getAmmoLeft());
264 }
265 } else if (item.ammoDef()) {
266 /* Search for used ammo and display name + ammo count */
267 Q_strcat(tooltipText, stringMaxLength, _("%s loaded\n"), _(item.ammoDef()->name));
268 Q_strcat(tooltipText, stringMaxLength, _("Ammo: %i\n"), item.getAmmoLeft());
269 }
270 } else if (item.def()->numWeapons) {
271 /* Check if this is a non-weapon and non-ammo item */
272 if (!(item.def()->numWeapons == 1 && item.def()->weapons[0] == item.def())) {
273 /* If it's ammo get the weapon names it can be used in */
274 Q_strcat(tooltipText, stringMaxLength, _("Usable in:\n"));
275 for (int i = 0; i < item.def()->numWeapons; i++) {
276 const objDef_t* weapon = item.def()->weapons[i];
277 if (GAME_ItemIsUseable(weapon)) {
278 Q_strcat(tooltipText, stringMaxLength, "* %s\n", _(weapon->name));
279 }
280 }
281 }
282 }
283 }
284}
285
291{
292 const invDef_t* const container = INVDEF(index);
293 uiNode_t* containerNode = UI_GetNode(parent, container->name);
294 return containerNode;
295}
296
300static void UI_DrawDisabled (const uiNode_t* node)
301{
302 const vec4_t color = { 0.3f, 0.3f, 0.3f, 0.7f };
303 vec2_t nodepos;
304
305 UI_GetNodeAbsPos(node, nodepos);
306 UI_DrawFill(nodepos[0], nodepos[1], node->box.size[0], node->box.size[1], color);
307}
308
312static void UI_DrawFree (containerIndex_t container, const uiNode_t* node, int posx, int posy, int sizex, int sizey, bool showTUs)
313{
314 const vec4_t color = { 0.0f, 1.0f, 0.0f, 0.7f };
315 invDef_t* inv = INVDEF(container);
316 vec2_t nodepos;
317
318 UI_GetNodeAbsPos(node, nodepos);
319 UI_DrawFill(posx, posy, sizex, sizey, color);
320
321 /* if showTUs is true (only the first time in none single containers)
322 * and we are connected to a game */
323 if (showTUs && CL_BattlescapeRunning()) {
324 UI_DrawString("f_verysmall", ALIGN_UL, nodepos[0] + 3, nodepos[1] + 3,
325 nodepos[0] + 3, node->box.size[0] - 6, 0,
326 va(_("In: %i Out: %i"), inv->in, inv->out));
327 }
328}
329
335{
336 const objDef_t* od = UI_DNDGetItem()->def();
337 vec2_t nodepos;
338
339 /* Draw only in dragging-mode and not for the equip-floor */
340 assert(UI_DNDIsDragging());
341 assert(inv);
342
343 UI_GetNodeAbsPos(node, nodepos);
344 /* if single container (hands, headgear) */
345 if (EXTRADATA(node).container->single) {
346 /* if container is free or the dragged-item is in it */
347 if (UI_DNDIsSourceNode(node) || inv->canHoldItem(EXTRADATA(node).container, od, 0, 0, dragInfoIC))
348 UI_DrawFree(EXTRADATA(node).container->id, node, nodepos[0], nodepos[1], node->box.size[0], node->box.size[1], true);
349 } else {
350 /* The shape of the free positions. */
351 uint32_t free[SHAPE_BIG_MAX_HEIGHT];
352 bool showTUs = true;
353
354 OBJZERO(free);
355
356 for (int y = 0; y < SHAPE_BIG_MAX_HEIGHT; y++) {
357 for (int x = 0; x < SHAPE_BIG_MAX_WIDTH; x++) {
358 /* Check if the current position is usable (topleft of the item). */
359
360 /* Add '1's to each position the item is 'blocking'. */
361 const int checkedTo = inv->canHoldItem(EXTRADATA(node).container, od, x, y, dragInfoIC);
362 if (checkedTo & INV_FITS) /* Item can be placed normally. */
363 INVSH_MergeShapes(free, od->shape, x, y);
364 if (checkedTo & INV_FITS_ONLY_ROTATED) /* Item can be placed rotated. */
365 INVSH_MergeShapes(free, od->getShapeRotated(), x, y);
366
367 /* Only draw on existing positions. */
368 if (INVSH_CheckShape(EXTRADATA(node).container->shape, x, y)) {
369 if (INVSH_CheckShape(free, x, y)) {
370 UI_DrawFree(EXTRADATA(node).container->id, node, nodepos[0] + x * C_UNIT, nodepos[1] + y * C_UNIT, C_UNIT, C_UNIT, showTUs);
371 showTUs = false;
372 }
373 }
374 }
375 }
376 }
377}
378
385{
386 const char* name;
387 const invDef_t* container;
388
390 name = node->name;
391 if (Q_strstart(node->name, "equip_"))
392 name = "equip";
393
395 if (container == nullptr)
396 return;
397
398 EXTRADATA(node).container = container;
399
400 if (UI_IsScrollContainerNode(node)) {
401 /* No need to compute the size, the script provide it */
402 } else {
403 int i, j;
404 /* Start on the last bit of the shape mask. */
405 for (i = SHAPE_BIG_MAX_WIDTH - 1; i >= 0; i--) {
406 for (j = 0; j < SHAPE_BIG_MAX_HEIGHT; j++)
407 if (container->shape[j] & (1 << i))
408 break;
409 if (j < SHAPE_BIG_MAX_HEIGHT)
410 break;
411 }
412 node->box.size[0] = C_UNIT * (i + 1) + 0.01;
413
414 /* start on the lower row of the shape mask */
415 for (i = SHAPE_BIG_MAX_HEIGHT - 1; i >= 0; i--)
416 if (container->shape[i] & ~0x0)
417 break;
418 node->box.size[1] = C_UNIT * (i + 1) + 0.01;
419 }
420}
421
422static const vec3_t scale = {3.5, 3.5, 3.5};
424static const vec4_t colorDefault = {1, 1, 1, 1};
425static const vec4_t colorLoadable = {0.5, 1, 0.5, 1};
426static const vec4_t colorDisabled = {0.5, 0.5, 0.5, 1};
427static const vec4_t colorDisabledLoadable = {0.5, 0.25, 0.25, 1.0};
428static const vec4_t colorPreview = { 0.5, 0.5, 1, 1 };
429
435static void UI_ContainerNodeDrawSingle (uiNode_t* node, const objDef_t* highlightType)
436{
437 vec4_t color;
438 vec3_t pos;
439
440 UI_GetNodeAbsPos(node, pos);
441 pos[0] += node->box.size[0] / 2.0;
442 pos[1] += node->box.size[1] / 2.0;
443 pos[2] = 0;
444
445 /* Single item container (special case for left hand). */
446 const invDef_t* contType = EXTRADATA(node).container;
447 if (contType->isLeftDef() && !ui_inventory->getLeftHandContainer()) {
448 if (ui_inventory->getRightHandContainer()) {
449 const Item* item = ui_inventory->getRightHandContainer();
450 assert(item);
451 assert(item->def());
452
453 if (item->isHeldTwoHanded()) {
454 if (highlightType && highlightType->isLoadableInWeapon(item->def()))
455 memcpy(color, colorLoadable, sizeof(vec4_t));
456 else
457 memcpy(color, colorDefault, sizeof(vec4_t));
458 color[3] = 0.5;
459 UI_DrawItem(node, pos, item, -1, -1, scale, color);
460 }
461 }
462 } else if (ui_inventory->getContainer2(contType->id)) {
463 bool disabled = false;
464 const Item* item;
465
466 if (ui_inventory->getRightHandContainer()) {
467 item = ui_inventory->getRightHandContainer();
468 /* If there is a weapon in the right hand that needs two hands to shoot it
469 * and there is a weapon in the left, then draw a disabled marker for the
470 * fireTwoHanded weapon. */
471 assert(item);
472 assert(item->def());
473 if (contType->isRightDef() && item->def()->fireTwoHanded && ui_inventory->getLeftHandContainer()) {
474 disabled = true;
475 UI_DrawDisabled(node);
476 }
477 }
478
479 item = ui_inventory->getContainer2(contType->id);
480 assert(item);
481 assert(item->def());
482 if (highlightType && highlightType->isLoadableInWeapon(item->def())) {
483 if (disabled)
485 else
487 } else {
488 if (disabled)
490 else
492 }
493 if (disabled)
494 color[3] = 0.5;
495 UI_DrawItem(node, pos, item, -1, -1, scale, color);
496 }
497}
498
502static void UI_ContainerNodeDrawGrid (uiNode_t* node, const objDef_t* highlightType)
503{
504 vec3_t pos;
505
506 UI_GetNodeAbsPos(node, pos);
507 pos[2] = 0;
508
509 const Container& cont = ui_inventory->getContainer(EXTRADATA(node).container->id);
510 Item* item = nullptr;
511 while ((item = cont.getNextItem(item))) {
512 assert(item->def());
513 if (highlightType && highlightType->isLoadableInWeapon(item->def()))
514 UI_DrawItem(node, pos, item, item->getX(), item->getY(), scale, colorLoadable);
515 else
516 UI_DrawItem(node, pos, item, item->getX(), item->getY(), scale, colorDefault);
517 }
518}
519
524{
525 Item previewItem;
526 int checkedTo;
527 vec3_t origine;
528
529 /* no preview into scrollable list */
530 if (UI_IsScrollContainerNode(target))
531 return;
532
533 /* copy the DND item to not change the original one */
534 previewItem = *UI_DNDGetItem();
535 previewItem.rotated = false;
536 checkedTo = ui_inventory->canHoldItem(EXTRADATA(target).container, previewItem.def(), dragInfoToX, dragInfoToY, dragInfoIC);
537 switch (checkedTo) {
538 case INV_DOES_NOT_FIT:
539 return;
540 case INV_FITS:
541 break;
542 case INV_FITS_BOTH:
545 break;
546 /* else fits rotated, fall through */
548 previewItem.rotated = true;
549 }
550
551 /* Hack, no preview for armour, we don't want it out of the armour container (and armour container is not visible) */
552 if (previewItem.isArmour())
553 return;
554
555 UI_GetNodeAbsPos(target, origine);
556 origine[2] = -40;
557
558 /* Get center of single container for placement of preview item */
559 if (EXTRADATA(target).container->single) {
560 origine[0] += target->box.size[0] / 2.0;
561 origine[1] += target->box.size[1] / 2.0;
562 /* This is a "grid" container - we need to calculate the item-position
563 * (on the screen) from stored placement in the container and the
564 * calculated rotation info. */
565 } else {
566 if (previewItem.rotated) {
567 origine[0] += (dragInfoToX + previewItem.def()->sy / 2.0) * C_UNIT;
568 origine[1] += (dragInfoToY + previewItem.def()->sx / 2.0) * C_UNIT;
569 } else {
570 origine[0] += (dragInfoToX + previewItem.def()->sx / 2.0) * C_UNIT;
571 origine[1] += (dragInfoToY + previewItem.def()->sy / 2.0) * C_UNIT;
572 }
573 }
574
575 UI_DrawItem(nullptr, origine, &previewItem, -1, -1, scale, colorPreview);
576}
577
582{
583 const objDef_t* highlightType = nullptr;
584
585 if (!EXTRADATA(node).container)
586 return;
587 if (!ui_inventory)
588 return;
589 /* is container invisible */
590 if (node->color[3] < 0.001)
591 return;
592
593 /* Highlight weapons that the dragged ammo (if it is one) can be loaded into. */
595 highlightType = UI_DNDGetItem()->def();
596 }
597
598 if (EXTRADATA(node).container->single) {
599 UI_ContainerNodeDrawSingle(node, highlightType);
600 } else {
601 if (UI_IsScrollContainerNode(node)) {
602 assert(false);
603 } else {
604 UI_ContainerNodeDrawGrid(node, highlightType);
605 }
606 }
607
608 /* Draw free space if dragging - but not for CID_EQUIP */
609 if (UI_DNDIsDragging() && EXTRADATA(node).container->id != CID_EQUIP)
611
612 if (UI_DNDIsTargetNode(node))
614}
615
625static Item* UI_ContainerNodeGetItemAtPosition (const uiNode_t* const node, int mouseX, int mouseY, int* contX = nullptr, int* contY = nullptr)
626{
627 if (!ui_inventory)
628 return nullptr;
629
630 /* Get coordinates inside a scrollable container (if it is one). */
631 if (UI_IsScrollContainerNode(node)) {
632 Sys_Error("UI_ContainerNodeGetItemAtPosition is not usable for scrollable containers!");
633 }
634
635 vec2_t nodepos;
636 UI_GetNodeAbsPos(node, nodepos);
637 /* Normalize screen coordinates to container coordinates. */
638 const int fromX = (int) (mouseX - nodepos[0]) / C_UNIT;
639 const int fromY = (int) (mouseY - nodepos[1]) / C_UNIT;
640 if (contX)
641 *contX = fromX;
642 if (contY)
643 *contY = fromY;
644
645 Item* result = ui_inventory->getItemAtPos(EXTRADATACONST(node).container, fromX, fromY);
646 return result;
647}
648
654void uiContainerNode::drawTooltip (const uiNode_t* node, int x, int y) const
655{
656 /* Find out where the mouse is. */
657 const Item* itemHover = UI_ContainerNodeGetItemAtPosition(node, x, y);
658
659 if (itemHover) {
660 static char tooltiptext[MAX_VAR * 2];
661 const int itemToolTipWidth = 250;
662
663 /* Get name and info about item */
664 UI_GetItemTooltip(*itemHover, tooltiptext, sizeof(tooltiptext));
665#ifdef DEBUG
666 /* Display stored container-coordinates of the item. */
667 Q_strcat(tooltiptext, sizeof(tooltiptext), "\n%i/%i", itemHover->getX(), itemHover->getY());
668#endif
669 UI_DrawTooltip(tooltiptext, x, y, itemToolTipWidth);
670 }
671}
672
673static bool UI_ContainerNodeAddItem (const invDef_t* container, Item* ic, containerIndex_t containerID, Item** icp)
674{
675 int px, py;
676 const invDef_t* target = INVDEF(containerID);
677 ui_inventory->findSpace(target, ic, &px, &py, nullptr);
678 return INV_MoveItem(ui_inventory, target, px, py, container, ic, icp);
679}
680
688{
689 containerIndex_t target;
690 bool ammoChanged = false;
691 const invDef_t* container = EXTRADATA(node).container;
692
693 /* Right click: automatic item assignment/removal. */
694 if (container->id != CID_EQUIP) {
695 target = CID_EQUIP;
696 if (ic->ammoDef()) {
697 /* Remove ammo on removing weapon from a soldier */
698 ammoChanged = INV_UnloadWeapon(ic, ui_inventory, INVDEF(target));
699 }
700 if (!ammoChanged && !ic->ammoDef()) {
701 /* Move back to CID_EQUIP (ground, floor) container. */
702 INV_MoveItem(ui_inventory, INVDEF(target), NONE, NONE, container, ic, nullptr);
703 }
704 } else {
705 bool packed = false;
706 assert(ic->def());
707 /* armour can only have one target */
708 if (ic->isArmour()) {
709 target = CID_ARMOUR;
710 packed = INV_MoveItem(ui_inventory, INVDEF(target), 0, 0, container, ic, nullptr);
711 /* ammo or item */
712 } else if (ic->def()->isAmmo()) {
713 /* Finally try left and right hand. There is no other place to put it now. */
715 const size_t size = lengthof(idxArray);
716 for (int i = 0; i < size; i++) {
717 target = idxArray[i];
718 packed = UI_ContainerNodeAddItem(container, ic, target, nullptr);
719 if (packed)
720 break;
721 }
722 } else if (ic->def()->headgear) {
723 target = CID_HEADGEAR;
724 packed = UI_ContainerNodeAddItem(container, ic, target, nullptr);
725 } else if (ic->def()->implant) {
726 target = CID_IMPLANT;
727 packed = UI_ContainerNodeAddItem(container, ic, target, nullptr);
728 } else {
729 /* left and right are single containers, but this might change - it's cleaner to check
730 * for available space here, too */
732 const size_t size = lengthof(idxArray);
733 Item* tItem = nullptr;
734 for (int i = 0; i < size; i++) {
735 target = idxArray[i];
736 packed = UI_ContainerNodeAddItem(container, ic, target, &tItem);
737 if (packed) {
738 if ((ic->isWeapon() && !ic->getAmmoLeft()) || ic->def()->weapons[0])
739 ammoChanged = INV_LoadWeapon(tItem, ui_inventory, container, INVDEF(target));
740 break;
741 }
742 }
743 }
744 /* no need to continue here - placement wasn't successful at all */
745 if (!packed)
746 return;
747 }
748
749 EXTRADATA(node).lastSelectedId = ic->def()->idx;
750 if (EXTRADATA(node).onSelect) {
751 UI_ExecuteEventActions(node, EXTRADATA(node).onSelect);
752 }
753 if (EXTRADATA(node).lua_onSelect != LUA_NOREF) {
754 UI_ExecuteLuaEventScript(node, EXTRADATA(node).lua_onSelect);
755 }
756 /* Run onChange events */
758 if (node->onChange) {
759 UI_ExecuteEventActions(node, node->onChange);
760 }
761 if (node->lua_onChange != LUA_NOREF) {
763 }
764 if (targetNode != nullptr && node != targetNode) {
765 if (targetNode->onChange) {
767 }
768 if (targetNode->lua_onChange != LUA_NOREF) {
770 }
771 }
772 /* Also call onChange for equip_ammo if ammo moved
773 * Maybe there's a better way to do this? */
774 if (ic->def()->isAmmo() || ammoChanged) {
776 uiNode_t* ammoNode = UI_GetNode(node->root, "equip_ammo");
777 if (ammoNode != nullptr && node != ammoNode) {
778 if (ammoNode->onChange) {
779 UI_ExecuteEventActions(ammoNode, ammoNode->onChange);
780 }
781 if (ammoNode->lua_onChange != LUA_NOREF) {
782 UI_ExecuteLuaEventScript(ammoNode, ammoNode->lua_onChange);
783 }
784 }
785 }
786}
787
795static void UI_ContainerNodeAutoPlace (uiNode_t* node, int mouseX, int mouseY)
796{
797 if (!ui_inventory)
798 return;
799
800 /* don't allow this in tactical missions */
802 return;
803
804 const int sel = cl_selected->integer;
805 if (sel < 0)
806 return;
807
808 assert(EXTRADATA(node).container);
809
810 Item* ic = UI_ContainerNodeGetItemAtPosition(node, mouseX, mouseY);
811 if (!ic)
812 return;
814}
815
816static int oldMouseX = 0;
817static int oldMouseY = 0;
818
820{
821 const int delta = abs(oldMouseX - x) + abs(oldMouseY - y);
822 if (delta > 15) {
825 }
826}
827
828void uiContainerNode::onMouseDown (uiNode_t* node, int x, int y, int button)
829{
830 switch (button) {
831 case K_MOUSE1:
832 {
833 /* start drag and drop */
834 int fromX, fromY;
835 dragInfoIC = UI_ContainerNodeGetItemAtPosition(node, x, y, &fromX, &fromY);
836 if (dragInfoIC) {
837 dragInfoFromX = fromX;
838 dragInfoFromY = fromY;
839 oldMouseX = x;
840 oldMouseY = y;
841 UI_SetMouseCapture(node);
842 EXTRADATA(node).lastSelectedId = dragInfoIC->def()->idx;
843 if (EXTRADATA(node).onSelect) {
844 UI_ExecuteEventActions(node, EXTRADATA(node).onSelect);
845 }
846 if (EXTRADATA(node).lua_onSelect != LUA_NOREF) {
847 UI_ExecuteLuaEventScript(node, EXTRADATA(node).lua_onSelect);
848 }
849 }
850 break;
851 }
852 case K_MOUSE2:
853 if (UI_DNDIsDragging()) {
854 UI_DNDAbort();
855 } else {
856 /* auto place */
857 UI_ContainerNodeAutoPlace(node, x, y);
858 }
859 break;
860 default:
861 break;
862 }
863}
864
865void uiContainerNode::onMouseUp (uiNode_t* node, int x, int y, int button)
866{
867 if (button != K_MOUSE1)
868 return;
869 if (UI_GetMouseCapture() == node) {
871 }
872 if (UI_DNDIsDragging()) {
873 UI_DNDDrop();
874 }
875}
876
878 /* initialize lua events */
880 EXTRADATA(node).lua_onSelect = LUA_NOREF;
881}
882
884{
885 EXTRADATA(node).container = nullptr;
886 node->color[3] = 1.0;
887}
888
893{
894 /* accept items only, if we have a container */
895 return UI_DNDGetType() == DND_ITEM && EXTRADATA(target).container && (!UI_IsScrollContainerNode(target) || UI_DNDGetSourceNode() != target);
896}
897
902bool uiContainerNode::onDndMove (uiNode_t* target, int x, int y)
903{
904 vec2_t nodepos;
905 bool exists;
906 int itemX = 0;
907 int itemY = 0;
908 Item* dragItem = UI_DNDGetItem();
909
910 /* we already check it when the node accept the DND */
911 assert(EXTRADATA(target).container);
912 const invDef_t* containerType = EXTRADATA(target).container;
913
914 UI_GetNodeAbsPos(target, nodepos);
915
921 if (dragItem->def()) {
922 itemX = C_UNIT * dragItem->def()->sx / 2; /* Half item-width. */
923 itemY = C_UNIT * dragItem->def()->sy / 2; /* Half item-height. */
924
925 /* Place relative center in the middle of the square. */
926 itemX -= C_UNIT / 2;
927 itemY -= C_UNIT / 2;
928 }
929
930 dragInfoToX = (mousePosX - nodepos[0] - itemX) / C_UNIT;
931 dragInfoToY = (mousePosY - nodepos[1] - itemY) / C_UNIT;
932
933 /* Check if the items already exists in the container. i.e. there is already at least one item. */
934 exists = false;
935 if ((containerType->isFloorDef() || containerType->isEquipDef())
937 && ui_inventory->containsItem(containerType->id, dragItem)) {
938 exists = true;
939 }
940
941 /* Search for a suitable position to render the item at if
942 * the container is "single", the cursor is out of bound of the container. */
943 if (!exists && dragItem->def() && (containerType->single
944 || dragInfoToX < 0 || dragInfoToY < 0
946#if 0
947/* ... or there is something in the way. */
948/* We would need to check for weapon/ammo as well here, otherwise a preview would be drawn as well when hovering over the correct weapon to reload. */
949 || (ui_inventory->canHoldItem(containerType, dragItem->item, dragInfoToX, dragInfoToY) == INV_DOES_NOT_FIT)) {
950#endif
951 ui_inventory->findSpace(containerType, dragItem, &dragInfoToX, &dragInfoToY, dragInfoIC);
952 }
953
954 /* we can drag every thing */
955 if (UI_IsScrollContainerNode(target)) {
956 return true;
957 }
958
959 {
960 Item* fItem;
961
962 /* is there empty slot? */
963 const int checkedTo = ui_inventory->canHoldItem(containerType, dragItem->def(), dragInfoToX, dragInfoToY, dragInfoIC);
964 if (checkedTo != INV_DOES_NOT_FIT)
965 return true;
966
967 /* can we equip dragging item into the target item? */
968 fItem = ui_inventory->getItemAtPos(containerType, dragInfoToX, dragInfoToY);
969 if (!fItem)
970 return false;
971 if (containerType->single)
972 return true;
973 return dragItem->def()->isLoadableInWeapon(fItem->def());
974 }
975}
976
981{
982 dragInfoToX = -1;
983 dragInfoToY = -1;
984}
985
989bool uiContainerNode::onDndFinished (uiNode_t* source, bool isDropped)
990{
991 Item* dragItem = UI_DNDGetItem();
992 const invDef_t* sourceContainer = EXTRADATACONST(source).container;
993
994 /* if the target can't finalize the DND we stop */
995 if (!isDropped) {
996 return false;
997 }
998
999 assert(sourceContainer);
1000
1001 /* on tactical mission */
1002 if (CL_BattlescapeRunning()) {
1003 const uiNode_t* target = UI_DNDGetTargetNode();
1004 const invDef_t* targetContainer = EXTRADATACONST(target).container;
1005 assert(targetContainer);
1007 targetContainer->id, dragInfoToX, dragInfoToY);
1008 } else {
1009 uiNode_t* target = UI_DNDGetTargetNode();
1010 if (target) {
1011 Item* fItem;
1012 Item* tItem;
1013 bool moved = false;
1014 const invDef_t* targetContainer = EXTRADATACONST(target).container;
1015 assert(targetContainer);
1016 if (UI_IsScrollContainerNode(source)) {
1017 fItem = INV_SearchInInventoryWithFilter(ui_inventory, sourceContainer, dragItem->def(), MAX_FILTERTYPES);
1018 } else
1019 fItem = ui_inventory->getItemAtPos(sourceContainer, dragInfoFromX, dragInfoFromY);
1020 assert(fItem);
1021
1023 /* Remove ammo on removing weapon from a soldier */
1024 if (UI_IsScrollContainerNode(target) && fItem->ammoDef())
1025 INV_UnloadWeapon(fItem, ui_inventory, targetContainer);
1026
1027 /* Save rotation: in case the move fails we don't want the item overlapping other items or
1028 * ending partially out of the container due to changed rotation */
1029 const bool rotated = fItem->rotated;
1030 /* rotate on Shift */
1033
1034 /* move the item */
1035 moved = INV_MoveItem(ui_inventory, targetContainer, dragInfoToX, dragInfoToY, sourceContainer, fItem, &tItem);
1036
1037 /* No need to continue move wasn't successful */
1038 if (!moved) {
1039 fItem->rotated = rotated;
1040 return false;
1041 }
1042
1043 /* Add ammo on adding weapon to a soldier */
1044 if (UI_IsScrollContainerNode(source) && ((fItem->isWeapon() && !fItem->getAmmoLeft())
1045 || (fItem->def()->weapons[0] && !fItem->def()->isAmmo())))
1046 INV_LoadWeapon(tItem, ui_inventory, sourceContainer, targetContainer);
1047
1048 /* Run onChange events */
1049 if (source->onChange) {
1050 UI_ExecuteEventActions(source, source->onChange);
1051 }
1052 if (source->lua_onChange != LUA_NOREF) {
1053 UI_ExecuteLuaEventScript(source, source->lua_onChange);
1054 }
1055
1056 if (source != target) {
1057 if (target->onChange) {
1058 UI_ExecuteEventActions(target, target->onChange);
1059 }
1060 if (target->lua_onChange != LUA_NOREF) {
1061 UI_ExecuteLuaEventScript(target, target->lua_onChange);
1062 }
1063 }
1064 }
1065 }
1066
1067 dragInfoFromX = -1;
1068 dragInfoFromY = -1;
1069 return true;
1070}
1071
1073{
1074 behaviour->name = "container";
1075 behaviour->manager = UINodePtr(new uiContainerNode());
1076 behaviour->extraDataSize = sizeof(EXTRADATA_TYPE);
1077 behaviour->lua_SWIG_typeinfo = UI_SWIG_TypeQuery("uiContainerNode_t *");
1078
1079 /* Callback value set before calling onSelect. It is used to know the item selected */
1080 UI_RegisterExtradataNodeProperty(behaviour, "lastselectedid", V_INT, containerExtraData_t, lastSelectedId);
1081 /* Callback event called when the user select an item */
1082 UI_RegisterExtradataNodeProperty(behaviour, "onselect", V_UI_ACTION, containerExtraData_t, onSelect);
1083}
le_t * selActor
Definition cl_actor.cpp:49
void CL_ActorInvMove(const le_t *le, containerIndex_t fromContainer, int fromX, int fromY, containerIndex_t toContainer, int toX, int toY)
Sends an inventory move event to the server.
bool CL_BattlescapeRunning(void)
Check whether we already have actors spawned on the battlefield.
bool GAME_ItemIsUseable(const objDef_t *od)
Definition cl_game.cpp:1104
const char * GAME_GetModelForItem(const objDef_t *od, uiModel_t **uiModel)
Get a model for an item.
Definition cl_game.cpp:1534
Shared game type headers.
int mousePosY
Definition cl_input.cpp:76
int mousePosX
Definition cl_input.cpp:76
bool INV_MoveItem(Inventory *inv, const invDef_t *toContainer, int toX, int toY, const invDef_t *fromContainer, Item *fItem, Item **uponItem)
Move item between containers.
bool INV_UnloadWeapon(Item *weapon, Inventory *inv, const invDef_t *container)
Unload a weapon and put the ammo in a container.
bool INV_LoadWeapon(const Item *weaponList, Inventory *inv, const invDef_t *srcContainer, const invDef_t *destContainer)
Load a weapon with ammo.
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...
Header file for inventory handling and Equipment menu.
@ FILTER_AIRCRAFT
@ MAX_FILTERTYPES
bool Key_IsDown(unsigned int key)
Checks whether a given key is currently pressed.
Definition cl_keys.cpp:214
@ K_SHIFT
Definition cl_keys.h:97
@ K_MOUSE2
Definition cl_keys.h:47
@ K_MOUSE1
Definition cl_keys.h:46
client_static_t cls
Definition cl_main.cpp:83
cvar_t * cl_selected
Definition cl_main.cpp:73
void R_Color(const vec4_t rgba)
Change the color to given value.
Definition r_state.cpp:1011
#define _(String)
Definition cl_shared.h:44
#define INVDEF(containerID)
Definition cl_shared.h:48
Item * getNextItem(const Item *prev) const
inventory definition with all its containers
Definition inv_shared.h:525
int canHoldItem(const invDef_t *container, const objDef_t *od, const int x, const int y, const Item *ignoredItem) const
Item * getEquipContainer() const
item instance data, with linked list capability
Definition inv_shared.h:402
bool isArmour() const
Definition inv_shared.h:489
const objDef_t * ammoDef(void) const
Definition inv_shared.h:460
int getAmmoLeft() const
Definition inv_shared.h:466
int getX() const
Definition inv_shared.h:454
int rotated
Definition inv_shared.h:412
bool mustReload() const
Definition inv_shared.h:483
int getAmount() const
Definition inv_shared.h:463
const objDef_t * def(void) const
Definition inv_shared.h:469
int getY() const
Definition inv_shared.h:457
bool isWeapon() const
Definition inv_shared.h:486
bool isHeldTwoHanded() const
Definition inv_shared.h:476
void initNode(uiNode_t *node) override
void onMouseUp(uiNode_t *node, int x, int y, int button) override
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...
void onLoading(uiNode_t *node) override
bool onDndEnter(uiNode_t *node) override
Call when a DND enter into the node.
bool onDndMove(uiNode_t *node, int x, int y) override
Call into the target when the DND hover it.
void draw(uiNode_t *node) override
Main function to draw a container node.
void onDndLeave(uiNode_t *node) override
Call when a DND enter into the node.
void onMouseDown(uiNode_t *node, int x, int y, int button) override
void onCapturedMouseMove(uiNode_t *node, int x, int y) override
bool onDndFinished(uiNode_t *node, bool isDroped) override
Call into the source when the DND end.
void drawTooltip(const uiNode_t *node, int x, int y) const override
Custom tooltip for container node.
virtual void initNode(uiNode_t *node)
Primary header for client.
csi_t csi
Definition common.cpp:39
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define NONE
Definition defines.h:68
void Sys_Error(const char *error,...)
Definition g_main.cpp:421
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
void INVSH_MergeShapes(uint32_t *shape, const uint32_t itemShape, const int x, const int y)
Will merge the second shape (=itemShape) into the first one (=big container shape) on the position x/...
bool INVSH_CheckShape(const uint32_t *shape, const int x, const int y)
Checks the shape if there is a 1-bit on the position x/y.
const invDef_t * INVSH_GetInventoryDefinitionByID(const char *id)
#define CID_BACKPACK
Definition inv_shared.h:51
#define CID_BELT
Definition inv_shared.h:52
#define CID_IMPLANT
Definition inv_shared.h:49
#define MAX_CONTAINERS
Definition inv_shared.h:394
@ INV_FITS
Definition inv_shared.h:363
@ INV_DOES_NOT_FIT
Definition inv_shared.h:362
@ INV_FITS_ONLY_ROTATED
Definition inv_shared.h:364
@ INV_FITS_BOTH
Definition inv_shared.h:365
#define CID_ARMOUR
Definition inv_shared.h:54
#define CID_HEADGEAR
Definition inv_shared.h:50
int32_t containerIndex_t
Definition inv_shared.h:46
#define SHAPE_BIG_MAX_WIDTH
32 bit mask
Definition inv_shared.h:190
#define SHAPE_BIG_MAX_HEIGHT
defines the max height of an inventory container
Definition inv_shared.h:188
#define CID_EQUIP
Definition inv_shared.h:56
#define CID_LEFT
Definition inv_shared.h:48
#define CID_HOLSTER
Definition inv_shared.h:53
#define CID_RIGHT
Definition inv_shared.h:47
voidpf void uLong size
Definition ioapi.h:42
voidpf uLong int origin
Definition ioapi.h:45
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
#define Mem_Dup(type, in, n)
Definition mem.h:47
#define Mem_Free(ptr)
Definition mem.h:35
QGL_EXTERN GLuint index
Definition r_gl.h:110
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
void R_DrawModelDirect(modelInfo_t *mi, modelInfo_t *pmi, const char *tagname)
Draws a model in 2d mode (for rendering model data from the ui).
Definition r_mesh.cpp:306
@ ALIGN_UL
Definition scripts.h:90
@ V_INT
Definition scripts.h:52
Header for lua script functions.
bool Q_strnull(const char *string)
Definition shared.h:138
#define OBJZERO(obj)
Definition shared.h:178
#define MAX_VAR
Definition shared.h:36
#define lengthof(x)
Definition shared.h:105
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition shared.cpp:475
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition shared.cpp:587
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
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
extradata for container widget
int numItems[MAX_OBJDEFS]
Definition inv_shared.h:608
inventory definition for our menus
Definition inv_shared.h:371
bool isFloorDef() const
Checks whether the inventory definition is the floor.
uint32_t shape[SHAPE_BIG_MAX_HEIGHT]
Definition inv_shared.h:384
char name[MAX_VAR]
Definition inv_shared.h:372
bool isLeftDef() const
Checks whether a given inventory definition is of special type.
bool isEquipDef() const
Checks whether a given inventory definition is of special type.
containerIndex_t id
Definition inv_shared.h:373
bool single
Definition inv_shared.h:375
bool isRightDef() const
Checks whether the inventory definition is the right Hand.
float * origin
Definition cl_renderer.h:61
float * center
Definition cl_renderer.h:64
float * angles
Definition cl_renderer.h:62
const char * name
Definition cl_renderer.h:59
float * color
Definition cl_renderer.h:71
float * scale
Definition cl_renderer.h:63
Defines all attributes of objects used in the inventory.
Definition inv_shared.h:264
bool isAmmo() const
Definition inv_shared.h:343
uint32_t getShapeRotated() const
Rotates a shape definition 90 degree to the left (CCW).
uint32_t shape
Definition inv_shared.h:273
bool weapon
Definition inv_shared.h:277
bool headgear
Definition inv_shared.h:280
bool isLoadableInWeapon(const objDef_s *weapon) const
Checks if an item can be used to reload a weapon.
bool fireTwoHanded
Definition inv_shared.h:279
const char * image
Definition inv_shared.h:270
bool implant
Definition inv_shared.h:282
vec3_t center
Definition inv_shared.h:276
const char * id
Definition inv_shared.h:268
float scale
Definition inv_shared.h:275
int numWeapons
Definition inv_shared.h:317
const struct objDef_s * weapons[MAX_WEAPONS_PER_OBJDEF]
Definition inv_shared.h:311
const char * name
Definition inv_shared.h:267
node behaviour, how a node work
const char * name
void * lua_SWIG_typeinfo
UINodePtr manager
intptr_t extraDataSize
vec2_t size
Definition ui_nodes.h:52
Model that have more than one part (top and down part of an aircraft).
Atomic structure used to define most of the UI.
Definition ui_nodes.h:80
vec4_t color
Definition ui_nodes.h:127
LUA_EVENT lua_onChange
Definition ui_nodes.h:162
uiNode_t * parent
Definition ui_nodes.h:92
struct uiAction_s * onChange
Definition ui_nodes.h:143
uiBox_t box
Definition ui_nodes.h:96
char name[MAX_VAR]
Definition ui_nodes.h:82
uiNode_t * root
Definition ui_nodes.h:93
vec_t vec3_t[3]
Definition ufotypes.h:39
vec_t vec4_t[4]
Definition ufotypes.h:40
vec_t vec2_t[2]
Definition ufotypes.h:38
void UI_ExecuteEventActions(uiNode_t *source, const uiAction_t *firstAction)
#define UI_RegisterExtradataNodeProperty(BEHAVIOUR, NAME, TYPE, EXTRADATATYPE, ATTRIBUTE)
Initialize a property from extradata of node.
bool UI_DNDIsDragging(void)
Return true if we are dragging something.
static uiNode_t * targetNode
void UI_DNDDrop(void)
Drop the object at the current position.
bool UI_DNDIsTargetNode(uiNode_t *node)
Return true if the requested node is the current target of the DND.
Item * UI_DNDGetItem(void)
uiNode_t * UI_DNDGetTargetNode(void)
Return target of the DND.
void UI_DNDAbort(void)
Drop the object at the current position.
void UI_DNDDragItem(uiNode_t *node, const Item *item)
Start to drag an item.
int UI_DNDGetType(void)
Return the current type of the dragging object, else DND_NOTHING.
bool UI_DNDIsSourceNode(uiNode_t *node)
Return true if the requested node is the source of the DND.
uiNode_t * UI_DNDGetSourceNode(void)
Return source of the DND.
@ DND_ITEM
void UI_SetMouseCapture(uiNode_t *node)
Captured the mouse into a node.
Definition ui_input.cpp:516
uiNode_t * UI_GetMouseCapture(void)
Return the captured node.
Definition ui_input.cpp:508
void UI_MouseRelease(void)
Release the captured node.
Definition ui_input.cpp:526
bool UI_ExecuteLuaEventScript(uiNode_t *node, LUA_EVENT event)
Executes a lua event handler.
Definition ui_lua.cpp:71
Basic lua initialization for the ui.
void * UI_SWIG_TypeQuery(const char *name)
This function queries the SWIG type table for a type information structure. It is used in combination...
uiNode_t * UI_GetNode(const uiNode_t *node, const char *name)
Search a child node by given name.
Definition ui_node.cpp:714
void UI_GetNodeAbsPos(const uiNode_t *node, vec2_t pos)
Returns the absolute position of a node.
Definition ui_node.cpp:526
SharedPtr< uiNode > UINodePtr
#define EXTRADATA_TYPE
#define EXTRADATA(node)
#define EXTRADATACONST(node)
static int dragInfoFromY
static const vec4_t colorLoadable
static int dragInfoFromX
static const vec4_t colorDefault
static int oldMouseY
static int oldMouseX
static const vec4_t colorDisabledLoadable
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.
static const vec3_t scale
static const Item * dragInfoIC
static bool UI_ContainerNodeAddItem(const invDef_t *container, Item *ic, containerIndex_t containerID, Item **icp)
static void UI_DrawDisabled(const uiNode_t *node)
Draws the rectangle in a 'free' style on position posx/posy (pixel) in the size sizex/sizey (pixel).
static void UI_ContainerNodeDrawFreeSpace(uiNode_t *node, Inventory *inv)
Draws the free and usable inventory positions when dragging an item.
uiNode_t * UI_GetContainerNodeByContainerIDX(const uiNode_t *const parent, const int index)
Search a child container node by the given container id.
Inventory * ui_inventory
static const vec4_t colorDisabled
static void UI_ContainerNodeDrawDropPreview(uiNode_t *target)
Draw a preview of the DND item dropped into the node.
void UI_ContainerNodeAutoPlaceItem(uiNode_t *node, Item *ic)
Try to autoplace an item from a container.
#define EXTRADATA(node)
static int dragInfoToX
static bool UI_IsScrollContainerNode(const uiNode_t *const node)
static void UI_DrawFree(containerIndex_t container, const uiNode_t *node, int posx, int posy, int sizex, int sizey, bool showTUs)
Draws the rectangle in a 'free' style on position posx/posy (pixel) in the size sizex/sizey (pixel).
static int dragInfoToY
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_GetItemTooltip(const Item &item, char *tooltipText, size_t stringMaxLength)
Generate tooltip text for an item.
void UI_ContainerNodeUpdateEquipment(Inventory *inv, const equipDef_t *ed)
Fills the ground container of the ui_inventory with unused items from a given equipment definition.
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.
static const vec4_t colorPreview
static void UI_ContainerNodeDrawGrid(uiNode_t *node, const objDef_t *highlightType)
Draw a grip container.
#define EXTRADATACONST(node)
static Item * UI_ContainerNodeGetItemAtPosition(const uiNode_t *const node, int mouseX, int mouseY, int *contX=nullptr, int *contY=nullptr)
Gets location of the item the mouse is over.
static void UI_ContainerNodeDrawSingle(uiNode_t *node, const objDef_t *highlightType)
Draw a container which only contains one item.
#define C_UNIT
One unit in the containers is 25x25.
Inventory * ui_inventory
void UI_GetItemTooltip(const Item &item, char *tooltipText, size_t stringMaxLength)
Generate tooltip text for an item.
void UI_RegisterContainerNode(uiBehaviour_t *behaviour)
void UI_DrawModelNode(uiNode_t *node, const char *source)
#define V_UI_ACTION
Definition ui_parse.h:54
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)
const image_t * UI_DrawNormImageByName(bool flip, float x, float y, float w, float h, float sh, float th, float sl, float tl, const char *name)
Draws an image or parts of it.
void UI_DrawFill(int x, int y, int w, int h, const vec4_t color)
Fills a box of pixels with a single color.
Definition ui_render.cpp:37
int UI_DrawTooltip(const char *string, int x, int y, int maxWidth)
Generic tooltip function.
#define VectorNegate(src, dest)
Definition vector.h:58
#define Vector4Copy(src, dest)
Definition vector.h:53
#define VectorCopy(src, dest)
Definition vector.h:51
#define VectorScale(in, scale, out)
Definition vector.h:79