perfect_dark/src/game/inv.c

1139 lines
25 KiB
C

#include <ultra64.h>
#include "constants.h"
#include "game/cheats.h"
#include "game/bondgun.h"
#include "game/game_0b0fd0.h"
#include "game/inv.h"
#include "game/training.h"
#include "game/lang.h"
#include "bss.h"
#include "lib/main.h"
#include "data.h"
#include "types.h"
void invClear(void)
{
s32 i;
for (i = 0; i < g_Vars.currentplayer->equipmaxitems; i++) {
g_Vars.currentplayer->equipment[i].type = -1;
}
g_Vars.currentplayer->weapons = NULL;
g_Vars.currentplayer->equipcuritem = 0;
}
/**
* Sorts subject into its correct position in the inventory list.
*
* Subject is expected to initially be at the head of the list. It works by
* swapping the subject with the item to its right as many times as needed.
*/
static void invSortItem(struct invitem *subject)
{
struct invitem *candidate;
s32 subjweapon1 = -1;
s32 subjweapon2 = -1;
s32 candweapon1;
s32 candweapon2;
// Prepare subject's properties for comparisons
if (subject->type == INVITEMTYPE_WEAP) {
subjweapon1 = subject->type_weap.weapon1;
} else if (subject->type == INVITEMTYPE_DUAL) {
subjweapon1 = subject->type_dual.weapon1;
subjweapon2 = subject->type_dual.weapon2;
} else if (subject->type == INVITEMTYPE_PROP) {
subjweapon1 = 2000;
}
candidate = subject->next;
while (g_Vars.currentplayer->weapons != subject->next) {
// Prepare candidate's properties for comparisons
candweapon1 = -1;
candweapon2 = -1;
if (subject->next->type == INVITEMTYPE_WEAP) {
candweapon1 = subject->next->type_weap.weapon1;
} else if (subject->next->type == INVITEMTYPE_DUAL) {
candweapon1 = subject->next->type_dual.weapon1;
candweapon2 = subject->next->type_dual.weapon2;
} else if (subject->next->type == INVITEMTYPE_PROP) {
candweapon1 = 1000;
}
// If the candidate should sort ahead of subject
// then subject is in the desired position.
if (candweapon1 >= subjweapon1 &&
(subjweapon1 != candweapon1 || subjweapon2 <= candweapon2)) {
return;
}
// If there's only two items in the list then there's no point swapping
// them. Just set the list head to the candidate.
if (candidate->next == subject) {
g_Vars.currentplayer->weapons = candidate;
} else {
// Swap subject with candidate
subject->next = candidate->next;
candidate->prev = subject->prev;
subject->prev = candidate;
candidate->next = subject;
subject->next->prev = subject;
candidate->prev->next = candidate;
// Set new list head if subject was the head
if (subject == g_Vars.currentplayer->weapons) {
g_Vars.currentplayer->weapons = candidate;
}
}
candidate = subject->next;
}
}
static void invInsertItem(struct invitem *item)
{
if (item->type == INVITEMTYPE_PROP) {
struct prop *prop = item->type_prop.prop;
if (prop && prop->obj) {
struct textoverride *override = invGetTextOverrideForObj(prop->obj);
bool setflag = true;
if (override) {
if (override->weapon >= WEAPON_UNARMED && override->weapon <= WEAPON_NECKLACE) {
setflag = false;
}
if (override->weapon == WEAPON_MPSHIELD) {
setflag = false;
}
if (override->weapon == WEAPON_SUICIDEPILL) {
setflag = false;
}
if (override->weapon == WEAPON_BRIEFCASE2) {
setflag = false;
}
}
if (setflag && prop->type == PROPTYPE_OBJ) {
struct defaultobj *obj = prop->obj;
obj->flags2 |= OBJFLAG2_00040000;
}
}
}
// Place item at head of weapons list
if (g_Vars.currentplayer->weapons) {
item->next = g_Vars.currentplayer->weapons;
item->prev = g_Vars.currentplayer->weapons->prev;
item->next->prev = item;
item->prev->next = item;
} else {
item->next = item;
item->prev = item;
}
g_Vars.currentplayer->weapons = item;
invSortItem(item);
invCalculateCurrentIndex();
}
static void invRemoveItem(struct invitem *item)
{
struct invitem *next = item->next;
struct invitem *prev = item->prev;
if (g_Vars.currentplayer->weapons == item) {
if (item == item->next) {
g_Vars.currentplayer->weapons = NULL;
} else {
g_Vars.currentplayer->weapons = item->next;
}
}
next->prev = prev;
prev->next = next;
item->type = -1;
invCalculateCurrentIndex();
}
static struct invitem *invFindUnusedSlot(void)
{
s32 i;
for (i = 0; i < g_Vars.currentplayer->equipmaxitems; i++) {
if (g_Vars.currentplayer->equipment[i].type == -1) {
return &g_Vars.currentplayer->equipment[i];
}
}
return NULL;
}
void invSetAllGuns(bool enable)
{
s32 weaponnum;
g_Vars.currentplayer->equipallguns = enable;
invCalculateCurrentIndex();
weaponnum = invGetWeaponNumByIndex(g_Vars.currentplayer->equipcuritem);
bgunEquipWeapon(weaponnum);
}
struct invitem *invFindSingleWeapon(s32 weaponnum)
{
struct invitem *first = g_Vars.currentplayer->weapons;
struct invitem *item = first;
while (item) {
if (item->type == INVITEMTYPE_WEAP && item->type_weap.weapon1 == weaponnum) {
return item;
}
item = item->next;
if (item == first) {
break;
}
}
return NULL;
}
bool invHasSingleWeaponExcAllGuns(s32 weaponnum)
{
return invFindSingleWeapon(weaponnum) != NULL;
}
static struct invitem *invFindDoubleWeapon(s32 weapon1, s32 weapon2)
{
struct invitem *first = g_Vars.currentplayer->weapons;
struct invitem *item = first;
while (item) {
if (item->type == INVITEMTYPE_DUAL
&& item->type_dual.weapon1 == weapon1
&& item->type_dual.weapon2 == weapon2) {
return item;
}
item = item->next;
if (item == first) {
break;
}
}
return NULL;
}
bool invHasDoubleWeaponExcAllGuns(s32 weapon1, s32 weapon2)
{
return invFindDoubleWeapon(weapon1, weapon2) != NULL;
}
bool invHasSingleWeaponOrProp(s32 weaponnum)
{
struct invitem *item = g_Vars.currentplayer->weapons;
while (item) {
if (item->type == INVITEMTYPE_WEAP) {
if (weaponnum == item->type_weap.weapon1) {
return true;
}
} else if (item->type == INVITEMTYPE_PROP) {
struct prop *prop = item->type_prop.prop;
if (prop && prop->type == PROPTYPE_WEAPON) {
struct defaultobj *obj = prop->obj;
if (obj && obj->type == OBJTYPE_WEAPON) {
struct weaponobj *weapon = (struct weaponobj *)prop->obj;
if (weapon->weaponnum == weaponnum) {
return true;
}
}
}
}
item = item->next;
if (item == g_Vars.currentplayer->weapons) {
break;
}
}
return false;
}
static s32 invAddOneIfCantHaveSlayer(s32 index)
{
if (g_StageNum != STAGE_ATTACKSHIP && g_StageNum != STAGE_SKEDARRUINS && index >= WEAPON_SLAYER) {
index++;
}
return index;
}
static s32 currentStageForbidsSlayer(void)
{
bool value = 0;
if (g_StageNum != STAGE_ATTACKSHIP && g_StageNum != STAGE_SKEDARRUINS) {
value++;
}
return value;
}
static bool invCanHaveAllGunsWeapon(s32 weaponnum)
{
bool canhave = true;
if (weaponnum == WEAPON_SLAYER) {
canhave = false;
}
// @bug: The stage conditions need an OR. This condition can never pass.
if ((g_StageNum == STAGE_ATTACKSHIP && g_StageNum == STAGE_SKEDARRUINS)
&& weaponnum == WEAPON_SLAYER) {
canhave = true;
}
return canhave;
}
bool invHasSingleWeaponIncAllGuns(s32 weaponnum)
{
if (g_Vars.currentplayer->equipallguns &&
weaponnum && weaponnum <= WEAPON_PSYCHOSISGUN &&
invCanHaveAllGunsWeapon(weaponnum)) {
return true;
}
return invHasSingleWeaponExcAllGuns(weaponnum);
}
bool invHasDoubleWeaponIncAllGuns(s32 weapon1, s32 weapon2)
{
if (weapon2 == WEAPON_NONE) {
return true;
}
if (g_Vars.currentplayer->equipallguns &&
weapon1 <= WEAPON_PSYCHOSISGUN &&
weapon1 == weapon2 &&
weaponHasFlag(weapon1, WEAPONFLAG_DUALWIELD) &&
invCanHaveAllGunsWeapon(weapon1)) {
return true;
}
return invHasDoubleWeaponExcAllGuns(weapon1, weapon2);
}
bool invGiveSingleWeapon(s32 weaponnum)
{
frSetWeaponFound(weaponnum);
g_ObjectivesDirty = true;
if (invHasSingleWeaponExcAllGuns(weaponnum) == 0) {
struct invitem *item;
if (g_Vars.currentplayer->equipallguns &&
weaponnum <= WEAPON_PSYCHOSISGUN &&
invCanHaveAllGunsWeapon(weaponnum)) {
return false;
}
item = invFindUnusedSlot();
if (item) {
item->type = INVITEMTYPE_WEAP;
item->type_weap.weapon1 = weaponnum;
item->type_weap.pickuppad = -1;
invInsertItem(item);
}
return true;
}
return false;
}
bool invGiveDoubleWeapon(s32 weapon1, s32 weapon2)
{
g_ObjectivesDirty = true;
if (invHasDoubleWeaponExcAllGuns(weapon1, weapon2) == 0) {
if (weaponHasFlag(weapon1, WEAPONFLAG_DUALWIELD)) {
struct invitem *item = invFindUnusedSlot();
if (item) {
item->type = INVITEMTYPE_DUAL;
item->type_dual.weapon1 = weapon1;
item->type_dual.weapon2 = weapon2;
invInsertItem(item);
}
return true;
} else {
return false;
}
} else {
return false;
}
return false;
}
void invRemoveItemByNum(s32 weaponnum)
{
if (g_Vars.currentplayer->weapons) {
// Begin iterating from the second item in the list. This is required
// because the item might be removed from the list when iterating it,
// and it needs to determine when the end of the list has been reached.
struct invitem *item = g_Vars.currentplayer->weapons->next;
while (true) {
// Have to preload this because item->next shouldn't be trusted
// after calling invRemoveItem()
struct invitem *next = item->next;
if (item->type == INVITEMTYPE_PROP) {
struct prop *prop = item->type_prop.prop;
struct textoverride *override = invGetTextOverrideForObj(prop->obj);
if (override && override->weapon == weaponnum) {
invRemoveItem(item);
}
} else if (item->type == INVITEMTYPE_WEAP) {
if (item->type_weap.weapon1 == weaponnum) {
invRemoveItem(item);
}
} else if (item->type == INVITEMTYPE_DUAL) {
if (item->type_dual.weapon1 == weaponnum || item->type_dual.weapon2 == weaponnum) {
invRemoveItem(item);
}
}
if (item == g_Vars.currentplayer->weapons || !g_Vars.currentplayer->weapons) {
break;
}
item = next;
}
}
}
bool invGiveProp(struct prop *prop)
{
struct invitem *item;
// Don't add duplicate night vision to inventory
// (night vision is already there when using perfect darkness)
// Note that this check doesn't work on Investigation because it uses the
// IR specs model. See bug note in Investigation's setup file (setupear.c).
if (cheatIsActive(CHEAT_PERFECTDARKNESS)
&& prop->type == PROPTYPE_OBJ
&& prop->obj
&& prop->obj->modelnum == MODEL_CHRNIGHTSIGHT) {
return true;
}
item = invFindUnusedSlot();
if (item) {
item->type = INVITEMTYPE_PROP;
item->type_prop.prop = prop;
invInsertItem(item);
g_ObjectivesDirty = true;
}
return true;
}
void invRemoveProp(struct prop *prop)
{
if (g_Vars.currentplayer->weapons) {
struct invitem *item = g_Vars.currentplayer->weapons->next;
while (true) {
struct invitem *next = item->next;
if (item->type == INVITEMTYPE_PROP && item->type_prop.prop == prop) {
invRemoveItem(item);
g_ObjectivesDirty = true;
}
if (item == g_Vars.currentplayer->weapons || !g_Vars.currentplayer->weapons) {
break;
}
item = next;
}
}
}
s32 invGiveWeaponsByProp(struct prop *prop)
{
s32 numgiven = 0;
if (prop->type == PROPTYPE_WEAPON) {
struct defaultobj *obj = prop->obj;
struct weaponobj *weapon;
struct weaponobj *otherweapon;
s32 weaponnum;
s32 otherweaponnum;
if (obj->type == OBJTYPE_WEAPON) {
weapon = prop->weapon;
weaponnum = weapon->weaponnum;
otherweaponnum;
if (cheatIsActive(CHEAT_PERFECTDARKNESS) && weaponnum == WEAPON_NIGHTVISION) {
return 1;
}
if (invGiveSingleWeapon(weaponnum)) {
numgiven = 1;
}
if (g_Vars.normmplayerisrunning
&& weaponHasFlag(weaponnum, WEAPONFLAG_DUALWIELD)
&& !invHasDoubleWeaponExcAllGuns(weaponnum, weaponnum)) {
struct invitem *invitem = invFindSingleWeapon(weaponnum);
if (invitem) {
if (invitem->type_weap.pickuppad < 0) {
if (obj->pad >= 0) {
invitem->type_weap.pickuppad = obj->pad;
}
} else if (obj->pad >= 0 && invitem->type_weap.pickuppad != obj->pad) {
if (invGiveDoubleWeapon(weaponnum, weaponnum)) {
numgiven = 2;
} else {
numgiven = 0;
}
}
}
}
otherweapon = weapon->dualweapon;
if (otherweapon) {
if (weapon->base.flags & OBJFLAG_WEAPON_LEFTHANDED) {
numgiven = invHasDoubleWeaponExcAllGuns(otherweapon->weaponnum, weaponnum) == 0;
} else {
numgiven = invHasDoubleWeaponExcAllGuns(weaponnum, otherweapon->weaponnum) == 0;
}
weapon->dualweapon->dualweaponnum = weaponnum;
weapon->dualweapon->dualweapon = NULL;
weapon->dualweapon = NULL;
} else if (weapon->dualweaponnum >= 0) {
if (weapon->base.flags & OBJFLAG_WEAPON_LEFTHANDED) {
if (invGiveDoubleWeapon(weapon->dualweaponnum, weaponnum)) {
numgiven = 2;
} else {
numgiven = 0;
}
} else {
if (invGiveDoubleWeapon(weaponnum, weapon->dualweaponnum)) {
numgiven = 2;
} else {
numgiven = 0;
}
}
}
}
}
return numgiven;
}
void invChooseCycleForwardWeapon(s32 *ptr1, s32 *ptr2, bool arg2)
{
s32 weapon1 = *ptr1;
s32 weapon2 = *ptr2;
if (g_Vars.currentplayer->equipallguns) {
s32 candidate = *ptr1;
if (weaponHasFlag(*ptr1, WEAPONFLAG_DUALWIELD) && *ptr2 != *ptr1) {
// Switching to dual from single
weapon1 = *ptr1;
weapon2 = *ptr1;
} else {
// Find next weapon
do {
candidate++;
WRAP(candidate, NUM_CYCLEABLE_WEAPONS);
if (candidate == WEAPON_NONE) {
candidate++;
WRAP(candidate, NUM_CYCLEABLE_WEAPONS);
}
if ((!arg2 || bgun0f0a1a10(candidate)) && invCanHaveAllGunsWeapon(candidate)) {
weapon1 = candidate;
weapon2 = WEAPON_NONE;
break;
}
} while (candidate != weapon1);
}
} else {
struct invitem *item = g_Vars.currentplayer->weapons;
while (item) {
if (item->type == INVITEMTYPE_WEAP) {
if (item->type_weap.weapon1 < NUM_CYCLEABLE_WEAPONS && item->type_weap.weapon1 > weapon1) {
if (!arg2 || bgun0f0a1a10(item->type_weap.weapon1)) {
weapon1 = item->type_weap.weapon1;
weapon2 = WEAPON_NONE;
break;
}
}
} else if (item->type == INVITEMTYPE_DUAL) {
if (item->type_dual.weapon1 > weapon1
|| (weapon1 == item->type_dual.weapon1 && item->type_dual.weapon2 > weapon2)) {
if (!arg2 || bgun0f0a1a10(item->type_dual.weapon1) || bgun0f0a1a10(item->type_dual.weapon2)) {
weapon1 = item->type_dual.weapon1;
weapon2 = item->type_dual.weapon2;
break;
}
}
}
item = item->next;
if (item == g_Vars.currentplayer->weapons) {
if (arg2) {
break;
}
weapon1 = -1;
weapon2 = -1;
}
}
}
*ptr1 = weapon1;
*ptr2 = weapon2;
}
void invChooseCycleBackWeapon(s32 *ptr1, s32 *ptr2, bool arg2)
{
s32 weapon1 = *ptr1;
s32 weapon2 = *ptr2;
if (g_Vars.currentplayer->equipallguns) {
s32 candidate = *ptr1;
if (weaponHasFlag(weapon1, WEAPONFLAG_DUALWIELD) && weapon1 == weapon2) {
// Switching from dual to single
weapon1 = candidate;
weapon2 = WEAPON_NONE;
} else {
// Find prev weapon
do {
candidate = (candidate + NUM_CYCLEABLE_WEAPONS - 1) % NUM_CYCLEABLE_WEAPONS;
if (candidate == WEAPON_NONE) {
candidate = (candidate + NUM_CYCLEABLE_WEAPONS - 1) % NUM_CYCLEABLE_WEAPONS;
}
} while ((arg2 && !bgun0f0a1a10(candidate)) || !invCanHaveAllGunsWeapon(candidate));
if (weaponHasFlag(candidate, WEAPONFLAG_DUALWIELD)) {
weapon1 = candidate;
weapon2 = candidate;
} else {
weapon1 = candidate;
weapon2 = WEAPON_NONE;
}
}
} else if (g_Vars.currentplayer->weapons != NULL) {
struct invitem *item = g_Vars.currentplayer->weapons->prev;
while (true) {
if (item->type == INVITEMTYPE_WEAP) {
if (item->type_weap.weapon1 < NUM_CYCLEABLE_WEAPONS
&& (item->type_weap.weapon1 < weapon1 || (weapon1 == item->type_weap.weapon1 && weapon2 > 0))) {
if (!arg2 || bgun0f0a1a10(item->type_weap.weapon1)) {
weapon1 = item->type_weap.weapon1;
weapon2 = WEAPON_NONE;
break;
}
}
} else if (item->type == INVITEMTYPE_DUAL) {
if (item->type_dual.weapon1 < weapon1
|| (weapon1 == item->type_dual.weapon1 && item->type_dual.weapon2 < weapon2)) {
if (!arg2 || bgun0f0a1a10(item->type_dual.weapon1) || bgun0f0a1a10(item->type_dual.weapon2)) {
weapon1 = item->type_dual.weapon1;
weapon2 = item->type_dual.weapon2;
break;
}
}
}
if (item == g_Vars.currentplayer->weapons) {
if (arg2) {
break;
}
weapon1 = 1000;
weapon2 = 1000;
}
item = item->prev;
}
}
*ptr1 = weapon1;
*ptr2 = weapon2;
}
bool invHasKeyFlags(u32 wantkeyflags)
{
u32 heldkeyflags = 0;
struct invitem *item = g_Vars.currentplayer->weapons;
while (item) {
if (item->type == INVITEMTYPE_PROP) {
struct prop *prop = item->type_prop.prop;
if (prop && prop->type == PROPTYPE_OBJ) {
struct defaultobj *obj = prop->obj;
if (obj && obj->type == OBJTYPE_KEY) {
struct keyobj *key = (struct keyobj *)prop->obj;
heldkeyflags |= key->keyflags;
if ((wantkeyflags & heldkeyflags) == wantkeyflags) {
return true;
}
}
}
}
item = item->next;
if (item == g_Vars.currentplayer->weapons) {
break;
}
}
return false;
}
bool invHasBriefcase(void)
{
if (g_Vars.currentplayer->isdead == false) {
return invHasSingleWeaponExcAllGuns(WEAPON_BRIEFCASE2);
}
return false;
}
bool invHasDataUplink(void)
{
if (g_Vars.currentplayer->isdead == false) {
return invHasSingleWeaponExcAllGuns(WEAPON_DATAUPLINK);
}
return false;
}
bool invHasProp(struct prop *prop)
{
struct invitem *item = g_Vars.currentplayer->weapons;
struct prop *child;
while (item) {
if (item->type == INVITEMTYPE_PROP && item->type_prop.prop == prop) {
return true;
}
item = item->next;
if (item == g_Vars.currentplayer->weapons) {
break;
}
}
child = g_Vars.currentplayer->prop->child;
while (child) {
if (child == prop) {
return true;
}
child = child->next;
}
return false;
}
s32 invGetCount(void)
{
s32 numitems = 0;
struct invitem *item;
if (g_Vars.currentplayer->equipallguns) {
numitems = WEAPON_PSYCHOSISGUN - currentStageForbidsSlayer();
}
item = g_Vars.currentplayer->weapons;
while (item) {
if (item->type == INVITEMTYPE_PROP) {
struct prop *prop = item->type_prop.prop;
if (prop) {
struct defaultobj *obj = prop->obj;
if (obj) {
if (prop->type == PROPTYPE_WEAPON) {
if (obj->hidden & OBJHFLAG_HASTEXTOVERRIDE) {
numitems++;
}
} else if (prop->type == PROPTYPE_OBJ) {
if ((obj->flags2 & OBJFLAG2_00040000) == 0) {
numitems++;
}
}
}
}
} else if (item->type == INVITEMTYPE_WEAP) {
if (g_Vars.currentplayer->equipallguns == false
|| item->type_weap.weapon1 > WEAPON_PSYCHOSISGUN) {
numitems++;
}
}
item = item->next;
if (item == g_Vars.currentplayer->weapons) {
break;
}
}
return numitems;
}
static struct invitem *invGetItemByIndex(s32 index)
{
struct invitem *item;
if (g_Vars.currentplayer->equipallguns) {
if (index < WEAPON_PSYCHOSISGUN - currentStageForbidsSlayer()) {
return NULL;
}
index += currentStageForbidsSlayer() - WEAPON_PSYCHOSISGUN;
}
item = g_Vars.currentplayer->weapons;
while (item) {
if (item->type == INVITEMTYPE_PROP) {
struct prop *prop = item->type_prop.prop;
if (prop) {
struct defaultobj *obj = prop->obj;
if (obj) {
if (prop->type == PROPTYPE_WEAPON) {
if (obj->hidden & OBJHFLAG_HASTEXTOVERRIDE) {
if (index == 0) {
return item;
}
index--;
}
} else if (prop->type == PROPTYPE_OBJ) {
if ((obj->flags2 & OBJFLAG2_00040000) == 0) {
if (index == 0) {
return item;
}
index--;
}
}
}
}
} else if (item->type == INVITEMTYPE_WEAP) {
if (g_Vars.currentplayer->equipallguns == false
|| item->type_weap.weapon1 > WEAPON_PSYCHOSISGUN) {
if (index == 0) {
return item;
}
index--;
}
}
item = item->next;
if (item == g_Vars.currentplayer->weapons) {
break;
}
}
return NULL;
}
struct textoverride *invGetTextOverrideForObj(struct defaultobj *obj)
{
struct textoverride *override = g_Vars.textoverrides;
while (override) {
if (override->obj == obj) {
return override;
}
override = override->next;
}
return NULL;
}
static struct textoverride *invGetTextOverrideForWeapon(s32 weaponnum)
{
struct textoverride *override = g_Vars.textoverrides;
while (override) {
if (override->objoffset == 0 && override->weapon == weaponnum) {
return override;
}
override = override->next;
}
return NULL;
}
s32 invGetWeaponNumByIndex(s32 index)
{
struct invitem *item = invGetItemByIndex(index);
if (item) {
if (item->type == INVITEMTYPE_PROP) {
struct prop *prop = item->type_prop.prop;
struct textoverride *override = invGetTextOverrideForObj(prop->obj);
if (override) {
return override->weapon;
}
} else if (item->type == INVITEMTYPE_WEAP) {
return item->type_weap.weapon1;
}
} else if (g_Vars.currentplayer->equipallguns) {
if (index < WEAPON_PSYCHOSISGUN - currentStageForbidsSlayer()) {
index++;
return invAddOneIfCantHaveSlayer(index);
}
}
return 0;
}
u16 invGetNameIdByIndex(s32 index)
{
struct invitem *item = invGetItemByIndex(index);
s32 weaponnum = 0;
struct textoverride *override;
if (item) {
if (item->type == INVITEMTYPE_PROP) {
struct prop *prop = item->type_prop.prop;
override = invGetTextOverrideForObj(prop->obj);
if (override) {
if (override->inventorytext) {
return override->inventorytext;
}
weaponnum = override->weapon;
}
} else if (item->type == INVITEMTYPE_WEAP) {
weaponnum = item->type_weap.weapon1;
override = invGetTextOverrideForWeapon(weaponnum);
if (override && override->inventorytext) {
return override->inventorytext;
}
}
} else {
if (g_Vars.currentplayer->equipallguns) {
if (index < WEAPON_PSYCHOSISGUN - currentStageForbidsSlayer()) {
index++;
return g_Weapons[invAddOneIfCantHaveSlayer(index)]->name;
}
}
}
return g_Weapons[weaponnum]->name;
}
char *invGetNameByIndex(s32 index)
{
return langGet(invGetNameIdByIndex(index));
}
char *invGetShortNameByIndex(s32 index)
{
struct invitem *item = invGetItemByIndex(index);
s32 weaponnum = 0;
struct textoverride *override;
if (item) {
if (item->type == INVITEMTYPE_PROP) {
struct prop *prop = item->type_prop.prop;
override = invGetTextOverrideForObj(prop->obj);
if (override) {
if (override->inventorytext) {
return langGet(override->inventorytext);
}
weaponnum = override->weapon;
}
} else if (item->type == INVITEMTYPE_WEAP) {
weaponnum = item->type_weap.weapon1;
override = invGetTextOverrideForWeapon(weaponnum);
if (override && override->inventorytext) {
return langGet(override->inventorytext);
}
}
} else if (g_Vars.currentplayer->equipallguns) {
if (index < WEAPON_PSYCHOSISGUN - currentStageForbidsSlayer()) {
index++;
return bgunGetShortName(invAddOneIfCantHaveSlayer(index));
}
}
return bgunGetShortName(weaponnum);
}
void invInsertTextOverride(struct textoverride *override)
{
override->next = g_Vars.textoverrides;
g_Vars.textoverrides = override;
}
u32 invGetCurrentIndex(void)
{
return g_Vars.currentplayer->equipcuritem;
}
void invSetCurrentIndex(u32 item)
{
g_Vars.currentplayer->equipcuritem = item;
}
void invCalculateCurrentIndex(void)
{
s32 curweaponnum = bgunGetWeaponNum(HAND_RIGHT);
s32 i;
g_Vars.currentplayer->equipcuritem = 0;
for (i = 0; i < invGetCount(); i++) {
if (invGetWeaponNumByIndex(i) == curweaponnum) {
g_Vars.currentplayer->equipcuritem = i;
break;
}
}
}
char *invGetPickupTextByObj(struct defaultobj *obj)
{
struct textoverride *override = invGetTextOverrideForObj(obj);
if (override && override->pickuptext) {
return langGet(override->pickuptext);
}
return NULL;
}
char *invGetPickupTextByWeaponNum(s32 weaponnum)
{
struct textoverride *override = invGetTextOverrideForWeapon(weaponnum);
if (override && override->pickuptext) {
return langGet(override->pickuptext);
}
return NULL;
}
void invIncrementHeldTime(s32 weapon1, s32 weapon2)
{
s32 leastusedtime;
s32 leastusedindex;
s32 i;
if (!weaponHasFlag(weapon1, WEAPONFLAG_TRACKTIMEUSED)) {
return;
}
leastusedtime = 0x7fffffff;
leastusedindex = 0;
if (!weaponHasFlag(weapon2, WEAPONFLAG_TRACKTIMEUSED)) {
weapon2 = 0;
}
for (i = 0; i < ARRAYCOUNT(g_Vars.currentplayer->gunheldarr); i++) {
s32 time = g_Vars.currentplayer->gunheldarr[i].totaltime240_60;
if (time >= 0) {
if (weapon1 == g_Vars.currentplayer->gunheldarr[i].weapon1 &&
weapon2 == g_Vars.currentplayer->gunheldarr[i].weapon2) {
g_Vars.currentplayer->gunheldarr[i].totaltime240_60 = time + g_Vars.lvupdate60;
break;
}
if (time < leastusedtime) {
leastusedtime = time;
leastusedindex = i;
}
} else {
leastusedindex = i;
i = ARRAYCOUNT(g_Vars.currentplayer->gunheldarr);
break;
}
}
if (i == ARRAYCOUNT(g_Vars.currentplayer->gunheldarr)) {
g_Vars.currentplayer->gunheldarr[leastusedindex].totaltime240_60 = g_Vars.lvupdate60;
g_Vars.currentplayer->gunheldarr[leastusedindex].weapon1 = weapon1;
g_Vars.currentplayer->gunheldarr[leastusedindex].weapon2 = weapon2;
}
}
void invGetWeaponOfChoice(s32 *weapon1, s32 *weapon2)
{
s32 mosttime = -1;
s32 i;
*weapon1 = 0;
*weapon2 = 0;
for (i = 0; i < ARRAYCOUNT(g_Vars.currentplayer->gunheldarr); i++) {
if (g_Vars.currentplayer->gunheldarr[i].totaltime240_60 >= 0
&& g_Vars.currentplayer->gunheldarr[i].totaltime240_60 > mosttime) {
mosttime = g_Vars.currentplayer->gunheldarr[i].totaltime240_60;
*weapon1 = g_Vars.currentplayer->gunheldarr[i].weapon1;
*weapon2 = g_Vars.currentplayer->gunheldarr[i].weapon2;
}
}
}