00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "q_shared.h"
00029
00030 static csi_t *CSI;
00031
00039 void INVSH_InitCSI (csi_t * import)
00040 {
00041 CSI = import;
00042 }
00043
00049 qboolean INV_IsFloorDef (const invDef_t* invDef)
00050 {
00051 return invDef->id == CSI->idFloor;
00052 }
00053
00059 qboolean INV_IsRightDef (const invDef_t* invDef)
00060 {
00061 return invDef->id == CSI->idRight;
00062 }
00063
00069 qboolean INV_IsLeftDef (const invDef_t* invDef)
00070 {
00071 return invDef->id == CSI->idLeft;
00072 }
00073
00079 qboolean INV_IsEquipDef (const invDef_t* invDef)
00080 {
00081 return invDef->id == CSI->idEquip;
00082 }
00083
00089 qboolean INV_IsArmourDef (const invDef_t* invDef)
00090 {
00091 return invDef->id == CSI->idArmour;
00092 }
00093
00094 invList_t* INVSH_HasArmour (const inventory_t *inv)
00095 {
00096 return inv->c[CSI->idArmour];
00097 }
00098
00099 static int cacheCheckToInventory = INV_DOES_NOT_FIT;
00100
00109 static qboolean INVSH_CheckShapeCollision (const uint32_t *shape, const uint32_t itemShape, const int x, const int y)
00110 {
00111 int i;
00112
00113
00114 if (x < 0 || y < 0) {
00115 Com_DPrintf(DEBUG_SHARED, "INVSH_CheckShapeCollision: x or y value negative: x=%i y=%i!\n", x, y);
00116 return qtrue;
00117 }
00118
00119 for (i = 0; i < SHAPE_SMALL_MAX_HEIGHT; i++) {
00120
00121 const int itemRow = (itemShape >> (i * SHAPE_SMALL_MAX_WIDTH)) & 0xFF;
00122
00123 const uint32_t itemRowShifted = itemRow << x;
00124
00125
00126 if (itemRowShifted >> x != itemRow)
00127
00128 return qtrue;
00129
00130
00131 if (y + i >= SHAPE_BIG_MAX_HEIGHT && itemRow)
00132
00133 return qtrue;
00134
00135
00136 if (itemRowShifted & shape[y + i])
00137 return qtrue;
00138 }
00139
00140 return qfalse;
00141 }
00142
00154 static qboolean INVSH_CheckToInventory_shape (const inventory_t * const i, const invDef_t * container, const uint32_t itemShape, const int x, const int y, const invList_t *ignoredItem)
00155 {
00156 invList_t *ic;
00157 static uint32_t mask[SHAPE_BIG_MAX_HEIGHT];
00158
00159 assert(container);
00160
00161 if (container->scroll)
00162 Sys_Error("INVSH_CheckToInventory_shape: No scrollable container will ever use this. This type does not support grid-packing!");
00163
00164
00165 if (x < 0 || y < 0 || x >= SHAPE_BIG_MAX_WIDTH || y >= SHAPE_BIG_MAX_HEIGHT)
00166 return qfalse;
00167
00168 if (!cacheCheckToInventory) {
00169 int j;
00170
00171 for (j = 0; j < SHAPE_BIG_MAX_HEIGHT; j++)
00172 mask[j] = ~container->shape[j];
00173
00174
00175 for (ic = i->c[container->id]; ic; ic = ic->next) {
00176 if (ignoredItem == ic)
00177 continue;
00178
00179 if (ic->item.rotated)
00180 INVSH_MergeShapes(mask, INVSH_ShapeRotate(ic->item.t->shape), ic->x, ic->y);
00181 else
00182 INVSH_MergeShapes(mask, ic->item.t->shape, ic->x, ic->y);
00183 }
00184 }
00185
00186
00187 if (INVSH_CheckShapeCollision(mask, itemShape, x, y))
00188 return qfalse;
00189
00190
00191 return qtrue;
00192 }
00193
00206 int INVSH_CheckToInventory (const inventory_t * const i, const objDef_t *od, const invDef_t * container, const int x, const int y, const invList_t *ignoredItem)
00207 {
00208 int fits;
00209 assert(i);
00210 assert(container);
00211 assert(od);
00212
00213
00214 if (INV_IsArmour(od)) {
00215 if (!container->armour && !container->all) {
00216 return INV_DOES_NOT_FIT;
00217 }
00218 } else if (!od->extension && container->extension) {
00219 return INV_DOES_NOT_FIT;
00220 } else if (!od->headgear && container->headgear) {
00221 return INV_DOES_NOT_FIT;
00222 } else if (container->armour) {
00223 return INV_DOES_NOT_FIT;
00224 }
00225
00226
00227 if (od->holdTwoHanded) {
00228 if ((INV_IsRightDef(container) && i->c[CSI->idLeft]) || INV_IsLeftDef(container))
00229 return INV_DOES_NOT_FIT;
00230 }
00231
00232
00233 if (INV_IsLeftDef(container)) {
00234 if (i->c[CSI->idRight] && i->c[CSI->idRight]->item.t->holdTwoHanded)
00235 return INV_DOES_NOT_FIT;
00236
00237
00238 if (od->fireTwoHanded)
00239 return INV_DOES_NOT_FIT;
00240 }
00241
00242
00243 if (container->single) {
00244 if (i->c[container->id]) {
00245
00246 return INV_DOES_NOT_FIT;
00247 } else {
00248 fits = INV_DOES_NOT_FIT;
00249
00250 if (INVSH_CheckToInventory_shape(i, container, od->shape, x, y, ignoredItem))
00251 fits |= INV_FITS;
00252 if (INVSH_CheckToInventory_shape(i, container, INVSH_ShapeRotate(od->shape), x, y, ignoredItem))
00253 fits |= INV_FITS_ONLY_ROTATED;
00254
00255 if (fits != INV_DOES_NOT_FIT)
00256 return fits;
00258 Com_DPrintf(DEBUG_SHARED, "INVSH_CheckToInventory: INFO: Moving to 'single' container but item would not fit normally.\n");
00259 return INV_FITS;
00260 }
00261 }
00262
00263
00264 if (container->scroll)
00265 return INV_FITS;
00266
00267
00268 fits = INV_DOES_NOT_FIT;
00269 if (INVSH_CheckToInventory_shape(i, container, od->shape, x, y, ignoredItem))
00270 fits |= INV_FITS;
00272 if (!INV_IsEquipDef(container) && !INV_IsFloorDef(container)
00273 && INVSH_CheckToInventory_shape(i, container, INVSH_ShapeRotate(od->shape), x, y, ignoredItem))
00274 fits |= INV_FITS_ONLY_ROTATED;
00275
00276 return fits;
00277 }
00278
00285 qboolean INVSH_CompareItem (item_t *item1, item_t *item2)
00286 {
00287 if (item1->t == item2->t && item1->m == item2->m && item1->a == item2->a)
00288 return qtrue;
00289
00290 return qfalse;
00291 }
00292
00299 static qboolean INVSH_ShapeCheckPosition (const invList_t *ic, const int x, const int y)
00300 {
00301 assert(ic);
00302
00303
00304 if (ic->item.rotated) {
00305 if (((INVSH_ShapeRotate(ic->item.t->shape) >> (x - ic->x) >> (y - ic->y) * SHAPE_SMALL_MAX_WIDTH)) & 1)
00306 return qtrue;
00307 } else {
00308 if (((ic->item.t->shape >> (x - ic->x) >> (y - ic->y) * SHAPE_SMALL_MAX_WIDTH)) & 1)
00309 return qtrue;
00310 }
00311
00312
00313 return qfalse;
00314 }
00315
00324 void INVSH_GetFirstShapePosition (const invList_t *ic, int* const x, int* const y)
00325 {
00326 int tempX, tempY;
00327
00328 assert(ic);
00329
00330 for (tempX = 0; tempX < SHAPE_SMALL_MAX_HEIGHT; tempX++)
00331 for (tempY = 0; tempY < SHAPE_SMALL_MAX_HEIGHT; tempY++)
00332 if (INVSH_ShapeCheckPosition(ic, ic->x + tempX, ic->y + tempY)) {
00333 *x = tempX;
00334 *y = tempY;
00335 return;
00336 }
00337
00338 *x = *y = NONE;
00339 }
00340
00348 qboolean INVSH_ExistsInInventory (const inventory_t* const inv, const invDef_t * container, item_t item)
00349 {
00350 invList_t *ic;
00351
00352 for (ic = inv->c[container->id]; ic; ic = ic->next)
00353 if (INVSH_CompareItem(&ic->item, &item)) {
00354 return qtrue;
00355 }
00356
00357 return qfalse;
00358 }
00359
00369 qboolean INV_IsCraftItem (const objDef_t *obj)
00370 {
00371 return obj->craftitem.type != MAX_ACITEMS && !obj->isDummy;
00372 }
00373
00383 qboolean INV_IsBaseDefenceItem (const objDef_t *obj)
00384 {
00385 return obj->craftitem.type != MAX_ACITEMS && obj->isDummy;
00386 }
00387
00396 invList_t *INVSH_SearchInInventory (const inventory_t* const i, const invDef_t * container, const int x, const int y)
00397 {
00398 invList_t *ic;
00399
00400 assert(container);
00401
00402
00403 if (container->single)
00404 return i->c[container->id];
00405
00406 if (container->scroll)
00407 Sys_Error("INVSH_SearchInInventory: Scrollable containers (%i:%s) are not supported by this function.\nUse INV_SearchInScrollableContainer instead!",
00408 container->id, container->name);
00409
00410
00411 for (ic = i->c[container->id]; ic; ic = ic->next)
00412 if (INVSH_ShapeCheckPosition(ic, x, y))
00413 return ic;
00414
00415
00416 return NULL;
00417 }
00418
00430 void INVSH_FindSpace (const inventory_t* const inv, const item_t *item, const invDef_t * container, int* const px, int* const py, const invList_t *ignoredItem)
00431 {
00432 int x, y;
00433
00434 assert(inv);
00435 assert(container);
00436 assert(!cacheCheckToInventory);
00437
00438
00439 if (container->scroll) {
00440 *px = *py = 0;
00441 return;
00442 }
00443
00446 for (y = 0; y < SHAPE_BIG_MAX_HEIGHT; y++) {
00447 for (x = 0; x < SHAPE_BIG_MAX_WIDTH; x++) {
00448 const int checkedTo = INVSH_CheckToInventory(inv, item->t, container, x, y, ignoredItem);
00449 if (checkedTo) {
00450 cacheCheckToInventory = INV_DOES_NOT_FIT;
00451 *px = x;
00452 *py = y;
00453 return;
00454 } else {
00455 cacheCheckToInventory = INV_FITS;
00456 }
00457 }
00458 }
00459 cacheCheckToInventory = INV_DOES_NOT_FIT;
00460
00461 #ifdef PARANOID
00462 Com_DPrintf(DEBUG_SHARED, "INVSH_FindSpace: no space for %s: %s in %s\n",
00463 item->t->type, item->t->id, container->name);
00464 #endif
00465 *px = *py = NONE;
00466 }
00467
00475 objDef_t *INVSH_GetItemByIDSilent (const char *id)
00476 {
00477 int i;
00478
00479 if (!id)
00480 return NULL;
00481 for (i = 0; i < CSI->numODs; i++) {
00482 objDef_t *item = &CSI->ods[i];
00483 if (!strcmp(id, item->id)) {
00484 return item;
00485 }
00486 }
00487 return NULL;
00488 }
00489
00493 objDef_t *INVSH_GetItemByIDX (int index)
00494 {
00495 if (index == NONE)
00496 return NULL;
00497
00498 if (index < 0 || index >= CSI->numODs)
00499 Sys_Error("Invalid object index given: %i", index);
00500
00501 return &CSI->ods[index];
00502 }
00503
00509 objDef_t *INVSH_GetItemByID (const char *id)
00510 {
00511 objDef_t *od = INVSH_GetItemByIDSilent(id);
00512 if (!od)
00513 Com_Printf("INVSH_GetItemByID: Item \"%s\" not found.\n", id);
00514
00515 return od;
00516 }
00517
00523 invDef_t *INVSH_GetInventoryDefinitionByID (const char *id)
00524 {
00525 containerIndex_t i;
00526 invDef_t *container;
00527
00528 for (i = 0, container = CSI->ids; i < CSI->numIDs; container++, i++)
00529 if (!strcmp(id, container->name))
00530 return container;
00531
00532 return NULL;
00533 }
00534
00541 qboolean INVSH_LoadableInWeapon (const objDef_t *od, const objDef_t *weapon)
00542 {
00543 int i;
00544 qboolean usable = qfalse;
00545
00546 #ifdef DEBUG
00547 if (!od) {
00548 Com_DPrintf(DEBUG_SHARED, "INVSH_LoadableInWeapon: No pointer given for 'od'.\n");
00549 return qfalse;
00550 }
00551 if (!weapon) {
00552 Com_DPrintf(DEBUG_SHARED, "INVSH_LoadableInWeapon: No weapon pointer given.\n");
00553 return qfalse;
00554 }
00555 #endif
00556
00557 if (od && od->numWeapons == 1 && od->weapons[0] && od->weapons[0] == od) {
00558
00559 return qfalse;
00560 }
00561
00562 for (i = 0; i < od->numWeapons; i++) {
00563 #ifdef DEBUG
00564 if (!od->weapons[i]) {
00565 Com_DPrintf(DEBUG_SHARED, "INVSH_LoadableInWeapon: No weapon pointer set for the %i. entry found in item '%s'.\n", i, od->id);
00566 break;
00567 }
00568 #endif
00569 if (weapon == od->weapons[i]) {
00570 usable = qtrue;
00571 break;
00572 }
00573 }
00574
00575 return usable;
00576 }
00577
00578
00579
00580
00581
00582
00583
00592 const fireDef_t* FIRESH_GetFiredef (const objDef_t *obj, const weaponFireDefIndex_t weapFdsIdx, const fireDefIndex_t fdIdx)
00593 {
00594 if (weapFdsIdx < 0 || weapFdsIdx >= MAX_WEAPONS_PER_OBJDEF)
00595 Sys_Error("FIRESH_GetFiredef: weapFdsIdx out of bounds [%i] for item '%s'", weapFdsIdx, obj->id);
00596 if (fdIdx < 0 || fdIdx >= MAX_FIREDEFS_PER_WEAPON)
00597 Sys_Error("FIRESH_GetFiredef: fdIdx out of bounds [%i] for item '%s'", fdIdx, obj->id);
00598 return &obj->fd[weapFdsIdx & (MAX_WEAPONS_PER_OBJDEF - 1)][fdIdx & (MAX_FIREDEFS_PER_WEAPON - 1)];
00599 }
00600
00607 const fireDef_t *FIRESH_FiredefForWeapon (const item_t *item)
00608 {
00609 int i;
00610 const objDef_t *ammo = item->m;
00611 const objDef_t *weapon = item->t;
00612
00613
00614
00615 if (weapon->numWeapons > 0)
00616 ammo = item->t;
00617
00618 if (!ammo)
00619 return NULL;
00620
00621 for (i = 0; i < ammo->numWeapons; i++) {
00622 if (weapon == ammo->weapons[i])
00623 return &ammo->fd[i][0];
00624 }
00625
00626 return NULL;
00627 }
00628
00634 const objDef_t* INVSH_HasReactionFireEnabledWeapon (const invList_t *invList)
00635 {
00636 if (!invList)
00637 return NULL;
00638
00639 while (invList) {
00640 if (invList->item.t) {
00641 const fireDef_t *fd = FIRESH_FiredefForWeapon(&invList->item);
00642 if (fd && fd->reaction)
00643 return invList->item.t;
00644 }
00645 invList = invList->next;
00646 }
00647
00648 return NULL;
00649 }
00650
00659 void INVSH_MergeShapes (uint32_t *shape, const uint32_t itemShape, const int x, const int y)
00660 {
00661 int i;
00662
00663 for (i = 0; (i < SHAPE_SMALL_MAX_HEIGHT) && (y + i < SHAPE_BIG_MAX_HEIGHT); i++)
00664 shape[y + i] |= ((itemShape >> i * SHAPE_SMALL_MAX_WIDTH) & 0xFF) << x;
00665 }
00666
00673 qboolean INVSH_CheckShape (const uint32_t *shape, const int x, const int y)
00674 {
00675 const uint32_t row = shape[y];
00676 int position = pow(2, x);
00677
00678 if (y >= SHAPE_BIG_MAX_HEIGHT || x >= SHAPE_BIG_MAX_WIDTH || x < 0 || y < 0) {
00679 Com_Printf("INVSH_CheckShape: Bad x or y value: (x=%i, y=%i)\n", x, y);
00680 return qfalse;
00681 }
00682
00683 if ((row & position) == 0)
00684 return qfalse;
00685 else
00686 return qtrue;
00687 }
00688
00695 static qboolean INVSH_CheckShapeSmall (const uint32_t shape, const int x, const int y)
00696 {
00697 if (y >= SHAPE_BIG_MAX_HEIGHT || x >= SHAPE_BIG_MAX_WIDTH || x < 0 || y < 0) {
00698 Com_Printf("INVSH_CheckShapeSmall: Bad x or y value: (x=%i, y=%i)\n", x, y);
00699 return qfalse;
00700 }
00701
00702 return shape & (0x01 << (y * SHAPE_SMALL_MAX_WIDTH + x));
00703 }
00704
00711 int INVSH_ShapeSize (const uint32_t shape)
00712 {
00713 int bitCounter = 0;
00714 int i;
00715
00716 for (i = 0; i < SHAPE_SMALL_MAX_HEIGHT * SHAPE_SMALL_MAX_WIDTH; i++)
00717 if (shape & (1 << i))
00718 bitCounter++;
00719
00720 return bitCounter;
00721 }
00722
00732 static uint32_t INVSH_ShapeSetBit (uint32_t shape, const int x, const int y)
00733 {
00734 if (x >= SHAPE_SMALL_MAX_WIDTH || y >= SHAPE_SMALL_MAX_HEIGHT || x < 0 || y < 0) {
00735 Com_Printf("INVSH_ShapeSetBit: Bad x or y value: (x=%i, y=%i)\n", x,y);
00736 return shape;
00737 }
00738
00739 shape |= 0x01 << (y * SHAPE_SMALL_MAX_WIDTH + x);
00740 return shape;
00741 }
00742
00743
00750 uint32_t INVSH_ShapeRotate (const uint32_t shape)
00751 {
00752 int h, w;
00753 uint32_t shapeNew = 0;
00754 int maxWidth = -1;
00755
00756 for (w = SHAPE_SMALL_MAX_WIDTH - 1; w >= 0; w--) {
00757 for (h = 0; h < SHAPE_SMALL_MAX_HEIGHT; h++) {
00758 if (INVSH_CheckShapeSmall(shape, w, h)) {
00759 if (w >= SHAPE_SMALL_MAX_HEIGHT) {
00760
00761 return shape;
00762 }
00763
00764 if (maxWidth < 0)
00765 maxWidth = w;
00766
00767 shapeNew = INVSH_ShapeSetBit(shapeNew, h, maxWidth - w);
00768 }
00769 }
00770 }
00771
00772 return shapeNew;
00773 }