UFO: Alien Invasion
Loading...
Searching...
No Matches
cl_inventory_callbacks.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
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
34static int itemIndex;
35static int fireModeIndex;
36
40static 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
68{
69 static char itemText[UI_MAX_SMALLTEXTLEN];
70
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++)
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
230static void INV_IncreaseFiremode_f (void)
231{
233 return;
234
236
238}
239
244static void INV_DecreaseFiremode_f (void)
245{
247 return;
248
250
252}
253
258static void INV_IncreaseItem_f (void)
259{
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
289static void INV_DecreaseItem_f (void)
290{
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
319static 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 */
350}
351
355static 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
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}
@ SKILL_HEAVY
Definition chr_shared.h:43
@ ABILITY_SPEED
Definition chr_shared.h:38
@ SKILL_SNIPER
Definition chr_shared.h:45
@ SKILL_CLOSE
Definition chr_shared.h:42
@ SKILL_EXPLOSIVE
Definition chr_shared.h:46
@ SKILL_ASSAULT
Definition chr_shared.h:44
character_t * GAME_GetSelectedChr(void)
Returns the currently selected character.
Definition cl_game.cpp:1555
bool GAME_ItemIsUseable(const objDef_t *od)
Definition cl_game.cpp:1104
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.
itemFilterTypes_t INV_GetFilterFromItem(const objDef_t *obj)
Header file for inventory handling and Equipment menu.
static const objDef_t * currentDisplayedObject
static void INV_UpdateObject_f(void)
Update the GUI with the selected item.
static int fireModeIndex
static void INV_DecreaseFiremode_f(void)
Decreases the number of the firemode to display.
void INV_ItemDescription(const objDef_t *od)
Prints the description for items (weapons, armour, ...).
static const char * CL_WeaponSkillToName(int weaponSkill)
Translate a weaponSkill integer to a translated string.
static void INV_IncreaseFiremode_f(void)
Increases the number of the firemode to display.
static int itemIndex
void INV_InitCallbacks(void)
static void INV_UpdateActorLoad_f(void)
Update the equipment weight for the selected actor.
static void INV_IncreaseItem_f(void)
Increases the number of the weapon to display (for ammo) or the ammo to display (for weapon).
static void INV_DecreaseItem_f(void)
Decreases the number of the firemode to display (for ammo) or the ammo to display (for weapon).
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
Item * _invList
Definition inv_shared.h:516
const invDef_t * def() const
int getWeight() const
Get the weight of the items in the given inventory (excluding those in temp containers).
const Container * getNextCont(const Container *prev, bool inclTemp=false) const
item instance data, with linked list capability
Definition inv_shared.h:402
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition cmd.cpp:516
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 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_Printf(const char *const fmt,...)
Definition common.cpp:428
cvar_t * Cvar_ForceSet(const char *varName, const char *value)
Will set the variable even if NOSET or LATCH.
Definition cvar.cpp:604
void Cvar_SetValue(const char *varName, float value)
Expands value to a string and calls Cvar_Set.
Definition cvar.cpp:671
cvar_t * Cvar_Set(const char *varName, const char *value,...)
Sets a cvar value.
Definition cvar.cpp:615
cvar_t * Cvar_FindVar(const char *varName)
Searches for a cvar given by parameter.
Definition cvar.cpp:106
#define UNIT_SIZE
Definition defines.h:121
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
#define MAX_FIREDEFS_PER_WEAPON
Definition inv_shared.h:42
#define WEIGHT_NORMAL_PENALTY
Definition q_shared.h:283
#define GET_TU(ab, md)
Definition q_shared.h:291
#define WEIGHT_FACTOR
Definition q_shared.h:285
#define GET_ENCUMBRANCE_PENALTY(weight, max)
Definition q_shared.h:287
QGL_EXTERN GLuint count
Definition r_gl.h:99
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
#define MAX_VAR
Definition shared.h:36
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 Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
Describes a character with all its attributes.
Definition chr_shared.h:388
chrScoreGlobal_t score
Definition chr_shared.h:406
Inventory inv
Definition chr_shared.h:411
int skills[SKILL_NUM_TYPES]
Definition chr_shared.h:122
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition cvar.h:71
int integer
Definition cvar.h:81
char id[MAX_VAR]
Definition inv_shared.h:621
this is a fire definition for our weapons/ammo
Definition inv_shared.h:110
const char * name
Definition inv_shared.h:111
vec2_t damage
Definition inv_shared.h:158
int weaponSkill
Definition inv_shared.h:162
vec2_t spldmg
Definition inv_shared.h:160
vec2_t spread
Definition inv_shared.h:146
float range
Definition inv_shared.h:152
bool temp
Definition inv_shared.h:381
bool isPermanent
Definition inv_shared.h:89
Defines all attributes of objects used in the inventory.
Definition inv_shared.h:264
bool isAmmo() const
Definition inv_shared.h:343
const struct objDef_s * ammos[MAX_AMMOS_PER_OBJDEF]
Definition inv_shared.h:307
bool weapon
Definition inv_shared.h:277
fireDef_t fd[MAX_WEAPONS_PER_OBJDEF][MAX_FIREDEFS_PER_WEAPON]
Definition inv_shared.h:314
fireDefIndex_t numFiredefs[MAX_WEAPONS_PER_OBJDEF]
Definition inv_shared.h:315
itemEffect_t * strengthenEffect
Definition inv_shared.h:283
int numAmmos
Definition inv_shared.h:308
bool fireTwoHanded
Definition inv_shared.h:279
short ratings[MAX_DAMAGETYPES]
Definition inv_shared.h:323
bool implant
Definition inv_shared.h:282
const char * id
Definition inv_shared.h:268
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
const char * name
Definition inv_shared.h:267
void UI_ResetData(int dataId)
Reset a shared data. Type became NONE and value became nullptr.
Definition ui_data.cpp:212
void UI_RegisterText(int dataId, const char *text)
share a text with a data id
Definition ui_data.cpp:115
@ TEXT_ITEMDESCRIPTION
Definition ui_dataids.h:70
void UI_ExecuteConfunc(const char *fmt,...)
Executes confunc - just to identify those confuncs in the code - in this frame.
Definition ui_main.cpp:110
void UI_Popup(const char *title, const char *text)
Popup on geoscape.
Definition ui_popup.cpp:47
char popupText[UI_MAX_SMALLTEXTLEN]
strings to be used for popup when text is not static
Definition ui_popup.cpp:37
#define UI_MAX_SMALLTEXTLEN
Definition ui_popup.h:34