UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cl_inventory.cpp
Go to the documentation of this file.
1 
7 /*
8 Copyright (C) 2002-2020 UFO: Alien Invasion.
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 
19 See the GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 
25 */
26 
27 #include "client.h"
28 #include "cl_inventory.h"
29 #include "cl_inventory_callbacks.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 
63 bool 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 
99 bool 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 
136 bool 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
155 
159 static 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 
187 static bool INV_EquipmentDefSanityCheck (void)
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 
268 bool 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 
286  case FILTER_S_SECONDARY:
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 
332  case FILTER_DISASSEMBLY:
334  break;
335 
337  case MAX_FILTERTYPES:
338  case FILTER_ENSURE_32BIT:
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 
357 Item* 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 
377 static 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 };
391 CASSERT(lengthof(filterTypeNames) == MAX_FILTERTYPES);
392 
397 itemFilterTypes_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 
425 void INV_InitStartup (void)
426 {
427 #ifdef DEBUG
428  Cmd_AddCommand("debug_listinventory", INV_InventoryList_f, "Print the current inventory to the game console");
429 #endif
431 
433 }
#define SHAPE_BIG_MAX_HEIGHT
defines the max height of an inventory container
Definition: inv_shared.h:188
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition: cmd.cpp:744
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
void setAmmoLeft(int value)
Definition: inv_shared.h:441
int numEDs
Definition: q_shared.h:541
bool implant
Definition: inv_shared.h:282
itemFilterTypes_t INV_GetFilterTypeID(const char *filterTypeID)
Searches for a filter type name (as used in console functions) and returns the matching itemFilterTyp...
bool isCraftItem() const
Checks whether a given item is an aircraftitem item.
Definition: inv_shared.cpp:226
bool INV_ItemMatchesFilter(const objDef_t *obj, const itemFilterTypes_t filterType)
Checks if the given object/item matched the given filter type.
InventoryInterface i
Definition: client.h:101
int getAmmoLeft() const
Definition: inv_shared.h:466
#define _(String)
Definition: cl_shared.h:43
Item * getContainer2(const containerIndex_t idx) const
Definition: inv_shared.h:546
static char const *const filterTypeNames[]
bool isSecondary
Definition: inv_shared.h:286
csi_t csi
Definition: common.cpp:39
char animationIndex
Definition: inv_shared.h:327
inventory_action_t moveInInventory(Inventory *const inv, const invDef_t *from, Item *item, const invDef_t *to, int tx, int ty, int *TU, Item **icp)
Conditions for moving items between containers.
Definition: inventory.cpp:239
bool holdTwoHanded
Definition: inv_shared.h:278
bool isMisc
Definition: inv_shared.h:288
itemFilterTypes_t
A list of filter types in the market and production view.
Definition: cl_inventory.h:35
Shared game type headers.
const objDef_t * def(void) const
Definition: inv_shared.h:469
equipDef_t eds[MAX_EQUIPDEFS]
Definition: q_shared.h:540
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
int numODs
Definition: q_shared.h:518
Header file for inventory handling and Equipment menu.
bool isReloadable() const
Definition: inv_shared.h:352
const struct objDef_s * ammos[MAX_AMMOS_PER_OBJDEF]
Definition: inv_shared.h:307
Item * getNext() const
Definition: inv_shared.h:451
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
const char * type
Definition: inv_shared.h:271
const equipDef_t * INV_GetEquipmentDefinitionByID(const char *name)
Gets equipment definition by id.
int GAME_GetChrMaxLoad(const character_t *chr)
Returns the max weight the given character can carry.
Definition: cl_game.cpp:1768
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
bool fireTwoHanded
Definition: inv_shared.h:279
client_static_t cls
Definition: cl_main.cpp:83
item instance data, with linked list capability
Definition: inv_shared.h:402
void getFirstShapePosition(int *const x, int *const y) const
Calculates the first "true" bit in the shape and returns its position in the item.
Definition: inv_shared.cpp:557
GLuint * id
Definition: r_gl.h:149
inventory definition with all its containers
Definition: inv_shared.h:525
bool deplete
Definition: inv_shared.h:301
#define ERR_DROP
Definition: common.h:211
static bool INV_EquipmentDefSanityCheck(void)
Make sure equipment definitions used to generate teams are proper.
#define SHAPE_BIG_MAX_WIDTH
32 bit mask
Definition: inv_shared.h:190
bool thrown
Definition: inv_shared.h:281
int numWeapons
Definition: inv_shared.h:317
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition: shared.cpp:587
bool weapon
Definition: inv_shared.h:277
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.
char id[MAX_VAR]
Definition: inv_shared.h:606
character_t * GAME_GetSelectedChr(void)
Returns the currently selected character.
Definition: cl_game.cpp:1746
const char * name
Definition: inv_shared.h:267
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. ...
Definition: inv_shared.cpp:919
Item * addToInventory(Inventory *const inv, const Item *const item, const invDef_t *container, int x, int y, int amount) __attribute__((warn_unused_result))
Add an item to a specified container in a given inventory.
Definition: inventory.cpp:91
QGL_EXTERN GLint i
Definition: r_gl.h:113
void INV_InitStartup(void)
int numItems[MAX_OBJDEFS]
Definition: inv_shared.h:608
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
bool isDummy
Definition: inv_shared.h:290
void setAmmoDef(const objDef_t *od)
Definition: inv_shared.h:435
int ammo
Definition: inv_shared.h:293
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.
Definition: inv_shared.cpp:844
bool isArmour() const
Definition: inv_shared.h:346
const objDef_t * ammoDef(void) const
Definition: inv_shared.h:460
inventory definition for our menus
Definition: inv_shared.h:371
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
Definition: inv_shared.cpp:266
bool isHeavy
Definition: inv_shared.h:287
int getX() const
Definition: inv_shared.h:454
containerIndex_t id
Definition: inv_shared.h:373
#define lengthof(x)
Definition: shared.h:105
bool isUGVitem
Definition: inv_shared.h:289
Primary header for client.
#define NONE
Definition: defines.h:68
itemFilterTypes_t INV_GetFilterFromItem(const objDef_t *obj)
#define Q_streq(a, b)
Definition: shared.h:136
void INV_InitCallbacks(void)
int numAmmos
Definition: inv_shared.h:308
bool isPrimary
Definition: inv_shared.h:285
CASSERT(lengthof(filterTypeNames)==MAX_FILTERTYPES)
bool INV_LoadWeapon(const Item *weaponList, Inventory *inv, const invDef_t *srcContainer, const invDef_t *destContainer)
Load a weapon with ammo.
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...
const char * INV_GetFilterType(itemFilterTypes_t id)
void UI_Popup(const char *title, const char *text)
Popup on geoscape.
Definition: ui_popup.cpp:47
bool INV_UnloadWeapon(Item *weapon, Inventory *inv, const invDef_t *container)
Unload a weapon and put the ammo in a container.
const char * id
Definition: inv_shared.h:268
int getY() const
Definition: inv_shared.h:457
const struct objDef_s * weapons[MAX_WEAPONS_PER_OBJDEF]
Definition: inv_shared.h:311