00001 #include "inventory.h"
00002
00003 static inline void I_Free (inventoryInterface_t* self, void *data)
00004 {
00005 self->import->Free(data);
00006 }
00007
00008 static inline void *I_Alloc (inventoryInterface_t* self, size_t size)
00009 {
00010 return self->import->Alloc(size);
00011 }
00012
00013 static void I_RemoveInvList (inventoryInterface_t* self, invList_t *invList)
00014 {
00015 Com_DPrintf(DEBUG_SHARED, "I_RemoveInvList: remove one slot (%s)\n", self->name);
00016
00017
00018 if (self->invList == invList) {
00019 invList_t *ic = self->invList;
00020 self->invList = ic->next;
00021 I_Free(self, ic);
00022 } else {
00023 invList_t *ic = self->invList;
00024 invList_t* prev = NULL;
00025 while (ic) {
00026 if (ic == invList) {
00027 prev->next = ic->next;
00028 I_Free(self, ic);
00029 break;
00030 }
00031 prev = ic;
00032 ic = ic->next;
00033 }
00034 }
00035 }
00036
00037 static invList_t* I_AddInvList (inventoryInterface_t* self, invList_t **invList)
00038 {
00039 invList_t *newEntry;
00040 invList_t *list;
00041
00042 Com_DPrintf(DEBUG_SHARED, "I_AddInvList: add one slot (%s)\n", self->name);
00043
00044
00045 if (!*invList) {
00046 *invList = (invList_t*)I_Alloc(self, sizeof(**invList));
00047 (*invList)->next = NULL;
00048 return *invList;
00049 } else
00050 list = *invList;
00051
00052 while (list->next)
00053 list = list->next;
00054
00055 newEntry = (invList_t*)I_Alloc(self, sizeof(*newEntry));
00056 list->next = newEntry;
00057 newEntry->next = NULL;
00058
00059 return newEntry;
00060 }
00061
00074 static invList_t *I_AddToInventory (inventoryInterface_t* self, inventory_t * const i, item_t item, const invDef_t * container, int x, int y, int amount)
00075 {
00076 invList_t *ic;
00077
00078 if (!item.t)
00079 return NULL;
00080
00081 if (amount <= 0)
00082 return NULL;
00083
00084 assert(i);
00085 assert(container);
00086
00087 if (container->single && i->c[container->id] && i->c[container->id]->next)
00088 return NULL;
00089
00114
00115 if (container->temp) {
00116 for (ic = i->c[container->id]; ic; ic = ic->next)
00117 if (INVSH_CompareItem(&ic->item, &item)) {
00118 ic->item.amount += amount;
00119 Com_DPrintf(DEBUG_SHARED, "I_AddToInventory: Amount of '%s': %i (%s)\n",
00120 ic->item.t->name, ic->item.amount, self->name);
00121 return ic;
00122 }
00123 }
00124
00125 if (x < 0 || y < 0 || x >= SHAPE_BIG_MAX_WIDTH || y >= SHAPE_BIG_MAX_HEIGHT) {
00126
00127 INVSH_FindSpace(i, &item, container, &x, &y, NULL);
00128 if (x == NONE)
00129 return NULL;
00130 }
00131
00132
00133 ic = I_AddInvList(self, &i->c[container->id]);
00134
00135
00136 ic->item = item;
00137 ic->item.amount = amount;
00138 ic->x = x;
00139 ic->y = y;
00140
00141 return ic;
00142 }
00143
00152 static qboolean I_RemoveFromInventory (inventoryInterface_t* self, inventory_t* const i, const invDef_t * container, invList_t *fItem)
00153 {
00154 invList_t *ic, *previous;
00155
00156 assert(i);
00157 assert(container);
00158 assert(fItem);
00159
00160 ic = i->c[container->id];
00161 if (!ic)
00162 return qfalse;
00163
00169 if (container->single || ic == fItem) {
00170 self->cacheItem = ic->item;
00171
00172 if (container->temp && ic->item.amount > 1) {
00173 ic->item.amount--;
00174 Com_DPrintf(DEBUG_SHARED, "I_RemoveFromInventory: Amount of '%s': %i (%s)\n",
00175 ic->item.t->name, ic->item.amount, self->name);
00176 return qtrue;
00177 }
00178
00179 if (container->single && ic->next)
00180 Com_Printf("I_RemoveFromInventory: Error: single container %s has many items. (%s)\n", container->name, self->name);
00181
00182
00183
00184
00185 assert(ic->item.amount == 1);
00186
00187 i->c[container->id] = ic->next;
00188
00189
00190 I_RemoveInvList(self, ic);
00191
00192 return qtrue;
00193 }
00194
00195 for (previous = i->c[container->id]; ic; ic = ic->next) {
00196 if (ic == fItem) {
00197 self->cacheItem = ic->item;
00198
00199 if (ic->item.amount > 1 && container->temp) {
00200 ic->item.amount--;
00201 Com_DPrintf(DEBUG_SHARED, "I_RemoveFromInventory: Amount of '%s': %i (%s)\n",
00202 ic->item.t->name, ic->item.amount, self->name);
00203 return qtrue;
00204 }
00205
00206 if (ic == i->c[container->id])
00207 i->c[container->id] = i->c[container->id]->next;
00208 else
00209 previous->next = ic->next;
00210
00211 I_RemoveInvList(self, ic);
00212
00213 return qtrue;
00214 }
00215 previous = ic;
00216 }
00217 return qfalse;
00218 }
00219
00239 static int I_MoveInInventory (inventoryInterface_t* self, inventory_t* const i, const invDef_t * from, invList_t *fItem, const invDef_t * to, int tx, int ty, int *TU, invList_t ** icp)
00240 {
00241 invList_t *ic;
00242
00243 int time;
00244 int checkedTo = INV_DOES_NOT_FIT;
00245 qboolean alreadyRemovedSource = qfalse;
00246
00247 assert(to);
00248 assert(from);
00249
00250 if (icp)
00251 *icp = NULL;
00252
00253 if (from == to && fItem->x == tx && fItem->y == ty)
00254 return IA_NONE;
00255
00256 time = from->out + to->in;
00257 if (from == to) {
00258 if (INV_IsFloorDef(from))
00259 time = 0;
00260 else
00261 time /= 2;
00262 }
00263
00264 if (TU && *TU < time)
00265 return IA_NOTIME;
00266
00267 assert(i);
00268
00269
00270 if (from == to) {
00271
00272 if (from->scroll)
00273 return IA_NONE;
00274
00275 ic = i->c[from->id];
00276 for (; ic; ic = ic->next) {
00277 if (ic == fItem) {
00278 if (ic->item.amount > 1) {
00279 checkedTo = INVSH_CheckToInventory(i, ic->item.t, to, tx, ty, fItem);
00280 if (checkedTo & INV_FITS) {
00281 ic->x = tx;
00282 ic->y = ty;
00283 if (icp)
00284 *icp = ic;
00285 return IA_MOVE;
00286 }
00287 return IA_NONE;
00288 }
00289 }
00290 }
00291 }
00292
00293
00294
00295 if (fItem->item.t->fireTwoHanded && INV_IsLeftDef(to) && INV_IsRightDef(from)) {
00296 return IA_NONE;
00297 }
00298
00299
00300
00301 if ((to->armour && !INV_IsArmour(fItem->item.t))
00302 || (to->extension && !fItem->item.t->extension)
00303 || (to->headgear && !fItem->item.t->headgear)) {
00304 return IA_NONE;
00305 }
00306
00307
00308 if (to->single)
00309 checkedTo = INVSH_CheckToInventory(i, fItem->item.t, to, 0, 0, fItem);
00310 else {
00311 if (tx == NONE || ty == NONE)
00312 INVSH_FindSpace(i, &fItem->item, to, &tx, &ty, fItem);
00313
00314 if (tx == NONE || ty == NONE)
00315 return IA_NONE;
00316
00317 checkedTo = INVSH_CheckToInventory(i, fItem->item.t, to, tx, ty, fItem);
00318 }
00319
00320 if (to->armour && from != to && !checkedTo) {
00321 item_t cacheItem2;
00322 invList_t *icTo;
00323
00324
00325 const int cacheFromX = fItem->x;
00326 const int cacheFromY = fItem->y;
00327
00328
00329
00330 icTo = INVSH_SearchInInventory(i, to, tx, ty);
00331 if (fItem->item.t == icTo->item.t)
00332 return IA_NONE;
00333
00334
00335 if (!self->RemoveFromInventory(self, i, from, fItem))
00336 return IA_NONE;
00337 else
00338
00339 alreadyRemovedSource = qtrue;
00340
00341 cacheItem2 = self->cacheItem;
00342
00343
00344 self->MoveInInventory(self, i, to, icTo, from, cacheFromX, cacheFromY, TU, icp);
00345
00346
00347 self->cacheItem = cacheItem2;
00348 } else if (!checkedTo) {
00349
00350
00351 ic = INVSH_SearchInInventory(i, to, tx, ty);
00352
00353 if (ic && !INV_IsEquipDef(to) && INVSH_LoadableInWeapon(fItem->item.t, ic->item.t)) {
00354
00355
00356 if (ic->item.a >= ic->item.t->ammo && ic->item.m == fItem->item.t) {
00357
00358 return IA_NORELOAD;
00359 }
00360 time += ic->item.t->reload;
00361 if (!TU || *TU >= time) {
00362 if (TU)
00363 *TU -= time;
00364 if (ic->item.a >= ic->item.t->ammo) {
00365
00366 const item_t item = {NONE_AMMO, NULL, ic->item.m, 0, 0};
00367
00368
00369 if (!self->RemoveFromInventory(self, i, from, fItem))
00370 return IA_NONE;
00371
00372
00373 if (self->AddToInventory(self, i, item, from, NONE, NONE, 1) == NULL)
00374 Sys_Error("Could not reload the weapon - add to inventory failed (%s)", self->name);
00375
00376 ic->item.m = self->cacheItem.t;
00377 if (icp)
00378 *icp = ic;
00379 return IA_RELOAD_SWAP;
00380 } else {
00381
00382 if (!self->RemoveFromInventory(self, i, from, fItem))
00383 return IA_NONE;
00384
00385 ic->item.m = self->cacheItem.t;
00386
00387 ic->item.a = ic->item.t->ammo;
00388 if (icp)
00389 *icp = ic;
00390 return IA_RELOAD;
00391 }
00392 }
00393
00394 return IA_NOTIME;
00395 }
00396
00397
00398 if (ic && to->temp) {
00399
00400
00401
00403 INVSH_FindSpace(i, &fItem->item, to, &tx, &ty, fItem);
00404 if (tx == NONE || ty == NONE) {
00405 Com_DPrintf(DEBUG_SHARED, "I_MoveInInventory - item will be added non-visible (%s)\n", self->name);
00406 }
00407 } else {
00408
00409 return IA_NONE;
00410 }
00411 }
00412
00413
00414 if (fItem->item.t->fireTwoHanded && INV_IsLeftDef(to))
00415 to = &self->csi->ids[self->csi->idRight];
00416
00417 if (checkedTo == INV_FITS_ONLY_ROTATED) {
00418
00419 fItem->item.rotated = qtrue;
00420 } else if (fItem->item.rotated) {
00421
00422 fItem->item.rotated = qfalse;
00423 }
00424
00425
00426 if (!alreadyRemovedSource)
00427 if (!self->RemoveFromInventory(self, i, from, fItem))
00428 return IA_NONE;
00429
00430
00431 if (TU)
00432 *TU -= time;
00433
00434 assert(self->cacheItem.t);
00435 ic = self->AddToInventory(self, i, self->cacheItem, to, tx, ty, 1);
00436
00437
00438 if (icp) {
00439 assert(ic);
00440 *icp = ic;
00441 }
00442
00443 if (INV_IsArmourDef(to)) {
00444 assert(INV_IsArmour(self->cacheItem.t));
00445 return IA_ARMOUR;
00446 } else
00447 return IA_MOVE;
00448 }
00449
00458 static qboolean I_TryAddToInventory (inventoryInterface_t* self, inventory_t* const inv, item_t item, const invDef_t * container)
00459 {
00460 int x, y;
00461
00462 INVSH_FindSpace(inv, &item, container, &x, &y, NULL);
00463
00464 if (x == NONE) {
00465 assert(y == NONE);
00466 return qfalse;
00467 } else {
00468 const int checkedTo = INVSH_CheckToInventory(inv, item.t, container, x, y, NULL);
00469 if (!checkedTo)
00470 return qfalse;
00471 else if (checkedTo == INV_FITS_ONLY_ROTATED)
00472 item.rotated = qtrue;
00473 else
00474 item.rotated = qfalse;
00475
00476 return self->AddToInventory(self, inv, item, container, x, y, 1) != NULL;
00477 }
00478 }
00479
00489 static void I_EmptyContainer (inventoryInterface_t* self, inventory_t* const i, const invDef_t * container)
00490 {
00491 invList_t *ic;
00492
00493 ic = i->c[container->id];
00494
00495 while (ic) {
00496 invList_t *old = ic;
00497 ic = ic->next;
00498 I_RemoveInvList(self, old);
00499 }
00500
00501 i->c[container->id] = NULL;
00502 }
00503
00511 static void I_DestroyInventory (inventoryInterface_t* self, inventory_t* const i)
00512 {
00513 containerIndex_t container;
00514
00515 if (!i)
00516 return;
00517
00518 for (container = 0; container < self->csi->numIDs; container++) {
00519 const invDef_t *invDef = &self->csi->ids[container];
00520 if (!invDef->temp)
00521 self->EmptyContainer(self, i, invDef);
00522 }
00523
00524 memset(i, 0, sizeof(*i));
00525 }
00526
00527
00528 #define WEAPONLESS_BONUS 0.4
00529
00538 static int I_PackAmmoAndWeapon (inventoryInterface_t *self, inventory_t* const inv, objDef_t* weapon, int missedPrimary, const equipDef_t *ed)
00539 {
00540 objDef_t *ammo = NULL;
00541 item_t item = {NONE_AMMO, NULL, NULL, 0, 0};
00542 qboolean allowLeft;
00543 qboolean packed;
00544 int ammoMult = 1;
00545
00546 assert(!INV_IsArmour(weapon));
00547 item.t = weapon;
00548
00549
00550 allowLeft = !(inv->c[self->csi->idRight] && inv->c[self->csi->idRight]->item.t->fireTwoHanded);
00551
00552 if (!weapon->reload) {
00553 item.m = item.t;
00554 } else {
00555 if (weapon->oneshot) {
00556
00557 item.a = weapon->ammo;
00558 item.m = weapon;
00559 Com_DPrintf(DEBUG_SHARED, "I_PackAmmoAndWeapon: oneshot weapon '%s' in equipment '%s' (%s).\n",
00560 weapon->id, ed->name, self->name);
00561 } else {
00562
00563
00564 int totalAvailableAmmo = 0;
00565 int i;
00566 for (i = 0; i < self->csi->numODs; i++) {
00567 objDef_t *obj = INVSH_GetItemByIDX(i);
00568 if (ed->numItems[i] && INVSH_LoadableInWeapon(obj, weapon)) {
00569 totalAvailableAmmo++;
00570 }
00571 }
00572 if (totalAvailableAmmo) {
00573 int randNumber = rand() % totalAvailableAmmo;
00574 for (i = 0; i < self->csi->numODs; i++) {
00575 objDef_t *obj = INVSH_GetItemByIDX(i);
00576 if (ed->numItems[i] && INVSH_LoadableInWeapon(obj, weapon)) {
00577 randNumber--;
00578 if (randNumber < 0) {
00579 ammo = obj;
00580 break;
00581 }
00582 }
00583 }
00584 }
00585
00586 if (!ammo) {
00587 Com_DPrintf(DEBUG_SHARED, "I_PackAmmoAndWeapon: no ammo for sidearm or primary weapon '%s' in equipment '%s' (%s).\n",
00588 weapon->id, ed->name, self->name);
00589 return 0;
00590 }
00591
00592 item.a = weapon->ammo;
00593 item.m = ammo;
00594 }
00595 }
00596
00597 if (!item.m) {
00598 Com_Printf("I_PackAmmoAndWeapon: no ammo for sidearm or primary weapon '%s' in equipment '%s' (%s).\n",
00599 weapon->id, ed->name, self->name);
00600 return 0;
00601 }
00602
00603
00604 packed = self->TryAddToInventory(self, inv, item, &self->csi->ids[self->csi->idRight]);
00605 if (packed)
00606 ammoMult = 3;
00607 if (!packed && allowLeft)
00608 packed = self->TryAddToInventory(self, inv, item, &self->csi->ids[self->csi->idLeft]);
00609 if (!packed)
00610 packed = self->TryAddToInventory(self, inv, item, &self->csi->ids[self->csi->idBelt]);
00611 if (!packed)
00612 packed = self->TryAddToInventory(self, inv, item, &self->csi->ids[self->csi->idHolster]);
00613 if (!packed)
00614 return 0;
00615
00616
00617
00618 if (ammo) {
00619 int num;
00620 int numpacked = 0;
00621
00622
00623 num = (1 + ed->numItems[ammo->idx])
00624 * (float) (1.0f + missedPrimary / 100.0);
00625
00626
00627 while (num--) {
00628 item_t mun = {NONE_AMMO, NULL, NULL, 0, 0};
00629
00630 mun.t = ammo;
00631
00632 numpacked += self->TryAddToInventory(self, inv, mun, &self->csi->ids[self->csi->idBackpack]);
00633
00634 if (numpacked > ammoMult || numpacked * weapon->ammo > 11)
00635 break;
00636 }
00637 }
00638
00639 return qtrue;
00640 }
00641
00642
00649 static void I_EquipActorMelee (inventoryInterface_t *self, inventory_t* const inv, const teamDef_t* td)
00650 {
00651 objDef_t *obj;
00652 item_t item;
00653
00654 assert(td->onlyWeapon);
00655
00656
00657 obj = td->onlyWeapon;
00658
00659
00660 item.t = obj;
00661 item.m = item.t;
00662 item.a = NONE_AMMO;
00663
00664 if (!obj->fireTwoHanded)
00665 Sys_Error("INVSH_EquipActorMelee: melee weapon %s for team %s is not firetwohanded! (%s)\n",
00666 obj->id, td->id, self->name);
00667 self->TryAddToInventory(self, inv, item, &self->csi->ids[self->csi->idRight]);
00668 }
00669
00676 static void I_EquipActorRobot (inventoryInterface_t *self, inventory_t* const inv, objDef_t* weapon)
00677 {
00678 item_t item;
00679
00680 assert(weapon);
00681
00682
00683 item.t = weapon;
00684 item.a = NONE_AMMO;
00685
00686
00687 assert(weapon->numAmmos > 0);
00688 assert(weapon->ammos[0]);
00689 item.m = weapon->ammos[0];
00690
00691 self->TryAddToInventory(self, inv, item, &self->csi->ids[self->csi->idRight]);
00692 }
00693
00697 typedef enum {
00698 WEAPON_PARTICLE_OR_NORMAL = 0,
00699 WEAPON_OTHER = 1,
00700 WEAPON_NO_PRIMARY = 2
00701 } equipPrimaryWeaponType_t;
00702
00714 static void I_EquipActor (inventoryInterface_t* self, inventory_t* const inv, const equipDef_t *ed, const teamDef_t* td)
00715 {
00716 int i;
00717 const int numEquip = lengthof(ed->numItems);
00718 int repeat = 0;
00719 const float AKIMBO_CHANCE = 0.3;
00722 if (td->weapons) {
00723 equipPrimaryWeaponType_t primary = WEAPON_NO_PRIMARY;
00724 int sum;
00725 int missedPrimary = 0;
00727 objDef_t *primaryWeapon = NULL;
00728 int hasWeapon = 0;
00729
00730 const int maxWeaponIdx = min(self->csi->numODs - 1, numEquip - 1);
00731 int randNumber = rand() % 100;
00732 for (i = 0; i < maxWeaponIdx; i++) {
00733 objDef_t *obj = INVSH_GetItemByIDX(i);
00734 if (ed->numItems[i] && obj->weapon && obj->fireTwoHanded && obj->isPrimary) {
00735 randNumber -= ed->numItems[i];
00736 missedPrimary += ed->numItems[i];
00737 if (!primaryWeapon && randNumber < 0)
00738 primaryWeapon = obj;
00739 }
00740 }
00741
00742 if (primaryWeapon) {
00743 hasWeapon += I_PackAmmoAndWeapon(self, inv, primaryWeapon, 0, ed);
00744 if (hasWeapon) {
00745 int ammo;
00746
00747
00748 for (ammo = 0; ammo < self->csi->numODs; ammo++)
00749 if (ed->numItems[ammo] && INVSH_LoadableInWeapon(&self->csi->ods[ammo], primaryWeapon))
00750 break;
00751 if (ammo < self->csi->numODs) {
00752 primary =
00753
00754 !(self->csi->ods[ammo].dmgtype == self->csi->damParticle)
00755
00756 && !(self->csi->ods[ammo].dmgtype == self->csi->damNormal);
00757 }
00758
00759 missedPrimary = 0;
00760 } else {
00761 Com_DPrintf(DEBUG_SHARED, "INVSH_EquipActor: primary weapon '%s' couldn't be equipped in equipment '%s' (%s).\n",
00762 primaryWeapon->id, ed->name, self->name);
00763 repeat = WEAPONLESS_BONUS > frand();
00764 }
00765 }
00766
00767
00768 do {
00769 int randNumber = rand() % 100;
00770 objDef_t *secondaryWeapon = NULL;
00771 for (i = 0; i < self->csi->numODs; i++) {
00772 objDef_t *obj = INVSH_GetItemByIDX(i);
00773 if (ed->numItems[i] && obj->weapon && obj->reload && !obj->deplete && obj->isSecondary) {
00774 randNumber -= ed->numItems[i] / (primary == WEAPON_PARTICLE_OR_NORMAL ? 2 : 1);
00775 if (randNumber < 0) {
00776 secondaryWeapon = obj;
00777 break;
00778 }
00779 }
00780 }
00781
00782 if (secondaryWeapon) {
00783 hasWeapon += I_PackAmmoAndWeapon(self, inv, secondaryWeapon, missedPrimary, ed);
00784 if (hasWeapon) {
00785
00786 if (primary == WEAPON_NO_PRIMARY && !secondaryWeapon->fireTwoHanded && frand() < AKIMBO_CHANCE) {
00787 I_PackAmmoAndWeapon(self, inv, secondaryWeapon, 0, ed);
00788 }
00789 }
00790 }
00791 } while (!hasWeapon && repeat--);
00792
00793
00794 if (!hasWeapon)
00795 repeat = WEAPONLESS_BONUS > frand();
00796 else
00797 repeat = 0;
00798
00799
00800 sum = 0;
00801 for (i = 0; i < self->csi->numODs; i++) {
00802 objDef_t *obj = INVSH_GetItemByIDX(i);
00803 if (ed->numItems[i] && ((obj->weapon && obj->isSecondary
00804 && (!obj->reload || obj->deplete)) || obj->isMisc)) {
00805
00806
00807
00808 sum += ed->numItems[i] ? max(ed->numItems[i] % 100, 1) : 0;
00809 }
00810 }
00811 if (sum) {
00812 do {
00813 int randNumber = rand() % sum;
00814 objDef_t *secondaryWeapon = NULL;
00815 for (i = 0; i < self->csi->numODs; i++) {
00816 objDef_t *obj = INVSH_GetItemByIDX(i);
00817 if (ed->numItems[i] && ((obj->weapon && obj->isSecondary
00818 && (!obj->reload || obj->deplete)) || obj->isMisc)) {
00819 randNumber -= ed->numItems[i] ? max(ed->numItems[i] % 100, 1) : 0;
00820 if (randNumber < 0) {
00821 secondaryWeapon = obj;
00822 break;
00823 }
00824 }
00825 }
00826
00827 if (secondaryWeapon) {
00828 int num = ed->numItems[secondaryWeapon->idx] / 100 + (ed->numItems[secondaryWeapon->idx] % 100 >= 100 * frand());
00829 while (num--) {
00830 hasWeapon += I_PackAmmoAndWeapon(self, inv, secondaryWeapon, 0, ed);
00831 }
00832 }
00833 } while (repeat--);
00834 }
00835
00836
00837 if (!hasWeapon) {
00838 int maxPrice = 0;
00839 objDef_t *blade = NULL;
00840 Com_DPrintf(DEBUG_SHARED, "INVSH_EquipActor: no weapon picked in equipment '%s', defaulting to the most expensive secondary weapon without reload. (%s)\n",
00841 ed->name, self->name);
00842 for (i = 0; i < self->csi->numODs; i++) {
00843 objDef_t *obj = INVSH_GetItemByIDX(i);
00844 if (ed->numItems[i] && obj->weapon && obj->isSecondary && !obj->reload) {
00845 if (obj->price > maxPrice) {
00846 maxPrice = obj->price;
00847 blade = obj;
00848 }
00849 }
00850 }
00851 if (maxPrice)
00852 hasWeapon += I_PackAmmoAndWeapon(self, inv, blade, 0, ed);
00853 }
00854
00855 if (!hasWeapon)
00856 Com_DPrintf(DEBUG_SHARED, "INVSH_EquipActor: cannot add any weapon; no secondary weapon without reload detected for equipment '%s' (%s).\n",
00857 ed->name, self->name);
00858
00859
00860 repeat = (float) missedPrimary > frand() * 100.0;
00861 } else {
00862 return;
00863 }
00864
00865 if (td->armour) {
00866 do {
00867 int randNumber = rand() % 100;
00868 for (i = 0; i < self->csi->numODs; i++) {
00869 objDef_t *armour = INVSH_GetItemByIDX(i);
00870 if (ed->numItems[i] && INV_IsArmour(armour)) {
00871 randNumber -= ed->numItems[i];
00872 if (randNumber < 0) {
00873 const item_t item = {NONE_AMMO, NULL, armour, 0, 0};
00874 if (self->TryAddToInventory(self, inv, item, &self->csi->ids[self->csi->idArmour])) {
00875 repeat = 0;
00876 break;
00877 }
00878 }
00879 }
00880 }
00881 } while (repeat-- > 0);
00882 } else {
00883 Com_DPrintf(DEBUG_SHARED, "INVSH_EquipActor: teamdef '%s' may not carry armour (%s)\n",
00884 td->name, self->name);
00885 }
00886
00887 {
00888 int randNumber = rand() % 10;
00889 for (i = 0; i < self->csi->numODs; i++) {
00890 if (ed->numItems[i]) {
00891 objDef_t *miscItem = INVSH_GetItemByIDX(i);
00892 if (miscItem->isMisc && !miscItem->weapon) {
00893 randNumber -= ed->numItems[i];
00894 if (randNumber < 0) {
00895 const item_t item = {NONE_AMMO, NULL, miscItem, 0, 0};
00896 containerIndex_t container;
00897 if (miscItem->headgear)
00898 container = self->csi->idHeadgear;
00899 else if (miscItem->extension)
00900 container = self->csi->idExtension;
00901 else
00902 container = self->csi->idBackpack;
00903 self->TryAddToInventory(self, inv, item, &self->csi->ids[container]);
00904 }
00905 }
00906 }
00907 }
00908 }
00909 }
00910
00915 static int I_GetUsedSlots (inventoryInterface_t* self)
00916 {
00917 int i = 0;
00918 const invList_t* slot = self->invList;
00919 while (slot) {
00920 slot = slot->next;
00921 i++;
00922 }
00923 Com_DPrintf(DEBUG_SHARED, "Used inventory slots %i (%s)\n", i, self->name);
00924 return i;
00925 }
00926
00937 void INV_InitInventory (const char *name, inventoryInterface_t *interface, csi_t* csi, const inventoryImport_t *import)
00938 {
00939 const item_t item = {NONE_AMMO, NULL, NULL, 0, 0};
00940
00941 memset(interface, 0, sizeof(*interface));
00942
00943 interface->import = import;
00944 interface->name = name;
00945 interface->cacheItem = item;
00946 interface->csi = csi;
00947 interface->invList = NULL;
00948
00949 interface->TryAddToInventory = I_TryAddToInventory;
00950 interface->AddToInventory = I_AddToInventory;
00951 interface->RemoveFromInventory = I_RemoveFromInventory;
00952 interface->MoveInInventory = I_MoveInInventory;
00953 interface->DestroyInventory = I_DestroyInventory;
00954 interface->EmptyContainer = I_EmptyContainer;
00955 interface->EquipActor = I_EquipActor;
00956 interface->EquipActorMelee = I_EquipActorMelee;
00957 interface->EquipActorRobot = I_EquipActorRobot;
00958 interface->GetUsedSlots = I_GetUsedSlots;
00959 }
00960
00961 void INV_DestroyInventory (inventoryInterface_t *interface)
00962 {
00963 if (interface->import == NULL)
00964 return;
00965 interface->import->FreeAll();
00966 memset(interface, 0, sizeof(*interface));
00967 }