Bug Summary

File:client/battlescape/cl_hud.cpp
Location:line 1040, column 3
Description:Value stored to 'iconOffsetY' is never read

Annotated Source Code

1/**
2 * @file
3 * @brief HUD related routines.
4 */
5
6/*
7Copyright (C) 2002-2012 UFO: Alien Invasion.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24*/
25
26#include "../client.h"
27#include "cl_localentity.h"
28#include "cl_actor.h"
29#include "cl_hud.h"
30#include "cl_hud_callbacks.h"
31#include "cl_view.h"
32#include "../cgame/cl_game.h"
33#include "../ui/ui_main.h"
34#include "../ui/ui_popup.h"
35#include "../ui/ui_nodes.h"
36#include "../ui/ui_draw.h"
37#include "../ui/ui_render.h"
38#include "../ui/ui_tooltip.h"
39#include "../renderer/r_mesh_anim.h"
40#include "../renderer/r_draw.h"
41#include "../../common/grid.h"
42
43static cvar_t *cl_hud_message_timeout;
44static cvar_t *cl_show_cursor_tooltips;
45cvar_t *cl_worldlevel;
46cvar_t *cl_hud;
47
48enum {
49 REMAINING_TU_RELOAD_RIGHT,
50 REMAINING_TU_RELOAD_LEFT,
51 REMAINING_TU_CROUCH,
52
53 REMAINING_TU_MAX
54};
55static bool displayRemainingTus[REMAINING_TU_MAX];
56
57typedef enum {
58 BT_RIGHT_FIRE,
59 BT_REACTION,
60 BT_LEFT_FIRE,
61 BT_RIGHT_RELOAD,
62 BT_LEFT_RELOAD,
63 BT_STAND,
64 BT_CROUCH,
65 BT_HEADGEAR,
66
67 BT_NUM_TYPES
68} buttonTypes_t;
69
70/** @brief a cbuf string for each button_types_t */
71static char const* const shootTypeStrings[] = {
72 "primaryright",
73 "reaction",
74 "primaryleft",
75 "reloadright",
76 "reloadleft",
77 "stand",
78 "crouch",
79 "headgear"
80};
81CASSERT(lengthof(shootTypeStrings) == BT_NUM_TYPES)extern int ASSERT_COMPILE[(((sizeof(shootTypeStrings) / sizeof
(*(shootTypeStrings))) == BT_NUM_TYPES) != 0) * 2 - 1]
;
82
83/**
84 * @brief Defines the various states of a button.
85 * @note Not all buttons do have all of these states (e.g. "unusable" is not very common).
86 */
87typedef enum {
88 BT_STATE_DISABLE, /**< 'Disabled' display (grey) */
89 BT_STATE_DESELECT /**< Normal display (blue) */
90} weaponButtonState_t;
91
92/** @note Order of elements here must correspond to order of elements in walkType_t. */
93static char const* const moveModeDescriptions[] = {
94 N_("Crouch walk")"Crouch walk",
95 N_("Autostand")"Autostand",
96 N_("Walk")"Walk",
97 N_("Crouch walk")"Crouch walk"
98};
99CASSERT(lengthof(moveModeDescriptions) == WALKTYPE_MAX)extern int ASSERT_COMPILE[(((sizeof(moveModeDescriptions) / sizeof
(*(moveModeDescriptions))) == WALKTYPE_MAX) != 0) * 2 - 1]
;
100
101typedef struct reserveShot_s {
102 actorHands_t hand;
103 int fireModeIndex;
104 int weaponIndex;
105 int TUs;
106} reserveShot_t;
107
108/**
109 * @brief Displays a message on the hud.
110 * @sa UI_DisplayNotice
111 * @param[in] text text is already translated here
112 */
113void HUD_DisplayMessage (const char *text)
114{
115 assert(text)(__builtin_expect(!(text), 0) ? __assert_rtn(__func__, "src/client/battlescape/cl_hud.cpp"
, 115, "text") : (void)0)
;
116 UI_DisplayNotice(text, cl_hud_message_timeout->integer, cl_hud->string);
117}
118
119/**
120 * @brief Updates the global character cvars for battlescape.
121 * @note This is only called when we are in battlescape rendering mode
122 * It's assumed that every living actor - @c le_t - has a character assigned, too
123 */
124static void HUD_UpdateAllActors (void)
125{
126 int i;
127 const size_t size = lengthof(cl.teamList)(sizeof(cl.teamList) / sizeof(*(cl.teamList)));
128
129 Cvar_SetValue("mn_numaliensspotted", cl.numEnemiesSpotted);
130 for (i = 0; i < size; i++) {
131 const le_t *le = cl.teamList[i];
132 if (le && !LE_IsDead(le)((le)->state & 0x0003)) {
133 const invList_t *invList;
134 const char* tooltip;
135 const character_t *chr = CL_ActorGetChr(le);
136 assert(chr)(__builtin_expect(!(chr), 0) ? __assert_rtn(__func__, "src/client/battlescape/cl_hud.cpp"
, 136, "chr") : (void)0)
;
137
138 invList = RIGHT(le)(((le)->i.c[(csi.idRight)]));
139 if ((!invList || !invList->item.t || !invList->item.t->holdTwoHanded) && LEFT(le)(((le)->i.c[(csi.idLeft)])))
140 invList = LEFT(le)(((le)->i.c[(csi.idLeft)]));
141
142 tooltip = va(_("%s\nHP: %i/%i TU: %i\n%s")gettext("%s\nHP: %i/%i TU: %i\n%s"),
143 chr->name, le->HP, le->maxHP, le->TU, (invList && invList->item.t) ? _(invList->item.t->name)gettext(invList->item.t->name) : "");
144
145 UI_ExecuteConfunc("updateactorvalues %i \"%s\" \"%i\" \"%i\" \"%i\" \"%i\" \"%i\" \"%i\" \"%i\" \"%s\"",
146 i, le->model2->name, le->HP, le->maxHP, le->TU, le->maxTU, le->morale, le->maxMorale, le->STUN, tooltip);
147 }
148 }
149}
150
151/**
152 * @brief Sets the display for a single weapon/reload HUD button.
153 * @todo This should be a confunc which also sets the tooltips
154 */
155static void HUD_SetWeaponButton (buttonTypes_t button, weaponButtonState_t state)
156{
157 const char *prefix;
158
159 switch (state) {
160 case BT_STATE_DESELECT:
161 prefix = "deselect_";
162 break;
163 case BT_STATE_DISABLE:
164 prefix = "disable_";
165 break;
166 default:
167 prefix = "";
168 break;
169 }
170
171 /* Connect confunc strings to the ones as defined in "menu hud_nohud". */
172 UI_ExecuteConfunc("%s%s", prefix, shootTypeStrings[button]);
173}
174
175/**
176 * @brief Returns the amount of usable "reaction fire" TUs for this actor (depends on active/inactive RF)
177 * @param[in] le The actor to check.
178 * @return The remaining/usable TUs for this actor
179 * @return -1 on error (this includes bad [very large] numbers stored in the struct).
180 * @todo Maybe only return "reaction" value if reaction-state is active? The value _should_ be 0, but one never knows :)
181 */
182static int HUD_UsableReactionTUs (const le_t * le)
183{
184 /* Get the amount of usable TUs depending on the state (i.e. is RF on or off?) */
185 if (le->state & STATE_REACTION0x0300)
186 /* CL_ActorUsableTUs DOES NOT return the stored value for "reaction" here. */
187 return CL_ActorUsableTUs(le) + CL_ActorReservedTUs(le, RES_REACTION);
188 else
189 /* CL_ActorUsableTUs DOES return the stored value for "reaction" here. */
190 return CL_ActorUsableTUs(le);
191}
192
193/**
194 * @brief Check if at least one firemode is available for reservation.
195 * @return true if there is at least one firemode - false otherwise.
196 * @sa HUD_RefreshButtons
197 * @sa HUD_PopupFiremodeReservation_f
198 */
199static bool HUD_CheckFiremodeReservation (void)
200{
201 actorHands_t hand = ACTOR_HAND_RIGHT;
202
203 if (!selActor)
204 return false;
205
206 do { /* Loop for the 2 hands (l/r) to avoid unnecessary code-duplication and abstraction. */
207 const fireDef_t *fireDef;
208
209 /* Get weapon (and its ammo) from the hand. */
210 fireDef = HUD_GetFireDefinitionForHand(selActor, hand);
211 if (fireDef) {
212 int i;
213 const objDef_t *ammo = fireDef->obj;
214 for (i = 0; i < ammo->numFiredefs[fireDef->weapFdsIdx]; i++) {
215 /* Check if at least one firemode is available for reservation. */
216 if (CL_ActorUsableTUs(selActor) + CL_ActorReservedTUs(selActor, RES_SHOT) >= ammo->fd[fireDef->weapFdsIdx][i].time)
217 return true;
218 }
219 }
220
221 /* Prepare for next run or for end of loop. */
222 if (hand == ACTOR_HAND_RIGHT)
223 hand = ACTOR_HAND_LEFT;
224 else
225 break;
226 } while (true);
227
228 /* No reservation possible */
229 return false;
230}
231
232
233/**
234 * @brief Sets TU-reservation and firemode
235 * @param[in] le The local entity of the actor to change the tu reservation for.
236 * @param[in] tus How many TUs to set.
237 * @param[in] hand Store the given hand.
238 * @param[in] fireModeIndex Store the given firemode for this hand.
239 * @param[in] weapon Pointer to weapon in the hand.
240 */
241static void HUD_SetShootReservation (const le_t* le, const int tus, const actorHands_t hand, const int fireModeIndex, const objDef_t *weapon)
242{
243 character_t* chr = CL_ActorGetChr(le);
244 assert(chr)(__builtin_expect(!(chr), 0) ? __assert_rtn(__func__, "src/client/battlescape/cl_hud.cpp"
, 244, "chr") : (void)0)
;
245
246 CL_ActorReserveTUs(le, RES_SHOT, tus);
247 CL_ActorSetShotSettings(chr, hand, fireModeIndex, weapon);
248}
249
250static linkedList_t* popupListData;
251static uiNode_t* popupListNode;
252
253/**
254 * @brief Creates a (text) list of all firemodes of the currently selected actor.
255 * @param[in] le The actor local entity
256 * @param[in] popupReload Prevent firemode reservation popup from being closed if
257 * no firemode is available because of insufficient TUs.
258 * @sa HUD_PopupFiremodeReservation_f
259 * @sa HUD_CheckFiremodeReservation
260 * @todo use components and confuncs here
261 */
262static void HUD_PopupFiremodeReservation (const le_t *le, bool popupReload)
263{
264 actorHands_t hand = ACTOR_HAND_RIGHT;
265 int i;
266 static char text[MAX_VAR64];
267 int selectedEntry;
268 linkedList_t* popupListText = NULL__null;
269 reserveShot_t reserveShotData;
270
271 /* reset the list */
272 UI_ResetData(TEXT_LIST);
273
274 LIST_Delete(&popupListData);
275
276 /* Add list-entry for deactivation of the reservation. */
277 LIST_AddPointer(&popupListText, _("[0 TU] No reservation")gettext("[0 TU] No reservation"));
278 reserveShotData.hand = ACTOR_HAND_NOT_SET;
279 reserveShotData.fireModeIndex = -1;
280 reserveShotData.weaponIndex = NONE-1;
281 reserveShotData.TUs = -1;
282 LIST_Add(&popupListData, reserveShotData);
283 selectedEntry = 0;
284
285 do { /* Loop for the 2 hands (l/r) to avoid unnecessary code-duplication and abstraction. */
286 const fireDef_t *fd = HUD_GetFireDefinitionForHand(le, hand);
287 character_t* chr = CL_ActorGetChr(le);
288 assert(chr)(__builtin_expect(!(chr), 0) ? __assert_rtn(__func__, "src/client/battlescape/cl_hud.cpp"
, 288, "chr") : (void)0)
;
289
290 if (fd) {
291 const objDef_t *ammo = fd->obj;
292
293 for (i = 0; i < ammo->numFiredefs[fd->weapFdsIdx]; i++) {
294 const fireDef_t* ammoFD = &ammo->fd[fd->weapFdsIdx][i];
295 if (CL_ActorUsableTUs(le) + CL_ActorReservedTUs(le, RES_SHOT) >= ammoFD->time) {
296 /* Get firemode name and TUs. */
297 Com_sprintf(text, lengthof(text)(sizeof(text) / sizeof(*(text))), _("[%i TU] %s")gettext("[%i TU] %s"), ammoFD->time, _(ammoFD->name)gettext(ammoFD->name));
298
299 /* Store text for popup */
300 LIST_AddString(&popupListText, text);
301
302 /* Store Data for popup-callback. */
303 reserveShotData.hand = hand;
304 reserveShotData.fireModeIndex = i;
305 reserveShotData.weaponIndex = ammo->weapons[fd->weapFdsIdx]->idx;
306 reserveShotData.TUs = ammoFD->time;
307 LIST_Add(&popupListData, reserveShotData);
308
309 /* Remember the line that is currently selected (if any). */
310 if (chr->reservedTus.shotSettings.hand == hand
311 && chr->reservedTus.shotSettings.fmIdx == i
312 && chr->reservedTus.shotSettings.weapon == ammo->weapons[fd->weapFdsIdx])
313 selectedEntry = LIST_Count(popupListData) - 1;
314 }
315 }
316 }
317
318 /* Prepare for next run or for end of loop. */
319 if (hand == ACTOR_HAND_RIGHT)
320 /* First run. Set hand for second run of the loop (other hand) */
321 hand = ACTOR_HAND_LEFT;
322 else
323 break;
324 } while (true);
325
326 if (LIST_Count(popupListData) > 1 || popupReload) {
327 /* We have more entries than the "0 TUs" one
328 * or we want to simply refresh/display the popup content (no matter how many TUs are left). */
329 popupListNode = UI_PopupList(_("Shot Reservation")gettext("Shot Reservation"), _("Reserve TUs for firing/using.")gettext("Reserve TUs for firing/using."), popupListText, "hud_shotreserve <lineselected>");
330 /* Set color for selected entry. */
331 VectorSet(popupListNode->selectedColor, 0.0, 0.78, 0.0)((popupListNode->selectedColor)[0]=(0.0), (popupListNode->
selectedColor)[1]=(0.78), (popupListNode->selectedColor)[2
]=(0.0))
;
332 popupListNode->selectedColor[3] = 1.0;
333 UI_TextNodeSelectLine(popupListNode, selectedEntry);
334 }
335}
336
337/**
338 * @brief Creates a (text) list of all firemodes of the currently selected actor.
339 * @sa HUD_PopupFiremodeReservation
340 */
341static void HUD_PopupFiremodeReservation_f (void)
342{
343 if (!selActor)
344 return;
345
346 /* A second parameter (the value itself will be ignored) was given.
347 * This is used to reset the shot-reservation.*/
348 if (Cmd_Argc() == 2) {
349 HUD_SetShootReservation(selActor, 0, ACTOR_HAND_NOT_SET, -1, NULL__null);
350 } else {
351 HUD_PopupFiremodeReservation(selActor, false);
352 }
353}
354
355/**
356 * @brief Get selected firemode in the list of the currently selected actor.
357 * @sa HUD_PopupFiremodeReservation_f
358 */
359static void HUD_ShotReserve_f (void)
360{
361 int selectedPopupIndex;
362 const reserveShot_t* reserveShotData;
363
364 if (Cmd_Argc() < 2) {
365 Com_Printf("Usage: %s <popupindex>\n", Cmd_Argv(0));
366 return;
367 }
368
369 if (!selActor)
370 return;
371
372 /* read and range check */
373 selectedPopupIndex = atoi(Cmd_Argv(1));
374 if (selectedPopupIndex < 0 || selectedPopupIndex >= LIST_Count(popupListData))
375 return;
376
377 reserveShotData = (const reserveShot_t *)LIST_GetByIdx(popupListData, selectedPopupIndex);
378 if (!reserveShotData)
379 return;
380
381 if (reserveShotData->weaponIndex == NONE-1) {
382 HUD_SetShootReservation(selActor, 0, ACTOR_HAND_NOT_SET, -1, NULL__null);
383 return;
384 }
385
386 /** @todo do this on the server */
387 /* Check if we have enough TUs (again) */
388 if (CL_ActorUsableTUs(selActor) + CL_ActorReservedTUs(selActor, RES_SHOT) >= reserveShotData->TUs) {
389 const objDef_t *od = INVSH_GetItemByIDX(reserveShotData->weaponIndex);
390 if (GAME_ItemIsUseable(od)) {
391 HUD_SetShootReservation(selActor, std::max(0, reserveShotData->TUs), reserveShotData->hand, reserveShotData->fireModeIndex, od);
392 if (popupListNode)
393 UI_TextNodeSelectLine(popupListNode, selectedPopupIndex);
394 }
395 }
396}
397
398/**
399 * @brief Sets the display for a single weapon/reload HUD button.
400 * @param[in] hand What list to display
401 */
402static void HUD_DisplayFiremodeEntry (const char* callback, const le_t* actor, const objDef_t* ammo, const weaponFireDefIndex_t weapFdsIdx, const actorHands_t hand, int index)
403{
404 int usableTusForRF;
405 char tuString[MAX_VAR64];
406 bool status;
407 const fireDef_t *fd;
408 const char *tooltip;
409 char id[32];
410
411 if (index < ammo->numFiredefs[weapFdsIdx]) {
412 /* We have a defined fd ... */
413 fd = &ammo->fd[weapFdsIdx][index];
414 } else {
415 return;
416 }
417
418 assert(actor)(__builtin_expect(!(actor), 0) ? __assert_rtn(__func__, "src/client/battlescape/cl_hud.cpp"
, 418, "actor") : (void)0)
;
419 assert(hand == ACTOR_HAND_RIGHT || hand == ACTOR_HAND_LEFT)(__builtin_expect(!(hand == ACTOR_HAND_RIGHT || hand == ACTOR_HAND_LEFT
), 0) ? __assert_rtn(__func__, "src/client/battlescape/cl_hud.cpp"
, 419, "hand == ACTOR_HAND_RIGHT || hand == ACTOR_HAND_LEFT")
: (void)0)
;
420
421 status = fd->time <= CL_ActorUsableTUs(actor);
422 usableTusForRF = HUD_UsableReactionTUs(actor);
423
424 if (usableTusForRF > fd->time) {
425 Com_sprintf(tuString, sizeof(tuString), _("Remaining TUs: %i")gettext("Remaining TUs: %i"), usableTusForRF - fd->time);
426 tooltip = tuString;
427 } else
428 tooltip = _("No remaining TUs left after shot.")gettext("No remaining TUs left after shot.");
429
430 /* unique identifier of the action */
431 /* @todo use this id as action callback instead of hand and index (we can extend it with any other soldier action we need (open door, reload...)) */
432 Com_sprintf(id, sizeof(id), "fire_hand%c_i%i", ACTOR_GET_HAND_CHAR(hand)((hand) == ACTOR_HAND_LEFT ? (char)'l' : (char)'r'), index);
433
434 UI_ExecuteConfunc("%s firemode %s %c %i %i %i \"%s\" \"%i\" \"%i\" \"%s\"", callback, id, ACTOR_GET_HAND_CHAR(hand)((hand) == ACTOR_HAND_LEFT ? (char)'l' : (char)'r'),
435 fd->fdIdx, fd->reaction, status, _(fd->name)gettext(fd->name), fd->time, fd->ammo, tooltip);
436
437 /* Display checkbox for reaction firemode */
438 if (fd->reaction) {
439 character_t* chr = CL_ActorGetChr(actor);
440 const bool active = THIS_FIREMODE(&chr->RFmode, hand, fd->fdIdx)((&chr->RFmode)->hand == (hand) && (&chr
->RFmode)->fmIdx == (fd->fdIdx))
;
441 /* Change the state of the checkbox. */
442 UI_ExecuteConfunc("%s reaction %s %c %i", callback, id, ACTOR_GET_HAND_CHAR(hand)((hand) == ACTOR_HAND_LEFT ? (char)'l' : (char)'r'), active);
443 }
444}
445
446/**
447 * List actions from a soldier to a callback confunc
448 * @param callback confunc callback
449 * @param actor actor who can do the actions
450 * @param right if true, list right firemode
451 * @param left if true, list left firemode
452 * @param reloadRight if true, list right weapon reload actions
453 * @param reloadLeft if true, list left weapon reload actions
454 * @todo we can extend it with short cut equip action, more reload, action on the map (like open doors)...
455 */
456static void HUD_DisplayActions (const char* callback, const le_t* actor, bool right, bool left, bool reloadRight, bool reloadLeft)
457{
458 const objDef_t *ammo;
459 const fireDef_t *fd;
460 int i;
461
462 if (!actor)
463 return;
464
465 if (cls.team != cl.actTeam) { /**< Not our turn */
466 return;
467 }
468
469 UI_ExecuteConfunc("%s begin", callback);
470
471 if (right) {
472 const actorHands_t hand = ACTOR_HAND_RIGHT;
473 fd = HUD_GetFireDefinitionForHand(actor, hand);
474 if (fd == NULL__null)
475 return;
476
477 ammo = fd->obj;
478 if (!ammo) {
479 Com_DPrintf(DEBUG_CLIENT0x20, "HUD_DisplayFiremodes: no weapon or ammo found.\n");
480 return;
481 }
482
483 for (i = 0; i < MAX_FIREDEFS_PER_WEAPON8; i++) {
484 /* Display the firemode information (image + text). */
485 HUD_DisplayFiremodeEntry(callback, actor, ammo, fd->weapFdsIdx, hand, i);
486 }
487 }
488
489 if (reloadRight) {
490 invList_t* weapon = RIGHT(actor)(((actor)->i.c[(csi.idRight)]));
491
492 /* Reloeadable item in hand. */
493 if (weapon && weapon->item.t && weapon->item.t->reload) {
494 int tus;
495 containerIndex_t container = csi.idRight;
496 bool noAmmo;
497 bool noTU;
498 const char *actionId = "reload_handr";
499
500 tus = HUD_CalcReloadTime(actor, weapon->item.t, container);
501 noAmmo = tus == -1;
502 noTU = actor->TU < tus;
503 UI_ExecuteConfunc("%s reload %s %c %i %i %i", callback, actionId, 'r', tus, !noAmmo, !noTU);
504 }
505 }
506
507 if (left) {
508 const actorHands_t hand = ACTOR_HAND_LEFT;
509 fd = HUD_GetFireDefinitionForHand(actor, hand);
510 if (fd == NULL__null)
511 return;
512
513 ammo = fd->obj;
514 if (!ammo) {
515 Com_DPrintf(DEBUG_CLIENT0x20, "HUD_DisplayFiremodes: no weapon or ammo found.\n");
516 return;
517 }
518
519 for (i = 0; i < MAX_FIREDEFS_PER_WEAPON8; i++) {
520 /* Display the firemode information (image + text). */
521 HUD_DisplayFiremodeEntry(callback, actor, ammo, fd->weapFdsIdx, hand, i);
522 }
523 }
524
525
526 if (reloadLeft) {
527 invList_t* weapon = LEFT(actor)(((actor)->i.c[(csi.idLeft)]));
528
529 /* Reloeadable item in hand. */
530 if (weapon && weapon->item.t && weapon->item.t->reload) {
531 int tus;
532 containerIndex_t container = csi.idLeft;
533 bool noAmmo;
534 bool noTU;
535 const char *actionId = "reload_handl";
536
537 tus = HUD_CalcReloadTime(actor, weapon->item.t, container);
538 noAmmo = tus == -1;
539 noTU = actor->TU < tus;
540 UI_ExecuteConfunc("%s reload %s %c %i %i %i", callback, actionId, 'l', tus, !noAmmo, !noTU);
541 }
542 }
543
544 UI_ExecuteConfunc("%s end", callback);
545}
546
547/**
548 * @brief Displays the firemodes for the given hand.
549 */
550static void HUD_DisplayActions_f (void)
551{
552 char callback[32];
553 bool right;
554 bool left;
555 bool rightReload;
556 bool leftReload;
557
558 if (!selActor)
559 return;
560
561 right = strchr(Cmd_Argv(2), 'r') != NULL__null;
562 left = strchr(Cmd_Argv(2), 'l') != NULL__null;
563 rightReload = strchr(Cmd_Argv(2), 'R') != NULL__null;
564 leftReload = strchr(Cmd_Argv(2), 'L') != NULL__null;
565
566 Q_strncpyz(callback, Cmd_Argv(1), sizeof(callback))Q_strncpyzDebug( callback, Cmd_Argv(1), sizeof(callback), "src/client/battlescape/cl_hud.cpp"
, 566 )
;
567 HUD_DisplayActions(callback, selActor, right, left, rightReload, leftReload);
568}
569
570/**
571 * @brief Displays the firemodes for the given hand.
572 */
573static void HUD_DisplayFiremodes_f (void)
574{
575 actorHands_t hand;
576 char callback[32];
577
578 if (!selActor)
579 return;
580
581 if (Cmd_Argc() < 3)
582 /* no argument given */
583 hand = ACTOR_HAND_RIGHT;
584 else
585 hand = ACTOR_GET_HAND_INDEX(Cmd_Argv(2)[0])((Cmd_Argv(2)[0]) == (char)'l' ? ACTOR_HAND_LEFT : ACTOR_HAND_RIGHT
)
;
586
587 Q_strncpyz(callback, Cmd_Argv(1), sizeof(callback))Q_strncpyzDebug( callback, Cmd_Argv(1), sizeof(callback), "src/client/battlescape/cl_hud.cpp"
, 587 )
;
588 HUD_DisplayActions(callback, selActor, hand == ACTOR_HAND_RIGHT, hand == ACTOR_HAND_LEFT, false, false);
589}
590
591/**
592 * @brief Changes the display of the firemode-list to a given hand, but only if the list is visible already.
593 * @todo Delete that function: Should be done from within the scripts
594 */
595static void HUD_SwitchFiremodeList_f (void)
596{
597 /* no argument given */
598 if (Cmd_Argc() < 2) {
599 Com_Printf("Usage: %s callback [l|r]\n", Cmd_Argv(0));
600 return;
601 }
602
603 {
604 char callback[32];
605 actorHands_t hand;
606 hand = ACTOR_GET_HAND_INDEX(Cmd_Argv(2)[0])((Cmd_Argv(2)[0]) == (char)'l' ? ACTOR_HAND_LEFT : ACTOR_HAND_RIGHT
)
;
607 Q_strncpyz(callback, Cmd_Argv(1), sizeof(callback))Q_strncpyzDebug( callback, Cmd_Argv(1), sizeof(callback), "src/client/battlescape/cl_hud.cpp"
, 607 )
;
608 HUD_DisplayActions(callback, selActor, hand == ACTOR_HAND_RIGHT, hand == ACTOR_HAND_LEFT, false, false);
609 }
610}
611
612/**
613 * @brief Updates the information in RFmode for the selected actor with the given data from the parameters.
614 * @param[in] actor The actor we want to update the reaction-fire firemode for.
615 * @param[in] hand Which weapon(-hand) to use.
616 * @param[in] firemodeActive Set this to the firemode index you want to activate or set it to -1 if the default one (currently the first one found) should be used.
617 */
618static void HUD_UpdateReactionFiremodes (const le_t * actor, const actorHands_t hand, fireDefIndex_t firemodeActive)
619{
620 const fireDef_t *fd;
621 const objDef_t *ammo, *od;
622
623 assert(actor)(__builtin_expect(!(actor), 0) ? __assert_rtn(__func__, "src/client/battlescape/cl_hud.cpp"
, 623, "actor") : (void)0)
;
624
625 fd = HUD_GetFireDefinitionForHand(actor, hand);
626 if (fd == NULL__null)
627 return;
628
629 ammo = fd->obj;
630 od = ammo->weapons[fd->weapFdsIdx];
631
632 if (!GAME_ItemIsUseable(od))
633 return;
634
635 MSG_Write_PA(PA_REACT_SELECT, actor->entnum, hand, firemodeActive, od ? od->idx : NONE-1);
636}
637
638/**
639 * @brief Checks if the selected firemode checkbox is ok as a reaction firemode and updates data+display.
640 */
641static void HUD_SelectReactionFiremode_f (void)
642{
643 actorHands_t hand;
644 fireDefIndex_t firemode;
645
646 if (Cmd_Argc() < 3) { /* no argument given */
647 Com_Printf("Usage: %s [l|r] <num> num=firemode number\n", Cmd_Argv(0));
648 return;
649 }
650
651 if (!selActor)
652 return;
653
654 hand = ACTOR_GET_HAND_INDEX(Cmd_Argv(1)[0])((Cmd_Argv(1)[0]) == (char)'l' ? ACTOR_HAND_LEFT : ACTOR_HAND_RIGHT
)
;
655 firemode = atoi(Cmd_Argv(2));
656
657 if (firemode >= MAX_FIREDEFS_PER_WEAPON8 || firemode < 0) {
658 Com_Printf("HUD_SelectReactionFiremode_f: Firemode out of bounds (%i).\n", firemode);
659 return;
660 }
661
662 HUD_UpdateReactionFiremodes(selActor, hand, firemode);
663}
664
665/**
666 * @brief Remember if we hover over a button that would cost some TUs when pressed.
667 * @note this is used in HUD_Update to update the "remaining TUs" bar correctly.
668 */
669static void HUD_RemainingTUs_f (void)
670{
671 bool state;
672 const char *type;
673
674 if (Cmd_Argc() < 3) {
675 Com_Printf("Usage: %s <type> <popupindex>\n", Cmd_Argv(0));
676 return;
677 }
678
679 type = Cmd_Argv(1);
680 state = Com_ParseBoolean(Cmd_Argv(2));
681
682 OBJZERO(displayRemainingTus)(memset(&((displayRemainingTus)), (0), sizeof((displayRemainingTus
))))
;
683
684 if (Q_streq(type, "reload_r")(strcmp(type, "reload_r") == 0)) {
685 displayRemainingTus[REMAINING_TU_RELOAD_RIGHT] = state;
686 } else if (Q_streq(type, "reload_l")(strcmp(type, "reload_l") == 0)) {
687 displayRemainingTus[REMAINING_TU_RELOAD_LEFT] = state;
688 } else if (Q_streq(type, "crouch")(strcmp(type, "crouch") == 0)) {
689 displayRemainingTus[REMAINING_TU_CROUCH] = state;
690 }
691}
692
693/**
694 * @return The minimum time needed to fire the weapons in the given @c invList
695 */
696static int HUD_GetMinimumTUsForUsage (const invList_t *invList)
697{
698 const fireDef_t *fdArray;
699 int time = 100;
700 int i;
701
702 assert(invList->item.t)(__builtin_expect(!(invList->item.t), 0) ? __assert_rtn(__func__
, "src/client/battlescape/cl_hud.cpp", 702, "invList->item.t"
) : (void)0)
;
703
704 fdArray = FIRESH_FiredefForWeapon(&invList->item);
705 if (fdArray == NULL__null)
706 return time;
707
708 /* Search for the smallest TU needed to shoot. */
709 for (i = 0; i < MAX_FIREDEFS_PER_WEAPON8; i++) {
710 if (!fdArray[i].time)
711 continue;
712 if (fdArray[i].time < time)
713 time = fdArray[i].time;
714 }
715
716 return time;
717}
718
719/**
720 * @brief Checks every case for reload buttons on the HUD.
721 * @param[in] le Pointer of local entity being an actor.
722 * @param[in] containerID of the container to reload the weapon in. Used to get the movement TUs for moving something into the container.
723 * @param[out] reason The reason why the reload didn't work - only set if @c -1 is the return value
724 * @return TU units needed for reloading or -1 if weapon cannot be reloaded.
725 */
726static int HUD_WeaponCanBeReloaded (const le_t *le, containerIndex_t containerID, const char **reason)
727{
728 const int tu = CL_ActorUsableTUs(le);
729 const invList_t *invList = CONTAINER(le, containerID)((le)->i.c[(containerID)]);
730 const objDef_t *weapon;
731
732 assert(le)(__builtin_expect(!(le), 0) ? __assert_rtn(__func__, "src/client/battlescape/cl_hud.cpp"
, 732, "le") : (void)0)
;
733
734 /* No weapon in hand. */
735 if (!invList) {
736 *reason = _("No weapon.")gettext("No weapon.");
737 return -1;
738 }
739
740 weapon = invList->item.t;
741 assert(weapon)(__builtin_expect(!(weapon), 0) ? __assert_rtn(__func__, "src/client/battlescape/cl_hud.cpp"
, 741, "weapon") : (void)0)
;
742
743 /* This weapon cannot be reloaded. */
744 if (!weapon->reload) {
745 *reason = _("Weapon cannot be reloaded.")gettext("Weapon cannot be reloaded.");
746 return -1;
747 }
748
749 /* Weapon is fully loaded. */
750 if (invList->item.m && weapon->ammo == invList->item.a) {
751 *reason = _("No reload possible, already fully loaded.")gettext("No reload possible, already fully loaded.");
752 return -1;
753 }
754
755 /* Weapon is empty or not fully loaded, find ammo of any type loadable to this weapon. */
756 if (!invList->item.m || weapon->ammo > invList->item.a) {
757 const int tuCosts = HUD_CalcReloadTime(le, weapon, containerID);
758 if (tuCosts >= 0) {
759 if (tu >= tuCosts)
760 return tuCosts;
761 *reason = _("Not enough TUs for reloading weapon.")gettext("Not enough TUs for reloading weapon.");
762 } else {
763 /* Found no ammo which could be used for this weapon. */
764 *reason = _("No reload possible, you don't have backup ammo.")gettext("No reload possible, you don't have backup ammo.");
765 }
766 }
767
768 return -1;
769}
770
771/**
772 * @brief Checks if there is a weapon in the hand that can be used for reaction fire.
773 * @param[in] actor What actor to check.
774 */
775static bool HUD_WeaponWithReaction (const le_t * actor)
776{
777 const objDef_t *weapon = INVSH_HasReactionFireEnabledWeapon(RIGHT(actor)(((actor)->i.c[(csi.idRight)])));
778 if (weapon)
779 return true;
780 return INVSH_HasReactionFireEnabledWeapon(LEFT(actor)(((actor)->i.c[(csi.idLeft)]))) != NULL__null;
781}
782
783/**
784 * @brief Display 'impossible" (red) reaction buttons.
785 * @param[in] actor the actor to check for his reaction state.
786 * @return true if nothing changed message was sent otherwise false.
787 */
788static bool HUD_DisplayImpossibleReaction (const le_t * actor)
789{
790 if (!actor)
791 return false;
792
793 /* Given actor does not equal the currently selected actor. */
794 if (!actor->selected)
795 return false;
796
797 /* Display 'impossible" (red) reaction buttons */
798 if (actor->state & STATE_REACTION0x0300) {
799 UI_ExecuteConfunc("startreaction_impos");
800 return false;
801 }
802
803 return true;
804}
805
806/**
807 * @brief Display 'usable" (blue) reaction buttons.
808 * @param[in] actor the actor to check for his reaction state.
809 */
810static void HUD_DisplayPossibleReaction (const le_t * actor)
811{
812 if (!actor)
813 return;
814
815 /* Given actor does not equal the currently selected actor. This normally only happens on game-start. */
816 if (!actor->selected)
817 return;
818
819 /* Display 'usable" (blue) reaction buttons */
820 if (actor->state & STATE_REACTION0x0300)
821 UI_ExecuteConfunc("startreaction");
822}
823
824/**
825 * @brief Refreshes the weapon/reload buttons on the HUD.
826 * @param[in] le Pointer to local entity for which we refresh HUD buttons.
827 */
828static void HUD_RefreshButtons (const le_t *le)
829{
830 invList_t *weaponr;
831 invList_t *weaponl;
832 invList_t *headgear;
833 int rightCanBeReloaded, leftCanBeReloaded;
834 const int time = CL_ActorUsableTUs(le);
835 const char *reason;
836
837 if (!le)
838 return;
839
840 weaponr = RIGHT(le)(((le)->i.c[(csi.idRight)]));
841 headgear = HEADGEAR(le)(((le)->i.c[(csi.idHeadgear)]));
842
843 /* check for two-handed weapon - if not, also define weaponl */
844 if (!weaponr || !weaponr->item.t->holdTwoHanded)
845 weaponl = LEFT(le)(((le)->i.c[(csi.idLeft)]));
846 else
847 weaponl = NULL__null;
848
849 /* Crouch/stand button. */
850 if (LE_IsCrouched(le)((le)->state & 0x0004)) {
851 if (time + CL_ActorReservedTUs(le, RES_CROUCH) < TU_CROUCH3) {
852 Cvar_Set("mn_crouchstand_tt", _("Not enough TUs for standing up.")gettext("Not enough TUs for standing up."));
853 HUD_SetWeaponButton(BT_CROUCH, BT_STATE_DISABLE);
854 } else {
855 Cvar_Set("mn_crouchstand_tt", va(_("Stand up (%i TU)")gettext("Stand up (%i TU)"), TU_CROUCH3));
856 HUD_SetWeaponButton(BT_CROUCH, BT_STATE_DESELECT);
857 }
858 } else {
859 if (time + CL_ActorReservedTUs(le, RES_CROUCH) < TU_CROUCH3) {
860 Cvar_Set("mn_crouchstand_tt", _("Not enough TUs for crouching.")gettext("Not enough TUs for crouching."));
861 HUD_SetWeaponButton(BT_STAND, BT_STATE_DISABLE);
862 } else {
863 Cvar_Set("mn_crouchstand_tt", va(_("Crouch (%i TU)")gettext("Crouch (%i TU)"), TU_CROUCH3));
864 HUD_SetWeaponButton(BT_STAND, BT_STATE_DESELECT);
865 }
866 }
867
868 /* Crouch/stand reservation checkbox. */
869 if (CL_ActorReservedTUs(le, RES_CROUCH) >= TU_CROUCH3) {
870 UI_ExecuteConfunc("crouch_checkbox_check");
871 Cvar_Set("mn_crouch_reservation_tt", va(_("%i TUs reserved for crouching/standing up.\nClick to clear.")gettext("%i TUs reserved for crouching/standing up.\nClick to clear."
)
,
872 CL_ActorReservedTUs(le, RES_CROUCH)));
873 } else if (time >= TU_CROUCH3) {
874 UI_ExecuteConfunc("crouch_checkbox_clear");
875 Cvar_Set("mn_crouch_reservation_tt", va(_("Reserve %i TUs for crouching/standing up.")gettext("Reserve %i TUs for crouching/standing up."), TU_CROUCH3));
876 } else {
877 UI_ExecuteConfunc("crouch_checkbox_disable");
878 Cvar_Set("mn_crouch_reservation_tt", _("Not enough TUs left to reserve for crouching/standing up.")gettext("Not enough TUs left to reserve for crouching/standing up."
)
);
879 }
880
881 /* Shot reservation button. mn_shot_reservation_tt is the tooltip text */
882 if (CL_ActorReservedTUs(le, RES_SHOT)) {
883 UI_ExecuteConfunc("reserve_shot_check");
884 Cvar_Set("mn_shot_reservation_tt", va(_("%i TUs reserved for shooting.\nClick to change.\nRight-Click to clear.")gettext("%i TUs reserved for shooting.\nClick to change.\nRight-Click to clear."
)
,
885 CL_ActorReservedTUs(le, RES_SHOT)));
886 } else if (HUD_CheckFiremodeReservation()) {
887 UI_ExecuteConfunc("reserve_shot_clear");
888 Cvar_Set("mn_shot_reservation_tt", _("Reserve TUs for shooting.")gettext("Reserve TUs for shooting."));
889 } else {
890 UI_ExecuteConfunc("reserve_shot_disable");
891 Cvar_Set("mn_shot_reservation_tt", _("Reserving TUs for shooting not possible.")gettext("Reserving TUs for shooting not possible."));
892 }
893
894 /* reaction-fire button */
895 if (!(le->state & STATE_REACTION0x0300)) {
896 if (time >= CL_ActorReservedTUs(le, RES_REACTION) && HUD_WeaponWithReaction(le))
897 HUD_SetWeaponButton(BT_REACTION, BT_STATE_DESELECT);
898 else
899 HUD_SetWeaponButton(BT_REACTION, BT_STATE_DISABLE);
900 } else {
901 if (HUD_WeaponWithReaction(le)) {
902 HUD_DisplayPossibleReaction(le);
903 } else {
904 HUD_DisplayImpossibleReaction(le);
905 }
906 }
907
908 /* Reload buttons */
909 rightCanBeReloaded = HUD_WeaponCanBeReloaded(le, csi.idRight, &reason);
910 if (rightCanBeReloaded != -1) {
911 HUD_SetWeaponButton(BT_RIGHT_RELOAD, BT_STATE_DESELECT);
912 Cvar_Set("mn_reloadright_tt", va(_("Reload weapon (%i TU).")gettext("Reload weapon (%i TU)."), rightCanBeReloaded));
913 } else {
914 Cvar_Set("mn_reloadright_tt", reason);
915 HUD_SetWeaponButton(BT_RIGHT_RELOAD, BT_STATE_DISABLE);
916 }
917
918 leftCanBeReloaded = HUD_WeaponCanBeReloaded(le, csi.idLeft, &reason);
919 if (leftCanBeReloaded != -1) {
920 HUD_SetWeaponButton(BT_LEFT_RELOAD, BT_STATE_DESELECT);
921 Cvar_Set("mn_reloadleft_tt", va(_("Reload weapon (%i TU).")gettext("Reload weapon (%i TU)."), leftCanBeReloaded));
922 } else {
923 Cvar_Set("mn_reloadleft_tt", reason);
924 HUD_SetWeaponButton(BT_LEFT_RELOAD, BT_STATE_DISABLE);
925 }
926
927 /* Headgear button */
928 if (headgear) {
929 const int minheadgeartime = HUD_GetMinimumTUsForUsage(headgear);
930 if (time < minheadgeartime)
931 HUD_SetWeaponButton(BT_HEADGEAR, BT_STATE_DISABLE);
932 else
933 HUD_SetWeaponButton(BT_HEADGEAR, BT_STATE_DESELECT);
934 } else {
935 HUD_SetWeaponButton(BT_HEADGEAR, BT_STATE_DISABLE);
936 }
937
938 /* Weapon firing buttons. */
939 if (weaponr) {
940 const int minweaponrtime = HUD_GetMinimumTUsForUsage(weaponr);
941 if (time < minweaponrtime)
942 HUD_SetWeaponButton(BT_RIGHT_FIRE, BT_STATE_DISABLE);
943 else
944 HUD_SetWeaponButton(BT_RIGHT_FIRE, BT_STATE_DESELECT);
945 } else {
946 HUD_SetWeaponButton(BT_RIGHT_FIRE, BT_STATE_DISABLE);
947 }
948
949 if (weaponl) {
950 const int minweaponltime = HUD_GetMinimumTUsForUsage(weaponl);
951 if (time < minweaponltime)
952 HUD_SetWeaponButton(BT_LEFT_FIRE, BT_STATE_DISABLE);
953 else
954 HUD_SetWeaponButton(BT_LEFT_FIRE, BT_STATE_DESELECT);
955 } else {
956 HUD_SetWeaponButton(BT_LEFT_FIRE, BT_STATE_DISABLE);
957 }
958
959 /* Check if the firemode reservation popup is shown and refresh its content. (i.e. close&open it) */
960 {
961 const char* menuName = UI_GetActiveWindowName();
962 if (menuName[0] != '\0' && strstr(UI_GetActiveWindowName(), POPUPLIST_NODE_NAME"popup_list")) {
963 /* Update firemode reservation popup. */
964 /** @todo this is called every frames... is this really needed? */
965 HUD_PopupFiremodeReservation(le, true);
966 }
967 }
968}
969
970/**
971 * @brief Draw the mouse cursor tooltips in battlescape
972 * @param xOffset
973 * @param yOffset
974 * @param textId The text id to get the tooltip string from.
975 */
976static void HUD_DrawMouseCursorText (int xOffset, int yOffset, int textId)
977{
978 const char *string = UI_GetText(textId);
979 if (string && cl_show_cursor_tooltips->integer)
980 UI_DrawTooltip(string, mousePosX + xOffset, mousePosY - yOffset, viddef.virtualWidth - mousePosX);
981}
982
983/**
984 * @brief Updates the cursor texts when in battlescape
985 */
986void HUD_UpdateCursor (void)
987{
988 /* Offset of the first icon on the x-axis. */
989 int iconOffsetX = 16;
990 /* Offset of the first icon on the y-axis. */
991 /* the space between different icons. */
992 const int iconSpacing = 2;
993 le_t *le = selActor;
994 if (le) {
995 int iconOffsetY = 16;
996 image_t *image;
997 /* icon width */
998 int iconW = 16;
999 /* icon height. */
1000 int iconH = 16;
1001 int width = 0;
1002 int bgX = mousePosX + iconOffsetX / 2 - 2;
1003
1004 /* checks if icons should be drawn */
1005 if (!(LE_IsCrouched(le)((le)->state & 0x0004) || (le->state & STATE_REACTION0x0300)))
1006 /* make place holder for icons */
1007 bgX += iconW + 4;
1008
1009 /* if exists gets width of player name */
1010 if (UI_GetText(TEXT_MOUSECURSOR_PLAYERNAMES))
1011 R_FontTextSize("f_verysmall", UI_GetText(TEXT_MOUSECURSOR_PLAYERNAMES), viddef.virtualWidth - bgX, LONGLINES_WRAP, &width, NULL__null, NULL__null, NULL__null);
1012
1013 /* gets width of background */
1014 if (width == 0 && UI_GetText(TEXT_MOUSECURSOR_RIGHT)) {
1015 R_FontTextSize("f_verysmall", UI_GetText(TEXT_MOUSECURSOR_RIGHT), viddef.virtualWidth - bgX, LONGLINES_WRAP, &width, NULL__null, NULL__null, NULL__null);
1016 }
1017
1018 /* Display 'crouch' icon if actor is crouched. */
1019 if (LE_IsCrouched(le)((le)->state & 0x0004)) {
1020 image = R_FindImage("pics/cursors/ducked", it_pic);
1021 if (image)
1022 R_DrawImage(mousePosX - image->width / 2 + iconOffsetX, mousePosY - image->height / 2 + iconOffsetY, image);
1023 }
1024
1025 /* Height of 'crouched' icon. */
1026 iconOffsetY += 16;
1027 iconOffsetY += iconSpacing;
1028
1029 /* Display 'Reaction shot' icon if actor has it activated. */
1030 if (le->state & STATE_REACTION0x0300)
1031 image = R_FindImage("pics/cursors/reactionfire", it_pic);
1032 else
1033 image = NULL__null;
1034
1035 if (image)
1036 R_DrawImage(mousePosX - image->width / 2 + iconOffsetX, mousePosY - image->height / 2 + iconOffsetY, image);
1037
1038 /* Height of 'reaction fire' icon. ... just in case we add further icons below.*/
1039 iconOffsetY += iconH;
1040 iconOffsetY += iconSpacing;
Value stored to 'iconOffsetY' is never read
1041
1042 /* Display weaponmode (text) heR_ */
1043 HUD_DrawMouseCursorText(iconOffsetX + iconW, -10, TEXT_MOUSECURSOR_RIGHT);
1044 }
1045
1046 /* playernames */
1047 HUD_DrawMouseCursorText(iconOffsetX + 16, -26, TEXT_MOUSECURSOR_PLAYERNAMES);
1048 UI_ResetData(TEXT_MOUSECURSOR_PLAYERNAMES);
1049
1050 if (cl_map_debug->integer & MAPDEBUG_TEXT(1<<1)) {
1051 /* Display ceiling text */
1052 HUD_DrawMouseCursorText(0, -64, TEXT_MOUSECURSOR_TOP);
1053 /* Display floor text */
1054 HUD_DrawMouseCursorText(0, 64, TEXT_MOUSECURSOR_BOTTOM);
1055 /* Display left text */
1056 HUD_DrawMouseCursorText(-64, 0, TEXT_MOUSECURSOR_LEFT);
1057 }
1058}
1059
1060/**
1061 * @brief Shows map pathfinding debugging parameters (if activated)
1062 * @param[in] le The current selected actors entity
1063 */
1064static void HUD_MapDebugCursor (const le_t *le)
1065{
1066 if (cl_map_debug->integer & MAPDEBUG_TEXT(1<<1)) {
1067 int dvec;
1068
1069 static char topText[UI_MAX_SMALLTEXTLEN1024];
1070 static char bottomText[UI_MAX_SMALLTEXTLEN1024];
1071 static char leftText[UI_MAX_SMALLTEXTLEN1024];
1072
1073 /* Display the floor and ceiling values for the current cell. */
1074 Com_sprintf(topText, lengthof(topText)(sizeof(topText) / sizeof(*(topText))), "%u-(%i,%i,%i)\n",
1075 Grid_Ceiling(cl.mapData->map, ACTOR_GET_FIELDSIZE(le)((le != __null) ? (le)->fieldSize : 1), truePos), truePos[0], truePos[1], truePos[2]);
1076 /* Save the text for later display next to the cursor. */
1077 UI_RegisterText(TEXT_MOUSECURSOR_TOP, topText);
1078
1079 /* Display the floor and ceiling values for the current cell. */
1080 Com_sprintf(bottomText, lengthof(bottomText)(sizeof(bottomText) / sizeof(*(bottomText))), "%i-(%i,%i,%i)\n",
1081 Grid_Floor(cl.mapData->map, ACTOR_GET_FIELDSIZE(le)((le != __null) ? (le)->fieldSize : 1), truePos), mousePos[0], mousePos[1], mousePos[2]);
1082 /* Save the text for later display next to the cursor. */
1083 UI_RegisterText(TEXT_MOUSECURSOR_BOTTOM, bottomText);
1084
1085 /* Display the floor and ceiling values for the current cell. */
1086 dvec = Grid_MoveNext(&cl.pathMap, mousePos, 0);
1087 Com_sprintf(leftText, lengthof(leftText)(sizeof(leftText) / sizeof(*(leftText))), "%i-%i\n", getDVdir(dvec)((dvec) >> 8), getDVz(dvec)((dvec) & 0x0007));
1088 /* Save the text for later display next to the cursor. */
1089 UI_RegisterText(TEXT_MOUSECURSOR_LEFT, leftText);
1090 }
1091}
1092
1093/**
1094 * @param actor The actor to update the hud for
1095 * @return The amount of TUs needed for the current pending action
1096 */
1097static int HUD_UpdateActorFireMode (le_t *actor)
1098{
1099 const invList_t *selWeapon;
1100 int time = 0;
1101
1102 /* get weapon */
1103 if (IS_MODE_FIRE_HEADGEAR(actor->actorMode)((actor->actorMode) == M_FIRE_HEADGEAR)) {
1104 selWeapon = HEADGEAR(actor)(((actor)->i.c[(csi.idHeadgear)]));
1105 } else if (IS_MODE_FIRE_LEFT(actor->actorMode)((actor->actorMode) == M_FIRE_L || (actor->actorMode) ==
M_PEND_FIRE_L)
) {
1106 selWeapon = HUD_GetLeftHandWeapon(actor, NULL__null);
1107 } else {
1108 selWeapon = RIGHT(actor)(((actor)->i.c[(csi.idRight)]));
1109 }
1110
1111 UI_ResetData(TEXT_MOUSECURSOR_RIGHT);
1112
1113 if (selWeapon) {
1114 static char infoText[UI_MAX_SMALLTEXTLEN1024];
1115
1116 if (!selWeapon->item.t) {
1117 /* No valid weapon in the hand. */
1118 CL_ActorSetFireDef(actor, NULL__null);
1119 } else {
1120 /* Check whether this item uses/has ammo. */
1121 if (!selWeapon->item.m) {
1122 CL_ActorSetFireDef(actor, NULL__null);
1123 /* This item does not use ammo, check for existing firedefs in this item. */
1124 /* This is supposed to be a weapon or other usable item. */
1125 if (selWeapon->item.t->numWeapons > 0) {
1126 if (selWeapon->item.t->weapon || selWeapon->item.t->weapons[0] == selWeapon->item.t) {
1127 const fireDef_t *fdArray = FIRESH_FiredefForWeapon(&selWeapon->item);
1128 if (fdArray != NULL__null) {
1129 /* Get firedef from the weapon (or other usable item) entry instead. */
1130 const fireDef_t *old = FIRESH_GetFiredef(selWeapon->item.t, fdArray->weapFdsIdx, actor->currentSelectedFiremode);
1131 CL_ActorSetFireDef(actor, old);
1132 }
1133 }
1134 }
1135 } else {
1136 const fireDef_t *fdArray = FIRESH_FiredefForWeapon(&selWeapon->item);
1137 if (fdArray != NULL__null) {
1138 const fireDef_t *old = FIRESH_GetFiredef(selWeapon->item.m, fdArray->weapFdsIdx, actor->currentSelectedFiremode);
1139 /* reset the align if we switched the firemode */
1140 CL_ActorSetFireDef(actor, old);
1141 }
1142 }
1143 }
1144
1145 if (!GAME_ItemIsUseable(selWeapon->item.t)) {
1146 HUD_DisplayMessage(_("You cannot use this unknown item.\nYou need to research it first.")gettext("You cannot use this unknown item.\nYou need to research it first."
)
);
1147 CL_ActorSetMode(actor, M_MOVE);
1148 } else if (actor->fd) {
1149 const int hitProbability = CL_GetHitProbability(actor);
1150 static char mouseText[UI_MAX_SMALLTEXTLEN1024];
1151
1152 Com_sprintf(infoText, lengthof(infoText)(sizeof(infoText) / sizeof(*(infoText))),
1153 "%s\n%s (%i) [%i%%] %i\n", _(selWeapon->item.t->name)gettext(selWeapon->item.t->name), _(actor->fd->name)gettext(actor->fd->name),
1154 actor->fd->ammo, hitProbability, actor->fd->time);
1155
1156 /* Save the text for later display next to the cursor. */
1157 Q_strncpyz(mouseText, infoText, lengthof(mouseText))Q_strncpyzDebug( mouseText, infoText, (sizeof(mouseText) / sizeof
(*(mouseText))), "src/client/battlescape/cl_hud.cpp", 1157 )
;
1158 UI_RegisterText(TEXT_MOUSECURSOR_RIGHT, mouseText);
1159
1160 time = actor->fd->time;
1161 /* if no TUs left for this firing action
1162 * or if the weapon is reloadable and out of ammo,
1163 * then change to move mode */
1164 if ((selWeapon->item.t->reload && selWeapon->item.a <= 0) || CL_ActorUsableTUs(actor) < time)
1165 CL_ActorSetMode(actor, M_MOVE);
1166 } else if (selWeapon) {
1167 Com_sprintf(infoText, lengthof(infoText)(sizeof(infoText) / sizeof(*(infoText))), _("%s\n(empty)\n")gettext("%s\n(empty)\n"), _(selWeapon->item.t->name)gettext(selWeapon->item.t->name));
1168 }
1169
1170 UI_RegisterText(TEXT_STANDARD, infoText);
1171 } else {
1172 CL_ActorSetMode(actor, M_MOVE);
1173 }
1174
1175 return time;
1176}
1177
1178/**
1179 * @param[in] actor The actor to update the hud for
1180 * @return The amount of TUs needed for the current pending action
1181 */
1182static int HUD_UpdateActorMove (const le_t *actor)
1183{
1184 const int reservedTUs = CL_ActorReservedTUs(actor, RES_ALL_ACTIVE);
1185 static char infoText[UI_MAX_SMALLTEXTLEN1024];
1186 if (actor->actorMoveLength == ROUTING_NOT_REACHABLE0xFF) {
1187 UI_ResetData(TEXT_MOUSECURSOR_RIGHT);
1188 if (reservedTUs > 0)
1189 Com_sprintf(infoText, lengthof(infoText)(sizeof(infoText) / sizeof(*(infoText))), _("Morale %i | Reserved TUs: %i\n")gettext("Morale %i | Reserved TUs: %i\n"), actor->morale, reservedTUs);
1190 else
1191 Com_sprintf(infoText, lengthof(infoText)(sizeof(infoText) / sizeof(*(infoText))), _("Morale %i")gettext("Morale %i"), actor->morale);
1192 } else {
1193 static char mouseText[UI_MAX_SMALLTEXTLEN1024];
1194 const int moveMode = CL_ActorMoveMode(actor, actor->actorMoveLength);
1195 if (reservedTUs > 0)
1196 Com_sprintf(infoText, lengthof(infoText)(sizeof(infoText) / sizeof(*(infoText))), _("Morale %i | Reserved TUs: %i\n%s %i (%i|%i TUs left)\n")gettext("Morale %i | Reserved TUs: %i\n%s %i (%i|%i TUs left)\n"
)
,
1197 actor->morale, reservedTUs, _(moveModeDescriptions[moveMode])gettext(moveModeDescriptions[moveMode]), actor->actorMoveLength,
1198 actor->TU - actor->actorMoveLength, actor->TU - reservedTUs - actor->actorMoveLength);
1199 else
1200 Com_sprintf(infoText, lengthof(infoText)(sizeof(infoText) / sizeof(*(infoText))), _("Morale %i\n%s %i (%i TUs left)\n")gettext("Morale %i\n%s %i (%i TUs left)\n"), actor->morale,
1201 _(moveModeDescriptions[moveMode])gettext(moveModeDescriptions[moveMode]), actor->actorMoveLength, actor->TU - actor->actorMoveLength);
1202
1203 if (actor->actorMoveLength <= CL_ActorUsableTUs(actor))
1204 Com_sprintf(mouseText, lengthof(mouseText)(sizeof(mouseText) / sizeof(*(mouseText))), "%i (%i)\n", actor->actorMoveLength, CL_ActorUsableTUs(actor));
1205 else
1206 Com_sprintf(mouseText, lengthof(mouseText)(sizeof(mouseText) / sizeof(*(mouseText))), "- (-)\n");
1207
1208 UI_RegisterText(TEXT_MOUSECURSOR_RIGHT, mouseText);
1209 }
1210
1211 UI_RegisterText(TEXT_STANDARD, infoText);
1212
1213 return actor->actorMoveLength;
1214}
1215
1216static void HUD_UpdateActorCvar (const le_t *actor, const char *cvarPrefix)
1217{
1218 const invList_t* invList;
1219 const char *animName;
1220 static char tuTooltipText[UI_MAX_SMALLTEXTLEN1024];
1221
1222 Cvar_SetValue(va("%s%s", cvarPrefix, "hp"), actor->HP);
1223 Cvar_SetValue(va("%s%s", cvarPrefix, "hpmax"), actor->maxHP);
1224 Cvar_SetValue(va("%s%s", cvarPrefix, "tu"), actor->TU);
1225 Cvar_SetValue(va("%s%s", cvarPrefix, "tumax"), actor->maxTU);
1226 Cvar_SetValue(va("%s%s", cvarPrefix, "tureserved"), CL_ActorReservedTUs(actor, RES_ALL_ACTIVE));
1227 Cvar_SetValue(va("%s%s", cvarPrefix, "morale"), actor->morale);
1228 Cvar_SetValue(va("%s%s", cvarPrefix, "moralemax"), actor->maxMorale);
1229 Cvar_SetValue(va("%s%s", cvarPrefix, "stun"), actor->STUN);
1230
1231 Com_sprintf(tuTooltipText, lengthof(tuTooltipText)(sizeof(tuTooltipText) / sizeof(*(tuTooltipText))),
1232 _("Time Units\n- Available: %i (of %i)\n- Reserved: %i\n- Remaining: %i\n")gettext("Time Units\n- Available: %i (of %i)\n- Reserved: %i\n- Remaining: %i\n"
)
,
1233 actor->TU, actor->maxTU, CL_ActorReservedTUs(actor, RES_ALL_ACTIVE), CL_ActorUsableTUs(actor));
1234 Cvar_Set(va("%s%s", cvarPrefix, "tu_tooltips"), tuTooltipText);
1235
1236 /* animation and weapons */
1237 animName = R_AnimGetName(&actor->as, actor->model1);
1238 if (animName)
1239 Cvar_Set(va("%s%s", cvarPrefix, "anim"), animName);
1240 if (RIGHT(actor)(((actor)->i.c[(csi.idRight)]))) {
1241 const invList_t *i = RIGHT(actor)(((actor)->i.c[(csi.idRight)]));
1242 Cvar_Set(va("%s%s", cvarPrefix, "rweapon"), i->item.t->model);
1243 Cvar_Set(va("%s%s", cvarPrefix, "rweapon_item"), i->item.t->id);
1244 } else {
1245 Cvar_Set(va("%s%s", cvarPrefix, "rweapon"), "");
1246 Cvar_Set(va("%s%s", cvarPrefix, "rweapon_item"), "");
1247 }
1248 if (LEFT(actor)(((actor)->i.c[(csi.idLeft)]))) {
1249 const invList_t *i = LEFT(actor)(((actor)->i.c[(csi.idLeft)]));
1250 Cvar_Set(va("%s%s", cvarPrefix, "lweapon"), i->item.t->model);
1251 Cvar_Set(va("%s%s", cvarPrefix, "lweapon_item"), i->item.t->id);
1252 } else {
1253 Cvar_Set(va("%s%s", cvarPrefix, "lweapon"), "");
1254 Cvar_Set(va("%s%s", cvarPrefix, "lweapon_item"), "");
1255 }
1256
1257 /* print ammo */
1258 invList = RIGHT(actor)(((actor)->i.c[(csi.idRight)]));
1259 if (invList)
1260 Cvar_SetValue(va("%s%s", cvarPrefix, "ammoright"), invList->item.a);
1261 else
1262 Cvar_Set(va("%s%s", cvarPrefix, "ammoright"), "");
1263
1264 invList = HUD_GetLeftHandWeapon(actor, NULL__null);
1265 if (invList)
1266 Cvar_SetValue(va("%s%s", cvarPrefix, "ammoleft"), invList->item.a);
1267 else
1268 Cvar_Set(va("%s%s", cvarPrefix, "ammoleft"), "");
1269}
1270
1271/**
1272 * @brief Update cvars according to a soldier from a list while we are on battlescape
1273 */
1274static void HUD_ActorGetCvarData_f (void)
1275{
1276 if (Cmd_Argc() < 3) {
1277 Com_Printf("Usage: %s <soldiernum> <cvarprefix>\n", Cmd_Argv(0));
1278 return;
1279 }
1280
1281 /* check whether we are connected (tactical mission) */
1282 if (CL_BattlescapeRunning()) {
1283 const int num = atoi(Cmd_Argv(1));
1284 const char *cvarPrefix = Cmd_Argv(2);
1285 le_t *le;
1286 character_t *chr;
1287
1288 /* check if actor exists */
1289 if (num >= cl.numTeamList || num < 0)
1290 return;
1291
1292 /* select actor */
1293 le = cl.teamList[num];
1294 if (!le)
1295 return;
1296
1297 chr = CL_ActorGetChr(le);
1298 if (!chr) {
1299 Com_Error(ERR_DROP1, "No character given for local entity");
1300 return;
1301 }
1302
1303 CL_UpdateCharacterValues(chr, cvarPrefix);
1304
1305 /* override some cvar with HUD data */
1306 HUD_UpdateActorCvar(le, cvarPrefix);
1307
1308 return;
1309 }
1310}
1311
1312/**
1313 * @brief Updates the hud for one actor
1314 * @param actor The actor to update the hud values for
1315 */
1316static void HUD_UpdateActor (le_t *actor)
1317{
1318 int time;
1319
1320 HUD_UpdateActorCvar(actor, "mn_");
1321
1322 /* write info */
1323 time = 0;
1324
1325 /* handle actor in a panic */
1326 if (LE_IsPaniced(actor)((actor)->state & 0x0008)) {
1327 UI_RegisterText(TEXT_STANDARD, _("Currently panics!\n")gettext("Currently panics!\n"));
1328 } else if (displayRemainingTus[REMAINING_TU_CROUCH]) {
1329 if (CL_ActorUsableTUs(actor) >= TU_CROUCH3)
1330 time = TU_CROUCH3;
1331 } else if (displayRemainingTus[REMAINING_TU_RELOAD_RIGHT]
1332 || displayRemainingTus[REMAINING_TU_RELOAD_LEFT]) {
1333 const invList_t *invList;
1334 containerIndex_t container;
1335
1336 if (displayRemainingTus[REMAINING_TU_RELOAD_RIGHT] && RIGHT(actor)(((actor)->i.c[(csi.idRight)]))) {
1337 container = csi.idRight;
1338 invList = RIGHT(actor)(((actor)->i.c[(csi.idRight)]));
1339 } else if (displayRemainingTus[REMAINING_TU_RELOAD_LEFT] && LEFT(actor)(((actor)->i.c[(csi.idLeft)]))) {
1340 container = NONE-1;
1341 invList = HUD_GetLeftHandWeapon(actor, &container);
1342 } else {
1343 container = NONE-1;
1344 invList = NULL__null;
1345 }
1346
1347 if (invList && invList->item.t && invList->item.m && invList->item.t->reload) {
1348 const int reloadtime = HUD_CalcReloadTime(actor, invList->item.t, container);
1349 if (reloadtime != -1 && reloadtime <= CL_ActorUsableTUs(actor))
1350 time = reloadtime;
1351 }
1352 } else if (CL_ActorFireModeActivated(actor->actorMode)) {
1353 time = HUD_UpdateActorFireMode(actor);
1354 } else {
1355 /* If the mouse is outside the world, and we haven't placed the cursor in pend
1356 * mode already */
1357 if (IN_GetMouseSpace()mouseSpace != MS_WORLD && actor->actorMode < M_PEND_MOVE)
1358 actor->actorMoveLength = ROUTING_NOT_REACHABLE0xFF;
1359 time = HUD_UpdateActorMove(actor);
1360 }
1361
1362 /* Calculate remaining TUs. */
1363 /* We use the full count of TUs since the "reserved" bar is overlaid over this one. */
1364 time = std::max(0, actor->TU - time);
1365 Cvar_Set("mn_turemain", va("%i", time));
1366
1367 HUD_MapDebugCursor(actor);
1368}
1369
1370/**
1371 * @brief Updates console vars for an actor.
1372 *
1373 * This function updates the cvars for the hud (battlefield)
1374 * unlike CL_ActorCvars and CL_UGVCvars which updates them for
1375 * displaying the data in the menu system
1376 *
1377 * @sa CL_ActorCvars
1378 * @sa CL_UGVCvars
1379 */
1380void HUD_Update (void)
1381{
1382 if (cls.state != ca_active)
1383 return;
1384
1385 /* worldlevel */
1386 if (cl_worldlevel->modified) {
1387 int i;
1388 for (i = 0; i < PATHFINDING_HEIGHT8; i++) {
1389 int status = 0;
1390 if (i == cl_worldlevel->integer)
1391 status = 2;
1392 else if (i < cl.mapMaxLevel)
1393 status = 1;
1394 UI_ExecuteConfunc("updateLevelStatus %i %i", i, status);
1395 }
1396 cl_worldlevel->modified = false;
1397 }
1398
1399 /* set Cvars for all actors */
1400 HUD_UpdateAllActors();
1401
1402 /* force them empty first */
1403 Cvar_Set("mn_anim", "stand0");
1404 Cvar_Set("mn_rweapon", "");
1405 Cvar_Set("mn_lweapon", "");
1406
1407 if (selActor) {
1408 HUD_UpdateActor(selActor);
1409 } else if (!cl.numTeamList) {
1410 /* This will stop the drawing of the bars over the whole screen when we test maps. */
1411 Cvar_SetValue("mn_hp", 0);
1412 Cvar_SetValue("mn_hpmax", 100);
1413 Cvar_SetValue("mn_tu", 0);
1414 Cvar_SetValue("mn_tumax", 100);
1415 Cvar_SetValue("mn_tureserved", 0);
1416 Cvar_SetValue("mn_morale", 0);
1417 Cvar_SetValue("mn_moralemax", 100);
1418 Cvar_SetValue("mn_stun", 0);
1419 }
1420}
1421
1422/**
1423 * @brief Callback that is called when the cl_selected cvar was changed
1424 * @param cvarName The cvar name (cl_selected)
1425 * @param oldValue The old value of the cvar (a sane actor idx)
1426 * @param newValue The new value of the cvar (a sane actor idx)
1427 */
1428static void HUD_ActorSelectionChangeListener (const char *cvarName, const char *oldValue, const char *newValue, void *data)
1429{
1430 if (!CL_OnBattlescape())
1431 return;
1432
1433 if (newValue[0] != '\0') {
1434 const int actorIdx = atoi(newValue);
1435 const size_t size = lengthof(cl.teamList)(sizeof(cl.teamList) / sizeof(*(cl.teamList)));
1436 if (actorIdx >= 0 && actorIdx < size)
1437 UI_ExecuteConfunc("hudselect %s", newValue);
1438 }
1439}
1440
1441/**
1442 * @brief Callback that is called when the right hand weapon of the current selected actor changed
1443 * @param cvarName The cvar name
1444 * @param oldValue The old value of the cvar
1445 * @param newValue The new value of the cvar
1446 */
1447static void HUD_RightHandChangeListener (const char *cvarName, const char *oldValue, const char *newValue, void *data)
1448{
1449 if (!CL_OnBattlescape())
1450 return;
1451
1452 HUD_RefreshButtons(selActor);
1453}
1454
1455/**
1456 * @brief Callback that is called when the left hand weapon of the current selected actor changed
1457 * @param cvarName The cvar name
1458 * @param oldValue The old value of the cvar
1459 * @param newValue The new value of the cvar
1460 */
1461static void HUD_LeftHandChangeListener (const char *cvarName, const char *oldValue, const char *newValue, void *data)
1462{
1463 if (!CL_OnBattlescape())
1464 return;
1465
1466 HUD_RefreshButtons(selActor);
1467}
1468
1469/**
1470 * @brief Callback that is called when the remaining TUs for the current selected actor changed
1471 * @param cvarName The cvar name
1472 * @param oldValue The old value of the cvar
1473 * @param newValue The new value of the cvar
1474 */
1475static void HUD_TUChangeListener (const char *cvarName, const char *oldValue, const char *newValue, void *data)
1476{
1477 if (!CL_OnBattlescape())
1478 return;
1479
1480 HUD_RefreshButtons(selActor);
1481}
1482
1483static bool CL_CvarWorldLevel (cvar_t *cvar)
1484{
1485 const int maxLevel = cl.mapMaxLevel ? cl.mapMaxLevel - 1 : PATHFINDING_HEIGHT8 - 1;
1486 return Cvar_AssertValue(cvar, 0, maxLevel, true);
1487}
1488
1489/**
1490 * @brief Checks that the given cvar is a valid hud cvar
1491 * @param cvar The cvar to check
1492 * @return @c true if cvar is valid, @c false otherwise
1493 */
1494static bool HUD_CheckCLHud (cvar_t *cvar)
1495{
1496 uiNode_t *window = UI_GetWindow(cvar->string);
1497 if (window == NULL__null) {
1498 return false;
1499 }
1500
1501 if (window->super == NULL__null) {
1502 return false;
1503 }
1504
1505 /**
1506 * @todo check for multiple base classes
1507 */
1508 return Q_streq(window->super->name, "hud")(strcmp(window->super->name, "hud") == 0);
1509}
1510
1511/**
1512 * @brief Display the user interface
1513 * @param optionWindowName Name of the window used to display options, else NULL if nothing
1514 * @param popAll If true
1515 * @todo Remove popAll when it is possible. It should always be true
1516 */
1517void HUD_InitUI (const char *optionWindowName, bool popAll)
1518{
1519 if (!HUD_CheckCLHud(cl_hud)) {
1520 Cvar_Set("cl_hud", "hud_default");
1521 }
1522 UI_InitStack(cl_hud->string, optionWindowName, popAll, true);
1523
1524 UI_ExecuteConfunc("hudinit");
1525}
1526
1527/**
1528 * @brief Checks that the given cvar is a valid hud cvar
1529 * @param cvar The cvar to check and to modify if the value is invalid
1530 * @return @c true if the valid is invalid, @c false otherwise
1531 */
1532static bool HUD_CvarCheckMNHud (cvar_t *cvar)
1533{
1534 if (!HUD_CheckCLHud(cl_hud)) {
1535 Cvar_Reset(cvar);
1536 return true;
1537 }
1538 return false;
1539}
1540
1541void HUD_InitStartup (void)
1542{
1543 HUD_InitCallbacks();
1544
1545 Cmd_AddCommand("hud_remainingtus", HUD_RemainingTUs_f, "Define if remaining TUs should be displayed in the TU-bar for some hovered-over button.");
1546 Cmd_AddCommand("hud_shotreserve", HUD_ShotReserve_f, "Reserve TUs for the selected entry in the popup.");
1547 Cmd_AddCommand("hud_shotreservationpopup", HUD_PopupFiremodeReservation_f, "Pop up a list of possible firemodes for reservation in the current turn.");
1548 Cmd_AddCommand("hud_switchfiremodelist", HUD_SwitchFiremodeList_f, "Switch firemode-list to one for the given hand, but only if the list is visible already.");
1549 Cmd_AddCommand("hud_selectreactionfiremode", HUD_SelectReactionFiremode_f, "Change/Select firemode used for reaction fire.");
1550 Cmd_AddCommand("hud_listfiremodes", HUD_DisplayFiremodes_f, "Display a list of firemodes for a weapon+ammo.");
1551 Cmd_AddCommand("hud_listactions", HUD_DisplayActions_f, "Display a list of action from the selected soldier.");
1552 Cmd_AddCommand("hud_getactorcvar", HUD_ActorGetCvarData_f, "Update cvars from actor from list.");
1553
1554 /** @note We can't check the value at startup cause scripts are not yet loaded */
1555 cl_hud = Cvar_Get("cl_hud", "hud_default", CVAR_ARCHIVE1 | CVAR_LATCH16, "Current selected HUD.");
1556 Cvar_SetCheckFunction("cl_hud", HUD_CvarCheckMNHud);
1557
1558 cl_worldlevel = Cvar_Get("cl_worldlevel", "0", 0, "Current worldlevel in tactical mode.");
1559 Cvar_SetCheckFunction("cl_worldlevel", CL_CvarWorldLevel);
1560 cl_worldlevel->modified = false;
1561
1562 Cvar_Get("mn_ammoleft", "", 0, "The remaining amount of ammunition in the left hand weapon.");
1563 Cvar_Get("mn_lweapon", "", 0, "The left hand weapon model of the current selected actor - empty if no weapon.");
1564 Cvar_RegisterChangeListener("mn_ammoleft", HUD_LeftHandChangeListener);
1565 Cvar_RegisterChangeListener("mn_lweapon", HUD_LeftHandChangeListener);
1566
1567 Cvar_Get("mn_ammoright", "", 0, "The remaining amount of ammunition in the right hand weapon.");
1568 Cvar_Get("mn_rweapon", "", 0, "The right hand weapon model of the current selected actor - empty if no weapon.");
1569 Cvar_RegisterChangeListener("mn_ammoright", HUD_RightHandChangeListener);
1570 Cvar_RegisterChangeListener("mn_rweapon", HUD_RightHandChangeListener);
1571
1572 Cvar_Get("mn_turemain", "", 0, "Remaining TUs for the current selected actor.");
1573 Cvar_RegisterChangeListener("mn_turemain", HUD_TUChangeListener);
1574
1575 Cvar_RegisterChangeListener("cl_selected", HUD_ActorSelectionChangeListener);
1576
1577 cl_hud_message_timeout = Cvar_Get("cl_hud_message_timeout", "2000", CVAR_ARCHIVE1, "Timeout for HUD messages (milliseconds).");
1578 cl_show_cursor_tooltips = Cvar_Get("cl_show_cursor_tooltips", "1", CVAR_ARCHIVE1, "Show cursor tooltips in tactical game mode.");
1579}