00001
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "../ui_main.h"
00036 #include "../ui_parse.h"
00037 #include "../ui_actions.h"
00038 #include "../ui_dragndrop.h"
00039 #include "../ui_tooltip.h"
00040 #include "../ui_nodes.h"
00041 #include "../ui_input.h"
00042 #include "../ui_render.h"
00043 #include "ui_node_model.h"
00044 #include "ui_node_container.h"
00045 #include "ui_node_abstractnode.h"
00046
00047 #include "../../client.h"
00048 #include "../../renderer/r_draw.h"
00049 #include "../../renderer/r_mesh.h"
00050 #include "../../cl_game.h"
00051 #include "../../cl_team.h"
00052 #include "../../battlescape/cl_actor.h"
00053 #include "../../cl_inventory.h"
00054
00059 inventory_t *ui_inventory = NULL;
00060
00061 #define EXTRADATA_TYPE containerExtraData_t
00062 #define EXTRADATA(node) UI_EXTRADATA(node, EXTRADATA_TYPE)
00063 #define EXTRADATACONST(node) UI_EXTRADATACONST(node, EXTRADATA_TYPE)
00064
00069 static int dragInfoFromX = -1;
00070 static int dragInfoFromY = -1;
00071
00076 static int dragInfoToX = -1;
00077 static int dragInfoToY = -1;
00078
00083 static const invList_t *dragInfoIC;
00084
00095 static invList_t *UI_ContainerNodeGetExistingItem (const uiNode_t *node, objDef_t *item, const itemFilterTypes_t filterType)
00096 {
00097 return INVSH_SearchInInventoryWithFilter(ui_inventory, EXTRADATACONST(node).container, NONE, NONE, item, filterType);
00098 }
00099
00106 static void UI_ContainerNodeUpdateScroll (uiNode_t* node)
00107 {
00108 if (EXTRADATA(node).onViewChange) {
00109 UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange);
00110 }
00111 }
00112
00113 static inline qboolean UI_IsScrollContainerNode (const uiNode_t* const node)
00114 {
00115 return EXTRADATACONST(node).container && EXTRADATACONST(node).container->scroll;
00116 }
00117
00130 void UI_ContainerNodeUpdateEquipment (inventory_t *inv, equipDef_t *ed)
00131 {
00132 int i;
00133
00134
00135
00136
00137 assert(MAX_CONTAINERS >= FILTER_AIRCRAFT);
00138
00139 for (i = 0; i < csi.numODs; i++) {
00140 objDef_t *od = INVSH_GetItemByIDX(i);
00141
00142 if (!GAME_ItemIsUseable(od))
00143 continue;
00144
00145 while (ed->numItems[i]) {
00146 const item_t item = {NONE_AMMO, NULL, od, 0, 0};
00147 if (!cls.i.AddToInventory(&cls.i, inv, item, INVDEF(csi.idEquip), NONE, NONE, 1)) {
00148
00149 break;
00150 }
00151 ed->numItems[item.t->idx]--;
00152 }
00153 }
00154
00155
00156 if (ui_inventory && !ui_inventory->c[csi.idEquip]) {
00157 ui_inventory->c[csi.idEquip] = inv->c[csi.idEquip];
00158 }
00159 }
00160
00174 void UI_DrawItem (uiNode_t *node, const vec3_t org, const item_t *item, int x, int y, const vec3_t scale, const vec4_t color)
00175 {
00176 objDef_t *od = item->t;
00177 vec4_t col;
00178 vec3_t origin;
00179
00180 assert(od);
00181 assert(org[2] > -1000 && org[2] < 1000);
00182
00183 Vector4Copy(color, col);
00184
00185 if (od->weapon && od->reload && !item->a) {
00186 col[1] *= 0.5;
00187 col[2] *= 0.5;
00188 }
00189
00190 VectorCopy(org, origin);
00191
00192
00195 if (x >= 0 || y >= 0) {
00196
00197 origin[0] += x * C_UNIT;
00198 origin[1] += y * C_UNIT;
00199
00200
00201 if (item->rotated) {
00202 origin[0] += od->sy * C_UNIT / 2.0;
00203 origin[1] += od->sx * C_UNIT / 2.0;
00208 } else {
00209 origin[0] += od->sx * C_UNIT / 2.0;
00210 origin[1] += od->sy * C_UNIT / 2.0;
00211 }
00212 }
00213
00214
00215 if (od->image[0] != '\0') {
00216 const int imgWidth = od->sx * C_UNIT;
00217 const int imgHeight = od->sy * C_UNIT;
00218 origin[0] -= od->sx * C_UNIT / 2.0;
00219 origin[1] -= od->sy * C_UNIT / 2.0;
00220
00221
00222 R_Color(color);
00223 UI_DrawNormImageByName(origin[0], origin[1], imgWidth, imgHeight, 0, 0, 0, 0, od->image);
00224 R_Color(NULL);
00225 } else {
00226 uiModel_t *model = NULL;
00227 const char *modelName = GAME_GetModelForItem(od, &model);
00228
00229
00230 if (modelName == NULL || modelName[0] == '\0') {
00231 Com_Printf("UI_DrawItem: No model given for item: '%s'\n", od->id);
00232 return;
00233 }
00234
00235 if (model && node) {
00236 UI_DrawModelNode(node, modelName);
00237 } else {
00238 modelInfo_t mi;
00239 vec3_t angles = {-10, 160, 70};
00240 vec3_t size = {scale[0], scale[1], scale[2]};
00241 vec3_t center;
00242
00243 if (item->rotated)
00244 angles[0] -= 90;
00245
00246 if (od->scale)
00247 VectorScale(size, od->scale, size);
00248
00249 VectorNegate(od->center, center);
00250
00251 memset(&mi, 0, sizeof(mi));
00252 mi.origin = origin;
00253 mi.angles = angles;
00254 mi.center = center;
00255 mi.scale = size;
00256 mi.color = col;
00257 mi.name = modelName;
00258
00259
00260 R_DrawModelDirect(&mi, NULL, NULL);
00261 }
00262 }
00263 }
00264
00272 static void UI_GetItemTooltip (item_t item, char *tooltipText, size_t stringMaxLength)
00273 {
00274 objDef_t *weapon;
00275
00276 assert(item.t);
00277
00278 if (item.amount > 1)
00279 Com_sprintf(tooltipText, stringMaxLength, "%i x %s\n", item.amount, _(item.t->name));
00280 else
00281 Com_sprintf(tooltipText, stringMaxLength, "%s\n", _(item.t->name));
00282
00283
00284 if (GAME_ItemIsUseable(item.t)) {
00285 if (item.t->weapon) {
00286
00287 if (item.t == item.m) {
00288
00289 if (item.a) {
00290 Q_strcat(tooltipText, va(_("Ammo: %i\n"), item.a), stringMaxLength);
00291 }
00292 } else if (item.m) {
00293
00294 Q_strcat(tooltipText, va(_("%s loaded\n"), _(item.m->name)), stringMaxLength);
00295 Q_strcat(tooltipText, va(_("Ammo: %i\n"), item.a), stringMaxLength);
00296 }
00297 } else if (item.t->numWeapons) {
00298
00299 if (!(item.t->numWeapons == 1 && item.t->weapons[0] == item.t)) {
00300 int i;
00301
00302 Q_strcat(tooltipText, _("Usable in:\n"), stringMaxLength);
00303 for (i = 0; i < item.t->numWeapons; i++) {
00304 weapon = item.t->weapons[i];
00305 if (GAME_ItemIsUseable(weapon)) {
00306 Q_strcat(tooltipText, va("* %s\n", _(weapon->name)), stringMaxLength);
00307 }
00308 }
00309 }
00310 }
00311 }
00312 }
00313
00317 static void UI_DrawDisabled (const uiNode_t* node)
00318 {
00319 const vec4_t color = { 0.3f, 0.3f, 0.3f, 0.7f };
00320 vec2_t nodepos;
00321
00322 UI_GetNodeAbsPos(node, nodepos);
00323 UI_DrawFill(nodepos[0], nodepos[1], node->size[0], node->size[1], color);
00324 }
00325
00329 static void UI_DrawFree (containerIndex_t container, const uiNode_t *node, int posx, int posy, int sizex, int sizey, qboolean showTUs)
00330 {
00331 const vec4_t color = { 0.0f, 1.0f, 0.0f, 0.7f };
00332 invDef_t* inv = INVDEF(container);
00333 vec2_t nodepos;
00334
00335 UI_GetNodeAbsPos(node, nodepos);
00336 UI_DrawFill(posx, posy, sizex, sizey, color);
00337
00338
00339
00340 if (showTUs && CL_BattlescapeRunning()) {
00341 UI_DrawString("f_verysmall", ALIGN_UL, nodepos[0] + 3, nodepos[1] + 3,
00342 nodepos[0] + 3, node->size[0] - 6, 0,
00343 va(_("In: %i Out: %i"), inv->in, inv->out), 0, 0, NULL, qfalse, 0);
00344 }
00345 }
00346
00351 static void UI_ContainerNodeDrawFreeSpace (uiNode_t *node, inventory_t *inv)
00352 {
00353 const objDef_t *od = UI_DNDGetItem()->t;
00354 vec2_t nodepos;
00355
00356
00357 assert(UI_DNDIsDragging());
00358 assert(inv);
00359
00360 UI_GetNodeAbsPos(node, nodepos);
00361
00362 if (EXTRADATA(node).container->single) {
00363
00364 if (UI_DNDIsSourceNode(node) || INVSH_CheckToInventory(inv, od, EXTRADATA(node).container, 0, 0, dragInfoIC))
00365 UI_DrawFree(EXTRADATA(node).container->id, node, nodepos[0], nodepos[1], node->size[0], node->size[1], qtrue);
00366 } else {
00367
00368 uint32_t free[SHAPE_BIG_MAX_HEIGHT];
00369 qboolean showTUs = qtrue;
00370 int x, y;
00371
00372 memset(free, 0, sizeof(free));
00373
00374 for (y = 0; y < SHAPE_BIG_MAX_HEIGHT; y++) {
00375 for (x = 0; x < SHAPE_BIG_MAX_WIDTH; x++) {
00376
00377
00378
00379 const int checkedTo = INVSH_CheckToInventory(inv, od, EXTRADATA(node).container, x, y, dragInfoIC);
00380 if (checkedTo & INV_FITS)
00381 INVSH_MergeShapes(free, (uint32_t)od->shape, x, y);
00382 if (checkedTo & INV_FITS_ONLY_ROTATED)
00383 INVSH_MergeShapes(free, INVSH_ShapeRotate((uint32_t)od->shape), x, y);
00384
00385
00386 if (INVSH_CheckShape(EXTRADATA(node).container->shape, x, y)) {
00387 if (INVSH_CheckShape(free, x, y)) {
00388 UI_DrawFree(EXTRADATA(node).container->id, node, nodepos[0] + x * C_UNIT, nodepos[1] + y * C_UNIT, C_UNIT, C_UNIT, showTUs);
00389 showTUs = qfalse;
00390 }
00391 }
00392 }
00393 }
00394 }
00395 }
00396
00402 static void UI_ContainerNodeLoaded (uiNode_t* const node)
00403 {
00404 const char *name;
00405 invDef_t *container;
00406
00408 name = node->name;
00409 if (!strncmp(node->name, "equip_", 6))
00410 name = "equip";
00411
00412 container = INVSH_GetInventoryDefinitionByID(name);
00413 if (container == NULL)
00414 return;
00415
00416 EXTRADATA(node).container = container;
00417
00418 if (UI_IsScrollContainerNode(node)) {
00419
00420 } else {
00421 int i, j;
00422
00423 for (i = SHAPE_BIG_MAX_WIDTH - 1; i >= 0; i--) {
00424 for (j = 0; j < SHAPE_BIG_MAX_HEIGHT; j++)
00425 if (container->shape[j] & (1 << i))
00426 break;
00427 if (j < SHAPE_BIG_MAX_HEIGHT)
00428 break;
00429 }
00430 node->size[0] = C_UNIT * (i + 1) + 0.01;
00431
00432
00433 for (i = SHAPE_BIG_MAX_HEIGHT - 1; i >= 0; i--)
00434 if (container->shape[i] & ~0x0)
00435 break;
00436 node->size[1] = C_UNIT * (i + 1) + 0.01;
00437 }
00438 }
00439
00440 static const vec3_t scale = {3.5, 3.5, 3.5};
00442 static const vec4_t colorDefault = {1, 1, 1, 1};
00443 static const vec4_t colorLoadable = {0.5, 1, 0.5, 1};
00444 static const vec4_t colorDisabled = {0.5, 0.5, 0.5, 1};
00445 static const vec4_t colorDisabledHiden = {0.5, 0.5, 0.5, 0.5};
00446 static const vec4_t colorDisabledLoadable = {0.5, 0.25, 0.25, 1.0};
00447 static const vec4_t colorPreview = { 0.5, 0.5, 1, 1 };
00454 static void UI_ContainerNodeDrawSingle (uiNode_t *node, objDef_t *highlightType)
00455 {
00456 vec4_t color;
00457 vec3_t pos;
00458
00459 UI_GetNodeAbsPos(node, pos);
00460 pos[0] += node->size[0] / 2.0;
00461 pos[1] += node->size[1] / 2.0;
00462 pos[2] = 0;
00463
00464
00465 if (INV_IsLeftDef(EXTRADATA(node).container) && !ui_inventory->c[csi.idLeft]) {
00466 if (ui_inventory->c[csi.idRight]) {
00467 const item_t *item = &ui_inventory->c[csi.idRight]->item;
00468 assert(item);
00469 assert(item->t);
00470
00471 if (item->t->holdTwoHanded) {
00472 if (highlightType && INVSH_LoadableInWeapon(highlightType, item->t))
00473 memcpy(color, colorLoadable, sizeof(vec4_t));
00474 else
00475 memcpy(color, colorDefault, sizeof(vec4_t));
00476 color[3] = 0.5;
00477 UI_DrawItem(node, pos, item, -1, -1, scale, color);
00478 }
00479 }
00480 } else if (ui_inventory->c[EXTRADATA(node).container->id]) {
00481 qboolean disabled = qfalse;
00482 const item_t *item;
00483
00484 if (ui_inventory->c[csi.idRight]) {
00485 item = &ui_inventory->c[csi.idRight]->item;
00486
00487
00488
00489 assert(item);
00490 assert(item->t);
00491 if (INV_IsRightDef(EXTRADATA(node).container) && item->t->fireTwoHanded && ui_inventory->c[csi.idLeft]) {
00492 disabled = qtrue;
00493 UI_DrawDisabled(node);
00494 }
00495 }
00496
00497 item = &ui_inventory->c[EXTRADATA(node).container->id]->item;
00498 assert(item);
00499 assert(item->t);
00500 if (highlightType && INVSH_LoadableInWeapon(highlightType, item->t)) {
00501 if (disabled)
00502 Vector4Copy(colorDisabledLoadable, color);
00503 else
00504 Vector4Copy(colorLoadable, color);
00505 } else {
00506 if (disabled)
00507 Vector4Copy(colorDisabled, color);
00508 else
00509 Vector4Copy(colorDefault, color);
00510 }
00511 if (disabled)
00512 color[3] = 0.5;
00513 UI_DrawItem(node, pos, item, -1, -1, scale, color);
00514 }
00515 }
00516
00520 static void UI_ContainerNodeDrawGrid (uiNode_t *node, objDef_t *highlightType)
00521 {
00522 const invList_t *ic;
00523 vec3_t pos;
00524
00525 UI_GetNodeAbsPos(node, pos);
00526 pos[2] = 0;
00527
00528 for (ic = ui_inventory->c[EXTRADATA(node).container->id]; ic; ic = ic->next) {
00529 assert(ic->item.t);
00530 if (highlightType && INVSH_LoadableInWeapon(highlightType, ic->item.t))
00531 UI_DrawItem(node, pos, &ic->item, ic->x, ic->y, scale, colorLoadable);
00532 else
00533 UI_DrawItem(node, pos, &ic->item, ic->x, ic->y, scale, colorDefault);
00534 }
00535 }
00536
00540 static void UI_ContainerNodeDrawDropPreview (uiNode_t *target)
00541 {
00542 item_t previewItem;
00543 int checkedTo;
00544 vec3_t origine;
00545
00546
00547 if (UI_IsScrollContainerNode(target))
00548 return;
00549
00550
00551 previewItem = *UI_DNDGetItem();
00552 previewItem.rotated = qfalse;
00553 checkedTo = INVSH_CheckToInventory(ui_inventory, previewItem.t, EXTRADATA(target).container, dragInfoToX, dragInfoToY, dragInfoIC);
00554 if (checkedTo == INV_FITS_ONLY_ROTATED)
00555 previewItem.rotated = qtrue;
00556
00557
00558 if (!checkedTo)
00559 return;
00560
00561
00562 if (INV_IsArmour(previewItem.t))
00563 return;
00564
00565 UI_GetNodeAbsPos(target, origine);
00566 origine[2] = -40;
00567
00568
00569 if (EXTRADATA(target).container->single) {
00570 origine[0] += target->size[0] / 2.0;
00571 origine[1] += target->size[1] / 2.0;
00572
00573
00574
00575 } else {
00576 if (previewItem.rotated) {
00577 origine[0] += (dragInfoToX + previewItem.t->sy / 2.0) * C_UNIT;
00578 origine[1] += (dragInfoToY + previewItem.t->sx / 2.0) * C_UNIT;
00579 } else {
00580 origine[0] += (dragInfoToX + previewItem.t->sx / 2.0) * C_UNIT;
00581 origine[1] += (dragInfoToY + previewItem.t->sy / 2.0) * C_UNIT;
00582 }
00583 }
00584
00585 UI_DrawItem(NULL, origine, &previewItem, -1, -1, scale, colorPreview);
00586 }
00587
00591 static void UI_ContainerNodeDraw (uiNode_t *node)
00592 {
00593 objDef_t *highlightType = NULL;
00594
00595 if (!EXTRADATA(node).container)
00596 return;
00597 if (!ui_inventory)
00598 return;
00599
00600 if (node->color[3] < 0.001)
00601 return;
00602
00603
00604 if (UI_DNDIsDragging() && UI_DNDGetType() == DND_ITEM) {
00605 highlightType = UI_DNDGetItem()->t;
00606 }
00607
00608 if (EXTRADATA(node).container->single) {
00609 UI_ContainerNodeDrawSingle(node, highlightType);
00610 } else {
00611 if (UI_IsScrollContainerNode(node)) {
00612 assert(qfalse);
00613 } else {
00614 UI_ContainerNodeDrawGrid(node, highlightType);
00615 }
00616 }
00617
00618
00619 if (UI_DNDIsDragging() && EXTRADATA(node).container->id != csi.idEquip)
00620 UI_ContainerNodeDrawFreeSpace(node, ui_inventory);
00621
00622 if (UI_DNDIsTargetNode(node))
00623 UI_ContainerNodeDrawDropPreview(node);
00624 }
00625
00635 static invList_t *UI_ContainerNodeGetItemAtPosition (const uiNode_t* const node, int mouseX, int mouseY, int* contX, int* contY)
00636 {
00637 invList_t *result = NULL;
00638
00639 if (UI_IsScrollContainerNode(node)) {
00640 assert(qfalse);
00641 } else {
00642 vec2_t nodepos;
00643 int fromX, fromY;
00644
00645 UI_GetNodeAbsPos(node, nodepos);
00646
00647 fromX = (int) (mouseX - nodepos[0]) / C_UNIT;
00648 fromY = (int) (mouseY - nodepos[1]) / C_UNIT;
00649 if (contX)
00650 *contX = fromX;
00651 if (contY)
00652 *contY = fromY;
00653
00654 result = INVSH_SearchInInventory(ui_inventory, EXTRADATACONST(node).container, fromX, fromY);
00655 }
00656 return result;
00657 }
00658
00665 static void UI_ContainerNodeDrawTooltip (uiNode_t *node, int x, int y)
00666 {
00667 static char tooltiptext[MAX_VAR * 2];
00668 const invList_t *itemHover;
00669 vec2_t nodepos;
00670
00671 UI_GetNodeAbsPos(node, nodepos);
00672
00673
00674 itemHover = UI_ContainerNodeGetItemAtPosition(node, x, y, NULL, NULL);
00675
00676 if (itemHover) {
00677 const int itemToolTipWidth = 250;
00678
00679
00680 UI_GetItemTooltip(itemHover->item, tooltiptext, sizeof(tooltiptext));
00681 #ifdef DEBUG
00682
00683 Q_strcat(tooltiptext, va("\n%i/%i", itemHover->x, itemHover->y), sizeof(tooltiptext));
00684 #endif
00685 UI_DrawTooltip(tooltiptext, x, y, itemToolTipWidth);
00686 }
00687 }
00688
00697 static void UI_ContainerNodeAutoPlace (uiNode_t* node, int mouseX, int mouseY)
00698 {
00699 int sel;
00700 #if 0
00701 int id;
00702 #endif
00703 invList_t *ic;
00704 int fromX, fromY;
00705
00706 if (!ui_inventory)
00707 return;
00708
00709
00710 if (CL_BattlescapeRunning())
00711 return;
00712
00713 sel = cl_selected->integer;
00714 if (sel < 0)
00715 return;
00716
00717 assert(EXTRADATA(node).container);
00718
00719 ic = UI_ContainerNodeGetItemAtPosition(node, mouseX, mouseY, &fromX, &fromY);
00720 Com_DPrintf(DEBUG_CLIENT, "UI_ContainerNodeAutoPlace: item %i/%i selected from scrollable container.\n", fromX, fromY);
00721 if (!ic)
00722 return;
00723 #if 0
00724 id = ic->item.t->idx;
00725 #endif
00726
00727
00728 if (EXTRADATA(node).container->id != csi.idEquip) {
00729 if (ic->item.m && ic->item.m != ic->item.t && ic->item.a) {
00730
00731 INV_UnloadWeapon(ic, ui_inventory, INVDEF(csi.idEquip));
00732 } else {
00733
00734 INV_MoveItem(ui_inventory, INVDEF(csi.idEquip), NONE, NONE, EXTRADATA(node).container, ic);
00735 }
00736 } else {
00737 qboolean packed = qfalse;
00738 int px, py;
00739 assert(ic->item.t);
00740
00741 if (INV_IsArmour(ic->item.t)) {
00742 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idArmour), 0, 0, EXTRADATA(node).container, ic);
00743
00744 } else if (INV_IsAmmo(ic->item.t)) {
00745 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idBelt), &px, &py, NULL);
00746 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idBelt), px, py, EXTRADATA(node).container, ic);
00747 if (!packed) {
00748 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idHolster), &px, &py, NULL);
00749 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idHolster), px, py, EXTRADATA(node).container, ic);
00750 }
00751 if (!packed) {
00752 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idBackpack), &px, &py, NULL);
00753 packed = INV_MoveItem( ui_inventory, INVDEF(csi.idBackpack), px, py, EXTRADATA(node).container, ic);
00754 }
00755
00756 if (!packed) {
00757 const invList_t *rightHand = INVSH_SearchInInventory(ui_inventory, INVDEF(csi.idRight), 0, 0);
00758
00759
00760 if (!rightHand || !rightHand->item.t->fireTwoHanded) {
00761 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idLeft), &px, &py, NULL);
00762 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idLeft), px, py, EXTRADATA(node).container, ic);
00763 }
00764 }
00765 if (!packed) {
00766 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idRight), &px, &py, NULL);
00767 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idRight), px, py, EXTRADATA(node).container, ic);
00768 }
00769 } else {
00770 if (ic->item.t->headgear) {
00771 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idHeadgear), &px, &py, NULL);
00772 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idHeadgear), px, py, EXTRADATA(node).container, ic);
00773 } else {
00774
00775
00776 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idRight), &px, &py, NULL);
00777 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idRight), px, py, EXTRADATA(node).container, ic);
00778 if (ic->item.t->weapon && !ic->item.a && packed)
00779 INV_LoadWeapon(ic, ui_inventory, EXTRADATA(node).container, INVDEF(csi.idRight));
00780 if (!packed) {
00781 const invList_t *rightHand = INVSH_SearchInInventory(ui_inventory, INVDEF(csi.idRight), 0, 0);
00782
00783
00784 if (!rightHand || (rightHand && !rightHand->item.t->fireTwoHanded)) {
00785 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idLeft), &px, &py, NULL);
00786 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idLeft), px, py, EXTRADATA(node).container, ic);
00787 if (ic->item.t->weapon && !ic->item.a && packed)
00788 INV_LoadWeapon(ic, ui_inventory, EXTRADATA(node).container, INVDEF(csi.idLeft));
00789 }
00790 }
00791 if (!packed) {
00792 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idBelt), &px, &py, NULL);
00793 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idBelt), px, py, EXTRADATA(node).container, ic);
00794 if (ic->item.t->weapon && !ic->item.a && packed)
00795 INV_LoadWeapon(ic, ui_inventory, EXTRADATA(node).container, INVDEF(csi.idBelt));
00796 }
00797 if (!packed) {
00798 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idHolster), &px, &py, NULL);
00799 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idHolster), px, py, EXTRADATA(node).container, ic);
00800 if (ic->item.t->weapon && !ic->item.a && packed)
00801 INV_LoadWeapon(ic, ui_inventory, EXTRADATA(node).container, INVDEF(csi.idHolster));
00802 }
00803 if (!packed) {
00804 INVSH_FindSpace(ui_inventory, &ic->item, INVDEF(csi.idBackpack), &px, &py, NULL);
00805 packed = INV_MoveItem(ui_inventory, INVDEF(csi.idBackpack), px, py, EXTRADATA(node).container, ic);
00806 if (ic->item.t->weapon && !ic->item.a && packed)
00807 INV_LoadWeapon(ic, ui_inventory, EXTRADATA(node).container, INVDEF(csi.idBackpack));
00808 }
00809 }
00810 }
00811
00812 if (!packed)
00813 return;
00814 }
00815
00821 if (INV_IsArmour(ic->item.t)) {
00822 uiNode_t *armour = UI_GetNode(node->root, "armour");
00823 if (armour && armour->onChange)
00824 UI_ExecuteEventActions(armour, armour->onChange);
00825 }
00826
00827
00828 if (UI_IsScrollContainerNode(node))
00829 UI_ContainerNodeUpdateScroll(node);
00830 }
00831
00832 static int oldMouseX = 0;
00833 static int oldMouseY = 0;
00834
00835 static void UI_ContainerNodeCapturedMouseMove (uiNode_t *node, int x, int y)
00836 {
00837 const int delta = abs(oldMouseX - x) + abs(oldMouseY - y);
00838 if (delta > 15) {
00839 UI_DNDDragItem(node, &(dragInfoIC->item));
00840 UI_MouseRelease();
00841 }
00842 }
00843
00844 static void UI_ContainerNodeMouseDown (uiNode_t *node, int x, int y, int button)
00845 {
00846 switch (button) {
00847 case K_MOUSE1:
00848 {
00849
00850 int fromX, fromY;
00851 dragInfoIC = UI_ContainerNodeGetItemAtPosition(node, x, y, &fromX, &fromY);
00852 if (dragInfoIC) {
00853 dragInfoFromX = fromX;
00854 dragInfoFromY = fromY;
00855 oldMouseX = x;
00856 oldMouseY = y;
00857 UI_SetMouseCapture(node);
00858 EXTRADATA(node).lastSelectedId = dragInfoIC->item.t->idx;
00859 if (EXTRADATA(node).onSelect) {
00860 UI_ExecuteEventActions(node, EXTRADATA(node).onSelect);
00861 }
00862 }
00863 break;
00864 }
00865 case K_MOUSE2:
00866 if (UI_DNDIsDragging()) {
00867 UI_DNDAbort();
00868 } else {
00869
00870 UI_ContainerNodeAutoPlace(node, x, y);
00871 }
00872 break;
00873 default:
00874 break;
00875 }
00876 }
00877
00878 static void UI_ContainerNodeMouseUp (uiNode_t *node, int x, int y, int button)
00879 {
00880 if (button != K_MOUSE1)
00881 return;
00882 if (UI_GetMouseCapture() == node) {
00883 UI_MouseRelease();
00884 }
00885 if (UI_DNDIsDragging()) {
00886 UI_DNDDrop();
00887 }
00888 }
00889 static void UI_ContainerNodeWheel (uiNode_t *node, qboolean down, int x, int y)
00890 {
00891 if (UI_IsScrollContainerNode(node)) {
00892 const int delta = 20;
00893 if (down) {
00894 const int lenght = EXTRADATA(node).scrollTotalNum - EXTRADATA(node).scrollNum;
00895 if (EXTRADATA(node).scrollCur < lenght) {
00896 EXTRADATA(node).scrollCur += delta;
00897 if (EXTRADATA(node).scrollCur > lenght)
00898 EXTRADATA(node).scrollCur = lenght;
00899 UI_ContainerNodeUpdateScroll(node);
00900 }
00901 } else {
00902 if (EXTRADATA(node).scrollCur > 0) {
00903 EXTRADATA(node).scrollCur -= delta;
00904 if (EXTRADATA(node).scrollCur < 0)
00905 EXTRADATA(node).scrollCur = 0;
00906 UI_ContainerNodeUpdateScroll(node);
00907 }
00908 }
00909 }
00910 }
00911
00912 static void UI_ContainerNodeLoading (uiNode_t *node)
00913 {
00914 EXTRADATA(node).container = NULL;
00915 EXTRADATA(node).columns = 1;
00916 node->color[3] = 1.0;
00917 }
00918
00922 static qboolean UI_ContainerNodeDNDEnter (uiNode_t *target)
00923 {
00924
00925 return UI_DNDGetType() == DND_ITEM && EXTRADATA(target).container && (!UI_IsScrollContainerNode(target) || UI_DNDGetSourceNode() != target);
00926 }
00927
00932 static qboolean UI_ContainerNodeDNDMove (uiNode_t *target, int x, int y)
00933 {
00934 vec2_t nodepos;
00935 qboolean exists;
00936 int itemX = 0;
00937 int itemY = 0;
00938 item_t *dragItem = UI_DNDGetItem();
00939
00940
00941 assert(EXTRADATA(target).container);
00942
00943 UI_GetNodeAbsPos(target, nodepos);
00944
00950 if (dragItem->t) {
00951 itemX = C_UNIT * dragItem->t->sx / 2;
00952 itemY = C_UNIT * dragItem->t->sy / 2;
00953
00954
00955 itemX -= C_UNIT / 2;
00956 itemY -= C_UNIT / 2;
00957 }
00958
00959 dragInfoToX = (mousePosX - nodepos[0] - itemX) / C_UNIT;
00960 dragInfoToY = (mousePosY - nodepos[1] - itemY) / C_UNIT;
00961
00962
00963 exists = qfalse;
00964 if ((INV_IsFloorDef(EXTRADATA(target).container) || INV_IsEquipDef(EXTRADATA(target).container))
00965 && (dragInfoToX < 0 || dragInfoToY < 0 || dragInfoToX >= SHAPE_BIG_MAX_WIDTH || dragInfoToY >= SHAPE_BIG_MAX_HEIGHT)
00966 && INVSH_ExistsInInventory(ui_inventory, EXTRADATA(target).container, *dragItem)) {
00967 exists = qtrue;
00968 }
00969
00970
00971
00972 if (!exists && dragItem->t && (EXTRADATA(target).container->single
00973 || dragInfoToX < 0 || dragInfoToY < 0
00974 || dragInfoToX >= SHAPE_BIG_MAX_WIDTH || dragInfoToY >= SHAPE_BIG_MAX_HEIGHT)) {
00975 #if 0
00976
00977
00978 || (INVSH_CheckToInventory(ui_inventory, dragItem->t, EXTRADATA(target).container, dragInfoToX, dragInfoToY) == INV_DOES_NOT_FIT)) {
00979 #endif
00980 INVSH_FindSpace(ui_inventory, dragItem, EXTRADATA(target).container, &dragInfoToX, &dragInfoToY, dragInfoIC);
00981 }
00982
00983
00984 if (UI_IsScrollContainerNode(target)) {
00985 return qtrue;
00986 }
00987
00988 {
00989 invList_t *fItem;
00990
00991
00992 const int checkedTo = INVSH_CheckToInventory(ui_inventory, dragItem->t, EXTRADATA(target).container, dragInfoToX, dragInfoToY, dragInfoIC);
00993 if (checkedTo != INV_DOES_NOT_FIT)
00994 return qtrue;
00995
00996
00997 fItem = INVSH_SearchInInventory(ui_inventory, EXTRADATA(target).container, dragInfoToX, dragInfoToY);
00998 if (!fItem)
00999 return qfalse;
01000 if (EXTRADATA(target).container->single)
01001 return qtrue;
01002 return INVSH_LoadableInWeapon(dragItem->t, fItem->item.t);
01003 }
01004 }
01005
01009 static void UI_ContainerNodeDNDLeave (uiNode_t *node)
01010 {
01011 dragInfoToX = -1;
01012 dragInfoToY = -1;
01013 }
01014
01018 static qboolean UI_ContainerNodeDNDFinished (uiNode_t *source, qboolean isDropped)
01019 {
01020 item_t *dragItem = UI_DNDGetItem();
01021
01022
01023 if (!isDropped) {
01024 return qfalse;
01025 }
01026
01027
01028 if (CL_BattlescapeRunning()) {
01029 const uiNode_t *target = UI_DNDGetTargetNode();
01030 assert(EXTRADATA(source).container);
01031 assert(target);
01032 assert(EXTRADATACONST(target).container);
01033 assert(selActor);
01034 CL_ActorInvMove(selActor, EXTRADATA(source).container->id, dragInfoFromX, dragInfoFromY,
01035 EXTRADATACONST(target).container->id, dragInfoToX, dragInfoToY);
01036 } else {
01037 uiNode_t *target = UI_DNDGetTargetNode();
01038 if (target) {
01039 invList_t *fItem;
01041 if (UI_IsScrollContainerNode(source)) {
01042 const int equipType = EXTRADATA(source).filterEquipType;
01043 fItem = UI_ContainerNodeGetExistingItem(source, dragItem->t, equipType);
01044 } else
01045 fItem = INVSH_SearchInInventory(ui_inventory, EXTRADATA(source).container, dragInfoFromX, dragInfoFromY);
01046
01048 assert(EXTRADATA(target).container);
01049 assert(fItem);
01050
01051
01052 if (UI_IsScrollContainerNode(target) && fItem->item.m && fItem->item.m != fItem->item.t)
01053 INV_UnloadWeapon(fItem, ui_inventory, EXTRADATA(target).container);
01054
01055 INV_MoveItem(ui_inventory,
01056 EXTRADATA(target).container, dragInfoToX, dragInfoToY,
01057 EXTRADATA(source).container, fItem);
01058
01059 if (UI_IsScrollContainerNode(source) && fItem->item.t->weapon && !fItem->item.a)
01060 INV_LoadWeapon(fItem, ui_inventory, EXTRADATA(source).container, EXTRADATA(target).container);
01061
01062 if (source->onChange)
01063 UI_ExecuteEventActions(source, source->onChange);
01064 if (source != target && target->onChange)
01065 UI_ExecuteEventActions(target, target->onChange);
01066 }
01067 }
01068
01069 dragInfoFromX = -1;
01070 dragInfoFromY = -1;
01071 return qtrue;
01072 }
01073
01074 static const value_t properties[] = {
01075
01076 {"displayweapon", V_BOOL, UI_EXTRADATA_OFFSETOF(containerExtraData_t, displayWeapon), MEMBER_SIZEOF(containerExtraData_t, displayWeapon)},
01077
01078 {"displayammo", V_BOOL, UI_EXTRADATA_OFFSETOF(containerExtraData_t, displayAmmo), MEMBER_SIZEOF(containerExtraData_t, displayAmmo)},
01079
01080 {"displayunavailableitem", V_BOOL, UI_EXTRADATA_OFFSETOF(containerExtraData_t, displayUnavailableItem), MEMBER_SIZEOF(containerExtraData_t, displayUnavailableItem)},
01081
01082 {"displayavailableontop", V_BOOL, UI_EXTRADATA_OFFSETOF(containerExtraData_t, displayAvailableOnTop), MEMBER_SIZEOF(containerExtraData_t, displayAvailableOnTop)},
01083
01084 {"displayammoofweapon", V_BOOL, UI_EXTRADATA_OFFSETOF(containerExtraData_t, displayAmmoOfWeapon), MEMBER_SIZEOF(containerExtraData_t, displayAmmoOfWeapon)},
01085
01086 {"displayunavailableammoofweapon", V_BOOL, UI_EXTRADATA_OFFSETOF(containerExtraData_t, displayUnavailableAmmoOfWeapon), MEMBER_SIZEOF(containerExtraData_t, displayUnavailableAmmoOfWeapon)},
01087
01088 {"columns", V_INT, UI_EXTRADATA_OFFSETOF(containerExtraData_t, columns), MEMBER_SIZEOF(containerExtraData_t, columns)},
01089
01090 {"filter", V_INT, UI_EXTRADATA_OFFSETOF(containerExtraData_t, filterEquipType), MEMBER_SIZEOF(containerExtraData_t, filterEquipType)},
01091
01092
01093 {"lastselectedid", V_INT, UI_EXTRADATA_OFFSETOF(containerExtraData_t, lastSelectedId), MEMBER_SIZEOF(containerExtraData_t, lastSelectedId)},
01094
01095 {"onselect", V_UI_ACTION, UI_EXTRADATA_OFFSETOF(containerExtraData_t, onSelect), MEMBER_SIZEOF(containerExtraData_t, onSelect)},
01096
01097
01098
01099
01100 {"scrollpos", V_INT, UI_EXTRADATA_OFFSETOF(containerExtraData_t, scrollCur), MEMBER_SIZEOF(containerExtraData_t, scrollCur)},
01101
01102 {"viewsize", V_INT, UI_EXTRADATA_OFFSETOF(containerExtraData_t, scrollNum), MEMBER_SIZEOF(containerExtraData_t, scrollNum)},
01103
01104 {"fullsize", V_INT, UI_EXTRADATA_OFFSETOF(containerExtraData_t, scrollTotalNum), MEMBER_SIZEOF(containerExtraData_t, scrollTotalNum)},
01105
01106 {"onviewchange", V_UI_ACTION, UI_EXTRADATA_OFFSETOF(containerExtraData_t, onViewChange), MEMBER_SIZEOF(containerExtraData_t, onViewChange)},
01107
01108 {NULL, V_NULL, 0, 0}
01109 };
01110
01111 void UI_RegisterContainerNode (uiBehaviour_t* behaviour)
01112 {
01113 behaviour->name = "container";
01114 behaviour->draw = UI_ContainerNodeDraw;
01115 behaviour->drawTooltip = UI_ContainerNodeDrawTooltip;
01116 behaviour->mouseDown = UI_ContainerNodeMouseDown;
01117 behaviour->mouseUp = UI_ContainerNodeMouseUp;
01118 behaviour->capturedMouseMove = UI_ContainerNodeCapturedMouseMove;
01119 behaviour->loading = UI_ContainerNodeLoading;
01120 behaviour->loaded = UI_ContainerNodeLoaded;
01121 behaviour->dndEnter = UI_ContainerNodeDNDEnter;
01122 behaviour->dndFinished = UI_ContainerNodeDNDFinished;
01123 behaviour->dndMove = UI_ContainerNodeDNDMove;
01124 behaviour->dndLeave = UI_ContainerNodeDNDLeave;
01125 behaviour->mouseWheel = UI_ContainerNodeWheel;
01126 behaviour->properties = properties;
01127 behaviour->extraDataSize = sizeof(EXTRADATA_TYPE);
01128 }