UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cl_inventory_callbacks.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 "cl_inventory_callbacks.h"
26 #include "cl_shared.h"
27 #include "cl_inventory.h"
28 #include "ui/ui_main.h"
29 #include "ui/ui_nodes.h"
30 #include "cgame/cl_game.h"
31 #include "ui/ui_popup.h"
32 
34 static int itemIndex;
35 static int fireModeIndex;
36 
40 static const char* CL_WeaponSkillToName (int weaponSkill)
41 {
42  switch (weaponSkill) {
43  case SKILL_CLOSE:
44  return _("Close quarters");
45 #if 0
46  case SKILL_HEAVY:
47  return _("Heavy");
48 #endif
49  case SKILL_ASSAULT:
50  return _("Assault");
51  case SKILL_SNIPER:
52  return _("Sniper");
53  case SKILL_EXPLOSIVE:
54  return _("Explosives");
55  default:
56  return _("Unknown weapon skill");
57  }
58 }
59 
67 void INV_ItemDescription (const objDef_t* od)
68 {
69  static char itemText[UI_MAX_SMALLTEXTLEN];
70 
71  currentDisplayedObject = od;
72  Cvar_Set("mn_firemodename", "%s", "");
73  Cvar_Set("mn_linkname", "%s", "");
74 
75  if (!od) { /* If nothing selected return */
76  Cvar_Set("mn_itemname", "%s", "");
77  Cvar_Set("mn_item", "%s", "");
80  UI_ExecuteConfunc("itemdesc_view 0 0;");
81  return;
82  }
83 
84  /* select item */
85  Cvar_Set("mn_itemname", "%s", _(od->name));
86  Cvar_Set("mn_item", "%s", od->id);
87 
88  int count = 0;
89  if (GAME_ItemIsUseable(od)) {
90  if (od->isAmmo()) {
91  /* We display the pre/next buttons for changing weapon only if there are at least 2 researched weapons
92  * we are counting the number of weapons that are usable with this ammo */
93  for (int i = 0; i < od->numWeapons; i++)
94  if (GAME_ItemIsUseable(od->weapons[i]))
95  count++;
96  if (itemIndex >= od->numWeapons || itemIndex < 0)
97  itemIndex = 0;
98  if (count > 0) {
99  while (!GAME_ItemIsUseable(od->weapons[itemIndex])) {
100  itemIndex++;
101  if (itemIndex >= od->numWeapons)
102  itemIndex = 0;
103  }
104  Cvar_ForceSet("mn_linkname", _(od->weapons[itemIndex]->name));
105  }
106  } else if (od->weapon) {
107  /* We display the pre/next buttons for changing ammo only if there are at least 2 researched ammo
108  * we are counting the number of ammo that is usable with this weapon */
109  for (int i = 0; i < od->numAmmos; i++)
110  if (GAME_ItemIsUseable(od->ammos[i]))
111  count++;
112 
113  if (itemIndex >= od->numAmmos || itemIndex < 0)
114  itemIndex = 0;
115 
116  /* Only display ammos if at least one has been researched */
117  if (count > 0) {
118  /* We have a weapon that uses ammos */
119  while (!GAME_ItemIsUseable(od->ammos[itemIndex])) {
120  itemIndex++;
121  if (itemIndex >= od->numAmmos)
122  itemIndex = 0;
123  }
124  Cvar_ForceSet("mn_linkname", _(od->ammos[itemIndex]->name));
125  }
126  } else {
127  Cvar_ForceSet("mn_linkname", "");
128  }
129  }
130 
131  /* set description text if item has been researched or one of its ammo/weapon has been researched */
132  if (count > 0 || GAME_ItemIsUseable(od)) {
133  int numFiredefs = 0;
134 
135  *itemText = '\0';
136  if (od->isArmour()) {
137  Com_sprintf(itemText, sizeof(itemText), _("Size:\t%i\n"), od->size);
138  Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight / WEIGHT_FACTOR);
139  Q_strcat(itemText, sizeof(itemText), "\n");
140  Q_strcat(itemText, sizeof(itemText), _("^BDamage type:\tProtection:\n"));
141  for (int i = 0; i < csi.numDTs; i++) {
142  const damageType_t* dt = &csi.dts[i];
143  if (!dt->showInMenu)
144  continue;
145  Q_strcat(itemText, sizeof(itemText), _("%s\t%i\n"), _(dt->id), od->ratings[i]);
146  }
147  } else if ((od->weapon && od->numAmmos) || od->isAmmo()) {
148  const objDef_t* odAmmo;
149 
150  if (count > 0) {
151  int weaponIndex;
152  if (od->weapon) {
153  Com_sprintf(itemText, sizeof(itemText), _("%s weapon\n"), (od->fireTwoHanded ? _("Two-handed") : _("One-handed")));
154  if (od->ammo > 0)
155  Q_strcat(itemText, sizeof(itemText), _("Max ammo:\t%i\n"), od->ammo);
156  odAmmo = (od->numAmmos) ? od->ammos[itemIndex] : od;
157  assert(odAmmo);
158  for (weaponIndex = 0; (weaponIndex < odAmmo->numWeapons) && (odAmmo->weapons[weaponIndex] != od); weaponIndex++) {}
159  } else {
160  odAmmo = od;
161  weaponIndex = itemIndex;
162  }
163 
164  Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight / WEIGHT_FACTOR);
166  if (GAME_ItemIsUseable(odAmmo) && odAmmo->numFiredefs[weaponIndex] > 0) {
167  numFiredefs = odAmmo->numFiredefs[weaponIndex];
168 
169  /* This contains everything common for weapons and ammos */
170  /* We check if the wanted firemode to display exists. */
171  if (fireModeIndex > numFiredefs - 1)
172  fireModeIndex = 0;
173  if (fireModeIndex < 0)
174  fireModeIndex = numFiredefs - 1;
175 
176  const fireDef_t* fd = &odAmmo->fd[weaponIndex][fireModeIndex];
177 
178  /* We always display the name of the firemode for an ammo */
179  Cvar_Set("mn_firemodename", "%s", _(fd->name));
180 
181  /* We display the characteristics of this firemode */
182  Q_strcat(itemText, sizeof(itemText), _("Skill:\t%s\n"), CL_WeaponSkillToName(fd->weaponSkill));
183  Q_strcat(itemText, sizeof(itemText), _("Damage:\t%i\n"), (int) (fd->damage[0] + fd->spldmg[0]) * fd->shots);
184  Q_strcat(itemText, sizeof(itemText), _("Time units:\t%i\n"), fd->time);
185  Q_strcat(itemText, sizeof(itemText), _("Range:\t%g\n"), fd->range / UNIT_SIZE);
186  Q_strcat(itemText, sizeof(itemText), _("Spreads:\t%g\n"), (fd->spread[0] + fd->spread[1]) / 2);
187  }
188  } else {
189  Com_sprintf(itemText, sizeof(itemText), _("%s. No detailed info available.\n"), od->isAmmo() ? _("Ammunition") : _("Weapon"));
190  Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight / WEIGHT_FACTOR);
191  }
192  } else if (od->implant) {
193  //const implantDef_t* implant = INVSH_GetImplantForObjDef(od);
194  /* the strengthen effect that is bound to the implant no matter whether the user triggers some action */
195  itemEffect_t* effect = od->strengthenEffect;
196  if (effect != nullptr) {
197  Q_strcat(itemText, sizeof(itemText), _("Permanent:\t%s\n"), (effect->isPermanent ? _("Yes") : _("No")));
198  Q_strcat(itemText, sizeof(itemText), _("Duration:\t%i\n"), effect->duration);
199  Q_strcat(itemText, sizeof(itemText), _("Period:\t%i\n"), effect->period);
200  }
201  Q_strcat(itemText, sizeof(itemText), _("Price:\t%i c\n"), od->price);
202  } else if (od->weapon) {
203  Com_sprintf(itemText, sizeof(itemText), _("%s ammo-less weapon\n"), (od->fireTwoHanded ? _("Two-handed") : _("One-handed")));
204  Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight / WEIGHT_FACTOR);
205  } else {
206  /* just an item - only primary definition */
207  Com_sprintf(itemText, sizeof(itemText), _("%s auxiliary equipment\n"), (od->fireTwoHanded ? _("Two-handed") : _("One-handed")));
208  Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight / WEIGHT_FACTOR);
209  if (od->numWeapons > 0 && od->numFiredefs[0] > 0) {
210  const fireDef_t* fd = &od->fd[0][0];
211  Q_strcat(itemText, sizeof(itemText), _("Action:\t%s\n"), _(fd->name));
212  Q_strcat(itemText, sizeof(itemText), _("Time units:\t%i\n"), fd->time);
213  Q_strcat(itemText, sizeof(itemText), _("Range:\t%g\n"), fd->range / UNIT_SIZE);
214  }
215  }
216 
218  UI_ExecuteConfunc("itemdesc_view %i %i;", count, numFiredefs);
219  } else {
220  Com_sprintf(itemText, sizeof(itemText), _("Unknown - not useable"));
222  UI_ExecuteConfunc("itemdesc_view 0 0;");
223  }
224 }
225 
230 static void INV_IncreaseFiremode_f (void)
231 {
232  if (!currentDisplayedObject)
233  return;
234 
235  fireModeIndex++;
236 
237  INV_ItemDescription(currentDisplayedObject);
238 }
239 
244 static void INV_DecreaseFiremode_f (void)
245 {
246  if (!currentDisplayedObject)
247  return;
248 
249  fireModeIndex--;
250 
251  INV_ItemDescription(currentDisplayedObject);
252 }
253 
258 static void INV_IncreaseItem_f (void)
259 {
260  const objDef_t* od = currentDisplayedObject;
261 
262  if (!od)
263  return;
264 
265  if (od->numWeapons) {
266  const int current = itemIndex;
267  do {
268  itemIndex++;
269  if (itemIndex > od->numWeapons - 1) {
270  itemIndex = 0;
271  }
272  } while (itemIndex != current && !GAME_ItemIsUseable(od->weapons[itemIndex]));
273  } else if (od->numAmmos) {
274  const int current = itemIndex;
275  do {
276  itemIndex++;
277  if (itemIndex > od->numAmmos - 1) {
278  itemIndex = 0;
279  }
280  } while (itemIndex != current && !GAME_ItemIsUseable(od->ammos[itemIndex]));
281  }
283 }
284 
289 static void INV_DecreaseItem_f (void)
290 {
291  const objDef_t* od = currentDisplayedObject;
292 
293  if (!od)
294  return;
295 
296  if (od->numWeapons) {
297  const int current = itemIndex;
298  do {
299  itemIndex--;
300  if (itemIndex < 0) {
301  itemIndex = od->numWeapons - 1;
302  }
303  } while (itemIndex != current && !GAME_ItemIsUseable(od->weapons[itemIndex]));
304  } else if (od->numAmmos) {
305  const int current = itemIndex;
306  do {
307  itemIndex--;
308  if (itemIndex < 0) {
309  itemIndex = od->numAmmos - 1;
310  }
311  } while (itemIndex != current && !GAME_ItemIsUseable(od->ammos[itemIndex]));
312  }
314 }
315 
319 static void INV_UpdateObject_f (void)
320 {
321  /* check syntax */
322  if (Cmd_Argc() < 3) {
323  Com_Printf("Usage: %s <objectid> <confunc> [mustwechangetab]\n", Cmd_Argv(0));
324  return;
325  }
326 
327  bool changeTab = true;
328  if (Cmd_Argc() == 4)
329  changeTab = atoi(Cmd_Argv(3)) >= 1;
330 
331  const int num = atoi(Cmd_Argv(1));
332  if (num < 0 || num >= csi.numODs) {
333  Com_Printf("Id %i out of range 0..%i\n", num, csi.numODs);
334  return;
335  }
336  const objDef_t* obj = INVSH_GetItemByIDX(num);
337 
338  /* update tab */
339  if (changeTab) {
340  const cvar_t* var = Cvar_FindVar("mn_equiptype");
341  const int filter = INV_GetFilterFromItem(obj);
342  if (var && var->integer != filter) {
343  Cvar_SetValue("mn_equiptype", filter);
344  UI_ExecuteConfunc("%s", Cmd_Argv(2));
345  }
346  }
347 
348  /* update item description */
349  INV_ItemDescription(obj);
350 }
351 
355 static void INV_UpdateActorLoad_f (void)
356 {
357  if (Cmd_Argc() < 2) {
358  Com_Printf("Usage: %s <callback>\n", Cmd_Argv(0));
359  return;
360  }
361 
362  const character_t* chr = GAME_GetSelectedChr();
363  if (chr == nullptr)
364  return;
365 
366  const float invWeight = chr->inv.getWeight();
367  const int maxWeight = GAME_GetChrMaxLoad(chr);
368  const float penalty = GET_ENCUMBRANCE_PENALTY(invWeight, maxWeight);
369  const int normalTU = GET_TU(chr->score.skills[ABILITY_SPEED], 1.0f - WEIGHT_NORMAL_PENALTY);
370  const int tus = GET_TU(chr->score.skills[ABILITY_SPEED], penalty);
371  const int tuPenalty = tus - normalTU;
372  int count = 0;
373 
374  const Container* cont = nullptr;
375  while ((cont = chr->inv.getNextCont(cont))) {
376  if (cont->def()->temp)
377  continue;
378  for (Item* invList = cont->_invList, *next; invList; invList = next) {
379  next = invList->getNext();
380  const fireDef_t* fireDef = invList->getFiredefs();
381  if (fireDef == nullptr)
382  continue;
383  for (int i = 0; i < MAX_FIREDEFS_PER_WEAPON; i++) {
384  if (fireDef[i].time <= 0)
385  continue;
386  if (fireDef[i].time <= tus)
387  continue;
388  if (count <= 0)
389  Com_sprintf(popupText, sizeof(popupText), _("This soldier no longer has enough TUs to use the following items:\n\n"));
390  Q_strcat(popupText, sizeof(popupText), "%s: %s (%i)\n", _(invList->def()->name), _(fireDef[i].name), fireDef[i].time);
391  ++count;
392  }
393  }
394  }
395 
396  if ((Cmd_Argc() < 3 || atoi(Cmd_Argv(2)) == 0) && count > 0)
397  UI_Popup(_("Warning"), popupText);
398 
399  char label[MAX_VAR];
400  char tooltip[MAX_VAR];
401  Com_sprintf(label, sizeof(label), "%g/%i %s %s", invWeight / WEIGHT_FACTOR, maxWeight, _("Kg"),
402  (count > 0 ? _("Warning!") : ""));
403  Com_sprintf(tooltip, sizeof(tooltip), "%s %i (%+i)", _("TU:"), tus, tuPenalty);
404  UI_ExecuteConfunc("%s \"%s\" \"%s\" %f %i", Cmd_Argv(1), label, tooltip, WEIGHT_NORMAL_PENALTY - (1.0f - penalty), count);
405 }
406 
407 void INV_InitCallbacks (void)
408 {
409  Cmd_AddCommand("mn_increasefiremode", INV_IncreaseFiremode_f, "Increases the number of the firemode to display");
410  Cmd_AddCommand("mn_decreasefiremode", INV_DecreaseFiremode_f, "Decreases the number of the firemode to display");
411  Cmd_AddCommand("mn_increaseitem", INV_IncreaseItem_f, "Increases the number of the weapon or the ammo to display");
412  Cmd_AddCommand("mn_decreaseitem", INV_DecreaseItem_f, "Decreases the number of the weapon or the ammo to display");
413  Cmd_AddCommand("object_update", INV_UpdateObject_f, "Update the GUI with the selected item");
414  Cmd_AddCommand("mn_updateactorload", INV_UpdateActorLoad_f, "Update the GUI with the selected actor inventory load");
415 }
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition: cmd.cpp:516
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition: cmd.cpp:744
#define WEIGHT_NORMAL_PENALTY
Definition: q_shared.h:283
static const objDef_t * currentDisplayedObject
bool showInMenu
Definition: inv_shared.h:622
int price
Definition: inv_shared.h:332
static int itemIndex
chrScoreGlobal_t score
Definition: chr_shared.h:387
char popupText[UI_MAX_SMALLTEXTLEN]
strings to be used for popup when text is not static
Definition: ui_popup.cpp:37
bool implant
Definition: inv_shared.h:282
this is a fire definition for our weapons/ammo
Definition: inv_shared.h:110
void UI_RegisterText(int dataId, const char *text)
share a text with a data id
Definition: ui_data.cpp:115
static void INV_DecreaseItem_f(void)
Decreases the number of the firemode to display (for ammo) or the ammo to display (for weapon) ...
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
vec2_t spread
Definition: inv_shared.h:146
#define _(String)
Definition: cl_shared.h:43
csi_t csi
Definition: common.cpp:39
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
vec2_t spldmg
Definition: inv_shared.h:160
Shared game type headers.
static int fireModeIndex
fireDef_t fd[MAX_WEAPONS_PER_OBJDEF][MAX_FIREDEFS_PER_WEAPON]
Definition: inv_shared.h:314
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.
int numDTs
Definition: q_shared.h:545
static const char * CL_WeaponSkillToName(int weaponSkill)
Translate a weaponSkill integer to a translated string.
const struct objDef_s * ammos[MAX_AMMOS_PER_OBJDEF]
Definition: inv_shared.h:307
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
int integer
Definition: cvar.h:81
bool isPermanent
Definition: inv_shared.h:89
int GAME_GetChrMaxLoad(const character_t *chr)
Returns the max weight the given character can carry.
Definition: cl_game.cpp:1768
#define UI_MAX_SMALLTEXTLEN
Definition: ui_popup.h:34
#define WEIGHT_FACTOR
Definition: q_shared.h:285
Share stuff between the different cgame implementations.
bool fireTwoHanded
Definition: inv_shared.h:279
item instance data, with linked list capability
Definition: inv_shared.h:402
void UI_ResetData(int dataId)
Reset a shared data. Type became NONE and value became nullptr.
Definition: ui_data.cpp:212
fireDefIndex_t numFiredefs[MAX_WEAPONS_PER_OBJDEF]
Definition: inv_shared.h:315
#define MAX_VAR
Definition: shared.h:36
#define GET_TU(ab, md)
Definition: q_shared.h:291
int getWeight() const
Get the weight of the items in the given inventory (excluding those in temp containers).
Definition: inv_shared.cpp:937
static void INV_DecreaseFiremode_f(void)
Decreases the number of the firemode to display.
int numWeapons
Definition: inv_shared.h:317
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition: cmd.cpp:505
void INV_ItemDescription(const objDef_t *od)
Prints the description for items (weapons, armour, ...)
bool isAmmo() const
Definition: inv_shared.h:343
#define MAX_FIREDEFS_PER_WEAPON
Definition: inv_shared.h:42
damageType_t dts[MAX_DAMAGETYPES]
Definition: q_shared.h:544
short ratings[MAX_DAMAGETYPES]
Definition: inv_shared.h:323
bool weapon
Definition: inv_shared.h:277
const invDef_t * def() const
Definition: inv_shared.cpp:667
Item * _invList
Definition: inv_shared.h:516
vec2_t damage
Definition: inv_shared.h:158
character_t * GAME_GetSelectedChr(void)
Returns the currently selected character.
Definition: cl_game.cpp:1746
const char * name
Definition: inv_shared.h:267
#define UNIT_SIZE
Definition: defines.h:121
QGL_EXTERN GLuint count
Definition: r_gl.h:99
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
char id[MAX_VAR]
Definition: inv_shared.h:621
static void INV_IncreaseFiremode_f(void)
Increases the number of the firemode to display.
#define GET_ENCUMBRANCE_PENALTY(weight, max)
Definition: q_shared.h:287
int weight
Definition: inv_shared.h:335
float range
Definition: inv_shared.h:152
QGL_EXTERN GLint i
Definition: r_gl.h:113
itemEffect_t * strengthenEffect
Definition: inv_shared.h:283
const Container * getNextCont(const Container *prev, bool inclTemp=false) const
Definition: inv_shared.cpp:722
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
int size
Definition: inv_shared.h:334
bool temp
Definition: inv_shared.h:381
int ammo
Definition: inv_shared.h:293
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition: shared.cpp:475
bool isArmour() const
Definition: inv_shared.h:346
const char * name
Definition: inv_shared.h:111
static void INV_IncreaseItem_f(void)
Increases the number of the weapon to display (for ammo) or the ammo to display (for weapon) ...
int weaponSkill
Definition: inv_shared.h:162
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
Inventory inv
Definition: chr_shared.h:392
cvar_t * Cvar_ForceSet(const char *varName, const char *value)
Will set the variable even if NOSET or LATCH.
Definition: cvar.cpp:604
cvar_t * Cvar_Set(const char *varName, const char *value,...)
Sets a cvar value.
Definition: cvar.cpp:615
itemFilterTypes_t INV_GetFilterFromItem(const objDef_t *obj)
void INV_InitCallbacks(void)
int numAmmos
Definition: inv_shared.h:308
bool GAME_ItemIsUseable(const objDef_t *od)
Definition: cl_game.cpp:1295
static void INV_UpdateActorLoad_f(void)
Update the equipment weight for the selected actor.
void UI_Popup(const char *title, const char *text)
Popup on geoscape.
Definition: ui_popup.cpp:47
void Cvar_SetValue(const char *varName, float value)
Expands value to a string and calls Cvar_Set.
Definition: cvar.cpp:671
cvar_t * Cvar_FindVar(const char *varName)
Searches for a cvar given by parameter.
Definition: cvar.cpp:106
int skills[SKILL_NUM_TYPES]
Definition: chr_shared.h:122
static void INV_UpdateObject_f(void)
Update the GUI with the selected item.
const char * id
Definition: inv_shared.h:268
const struct objDef_s * weapons[MAX_WEAPONS_PER_OBJDEF]
Definition: inv_shared.h:311
void UI_ExecuteConfunc(const char *fmt,...)
Executes confunc - just to identify those confuncs in the code - in this frame.
Definition: ui_main.cpp:110
Describes a character with all its attributes.
Definition: chr_shared.h:369