UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
g_inventory.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 2002-2020 UFO: Alien Invasion.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 */
24 
25 #include "g_inventory.h"
26 #include "g_client.h"
27 #include "g_spawn.h"
28 #include "g_utils.h"
29 #include "g_vis.h"
30 
31 const equipDef_t* G_GetEquipDefByID (const char* equipID)
32 {
33  const equipDef_t* ed = gi.csi->eds;
34 
35  for (int i = 0; i < gi.csi->numEDs; i++, ed++)
36  if (Q_streq(equipID, ed->id))
37  return ed;
38 
39  gi.DPrintf("Could not find the equipment with the id: '%s'\n", equipID);
40  return nullptr;
41 }
42 
49 {
50  return G_GetEdictFromPos(pos, ET_ITEM);
51 }
52 
60 {
61  Edict* floor = G_GetFloorItemFromPos(ent->pos);
62  /* found items */
63  if (floor) {
64  ent->setFloor(floor);
65  return floor;
66  }
67 
68  /* no items on ground found */
69  ent->resetFloor();
70  return nullptr;
71 }
72 
80 bool G_InventoryRemoveItemByID (const char* itemID, Edict* ent, containerIndex_t container)
81 {
82  Item* ic = ent->getContainer(container);
83  while (ic) {
84  const objDef_t* item = ic->def();
85  if (item != nullptr && Q_streq(item->id, itemID)) {
86  /* remove the virtual item to update the inventory lists */
87  if (!game.invi.removeFromInventory(&ent->chr.inv, INVDEF(container), ic))
88  gi.Error("Could not remove item '%s' from inventory %i",
89  ic->def()->id, container);
90  G_EventInventoryDelete(*ent, G_VisToPM(ent->visflags), container, ic->getX(), ic->getY());
91  return true;
92  }
93  ic = ic->getNext();
94  }
95 
96  return false;
97 }
98 
108 {
109  if (container == CID_ARMOUR || container == CID_IMPLANT)
110  return false;
111 
112  Item* ic = ent->getContainer(container);
113  if (!ic)
114  return false;
115 
116  bool check = false;
117  while (ic) {
118  assert(ic->def());
119  if (ic->def()->isVirtual) {
120  Item* next = ic->getNext();
121  /* remove the virtual item to update the inventory lists */
122  if (!game.invi.removeFromInventory(&ent->chr.inv, INVDEF(container), ic))
123  gi.Error("Could not remove virtual item '%s' from inventory %i",
124  ic->def()->id, container);
125  ic = next;
126  } else {
127  /* there are none virtual items left that should be send to the client */
128  check = true;
129  ic = ic->getNext();
130  }
131  }
132  return check;
133 }
134 
140 bool G_AddItemToFloor (const pos3_t pos, const char* itemID)
141 {
142  const objDef_t* od = INVSH_GetItemByIDSilent(itemID);
143  if (!od) {
144  gi.DPrintf("Could not find item '%s'\n", itemID);
145  return false;
146  }
147 
148  /* Also sets FLOOR(ent) to correct value. */
149  Edict* floor = G_GetFloorItemFromPos(pos);
150  /* nothing on the ground yet? */
151  if (!floor)
152  floor = G_SpawnFloor(pos);
153 
154  Item item(od);
155  return game.invi.tryAddToInventory(&floor->chr.inv, &item, INVDEF(CID_FLOOR));
156 }
157 
160 /* #define ADJACENT */
161 
162 #ifdef ADJACENT
163 static bool G_InventoryPlaceItemAdjacent (Edict* ent)
164 {
165  vec2_t oldPos; /* if we have to place it to adjacent */
166  int i;
167 
168  Vector2Copy(ent->pos, oldPos);
169  Edict* floorAdjacent = nullptr;
170 
171  for (i = 0; i < DIRECTIONS; i++) {
173  /* extend pos with the direction vectors */
176  Vector2Set(ent->pos, ent->pos[0] + dvecs[i][0], ent->pos[0] + dvecs[i][1]);
177  /* now try to get a floor entity for that new location */
178  floorAdjacent = G_GetFloorItems(ent);
179  if (!floorAdjacent) {
180  floorAdjacent = G_SpawnFloor(ent->pos);
181  } else {
182  /* destroy this edict (send this event to all clients that see the edict) */
183  G_EventPerish(*floorAdjacent);
184  G_VisFlagsReset(*floorAdjacent);
185  }
186 
187  Item* ic = nullptr;
188  int x, y;
189  floorAdjacent->chr.inv.findSpace(INVDEF(CID_FLOOR), ic, &x, &y, ic);
190  if (x != NONE) {
191  ic->setX(x);
192  ic->setY(y);
193  ic->setNext(floorAdjacent->getFloor());
194  floorAdjacent->chr.inv.setFloorContainer(ic);
195  break;
196  }
197  /* restore original pos */
198  Vector2Copy(oldPos, ent->pos);
199  }
200 
201  /* added to adjacent pos? */
202  if (i < DIRECTIONS) {
203  /* restore original pos - if no free space, this was done
204  * already in the for loop */
205  Vector2Copy(oldPos, ent->pos);
206  return false;
207  }
208 
209  if (floorAdjacent)
210  G_CheckVis(floorAdjacent, true);
211 
212  return true;
213 }
214 #endif
215 
222 {
223  /* check for items that should be dropped */
224  /* ignore items linked from any temp container */
225  const Container* cont = nullptr;
226  while ((cont = ent->chr.inv.getNextCont(cont))) {
227  if (G_InventoryDropToFloorCheck(ent, cont->id))
228  break; /* found at least one item */
229  }
230 
231  /* edict is not carrying any items */
232  if (!cont)
233  return;
234 
235  /* find the floor */
236  Edict* floor = G_GetFloorItems(ent);
237  if (!floor) {
238  floor = G_SpawnFloor(ent->pos);
239  } else {
240  /* destroy this edict (send this event to all clients that see the edict) */
241  G_EventPerish(*floor);
242  G_VisFlagsReset(*floor);
243  }
244 
245  /* drop items */
246  /* cycle through all containers */
247  for (containerIndex_t container = 0; container < CID_MAX; container++) {
248  /* skip floor - we want to drop to floor */
249  if (container == CID_FLOOR)
250  continue;
251 
252  /* skip CID_ARMOUR, we will collect armours using armour container,
253  * not CID_FLOOR */
254  if (container == CID_ARMOUR || container == CID_IMPLANT)
255  continue;
256 
257  /* now cycle through all items for the container of the character (or the entity) */
258  Item* ic, *next;
259  for (ic = ent->getContainer(container); ic; ic = next) {
260  /* Save the next inv-list before it gets overwritten below.
261  * Do not put this in the "for" statement,
262  * unless you want an endless loop. ;) */
263  next = ic->getNext();
264  Item item = *ic;
265 
266  /* only floor can summarize, so everything on the actor must have amount=1 */
267  assert(item.getAmount() == 1);
268  if (!game.invi.removeFromInventory(&ent->chr.inv, INVDEF(container), ic))
269  gi.Error("Could not remove item '%s' from inventory %i of entity %i",
270  ic->def()->id, container, ent->getIdNum());
271  G_EventInventoryDelete(*ent, G_VisToPM(ent->visflags), container, ic->getX(), ic->getY());
272  if (game.invi.addToInventory(&floor->chr.inv, &item, INVDEF(CID_FLOOR), NONE, NONE, 1) == nullptr)
273  gi.Error("Could not add item '%s' from inventory %i of entity %i to floor container",
274  ic->def()->id, container, ent->getIdNum());
275 #ifdef ADJACENT
276  G_InventoryPlaceItemAdjacent(ent);
277 #endif
278  }
279  /* destroy link */
280  ent->resetContainer(container);
281  }
282 
283  ent->setFloor(floor);
284 
285  /* send item info to the clients */
286  G_CheckVis(floor);
287 }
288 
297 void G_ReadItem (Item* item, const invDef_t** container, int* x, int* y)
298 {
299  int t, m;
300  int ammoleft;
301  int amount;
302  containerIndex_t containerID;
303 
304  gi.ReadFormat("sbsbbbbs", &t, &ammoleft, &m, &containerID, x, y, &item->rotated, &amount);
305  item->setAmmoLeft(ammoleft);
306  item->setAmount(amount);
307 
308  if (t < 0 || t >= gi.csi->numODs)
309  gi.Error("Item index out of bounds: %i", t);
310  item->setDef(&gi.csi->ods[t]);
311 
312  if (m != NONE) {
313  if (m < 0 || m >= gi.csi->numODs)
314  gi.Error("Ammo index out of bounds: %i", m);
315  item->setAmmoDef(&gi.csi->ods[m]);
316  } else {
317  item->setAmmoDef(nullptr);
318  }
319 
320  if (isValidContId(containerID))
321  *container = INVDEF(containerID);
322  else
323  gi.Error("container id is out of bounds: %i", containerID);
324 }
325 
334 void G_WriteItem (const Item& item, const containerIndex_t contId, int x, int y)
335 {
336  assert(item.def());
337  gi.WriteFormat("sbsbbbbs", item.def()->idx, item.getAmmoLeft(), item.ammoDef() ? item.ammoDef()->idx : NONE, contId, x, y, item.rotated, item.getAmount());
338 }
339 
347 void G_SendInventory (playermask_t playerMask, const Edict& ent)
348 {
349  int nr = 0;
350 
351  /* test for pointless player mask */
352  if (!playerMask)
353  return;
354 
355  const Container* cont = nullptr;
356  while ((cont = ent.chr.inv.getNextCont(cont, true))) {
357  if (!G_IsItem(&ent) && INVDEF(cont->id)->temp)
358  continue;
359  nr += cont->countItems();
360  }
361 
362  /* return if no inventory items to send */
363  if (nr == 0)
364  return;
365 
366  G_EventInventoryAdd(ent, playerMask, nr);
367  cont = nullptr;
368  while ((cont = ent.chr.inv.getNextCont(cont, true))) {
369  if (!G_IsItem(&ent) && INVDEF(cont->id)->temp)
370  continue;
371  const Item* item = nullptr;
372  while ((item = cont->getNextItem(item))) {
373  /* send a single item */
374  assert(item->def());
375  G_WriteItem(*item, cont->id, item->getX(), item->getY());
376  }
377  }
378  G_EventEnd();
379 }
void G_EventEnd(void)
Definition: g_events.cpp:711
Edict * G_SpawnFloor(const pos3_t pos)
Spawns a new entity at the floor.
Definition: g_spawn.cpp:535
const objDef_t * INVSH_GetItemByIDSilent(const char *id)
Returns the item that belongs to the given id or nullptr if it wasn't found.
Definition: inv_shared.cpp:249
int getIdNum() const
Definition: g_edict.h:231
Item * getFloor() const
Definition: g_edict.h:262
bool tryAddToInventory(Inventory *const inv, const Item *const item, const invDef_t *container)
Tries to add an item to a container (in the inventory inv).
Definition: inventory.cpp:470
void setAmmoLeft(int value)
Definition: inv_shared.h:441
int numEDs
Definition: q_shared.h:541
void G_CheckVis(Edict *check, const vischeckflags_t visFlags)
Check if the edict appears/perishes for the other teams. If they appear for other teams...
Definition: g_vis.cpp:409
int getAmmoLeft() const
Definition: inv_shared.h:466
Edict * G_GetEdictFromPos(const pos3_t pos, const entity_type_t type)
Searches an edict of the given type at the given grid location.
Definition: g_utils.cpp:59
Misc utility functions for game module.
bool G_InventoryRemoveItemByID(const char *itemID, Edict *ent, containerIndex_t container)
Removes one particular item from a given container.
Definition: g_inventory.cpp:80
static bool G_InventoryDropToFloorCheck(Edict *ent, containerIndex_t container)
Checks whether the given container contains items that should be dropped to the floor. Also removes virtual items.
unsigned int playermask_t
Definition: g_events.h:34
character_t chr
Definition: g_edict.h:116
void setY(const int val)
Definition: inv_shared.h:432
const objDef_t * def(void) const
Definition: inv_shared.h:469
#define CID_ARMOUR
Definition: inv_shared.h:54
const vec4_t dvecs[PATHFINDING_DIRECTIONS]
Definition: mathlib.cpp:58
equipDef_t eds[MAX_EQUIPDEFS]
Definition: q_shared.h:540
static int oldPos
void G_SendInventory(playermask_t playerMask, const Edict &ent)
Sends whole inventory through the network buffer.
InventoryInterface invi
Definition: g_local.h:76
int numODs
Definition: q_shared.h:518
void setDef(const objDef_t *objDef)
Definition: inv_shared.h:444
Item * getNext() const
Definition: inv_shared.h:451
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
const csi_t * csi
Definition: game.h:176
Item * getContainer(const containerIndex_t idx) const
Definition: g_edict.h:243
game_locals_t game
Definition: g_main.cpp:37
item instance data, with linked list capability
Definition: inv_shared.h:402
void G_InventoryToFloor(Edict *ent)
Move items to adjacent locations if the containers on the current floor edict are full...
void setNext(Item *nx)
Definition: inv_shared.h:426
game_import_t gi
Definition: g_main.cpp:39
void findSpace(const invDef_t *container, const Item *item, int *const px, int *const py, const Item *ignoredItem) const
Finds space for item in inv at container.
Definition: inv_shared.cpp:876
void setFloor(const Edict *other)
Definition: g_edict.h:207
#define Vector2Set(v, x, y)
Definition: vector.h:61
void G_ReadItem(Item *item, const invDef_t **container, int *x, int *y)
Read item from the network buffer.
teammask_t visflags
Definition: g_edict.h:82
#define CID_IMPLANT
Definition: inv_shared.h:49
pos3_t pos
Definition: g_edict.h:55
#define CID_FLOOR
Definition: inv_shared.h:55
Edict * G_GetFloorItemFromPos(const pos3_t pos)
Callback to G_GetEdictFromPos() for given position, used to get items from position.
Definition: g_inventory.cpp:48
playermask_t G_VisToPM(teammask_t teamMask)
Converts vis mask to player mask.
Definition: g_client.cpp:186
int getAmount() const
Definition: inv_shared.h:463
#define INVDEF(containerID)
Definition: cl_shared.h:47
int countItems() const
Count the number of items in the Container.
Definition: inv_shared.cpp:681
const equipDef_t * G_GetEquipDefByID(const char *equipID)
Definition: g_inventory.cpp:31
Item * getNextItem(const Item *prev) const
Definition: inv_shared.cpp:671
pos_t pos3_t[3]
Definition: ufotypes.h:58
char id[MAX_VAR]
Definition: inv_shared.h:606
void G_WriteItem(const Item &item, const containerIndex_t contId, int x, int y)
Write an item to the network buffer.
int32_t containerIndex_t
Definition: inv_shared.h:46
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
#define G_IsItem(ent)
Definition: g_local.h:134
bool G_AddItemToFloor(const pos3_t pos, const char *itemID)
Adds a new item to an existing or new floor container edict at the given grid location.
void G_VisFlagsReset(Edict &ent)
Definition: g_vis.cpp:438
QGL_EXTERN GLint i
Definition: r_gl.h:113
void G_EventInventoryDelete(const Edict &ent, playermask_t playerMask, const containerIndex_t containerId, int x, int y)
Tell the client to remove the item from the container.
Definition: g_events.cpp:131
const Container * getNextCont(const Container *prev, bool inclTemp=false) const
Definition: inv_shared.cpp:722
Brings new objects into the world.
void resetFloor()
Definition: g_edict.h:210
void setAmmoDef(const objDef_t *od)
Definition: inv_shared.h:435
void setX(const int val)
Definition: inv_shared.h:429
#define CID_MAX
Definition: inv_shared.h:57
void setFloorContainer(Item *cont)
Definition: inv_shared.cpp:950
void G_EventPerish(const Edict &ent)
Send an event to all clients that are seeing the given edict, that it just has disappeared.
Definition: g_events.cpp:158
void G_EventInventoryAdd(const Edict &ent, playermask_t playerMask, int itemAmount)
Tell the client to add the item from the container.
Definition: g_events.cpp:147
const objDef_t * ammoDef(void) const
Definition: inv_shared.h:460
inventory definition for our menus
Definition: inv_shared.h:371
#define Vector2Copy(src, dest)
Definition: vector.h:52
vec_t vec2_t[2]
Definition: ufotypes.h:38
#define DIRECTIONS
Number of angles from a position (2-dimensional)
Definition: mathlib.h:78
void setAmount(int value)
Definition: inv_shared.h:438
Inventory inv
Definition: chr_shared.h:392
int getX() const
Definition: inv_shared.h:454
bool isValidContId(const containerIndex_t id)
Definition: inv_shared.h:59
objDef_t ods[MAX_OBJDEFS]
Definition: q_shared.h:517
int rotated
Definition: inv_shared.h:412
Edict * G_GetFloorItems(Edict *ent)
Prepares a list of items on the floor at given entity position.
Definition: g_inventory.cpp:59
#define NONE
Definition: defines.h:68
#define Q_streq(a, b)
Definition: shared.h:136
void resetContainer(const containerIndex_t idx)
Definition: g_edict.h:204
Definition: g_edict.h:45
bool isVirtual
Definition: inv_shared.h:284
static struct mdfour * m
Definition: md4.cpp:35
const char * id
Definition: inv_shared.h:268
Interface for g_client.cpp.
int getY() const
Definition: inv_shared.h:457
bool removeFromInventory(Inventory *const inv, const invDef_t *container, Item *fItem) __attribute__((warn_unused_result))
Definition: inventory.cpp:152