UFO: Alien Invasion
Loading...
Searching...
No Matches
cl_inventory.cpp
Go to the documentation of this file.
1
6
7/*
8Copyright (C) 2002-2025 UFO: Alien Invasion.
9
10This program is free software; you can redistribute it and/or
11modify it under the terms of the GNU General Public License
12as published by the Free Software Foundation; either version 2
13of the License, or (at your option) any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25*/
26
27#include "client.h"
28#include "cl_inventory.h"
30#include "../shared/parse.h"
31#include "ui/ui_popup.h"
32#include "cgame/cl_game.h"
33
40{
41 for (int i = 0; i < csi.numEDs; i++) {
42 const equipDef_t* ed = &csi.eds[i];
43 if (Q_streq(name, ed->id))
44 return ed;
45 }
46
47 Com_Error(ERR_DROP, "Could not find equipment %s", name);
48}
49
63bool INV_MoveItem (Inventory* inv, const invDef_t* toContainer, int toX, int toY,
64 const invDef_t* fromContainer, Item* fItem, Item** uponItem)
65{
66 if (toX >= SHAPE_BIG_MAX_WIDTH || toY >= SHAPE_BIG_MAX_HEIGHT)
67 return false;
68
69 if (!fItem)
70 return false;
71
72 const int maxWeight = GAME_GetChrMaxLoad(GAME_GetSelectedChr());
73 if (!inv->canHoldItemWeight(fromContainer->id, toContainer->id, *fItem, maxWeight)) {
74 UI_Popup(_("Warning"), _("This soldier can not carry anything else."));
75 return false;
76 }
77
78 /* move the item */
79 const int moved = cls.i.moveInInventory(inv, fromContainer, fItem, toContainer, toX, toY, nullptr, uponItem);
80
81 switch (moved) {
82 case IA_MOVE:
83 case IA_ARMOUR:
84 case IA_RELOAD:
85 case IA_RELOAD_SWAP:
86 return true;
87 default:
88 return false;
89 }
90}
91
99bool INV_LoadWeapon (const Item* weaponList, Inventory* inv, const invDef_t* srcContainer, const invDef_t* destContainer)
100{
101 assert(weaponList);
102
103 int x, y;
104 weaponList->getFirstShapePosition(&x, &y);
105 x += weaponList->getX();
106 y += weaponList->getY();
107
108 const objDef_t* weapon = weaponList->def();
109 if (weapon->weapons[0]) {
110 Item* ic = inv->getItemAtPos(destContainer, x, y);
111 if (ic) {
112 ic->setAmmoLeft(weapon->ammo);
113 ic->setAmmoDef(weapon);
114 }
115 } else if (weapon->isReloadable()) {
116 const itemFilterTypes_t equipType = INV_GetFilterFromItem(weapon);
117 /* search an ammo */
118 for (int i = 0; i < weapon->numAmmos; i++) {
119 const objDef_t* ammo = weapon->ammos[i];
120 Item* ic = INV_SearchInInventoryWithFilter(inv, srcContainer, ammo, equipType);
121 if (ic)
122 return INV_MoveItem(inv, destContainer, x, y, srcContainer, ic, nullptr);
123 }
124 }
125
126 return false;
127}
128
136bool INV_UnloadWeapon (Item* weapon, Inventory* inv, const invDef_t* container)
137{
138 assert(weapon);
139 if (container && inv) {
140 bool moved = false;
141 if (weapon->def() != weapon->ammoDef() && weapon->getAmmoLeft() > 0) {
142 const Item item(weapon->ammoDef());
143 moved = cls.i.addToInventory(inv, &item, container, NONE, NONE, 1) != nullptr;
144 }
145 if (moved || weapon->def() == weapon->ammoDef()) {
146 weapon->setAmmoDef(nullptr);
147 weapon->setAmmoLeft(0);
148 return moved;
149 }
150 }
151 return false;
152}
153
154#ifdef DEBUG
159static void INV_InventoryList_f (void)
160{
161 for (int i = 0; i < csi.numODs; i++) {
162 const objDef_t* od = INVSH_GetItemByIDX(i);
163
164 Com_Printf("Item: %s\n", od->id);
165 Com_Printf("... name -> %s\n", od->name);
166 Com_Printf("... type -> %s\n", od->type);
167 Com_Printf("... category -> %i\n", od->animationIndex);
168 Com_Printf("... weapon -> %i\n", od->weapon);
169 Com_Printf("... holdtwohanded -> %i\n", od->holdTwoHanded);
170 Com_Printf("... firetwohanded -> %i\n", od->fireTwoHanded);
171 Com_Printf("... thrown -> %i\n", od->thrown);
172 Com_Printf("... usable for weapon (if type is ammo):\n");
173 for (int j = 0; j < od->numWeapons; j++) {
174 if (od->weapons[j])
175 Com_Printf(" ... %s\n", od->weapons[j]->name);
176 }
177 Com_Printf("\n");
178 }
179}
180#endif
181
188{
189 bool result = true;
190
191 for (int i = 0; i < csi.numEDs; i++) {
192 const equipDef_t* const ed = &csi.eds[i];
193 /* only check definitions used for generating teams */
194 if (!Q_strstart(ed->id, "alien") && !Q_strstart(ed->id, "phalanx"))
195 continue;
196
197 /* Check primary */
198 int sum = 0;
199 for (int j = 0; j < csi.numODs; j++) {
200 const objDef_t* const obj = INVSH_GetItemByIDX(j);
201 if (obj->weapon && obj->fireTwoHanded
203 sum += ed->numItems[j];
204 }
205 if (sum > 100) {
206 Com_Printf("INV_EquipmentDefSanityCheck: Equipment Def '%s' has a total probability for primary weapons greater than 100\n", ed->id);
207 result = false;
208 }
209
210 /* Check secondary */
211 sum = 0;
212 for (int j = 0; j < csi.numODs; j++) {
213 const objDef_t* const obj = INVSH_GetItemByIDX(j);
214 if (obj->weapon && obj->isReloadable() && !obj->deplete && INV_ItemMatchesFilter(obj, FILTER_S_SECONDARY))
215 sum += ed->numItems[j];
216 }
217 if (sum > 100) {
218 Com_Printf("INV_EquipmentDefSanityCheck: Equipment Def '%s' has a total probability for secondary weapons greater than 100\n", ed->id);
219 result = false;
220 }
221
222 /* Check armour */
223 sum = 0;
224 for (int j = 0; j < csi.numODs; j++) {
225 const objDef_t* const obj = INVSH_GetItemByIDX(j);
227 sum += ed->numItems[j];
228 }
229 if (sum > 100) {
230 Com_Printf("INV_EquipmentDefSanityCheck: Equipment Def '%s' has a total probability for armours greater than 100\n", ed->id);
231 result = false;
232 }
233
234 /* Don't check misc: the total probability can be greater than 100 */
235 }
236
237 return result;
238}
239
241{
242 assert(obj);
243
244 /* heavy weapons may be primary too. check heavy first */
245 if (obj->isHeavy)
246 return FILTER_S_HEAVY;
247 if (obj->implant)
248 return FILTER_S_IMPLANT;
249 else if (obj->isPrimary)
250 return FILTER_S_PRIMARY;
251 else if (obj->isSecondary)
252 return FILTER_S_SECONDARY;
253 else if (obj->isMisc)
254 return FILTER_S_MISC;
255 else if (obj->isArmour())
256 return FILTER_S_ARMOUR;
257
259 Sys_Error("INV_GetFilterFromItem: unknown filter category for item '%s'", obj->id);
260}
261
268bool INV_ItemMatchesFilter (const objDef_t* obj, const itemFilterTypes_t filterType)
269{
270 if (!obj)
271 return false;
272
273 switch (filterType) {
274 case FILTER_S_PRIMARY:
275 if (obj->isPrimary && !obj->isHeavy)
276 return true;
277
278 /* Check if one of the items that uses this ammo matches this filter type. */
279 for (int i = 0; i < obj->numWeapons; i++) {
280 const objDef_t* weapon = obj->weapons[i];
281 if (weapon && weapon != obj && INV_ItemMatchesFilter(weapon, filterType))
282 return true;
283 }
284 break;
285
287 if (obj->isSecondary && !obj->isHeavy)
288 return true;
289
290 /* Check if one of the items that uses this ammo matches this filter type. */
291 for (int i = 0; i < obj->numWeapons; i++) {
292 const objDef_t* weapon = obj->weapons[i];
293 if (weapon && weapon != obj && INV_ItemMatchesFilter(weapon, filterType))
294 return true;
295 }
296 break;
297
298 case FILTER_S_HEAVY:
299 if (obj->isHeavy)
300 return true;
301
302 /* Check if one of the items that uses this ammo matches this filter type. */
303 for (int i = 0; i < obj->numWeapons; i++) {
304 const objDef_t* weapon = obj->weapons[i];
305 if (weapon && weapon != obj && INV_ItemMatchesFilter(weapon, filterType))
306 return true;
307 }
308 break;
309
310 case FILTER_S_IMPLANT:
311 return obj->implant;
312
313 case FILTER_S_ARMOUR:
314 return obj->isArmour();
315
316 case FILTER_S_MISC:
317 return obj->isMisc;
318
319 case FILTER_CRAFTITEM:
321 return obj->isCraftItem();
322
323 case FILTER_UGVITEM:
324 return obj->isUGVitem;
325
326 case FILTER_DUMMY:
327 return obj->isDummy;
328
329 case FILTER_AIRCRAFT:
330 return Q_streq(obj->type, "aircraft");
331
334 break;
335
337 case MAX_FILTERTYPES:
339 Com_Printf("INV_ItemMatchesFilter: Unknown filter type for items: %i\n", filterType);
340 break;
341 }
342
343 /* The given filter type is unknown. */
344 return false;
345}
346
357Item* INV_SearchInInventoryWithFilter (const Inventory* const inv, const invDef_t* container, const objDef_t* itemType, const itemFilterTypes_t filterType)
358{
359 if (itemType == nullptr)
360 return nullptr;
361
362 for (Item* ic = inv->getContainer2(container->id); ic; ic = ic->getNext()) {
363 /* Search only in the items that could get displayed. */
364 if (ic && ic->def() && (filterType == MAX_FILTERTYPES || INV_ItemMatchesFilter(ic->def(), filterType))) {
365 /* We search _everything_, no matter what location it is (i.e. x/y are ignored). */
366 if (itemType == ic->def())
367 return ic;
368 }
369 }
370
371 /* No item with these coordinates (or matching item) found. */
372 return nullptr;
373}
374
377static char const* const filterTypeNames[] = {
378 "primary",
379 "secondary",
380 "heavy",
381 "misc",
382 "armour",
383 "implant",
384 "",
385 "craftitem",
386 "ugvitem",
387 "aircraft",
388 "dummy",
389 "disassembly"
390};
392
397itemFilterTypes_t INV_GetFilterTypeID (const char* filterTypeID)
398{
399 if (!filterTypeID)
400 return MAX_FILTERTYPES;
401
402 /* default filter type is primary */
403 if (filterTypeID[0] == '\0')
404 return FILTER_S_PRIMARY;
405
406 for (int i = 0; i < MAX_FILTERTYPES; i++) {
407 const char* fileTypeName = filterTypeNames[i];
408 if (fileTypeName && Q_streq(fileTypeName, filterTypeID))
409 return (itemFilterTypes_t)i;
410 }
411
412 /* No matching filter type found, returning max value. */
413 return MAX_FILTERTYPES;
414}
415
420{
421 assert(id < MAX_FILTERTYPES);
422 return filterTypeNames[id];
423}
424
426{
427#ifdef DEBUG
428 Cmd_AddCommand("debug_listinventory", INV_InventoryList_f, "Print the current inventory to the game console");
429#endif
431
433}
character_t * GAME_GetSelectedChr(void)
Returns the currently selected character.
Definition cl_game.cpp:1555
int GAME_GetChrMaxLoad(const character_t *chr)
Returns the max weight the given character can carry.
Definition cl_game.cpp:1577
Shared game type headers.
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.
itemFilterTypes_t INV_GetFilterFromItem(const objDef_t *obj)
static bool INV_EquipmentDefSanityCheck(void)
Make sure equipment definitions used to generate teams are proper.
void INV_InitStartup(void)
itemFilterTypes_t INV_GetFilterTypeID(const char *filterTypeID)
Searches for a filter type name (as used in console functions) and returns the matching itemFilterTyp...
const equipDef_t * INV_GetEquipmentDefinitionByID(const char *name)
Gets equipment definition by id.
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.
const char * INV_GetFilterType(itemFilterTypes_t id)
static char const *const filterTypeNames[]
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...
bool INV_ItemMatchesFilter(const objDef_t *obj, const itemFilterTypes_t filterType)
Checks if the given object/item matched the given filter type.
Header file for inventory handling and Equipment menu.
itemFilterTypes_t
A list of filter types in the market and production view.
@ FILTER_S_ARMOUR
@ FILTER_S_HEAVY
@ FILTER_CRAFTITEM
@ FILTER_S_PRIMARY
@ MAX_SOLDIER_FILTERTYPES
@ FILTER_AIRCRAFT
@ FILTER_S_MISC
@ FILTER_DUMMY
@ FILTER_S_IMPLANT
@ FILTER_S_SECONDARY
@ FILTER_ENSURE_32BIT
@ FILTER_DISASSEMBLY
@ MAX_FILTERTYPES
@ FILTER_UGVITEM
void INV_InitCallbacks(void)
client_static_t cls
Definition cl_main.cpp:83
#define _(String)
Definition cl_shared.h:44
inventory definition with all its containers
Definition inv_shared.h:525
bool canHoldItemWeight(containerIndex_t from, containerIndex_t to, const Item &item, int maxWeight) const
Check that adding an item to the inventory won't exceed the max permitted weight.
Item * getItemAtPos(const invDef_t *container, const int x, const int y) const
Searches if there is an item at location (x,y) in a container.
Item * getContainer2(const containerIndex_t idx) const
Definition inv_shared.h:546
item instance data, with linked list capability
Definition inv_shared.h:402
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
void setAmmoDef(const objDef_t *od)
Definition inv_shared.h:435
const objDef_t * def(void) const
Definition inv_shared.h:469
int getY() const
Definition inv_shared.h:457
void getFirstShapePosition(int *const x, int *const y) const
Calculates the first "true" bit in the shape and returns its position in the item.
void setAmmoLeft(int value)
Definition inv_shared.h:441
Item * getNext() const
Definition inv_shared.h:451
Primary header for client.
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition cmd.cpp:744
csi_t csi
Definition common.cpp:39
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define ERR_DROP
Definition common.h:211
#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.
#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
@ IA_MOVE
Definition inv_shared.h:68
@ IA_ARMOUR
Definition inv_shared.h:69
@ IA_RELOAD
Definition inv_shared.h:70
@ IA_RELOAD_SWAP
Definition inv_shared.h:71
Shared parsing functions.
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
QGL_EXTERN GLuint * id
Definition r_gl.h:86
#define Q_streq(a, b)
Definition shared.h:136
#define lengthof(x)
Definition shared.h:105
#define CASSERT(x)
Definition shared.h:107
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition shared.cpp:587
char id[MAX_VAR]
Definition inv_shared.h:606
int numItems[MAX_OBJDEFS]
Definition inv_shared.h:608
inventory definition for our menus
Definition inv_shared.h:371
containerIndex_t id
Definition inv_shared.h:373
Defines all attributes of objects used in the inventory.
Definition inv_shared.h:264
bool isUGVitem
Definition inv_shared.h:289
const struct objDef_s * ammos[MAX_AMMOS_PER_OBJDEF]
Definition inv_shared.h:307
const char * type
Definition inv_shared.h:271
bool holdTwoHanded
Definition inv_shared.h:278
bool isPrimary
Definition inv_shared.h:285
bool deplete
Definition inv_shared.h:301
bool weapon
Definition inv_shared.h:277
bool isSecondary
Definition inv_shared.h:286
bool isDummy
Definition inv_shared.h:290
int numAmmos
Definition inv_shared.h:308
bool fireTwoHanded
Definition inv_shared.h:279
bool isReloadable() const
Definition inv_shared.h:352
char animationIndex
Definition inv_shared.h:327
bool isHeavy
Definition inv_shared.h:287
bool implant
Definition inv_shared.h:282
const char * id
Definition inv_shared.h:268
bool isMisc
Definition inv_shared.h:288
bool thrown
Definition inv_shared.h:281
bool isArmour() const
Definition inv_shared.h:346
int numWeapons
Definition inv_shared.h:317
const struct objDef_s * weapons[MAX_WEAPONS_PER_OBJDEF]
Definition inv_shared.h:311
bool isCraftItem() const
Checks whether a given item is an aircraftitem item.
const char * name
Definition inv_shared.h:267
void UI_Popup(const char *title, const char *text)
Popup on geoscape.
Definition ui_popup.cpp:47