cl_hud.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "../client.h"
00027 #include "cl_localentity.h"
00028 #include "cl_actor.h"
00029 #include "cl_hud.h"
00030 #include "cl_hud_callbacks.h"
00031 #include "cl_view.h"
00032 #include "../cl_team.h"
00033 #include "../cl_game.h"
00034 #include "../ui/ui_main.h"
00035 #include "../ui/ui_popup.h"
00036 #include "../ui/ui_nodes.h"
00037 #include "../ui/ui_draw.h"
00038 #include "../ui/ui_render.h"
00039 #include "../renderer/r_mesh_anim.h"
00040 #include "../renderer/r_draw.h"
00041 #include "../../common/grid.h"
00042 
00044 static qboolean visibleFiremodeListLeft = qfalse;
00045 static qboolean visibleFiremodeListRight = qfalse;
00046 
00047 static cvar_t *cl_hud_message_timeout;
00048 static cvar_t *cl_show_cursor_tooltips;
00049 cvar_t *cl_worldlevel;
00050 
00051 enum {
00052     REMAINING_TU_RELOAD_RIGHT,
00053     REMAINING_TU_RELOAD_LEFT,
00054     REMAINING_TU_CROUCH,
00055 
00056     REMAINING_TU_MAX
00057 };
00058 static qboolean displayRemainingTus[REMAINING_TU_MAX];
00059 
00060 typedef enum {
00061     BT_RIGHT_FIRE,
00062     BT_REACTION,
00063     BT_LEFT_FIRE,
00064     BT_RIGHT_RELOAD,
00065     BT_LEFT_RELOAD,
00066     BT_STAND,
00067     BT_CROUCH,
00068     BT_HEADGEAR,
00069 
00070     BT_NUM_TYPES
00071 } buttonTypes_t;
00072 
00074 static const char *shootTypeStrings[] = {
00075     "primaryright",
00076     "reaction",
00077     "primaryleft",
00078     "reloadright",
00079     "reloadleft",
00080     "stand",
00081     "crouch",
00082     "headgear"
00083 };
00084 CASSERT(lengthof(shootTypeStrings) == BT_NUM_TYPES);
00085 
00090 typedef enum {
00091     BT_STATE_DISABLE,       
00092     BT_STATE_DESELECT       
00093 } weaponButtonState_t;
00094 
00096 static const char *moveModeDescriptions[] = {
00097     N_("Crouch walk"),
00098     N_("Autostand"),
00099     N_("Walk"),
00100     N_("Crouch walk")
00101 };
00102 CASSERT(lengthof(moveModeDescriptions) == WALKTYPE_MAX);
00103 
00104 typedef struct reserveShot_s {
00105     actorHands_t hand;
00106     int fireModeIndex;
00107     int weaponIndex;
00108     int TUs;
00109 } reserveShot_t;
00110 
00111 static int hudTime;
00112 static char hudText[256];
00113 
00119 void HUD_DisplayMessage (const char *text)
00120 {
00121     assert(text);
00122     UI_DisplayNotice(text, cl_hud_message_timeout->integer, mn_hud->string);
00123 }
00124 
00130 static void HUD_UpdateAllActors (void)
00131 {
00132     int i;
00133     const size_t size = lengthof(cl.teamList);
00134 
00135     Cvar_SetValue("mn_numaliensspotted", cl.numAliensSpotted);
00136     for (i = 0; i < size; i++) {
00137         const le_t *le = cl.teamList[i];
00138         if (le && !LE_IsDead(le)) {
00139             const invList_t *invList;
00140             const char* tooltip;
00141             const character_t *chr = CL_ActorGetChr(le);
00142             assert(chr);
00143 
00144             invList = RIGHT(le);
00145             if ((!invList || !invList->item.t || !invList->item.t->holdTwoHanded) && LEFT(le))
00146                 invList = LEFT(le);
00147 
00148             tooltip = va(_("%s\nHP: %i/%i TU: %i\n%s"),
00149                 chr->name, le->HP, le->maxHP, le->TU, (invList && invList->item.t) ? _(invList->item.t->name) : "");
00150 
00151             UI_ExecuteConfunc("updateactorvalues %i \"%s\" \"%i\" \"%i\" \"%i\" \"%i\" \"%i\" \"%i\" \"%i\" \"%s\"",
00152                     i, le->model2->name, le->HP, le->maxHP, le->TU, le->maxTU, le->morale, le->maxMorale, le->STUN, tooltip);
00153         }
00154     }
00155 }
00156 
00161 static void HUD_SetWeaponButton (buttonTypes_t button, weaponButtonState_t state)
00162 {
00163     const char const* prefix;
00164 
00165     switch (state) {
00166     case BT_STATE_DESELECT:
00167         prefix = "deselect_";
00168         break;
00169     case BT_STATE_DISABLE:
00170         prefix = "disable_";
00171         break;
00172     default:
00173         prefix = "";
00174         break;
00175     }
00176 
00177     /* Connect confunc strings to the ones as defined in "menu nohud". */
00178     UI_ExecuteConfunc("%s%s", prefix, shootTypeStrings[button]);
00179 }
00180 
00184 void HUD_HideFiremodes (void)
00185 {
00186     visibleFiremodeListLeft = qfalse;
00187     visibleFiremodeListRight = qfalse;
00188     UI_ExecuteConfunc("hide_firemodes");
00189 }
00190 
00198 static int HUD_UsableReactionTUs (const le_t * le)
00199 {
00200     /* Get the amount of usable TUs depending on the state (i.e. is RF on or off?) */
00201     if (le->state & STATE_REACTION)
00202         /* CL_ActorUsableTUs DOES NOT return the stored value for "reaction" here. */
00203         return CL_ActorUsableTUs(le) + CL_ActorReservedTUs(le, RES_REACTION);
00204     else
00205         /* CL_ActorUsableTUs DOES return the stored value for "reaction" here. */
00206         return CL_ActorUsableTUs(le);
00207 }
00208 
00215 static qboolean HUD_CheckFiremodeReservation (void)
00216 {
00217     actorHands_t hand = ACTOR_HAND_RIGHT;
00218 
00219     if (!selActor)
00220         return qfalse;
00221 
00222     do {    /* Loop for the 2 hands (l/r) to avoid unnecessary code-duplication and abstraction. */
00223         const fireDef_t *fireDef;
00224 
00225         /* Get weapon (and its ammo) from the hand. */
00226         fireDef = HUD_GetFireDefinitionForHand(selActor, hand);
00227         if (fireDef) {
00228             int i;
00229             const objDef_t *ammo = fireDef->obj;
00230             for (i = 0; i < ammo->numFiredefs[fireDef->weapFdsIdx]; i++) {
00231                 /* Check if at least one firemode is available for reservation. */
00232                 if (CL_ActorUsableTUs(selActor) + CL_ActorReservedTUs(selActor, RES_SHOT) >= ammo->fd[fireDef->weapFdsIdx][i].time)
00233                     return qtrue;
00234             }
00235         }
00236 
00237         /* Prepare for next run or for end of loop. */
00238         if (hand == ACTOR_HAND_RIGHT)
00239             hand = ACTOR_HAND_LEFT;
00240         else
00241             break;
00242     } while (qtrue);
00243 
00244     /* No reservation possible */
00245     return qfalse;
00246 }
00247 
00248 
00257 static void HUD_SetShootReservation (const le_t* le, const int tus, const actorHands_t hand, const int fireModeIndex, const objDef_t *weapon)
00258 {
00259     character_t* chr = CL_ActorGetChr(le);
00260     assert(chr);
00261 
00262     CL_ActorReserveTUs(le, RES_SHOT, tus);
00263     CL_ActorSetShotSettings(chr, hand, fireModeIndex, weapon);
00264 }
00265 
00266 static linkedList_t* popupListData;
00267 static uiNode_t* popupListNode;
00268 
00277 static void HUD_PopupFiremodeReservation (qboolean reset, qboolean popupReload)
00278 {
00279     actorHands_t hand = ACTOR_HAND_RIGHT;
00280     int i;
00281     static char text[MAX_VAR];
00282     int selectedEntry;
00283     linkedList_t* popupListText = NULL;
00284     reserveShot_t reserveShotData;
00285 
00286     if (!selActor)
00287         return;
00288 
00289     if (reset) {
00290         HUD_SetShootReservation(selActor, 0, ACTOR_HAND_NOT_SET, -1, NULL);
00291         return;
00292     }
00293 
00294     /* reset the list */
00295     UI_ResetData(TEXT_LIST);
00296 
00297     LIST_Delete(&popupListData);
00298 
00299     /* Add list-entry for deactivation of the reservation. */
00300     LIST_AddPointer(&popupListText, _("[0 TU] No reservation"));
00301     reserveShotData.hand = ACTOR_HAND_NOT_SET;
00302     reserveShotData.fireModeIndex = -1;
00303     reserveShotData.weaponIndex = NONE;
00304     reserveShotData.TUs = -1;
00305     LIST_Add(&popupListData, (byte *)&reserveShotData, sizeof(reserveShotData));
00306     selectedEntry = 0;
00307 
00308     do {    /* Loop for the 2 hands (l/r) to avoid unnecessary code-duplication and abstraction. */
00309         const fireDef_t *fd = HUD_GetFireDefinitionForHand(selActor, hand);
00310         character_t* chr = CL_ActorGetChr(selActor);
00311         assert(chr);
00312 
00313         if (fd) {
00314             const objDef_t *ammo = fd->obj;
00315 
00316             for (i = 0; i < ammo->numFiredefs[fd->weapFdsIdx]; i++) {
00317                 const fireDef_t* ammoFD = &ammo->fd[fd->weapFdsIdx][i];
00318                 if (CL_ActorUsableTUs(selActor) + CL_ActorReservedTUs(selActor, RES_SHOT) >= ammoFD->time) {
00319                     /* Get firemode name and TUs. */
00320                     Com_sprintf(text, lengthof(text), _("[%i TU] %s"), ammoFD->time, _(ammoFD->name));
00321 
00322                     /* Store text for popup */
00323                     LIST_AddString(&popupListText, text);
00324 
00325                     /* Store Data for popup-callback. */
00326                     reserveShotData.hand = hand;
00327                     reserveShotData.fireModeIndex = i;
00328                     reserveShotData.weaponIndex = ammo->weapons[fd->weapFdsIdx]->idx;
00329                     reserveShotData.TUs = ammoFD->time;
00330                     LIST_Add(&popupListData, (byte *)&reserveShotData, sizeof(reserveShotData));
00331 
00332                     /* Remember the line that is currently selected (if any). */
00333                     if (chr->reservedTus.shotSettings.hand == hand
00334                      && chr->reservedTus.shotSettings.fmIdx == i
00335                      && chr->reservedTus.shotSettings.weapon == ammo->weapons[fd->weapFdsIdx])
00336                         selectedEntry = LIST_Count(popupListData) - 1;
00337                 }
00338             }
00339         }
00340 
00341         /* Prepare for next run or for end of loop. */
00342         if (hand == ACTOR_HAND_RIGHT)
00343             /* First run. Set hand for second run of the loop (other hand) */
00344             hand = ACTOR_HAND_LEFT;
00345         else
00346             break;
00347     } while (qtrue);
00348 
00349     if (LIST_Count(popupListData) > 1 || popupReload) {
00350         /* We have more entries than the "0 TUs" one
00351          * or we want to simply refresh/display the popup content (no matter how many TUs are left). */
00352         popupListNode = UI_PopupList(_("Shot Reservation"), _("Reserve TUs for firing/using."), popupListText, "hud_shotreserve <lineselected>");
00353         /* Set color for selected entry. */
00354         VectorSet(popupListNode->selectedColor, 0.0, 0.78, 0.0);
00355         popupListNode->selectedColor[3] = 1.0;
00356         UI_TextNodeSelectLine(popupListNode, selectedEntry);
00357     }
00358 }
00359 
00364 static void HUD_PopupFiremodeReservation_f (void)
00365 {
00366     /* A second parameter (the value itself will be ignored) was given.
00367      * This is used to reset the shot-reservation.*/
00368     HUD_PopupFiremodeReservation(Cmd_Argc() == 2, qfalse);
00369 }
00370 
00375 static void HUD_ShotReserve_f (void)
00376 {
00377     int selectedPopupIndex;
00378     const reserveShot_t* reserveShotData;
00379 
00380     if (Cmd_Argc() < 2) {
00381         Com_Printf("Usage: %s <popupindex>\n", Cmd_Argv(0));
00382         return;
00383     }
00384 
00385     if (!selActor)
00386         return;
00387 
00388     /* read and range check */
00389     selectedPopupIndex = atoi(Cmd_Argv(1));
00390     if (selectedPopupIndex < 0 || selectedPopupIndex >= LIST_Count(popupListData))
00391         return;
00392 
00393     reserveShotData = LIST_GetByIdx(popupListData, selectedPopupIndex);
00394     if (!reserveShotData)
00395         return;
00396 
00397     if (reserveShotData->weaponIndex == NONE) {
00398         HUD_SetShootReservation(selActor, 0, ACTOR_HAND_NOT_SET, -1, NULL);
00399         return;
00400     }
00401 
00403     /* Check if we have enough TUs (again) */
00404     if (CL_ActorUsableTUs(selActor) + CL_ActorReservedTUs(selActor, RES_SHOT) >= reserveShotData->TUs) {
00405         const objDef_t *od = INVSH_GetItemByIDX(reserveShotData->weaponIndex);
00406         if (GAME_ItemIsUseable(od)) {
00407             HUD_SetShootReservation(selActor, max(0, reserveShotData->TUs), reserveShotData->hand, reserveShotData->fireModeIndex, od);
00408             if (popupListNode)
00409                 UI_TextNodeSelectLine(popupListNode, selectedPopupIndex);
00410         }
00411     }
00412 }
00413 
00418 static void HUD_DisplayFiremodeEntry (const le_t* actor, const objDef_t* ammo, const weaponFireDefIndex_t weapFdsIdx, const actorHands_t hand, int index)
00419 {
00420     int usableTusForRF;
00421     char tuString[MAX_VAR];
00422     qboolean status;
00423     const fireDef_t *fd;
00424     const char *tooltip;
00425 
00426     if (index < ammo->numFiredefs[weapFdsIdx]) {
00427         /* We have a defined fd ... */
00428         fd = &ammo->fd[weapFdsIdx][index];
00429     } else {
00430         /* Hide this entry */
00431         if (hand == ACTOR_HAND_RIGHT)
00432             UI_ExecuteConfunc("set_right_inv %i", index);
00433         else
00434             UI_ExecuteConfunc("set_left_inv %i", index);
00435         return;
00436     }
00437 
00438     assert(actor);
00439     assert(hand == ACTOR_HAND_RIGHT || hand == ACTOR_HAND_LEFT);
00440 
00441     status = fd->time <= CL_ActorUsableTUs(actor);
00442     usableTusForRF = HUD_UsableReactionTUs(actor);
00443 
00444     if (usableTusForRF > fd->time) {
00445         Com_sprintf(tuString, sizeof(tuString), _("Remaining TUs: %i"), usableTusForRF - fd->time);
00446         tooltip = tuString;
00447     } else
00448         tooltip = _("No remaining TUs left after shot.");
00449 
00450     UI_ExecuteConfunc("set_firemode %c %i %i %i \"%s\" \"%s\" \"%s\" \"%s\"", ACTOR_GET_HAND_CHAR(hand),
00451             fd->fdIdx, fd->reaction, status, _(fd->name), va(_("TU: %i"), fd->time),
00452             va(_("Shots: %i"), fd->ammo), tooltip);
00453 
00454     /* Display checkbox for reaction firemode */
00455     if (fd->reaction) {
00456         character_t* chr = CL_ActorGetChr(actor);
00457         const qboolean active = THIS_FIREMODE(&chr->RFmode, hand, fd->fdIdx);
00458         /* Change the state of the checkbox. */
00459         UI_ExecuteConfunc("set_firemode_checkbox %c %i %i", ACTOR_GET_HAND_CHAR(hand), fd->fdIdx, active);
00460     }
00461 }
00462 
00463 void HUD_DisplayFiremodes (const le_t* actor, actorHands_t hand, qboolean firemodesChangeDisplay)
00464 {
00465     const objDef_t *ammo;
00466     const fireDef_t *fd;
00467     int i;
00468     character_t* chr;
00469 
00470     if (!actor)
00471         return;
00472 
00473     if (cls.team != cl.actTeam) {   
00474         HUD_HideFiremodes();
00475         return;
00476     }
00477 
00478     fd = HUD_GetFireDefinitionForHand(actor, hand);
00479     if (fd == NULL)
00480         return;
00481 
00482     ammo = fd->obj;
00483     if (!ammo) {
00484         Com_DPrintf(DEBUG_CLIENT, "HUD_DisplayFiremodes: no weapon or ammo found.\n");
00485         return;
00486     }
00487 
00488     if (firemodesChangeDisplay) {
00489         /* Toggle firemode lists if needed. */
00490         HUD_HideFiremodes();
00491         if (hand == ACTOR_HAND_RIGHT) {
00492             visibleFiremodeListRight = qtrue;
00493         } else {
00494             visibleFiremodeListLeft = qtrue;
00495         }
00496     }
00497 
00498     chr = CL_ActorGetChr(actor);
00499     assert(chr);
00500 
00501     for (i = 0; i < MAX_FIREDEFS_PER_WEAPON; i++) {
00502         /* Display the firemode information (image + text). */
00503         HUD_DisplayFiremodeEntry(actor, ammo, fd->weapFdsIdx, hand, i);
00504     }
00505 }
00506 
00510 static void HUD_DisplayFiremodes_f (void)
00511 {
00512     actorHands_t hand;
00513 
00514     if (!selActor)
00515         return;
00516 
00517     if (Cmd_Argc() < 2)
00518         /* no argument given */
00519         hand = ACTOR_HAND_RIGHT;
00520     else
00521         hand = ACTOR_GET_HAND_INDEX(Cmd_Argv(1)[0]);
00522 
00523     HUD_DisplayFiremodes(selActor, hand, qtrue);
00524 }
00525 
00530 static void HUD_SwitchFiremodeList_f (void)
00531 {
00532     /* no argument given */
00533     if (Cmd_Argc() < 2) {
00534         Com_Printf("Usage: %s [l|r]\n", Cmd_Argv(0));
00535         return;
00536     }
00537 
00538     if (visibleFiremodeListRight || visibleFiremodeListLeft)
00539         HUD_DisplayFiremodes(selActor, ACTOR_GET_HAND_INDEX(Cmd_Argv(1)[0]), qfalse);
00540 }
00541 
00548 static void HUD_UpdateReactionFiremodes (const le_t * actor, const actorHands_t hand, fireDefIndex_t firemodeActive)
00549 {
00550     const fireDef_t *fd;
00551     const objDef_t *ammo, *od;
00552 
00553     assert(actor);
00554 
00555     fd = HUD_GetFireDefinitionForHand(actor, hand);
00556     if (fd == NULL)
00557         return;
00558 
00559     ammo = fd->obj;
00560     od = ammo->weapons[fd->weapFdsIdx];
00561 
00562     if (!GAME_ItemIsUseable(od))
00563         return;
00564 
00565     MSG_Write_PA(PA_REACT_SELECT, actor->entnum, hand, firemodeActive, od ? od->idx : NONE);
00566 }
00567 
00571 static void HUD_SelectReactionFiremode_f (void)
00572 {
00573     actorHands_t hand;
00574     fireDefIndex_t firemode;
00575 
00576     if (Cmd_Argc() < 3) { /* no argument given */
00577         Com_Printf("Usage: %s [l|r] <num>   num=firemode number\n", Cmd_Argv(0));
00578         return;
00579     }
00580 
00581     if (!selActor)
00582         return;
00583 
00584     hand = ACTOR_GET_HAND_INDEX(Cmd_Argv(1)[0]);
00585     firemode = atoi(Cmd_Argv(2));
00586 
00587     if (firemode >= MAX_FIREDEFS_PER_WEAPON || firemode < 0) {
00588         Com_Printf("HUD_SelectReactionFiremode_f: Firemode out of bounds (%i).\n", firemode);
00589         return;
00590     }
00591 
00592     HUD_UpdateReactionFiremodes(selActor, hand, firemode);
00593 }
00594 
00599 static void HUD_RemainingTUs_f (void)
00600 {
00601     qboolean state;
00602     const char *type;
00603 
00604     if (Cmd_Argc() < 3) {
00605         Com_Printf("Usage: %s <type> <popupindex>\n", Cmd_Argv(0));
00606         return;
00607     }
00608 
00609     type = Cmd_Argv(1);
00610     state = Com_ParseBoolean(Cmd_Argv(2));
00611 
00612     memset(displayRemainingTus, 0, sizeof(displayRemainingTus));
00613 
00614     if (!strcmp(type, "reload_r")) {
00615         displayRemainingTus[REMAINING_TU_RELOAD_RIGHT] = state;
00616     } else if (!strcmp(type, "reload_l")) {
00617         displayRemainingTus[REMAINING_TU_RELOAD_LEFT] = state;
00618     } else if (!strcmp(type, "crouch")) {
00619         displayRemainingTus[REMAINING_TU_CROUCH] = state;
00620     }
00621 }
00622 
00626 static int HUD_GetMinimumTUsForUsage (const invList_t *invList)
00627 {
00628     const fireDef_t *fdArray;
00629     int time = 100;
00630     int i;
00631 
00632     assert(invList->item.t);
00633 
00634     fdArray = FIRESH_FiredefForWeapon(&invList->item);
00635     if (fdArray == NULL)
00636         return time;
00637 
00638     /* Search for the smallest TU needed to shoot. */
00639     for (i = 0; i < MAX_FIREDEFS_PER_WEAPON; i++) {
00640         if (!fdArray[i].time)
00641             continue;
00642         if (fdArray[i].time < time)
00643             time = fdArray[i].time;
00644     }
00645 
00646     return time;
00647 }
00648 
00656 static int HUD_WeaponCanBeReloaded (const le_t *le, containerIndex_t containerID, const char **reason)
00657 {
00658     const int tu = CL_ActorUsableTUs(le);
00659     const invList_t *invList = CONTAINER(le, containerID);
00660     const objDef_t *weapon;
00661 
00662     assert(le);
00663 
00664     /* No weapon in hand. */
00665     if (!invList) {
00666         *reason = _("No weapon.");
00667         return -1;
00668     }
00669 
00670     weapon = invList->item.t;
00671     assert(weapon);
00672 
00673     /* This weapon cannot be reloaded. */
00674     if (!weapon->reload) {
00675         *reason = _("Weapon cannot be reloaded.");
00676         return -1;
00677     }
00678 
00679     /* Weapon is fully loaded. */
00680     if (invList->item.m && weapon->ammo == invList->item.a) {
00681         *reason = _("No reload possible, already fully loaded.");
00682         return -1;
00683     }
00684 
00685     /* Weapon is empty or not fully loaded, find ammo of any type loadable to this weapon. */
00686     if (!invList->item.m || weapon->ammo > invList->item.a) {
00687         const int tuCosts = HUD_CalcReloadTime(le, weapon, containerID);
00688         if (tuCosts >= 0) {
00689             if (tu >= tuCosts)
00690                 return tuCosts;
00691             *reason = _("Not enough TUs for reloading weapon.");
00692         } else {
00693             /* Found no ammo which could be used for this weapon. */
00694             *reason = _("No reload possible, you don't have backup ammo.");
00695         }
00696     }
00697 
00698     return -1;
00699 }
00700 
00705 static qboolean HUD_WeaponWithReaction (const le_t * actor)
00706 {
00707     const objDef_t *weapon = INVSH_HasReactionFireEnabledWeapon(RIGHT(actor));
00708     if (weapon)
00709         return qtrue;
00710     return INVSH_HasReactionFireEnabledWeapon(LEFT(actor)) != NULL;
00711 }
00712 
00718 static qboolean HUD_DisplayImpossibleReaction (const le_t * actor)
00719 {
00720     if (!actor)
00721         return qfalse;
00722 
00723     /* Given actor does not equal the currently selected actor. */
00724     if (!actor->selected)
00725         return qfalse;
00726 
00727     /* Display 'impossible" (red) reaction buttons */
00728     if (actor->state & STATE_REACTION_ONCE)
00729         UI_ExecuteConfunc("startreactiononce_impos");
00730     else if (actor->state & STATE_REACTION_MANY)
00731         UI_ExecuteConfunc("startreactionmany_impos");
00732     else
00733         return qtrue;
00734 
00735     return qfalse;
00736 }
00737 
00742 static void HUD_DisplayPossibleReaction (const le_t * actor)
00743 {
00744     if (!actor)
00745         return;
00746 
00747     /* Given actor does not equal the currently selected actor. This normally only happens on game-start. */
00748     if (!actor->selected)
00749         return;
00750 
00751     /* Display 'usable" (blue) reaction buttons */
00752     if (actor->state & STATE_REACTION_ONCE)
00753         UI_ExecuteConfunc("startreactiononce");
00754     else if (actor->state & STATE_REACTION_MANY)
00755         UI_ExecuteConfunc("startreactionmany");
00756 }
00757 
00762 static void HUD_RefreshButtons (const le_t *le)
00763 {
00764     invList_t *weaponr;
00765     invList_t *weaponl;
00766     invList_t *headgear;
00767     int rightCanBeReloaded, leftCanBeReloaded;
00768     const int time = CL_ActorUsableTUs(le);
00769     const char *reason;
00770 
00771     if (!le)
00772         return;
00773 
00774     weaponr = RIGHT(le);
00775     headgear = HEADGEAR(le);
00776 
00777     /* check for two-handed weapon - if not, also define weaponl */
00778     if (!weaponr || !weaponr->item.t->holdTwoHanded)
00779         weaponl = LEFT(le);
00780     else
00781         weaponl = NULL;
00782 
00783     /* Crouch/stand button. */
00784     if (LE_IsCrouched(le)) {
00785         if (time + CL_ActorReservedTUs(le, RES_CROUCH) < TU_CROUCH) {
00786             Cvar_Set("mn_crouchstand_tt", _("Not enough TUs for standing up."));
00787             HUD_SetWeaponButton(BT_CROUCH, BT_STATE_DISABLE);
00788         } else {
00789             Cvar_Set("mn_crouchstand_tt", va(_("Stand up (%i TU)"), TU_CROUCH));
00790             HUD_SetWeaponButton(BT_CROUCH, BT_STATE_DESELECT);
00791         }
00792     } else {
00793         if (time + CL_ActorReservedTUs(le, RES_CROUCH) < TU_CROUCH) {
00794             Cvar_Set("mn_crouchstand_tt", _("Not enough TUs for crouching."));
00795             HUD_SetWeaponButton(BT_STAND, BT_STATE_DISABLE);
00796         } else {
00797             Cvar_Set("mn_crouchstand_tt", va(_("Crouch (%i TU)"), TU_CROUCH));
00798             HUD_SetWeaponButton(BT_STAND, BT_STATE_DESELECT);
00799         }
00800     }
00801 
00802     /* Crouch/stand reservation checkbox. */
00803     if (CL_ActorReservedTUs(le, RES_CROUCH) >= TU_CROUCH) {
00804         UI_ExecuteConfunc("crouch_checkbox_check");
00805         Cvar_Set("mn_crouch_reservation_tt", va(_("%i TUs reserved for crouching/standing up.\nClick to clear."),
00806                 CL_ActorReservedTUs(le, RES_CROUCH)));
00807     } else if (time >= TU_CROUCH) {
00808         UI_ExecuteConfunc("crouch_checkbox_clear");
00809         Cvar_Set("mn_crouch_reservation_tt", va(_("Reserve %i TUs for crouching/standing up."), TU_CROUCH));
00810     } else {
00811         UI_ExecuteConfunc("crouch_checkbox_disable");
00812         Cvar_Set("mn_crouch_reservation_tt", _("Not enough TUs left to reserve for crouching/standing up."));
00813     }
00814 
00815     /* Shot reservation button. mn_shot_reservation_tt is the tooltip text */
00816     if (CL_ActorReservedTUs(le, RES_SHOT)) {
00817         UI_ExecuteConfunc("reserve_shot_check");
00818         Cvar_Set("mn_shot_reservation_tt", va(_("%i TUs reserved for shooting.\nClick to change.\nRight-Click to clear."),
00819                 CL_ActorReservedTUs(le, RES_SHOT)));
00820     } else if (HUD_CheckFiremodeReservation()) {
00821         UI_ExecuteConfunc("reserve_shot_clear");
00822         Cvar_Set("mn_shot_reservation_tt", _("Reserve TUs for shooting."));
00823     } else {
00824         UI_ExecuteConfunc("reserve_shot_disable");
00825         Cvar_Set("mn_shot_reservation_tt", _("Reserving TUs for shooting not possible."));
00826     }
00827 
00828     /* reaction-fire button */
00829     if (!(le->state & STATE_REACTION)) {
00830         if (time >= CL_ActorReservedTUs(le, RES_REACTION) && HUD_WeaponWithReaction(le))
00831             HUD_SetWeaponButton(BT_REACTION, BT_STATE_DESELECT);
00832         else
00833             HUD_SetWeaponButton(BT_REACTION, BT_STATE_DISABLE);
00834     } else {
00835         if (HUD_WeaponWithReaction(le)) {
00836             HUD_DisplayPossibleReaction(le);
00837         } else {
00838             HUD_DisplayImpossibleReaction(le);
00839         }
00840     }
00841 
00842     /* Reload buttons */
00843     rightCanBeReloaded = HUD_WeaponCanBeReloaded(le, csi.idRight, &reason);
00844     if (rightCanBeReloaded != -1) {
00845         HUD_SetWeaponButton(BT_RIGHT_RELOAD, BT_STATE_DESELECT);
00846         Cvar_Set("mn_reloadright_tt", va(_("Reload weapon (%i TU)."), rightCanBeReloaded));
00847     } else {
00848         Cvar_Set("mn_reloadright_tt", reason);
00849         HUD_SetWeaponButton(BT_RIGHT_RELOAD, BT_STATE_DISABLE);
00850     }
00851 
00852     leftCanBeReloaded = HUD_WeaponCanBeReloaded(le, csi.idLeft, &reason);
00853     if (leftCanBeReloaded != -1) {
00854         HUD_SetWeaponButton(BT_LEFT_RELOAD, BT_STATE_DESELECT);
00855         Cvar_Set("mn_reloadleft_tt", va(_("Reload weapon (%i TU)."), leftCanBeReloaded));
00856     } else {
00857         Cvar_Set("mn_reloadleft_tt", reason);
00858         HUD_SetWeaponButton(BT_LEFT_RELOAD, BT_STATE_DISABLE);
00859     }
00860 
00861     /* Headgear button */
00862     if (headgear) {
00863         const int minheadgeartime = HUD_GetMinimumTUsForUsage(headgear);
00864         if (time < minheadgeartime)
00865             HUD_SetWeaponButton(BT_HEADGEAR, BT_STATE_DISABLE);
00866         else
00867             HUD_SetWeaponButton(BT_HEADGEAR, BT_STATE_DESELECT);
00868     } else {
00869         HUD_SetWeaponButton(BT_HEADGEAR, BT_STATE_DISABLE);
00870     }
00871 
00872     /* Weapon firing buttons. */
00873     if (weaponr) {
00874         const int minweaponrtime = HUD_GetMinimumTUsForUsage(weaponr);
00875         if (time < minweaponrtime)
00876             HUD_SetWeaponButton(BT_RIGHT_FIRE, BT_STATE_DISABLE);
00877         else
00878             HUD_SetWeaponButton(BT_RIGHT_FIRE, BT_STATE_DESELECT);
00879     } else {
00880         HUD_SetWeaponButton(BT_RIGHT_FIRE, BT_STATE_DISABLE);
00881     }
00882 
00883     if (weaponl) {
00884         const int minweaponltime = HUD_GetMinimumTUsForUsage(weaponl);
00885         if (time < minweaponltime)
00886             HUD_SetWeaponButton(BT_LEFT_FIRE, BT_STATE_DISABLE);
00887         else
00888             HUD_SetWeaponButton(BT_LEFT_FIRE, BT_STATE_DESELECT);
00889     } else {
00890         HUD_SetWeaponButton(BT_LEFT_FIRE, BT_STATE_DISABLE);
00891     }
00892 
00893     /* Check if the firemode reservation popup is shown and refresh its content. (i.e. close&open it) */
00894     {
00895         const char* menuName = UI_GetActiveWindowName();
00896         if (menuName[0] != '\0' && strstr(UI_GetActiveWindowName(), POPUPLIST_NODE_NAME)) {
00897             /* Update firemode reservation popup. */
00899             HUD_PopupFiremodeReservation(qfalse, qtrue);
00900         }
00901     }
00902 }
00903 
00910 static void HUD_DrawMouseCursorText (int xOffset, int yOffset, int textId)
00911 {
00912     const char *string = UI_GetText(textId);
00913 
00914     if (string && cl_show_cursor_tooltips->integer) {
00915         int width = 0;
00916         int height = 0;
00917 
00918         R_FontTextSize("f_verysmall", string, viddef.virtualWidth - mousePosX, LONGLINES_WRAP, &width, &height, NULL, NULL);
00919 
00920         if (!width)
00921             return;
00922 
00923         UI_DrawString("f_verysmall", ALIGN_UL, mousePosX + xOffset, mousePosY - yOffset, 0, viddef.virtualWidth, 12, string, 0, 0, NULL, qfalse, 0);
00924     }
00925 }
00926 
00930 void HUD_UpdateCursor (void)
00931 {
00932     /* Offset of the first icon on the x-axis. */
00933     int iconOffsetX = 16;
00934     /* Offset of the first icon on the y-axis. */
00935     /* the space between different icons. */
00936     const int iconSpacing = 2;
00937     le_t *le = selActor;
00938     if (le) {
00939         int iconOffsetY = 16;
00940         image_t *image;
00941         /* icon width */
00942         int iconW = 16;
00943         /* icon height. */
00944         int iconH = 16;
00945         int width = 0;
00946         int bgX = mousePosX + iconOffsetX / 2 - 2;
00947 
00948         /* checks if icons should be drawn */
00949         if (!(LE_IsCrouched(le) || (le->state & STATE_REACTION)))
00950             /* make place holder for icons */
00951             bgX += iconW + 4;
00952 
00953         /* if exists gets width of player name */
00954         if (UI_GetText(TEXT_MOUSECURSOR_PLAYERNAMES))
00955             R_FontTextSize("f_verysmall", UI_GetText(TEXT_MOUSECURSOR_PLAYERNAMES), viddef.virtualWidth - bgX, LONGLINES_WRAP, &width, NULL, NULL, NULL);
00956 
00957         /* gets width of background */
00958         if (width == 0 && UI_GetText(TEXT_MOUSECURSOR_RIGHT)) {
00959             R_FontTextSize("f_verysmall", UI_GetText(TEXT_MOUSECURSOR_RIGHT), viddef.virtualWidth - bgX, LONGLINES_WRAP, &width, NULL, NULL, NULL);
00960         }
00961 
00962         /* Display 'crouch' icon if actor is crouched. */
00963         if (LE_IsCrouched(le)) {
00964             image = R_FindImage("pics/cursors/ducked", it_pic);
00965             if (image)
00966                 R_DrawImage(mousePosX - image->width / 2 + iconOffsetX, mousePosY - image->height / 2 + iconOffsetY, image);
00967         }
00968 
00969         /* Height of 'crouched' icon. */
00970         iconOffsetY += 16;
00971         iconOffsetY += iconSpacing;
00972 
00973         /* Display 'Reaction shot' icon if actor has it activated. */
00974         if (le->state & STATE_REACTION_ONCE)
00975             image = R_FindImage("pics/cursors/reactionfire", it_pic);
00976         else if (le->state & STATE_REACTION_MANY)
00977             image = R_FindImage("pics/cursors/reactionfiremany", it_pic);
00978         else
00979             image = NULL;
00980 
00981         if (image)
00982             R_DrawImage(mousePosX - image->width / 2 + iconOffsetX, mousePosY - image->height / 2 + iconOffsetY, image);
00983 
00984         /* Height of 'reaction fire' icon. ... just in case we add further icons below.*/
00985         iconOffsetY += iconH;
00986         iconOffsetY += iconSpacing;
00987 
00988         /* Display weaponmode (text) heR_ */
00989         HUD_DrawMouseCursorText(iconOffsetX + iconW, -10, TEXT_MOUSECURSOR_RIGHT);
00990     }
00991 
00992     /* playernames */
00993     HUD_DrawMouseCursorText(iconOffsetX + 16, -26, TEXT_MOUSECURSOR_PLAYERNAMES);
00994     UI_ResetData(TEXT_MOUSECURSOR_PLAYERNAMES);
00995 
00996     if (cl_map_debug->integer & MAPDEBUG_TEXT) {
00997         /* Display ceiling text */
00998         HUD_DrawMouseCursorText(0, -64, TEXT_MOUSECURSOR_TOP);
00999         /* Display floor text */
01000         HUD_DrawMouseCursorText(0, 64, TEXT_MOUSECURSOR_BOTTOM);
01001         /* Display left text */
01002         HUD_DrawMouseCursorText(-64, 0, TEXT_MOUSECURSOR_LEFT);
01003     }
01004 }
01005 
01010 static void HUD_MapDebugCursor (const le_t *le)
01011 {
01012     if (cl_map_debug->integer & MAPDEBUG_TEXT) {
01013         int dv;
01014 
01015         static char topText[UI_MAX_SMALLTEXTLEN];
01016         static char bottomText[UI_MAX_SMALLTEXTLEN];
01017         static char leftText[UI_MAX_SMALLTEXTLEN];
01018 
01019         /* Display the floor and ceiling values for the current cell. */
01020         Com_sprintf(topText, lengthof(topText), "%u-(%i,%i,%i)\n",
01021                 Grid_Ceiling(cl.mapData->map, ACTOR_GET_FIELDSIZE(le), truePos), truePos[0], truePos[1], truePos[2]);
01022         /* Save the text for later display next to the cursor. */
01023         UI_RegisterText(TEXT_MOUSECURSOR_TOP, topText);
01024 
01025         /* Display the floor and ceiling values for the current cell. */
01026         Com_sprintf(bottomText, lengthof(bottomText), "%i-(%i,%i,%i)\n",
01027                 Grid_Floor(cl.mapData->map, ACTOR_GET_FIELDSIZE(le), truePos), mousePos[0], mousePos[1], mousePos[2]);
01028         /* Save the text for later display next to the cursor. */
01029         UI_RegisterText(TEXT_MOUSECURSOR_BOTTOM, bottomText);
01030 
01031         /* Display the floor and ceiling values for the current cell. */
01032         dv = Grid_MoveNext(le->pathMap, mousePos, 0);
01033         Com_sprintf(leftText, lengthof(leftText), "%i-%i\n", getDVdir(dv), getDVz(dv));
01034         /* Save the text for later display next to the cursor. */
01035         UI_RegisterText(TEXT_MOUSECURSOR_LEFT, leftText);
01036     }
01037 }
01038 
01043 static int HUD_UpdateActorFireMode (le_t *actor)
01044 {
01045     const invList_t *selWeapon;
01046     int time = 0;
01047 
01048     /* get weapon */
01049     if (IS_MODE_FIRE_HEADGEAR(actor->actorMode)) {
01050         selWeapon = HEADGEAR(actor);
01051     } else if (IS_MODE_FIRE_LEFT(actor->actorMode)) {
01052         selWeapon = HUD_GetLeftHandWeapon(actor, NULL);
01053     } else {
01054         selWeapon = RIGHT(actor);
01055     }
01056 
01057     UI_ResetData(TEXT_MOUSECURSOR_RIGHT);
01058 
01059     if (selWeapon) {
01060         static char infoText[UI_MAX_SMALLTEXTLEN];
01061 
01062         if (!selWeapon->item.t) {
01063             /* No valid weapon in the hand. */
01064             CL_ActorSetFireDef(actor, NULL);
01065         } else {
01066             /* Check whether this item uses/has ammo. */
01067             if (!selWeapon->item.m) {
01068                 CL_ActorSetFireDef(actor, NULL);
01069                 /* This item does not use ammo, check for existing firedefs in this item. */
01070                 /* This is supposed to be a weapon or other usable item. */
01071                 if (selWeapon->item.t->numWeapons > 0) {
01072                     if (selWeapon->item.t->weapon || selWeapon->item.t->weapons[0] == selWeapon->item.t) {
01073                         const fireDef_t *fdArray = FIRESH_FiredefForWeapon(&selWeapon->item);
01074                         if (fdArray != NULL) {
01075                             /* Get firedef from the weapon (or other usable item) entry instead. */
01076                             const fireDef_t *old = FIRESH_GetFiredef(selWeapon->item.t, fdArray->weapFdsIdx, actor->currentSelectedFiremode);
01077                             CL_ActorSetFireDef(actor, old);
01078                         }
01079                     }
01080                 }
01081             } else {
01082                 const fireDef_t *fdArray = FIRESH_FiredefForWeapon(&selWeapon->item);
01083                 if (fdArray != NULL) {
01084                     const fireDef_t *old = FIRESH_GetFiredef(selWeapon->item.m, fdArray->weapFdsIdx, actor->currentSelectedFiremode);
01085                     /* reset the align if we switched the firemode */
01086                     CL_ActorSetFireDef(actor, old);
01087                 }
01088             }
01089         }
01090 
01091         if (!GAME_ItemIsUseable(selWeapon->item.t)) {
01092             HUD_DisplayMessage(_("You cannot use this unknown item.\nYou need to research it first.\n"));
01093             CL_ActorSetMode(actor, M_MOVE);
01094         } else if (actor->fd) {
01095             const int hitProbability = CL_GetHitProbability(actor);
01096             static char mouseText[UI_MAX_SMALLTEXTLEN];
01097 
01098             Com_sprintf(infoText, lengthof(infoText),
01099                         "%s\n%s (%i) [%i%%] %i\n", _(selWeapon->item.t->name), _(actor->fd->name),
01100                         actor->fd->ammo, hitProbability, actor->fd->time);
01101 
01102             /* Save the text for later display next to the cursor. */
01103             Q_strncpyz(mouseText, infoText, lengthof(mouseText));
01104             UI_RegisterText(TEXT_MOUSECURSOR_RIGHT, mouseText);
01105 
01106             time = actor->fd->time;
01107             /* if no TUs left for this firing action
01108              * or if the weapon is reloadable and out of ammo,
01109              * then change to move mode */
01110             if ((selWeapon->item.t->reload && selWeapon->item.a <= 0) || CL_ActorUsableTUs(actor) < time)
01111                 CL_ActorSetMode(actor, M_MOVE);
01112         } else if (selWeapon) {
01113             Com_sprintf(infoText, lengthof(infoText), _("%s\n(empty)\n"), _(selWeapon->item.t->name));
01114         }
01115 
01116         UI_RegisterText(TEXT_STANDARD, infoText);
01117     } else {
01118         CL_ActorSetMode(actor, M_MOVE);
01119     }
01120 
01121     return time;
01122 }
01123 
01128 static int HUD_UpdateActorMove (const le_t *actor)
01129 {
01130     const int reservedTUs = CL_ActorReservedTUs(actor, RES_ALL_ACTIVE);
01131     static char infoText[UI_MAX_SMALLTEXTLEN];
01132     if (actor->actorMoveLength == ROUTING_NOT_REACHABLE) {
01133         UI_ResetData(TEXT_MOUSECURSOR_RIGHT);
01134         if (reservedTUs > 0)
01135             Com_sprintf(infoText, lengthof(infoText), _("Morale  %i | Reserved TUs: %i\n"), actor->morale, reservedTUs);
01136         else
01137             Com_sprintf(infoText, lengthof(infoText), _("Morale  %i"), actor->morale);
01138     } else {
01139         static char mouseText[UI_MAX_SMALLTEXTLEN];
01140         const int moveMode = CL_ActorMoveMode(actor, actor->actorMoveLength);
01141         if (reservedTUs > 0)
01142             Com_sprintf(infoText, lengthof(infoText), _("Morale  %i | Reserved TUs: %i\n%s %i (%i|%i TU left)\n"),
01143                 actor->morale, reservedTUs, _(moveModeDescriptions[moveMode]), actor->actorMoveLength,
01144                 actor->TU - actor->actorMoveLength, actor->TU - reservedTUs - actor->actorMoveLength);
01145         else
01146             Com_sprintf(infoText, lengthof(infoText), _("Morale  %i\n%s %i (%i TU left)\n"), actor->morale,
01147                 _(moveModeDescriptions[moveMode]), actor->actorMoveLength, actor->TU - actor->actorMoveLength);
01148 
01149         if (actor->actorMoveLength <= CL_ActorUsableTUs(actor))
01150             Com_sprintf(mouseText, lengthof(mouseText), "%i (%i)\n", actor->actorMoveLength, CL_ActorUsableTUs(actor));
01151         else
01152             Com_sprintf(mouseText, lengthof(mouseText), "- (-)\n");
01153 
01154         UI_RegisterText(TEXT_MOUSECURSOR_RIGHT, mouseText);
01155     }
01156 
01157     UI_RegisterText(TEXT_STANDARD, infoText);
01158 
01159     return actor->actorMoveLength;
01160 }
01161 
01162 static void HUD_UpdateActorCvar (le_t *actor, const char *cvarPrefix)
01163 {
01164     const invList_t* invList;
01165     const char *animName;
01166     static char tuTooltipText[UI_MAX_SMALLTEXTLEN];
01167 
01168     Cvar_SetValue(va("%s%s", cvarPrefix, "hp"), actor->HP);
01169     Cvar_SetValue(va("%s%s", cvarPrefix, "hpmax"), actor->maxHP);
01170     Cvar_SetValue(va("%s%s", cvarPrefix, "tu"), actor->TU);
01171     Cvar_SetValue(va("%s%s", cvarPrefix, "tumax"), actor->maxTU);
01172     Cvar_SetValue(va("%s%s", cvarPrefix, "tureserved"), CL_ActorReservedTUs(actor, RES_ALL_ACTIVE));
01173     Cvar_SetValue(va("%s%s", cvarPrefix, "morale"), actor->morale);
01174     Cvar_SetValue(va("%s%s", cvarPrefix, "moralemax"), actor->maxMorale);
01175     Cvar_SetValue(va("%s%s", cvarPrefix, "stun"), actor->STUN);
01176 
01177     Com_sprintf(tuTooltipText, lengthof(tuTooltipText),
01178         _("Time Units\n- Available: %i (of %i)\n- Reserved:  %i\n- Remaining: %i\n"),
01179                 actor->TU, actor->maxTU, CL_ActorReservedTUs(actor, RES_ALL_ACTIVE), CL_ActorUsableTUs(actor));
01180     Cvar_Set(va("%s%s", cvarPrefix, "tu_tooltips"), tuTooltipText);
01181 
01182     /* animation and weapons */
01183     animName = R_AnimGetName(&actor->as, actor->model1);
01184     if (animName)
01185         Cvar_Set(va("%s%s", cvarPrefix, "anim"), animName);
01186     if (RIGHT(actor)) {
01187         const invList_t *i = RIGHT(actor);
01188         Cvar_Set(va("%s%s", cvarPrefix, "rweapon"), i->item.t->model);
01189         Cvar_Set(va("%s%s", cvarPrefix, "rweapon_item"), i->item.t->id);
01190     } else {
01191         Cvar_Set(va("%s%s", cvarPrefix, "rweapon"), "");
01192         Cvar_Set(va("%s%s", cvarPrefix, "rweapon_item"), "");
01193     }
01194     if (LEFT(actor)) {
01195         const invList_t *i = LEFT(actor);
01196         Cvar_Set(va("%s%s", cvarPrefix, "lweapon"), i->item.t->model);
01197         Cvar_Set(va("%s%s", cvarPrefix, "lweapon_item"), i->item.t->id);
01198     } else {
01199         Cvar_Set(va("%s%s", cvarPrefix, "lweapon"), "");
01200         Cvar_Set(va("%s%s", cvarPrefix, "lweapon_item"), "");
01201     }
01202 
01203     /* print ammo */
01204     invList = RIGHT(actor);
01205     if (invList)
01206         Cvar_SetValue(va("%s%s", cvarPrefix, "ammoright"), invList->item.a);
01207     else
01208         Cvar_Set(va("%s%s", cvarPrefix, "ammoright"), "");
01209 
01210     invList = HUD_GetLeftHandWeapon(actor, NULL);
01211     if (invList)
01212         Cvar_SetValue(va("%s%s", cvarPrefix, "ammoleft"), invList->item.a);
01213     else
01214         Cvar_Set(va("%s%s", cvarPrefix, "ammoleft"), "");
01215 }
01216 
01220 static void HUD_ActorGetCvarData_f (void)
01221 {
01222     if (Cmd_Argc() < 3) {
01223         Com_Printf("Usage: %s <soldiernum> <cvarprefix>\n", Cmd_Argv(0));
01224         return;
01225     }
01226 
01227     /* check whether we are connected (tactical mission) */
01228     if (CL_BattlescapeRunning()) {
01229         const int num = atoi(Cmd_Argv(1));
01230         const char *cvarPrefix = Cmd_Argv(2);
01231         le_t *le;
01232         character_t *chr;
01233 
01234         /* check if actor exists */
01235         if (num >= cl.numTeamList || num < 0)
01236             return;
01237 
01238         /* select actor */
01239         le = cl.teamList[num];
01240         if (!le)
01241             return;
01242 
01243         chr = CL_ActorGetChr(le);
01244         if (!chr) {
01245             Com_Error(ERR_DROP, "No character given for local entity");
01246             return;
01247         }
01248 
01249         CL_UpdateCharacterValues(chr, cvarPrefix);
01250 
01251         /* override some cvar with HUD data */
01252         HUD_UpdateActorCvar(le, cvarPrefix);
01253 
01254         return;
01255     }
01256 }
01257 
01262 static void HUD_UpdateActor (le_t *actor)
01263 {
01264     int time;
01265 
01266     HUD_UpdateActorCvar(actor, "mn_");
01267 
01268     /* write info */
01269     time = 0;
01270 
01271     /* handle actor in a panic */
01272     if (LE_IsPaniced(actor)) {
01273         UI_RegisterText(TEXT_STANDARD, _("Currently panics!\n"));
01274     } else if (displayRemainingTus[REMAINING_TU_CROUCH]) {
01275         if (CL_ActorUsableTUs(actor) >= TU_CROUCH)
01276             time = TU_CROUCH;
01277     } else if (displayRemainingTus[REMAINING_TU_RELOAD_RIGHT]
01278      || displayRemainingTus[REMAINING_TU_RELOAD_LEFT]) {
01279         const invList_t *invList;
01280         containerIndex_t container;
01281 
01282         if (displayRemainingTus[REMAINING_TU_RELOAD_RIGHT] && RIGHT(actor)) {
01283             container = csi.idRight;
01284             invList = RIGHT(actor);
01285         } else if (displayRemainingTus[REMAINING_TU_RELOAD_LEFT] && LEFT(actor)) {
01286             container = NONE;
01287             invList = HUD_GetLeftHandWeapon(actor, &container);
01288         } else {
01289             container = NONE;
01290             invList = NULL;
01291         }
01292 
01293         if (invList && invList->item.t && invList->item.m && invList->item.t->reload) {
01294             const int reloadtime = HUD_CalcReloadTime(actor, invList->item.t, container);
01295             if (reloadtime != -1 && reloadtime <= CL_ActorUsableTUs(actor))
01296                 time = reloadtime;
01297         }
01298     } else if (CL_ActorFireModeActivated(actor->actorMode)) {
01299         time = HUD_UpdateActorFireMode(actor);
01300     } else {
01301         /* If the mouse is outside the world, and we haven't placed the cursor in pend
01302          * mode already */
01303         if (mouseSpace != MS_WORLD && actor->actorMode < M_PEND_MOVE)
01304             actor->actorMoveLength = ROUTING_NOT_REACHABLE;
01305         time = HUD_UpdateActorMove(actor);
01306     }
01307 
01308     /* Calculate remaining TUs. */
01309     /* We use the full count of TUs since the "reserved" bar is overlaid over this one. */
01310     time = max(0, actor->TU - time);
01311     Cvar_Set("mn_turemain", va("%i", time));
01312 
01313     HUD_MapDebugCursor(actor);
01314 }
01315 
01326 void HUD_Update (void)
01327 {
01328     if (cls.state != ca_active)
01329         return;
01330 
01331     /* worldlevel */
01332     if (cl_worldlevel->modified) {
01333         int i;
01334         for (i = 0; i < PATHFINDING_HEIGHT; i++) {
01335             int status = 0;
01336             if (i == cl_worldlevel->integer)
01337                 status = 2;
01338             else if (i < cl.mapMaxLevel)
01339                 status = 1;
01340             UI_ExecuteConfunc("updateLevelStatus %i %i", i, status);
01341         }
01342         cl_worldlevel->modified = qfalse;
01343     }
01344 
01345     /* set Cvars for all actors */
01346     HUD_UpdateAllActors();
01347 
01348     /* force them empty first */
01349     Cvar_Set("mn_anim", "stand0");
01350     Cvar_Set("mn_rweapon", "");
01351     Cvar_Set("mn_lweapon", "");
01352 
01353     if (selActor) {
01354         HUD_UpdateActor(selActor);
01355     } else if (!cl.numTeamList) {
01356         /* This will stop the drawing of the bars over the whole screen when we test maps. */
01357         Cvar_SetValue("mn_hp", 0);
01358         Cvar_SetValue("mn_hpmax", 100);
01359         Cvar_SetValue("mn_tu", 0);
01360         Cvar_SetValue("mn_tumax", 100);
01361         Cvar_SetValue("mn_tureserved", 0);
01362         Cvar_SetValue("mn_morale", 0);
01363         Cvar_SetValue("mn_moralemax", 100);
01364         Cvar_SetValue("mn_stun", 0);
01365     }
01366 
01367     /* display special message */
01368     if (cl.time < hudTime)
01369         UI_RegisterText(TEXT_STANDARD, hudText);
01370 }
01371 
01378 static void HUD_ActorSelectionChangeListener (const char *cvarName, const char *oldValue, const char *newValue)
01379 {
01380     if (!CL_OnBattlescape())
01381         return;
01382 
01383     if (newValue[0] != '\0') {
01384         const int actorIdx = atoi(newValue);
01385         const size_t size = lengthof(cl.teamList);
01386         if (actorIdx >= 0 && actorIdx < size)
01387             UI_ExecuteConfunc("hudselect %s", newValue);
01388     }
01389 }
01390 
01397 static void HUD_RightHandChangeListener (const char *cvarName, const char *oldValue, const char *newValue)
01398 {
01399     if (!CL_OnBattlescape())
01400         return;
01401 
01402     HUD_RefreshButtons(selActor);
01403 }
01404 
01411 static void HUD_LeftHandChangeListener (const char *cvarName, const char *oldValue, const char *newValue)
01412 {
01413     if (!CL_OnBattlescape())
01414         return;
01415 
01416     HUD_RefreshButtons(selActor);
01417 }
01418 
01425 static void HUD_TUChangeListener (const char *cvarName, const char *oldValue, const char *newValue)
01426 {
01427     if (!CL_OnBattlescape())
01428         return;
01429 
01430     HUD_RefreshButtons(selActor);
01431 }
01432 
01433 static qboolean CL_CvarWorldLevel (cvar_t *cvar)
01434 {
01435     const int maxLevel = cl.mapMaxLevel ? cl.mapMaxLevel - 1 : PATHFINDING_HEIGHT - 1;
01436     return Cvar_AssertValue(cvar, 0, maxLevel, qtrue);
01437 }
01438 
01439 void HUD_InitStartup (void)
01440 {
01441     HUD_InitCallbacks();
01442 
01443     Cmd_AddCommand("hud_remainingtus", HUD_RemainingTUs_f, "Define if remaining TUs should be displayed in the TU-bar for some hovered-over button.");
01444     Cmd_AddCommand("hud_shotreserve", HUD_ShotReserve_f, "Reserve The TUs for the selected entry in the popup.");
01445     Cmd_AddCommand("hud_shotreservationpopup", HUD_PopupFiremodeReservation_f, "Pop up a list of possible firemodes for reservation in the current turn.");
01446     Cmd_AddCommand("hud_switchfiremodelist", HUD_SwitchFiremodeList_f, "Switch firemode-list to one for the given hand, but only if the list is visible already.");
01447     Cmd_AddCommand("hud_selectreactionfiremode", HUD_SelectReactionFiremode_f, "Change/Select firemode used for reaction fire.");
01448     Cmd_AddCommand("hud_listfiremodes", HUD_DisplayFiremodes_f, "Display a list of firemodes for a weapon+ammo.");
01449     Cmd_AddCommand("hud_getactorcvar", HUD_ActorGetCvarData_f, _("Update cvars from actor from list"));
01450 
01451     cl_worldlevel = Cvar_Get("cl_worldlevel", "0", 0, "Current worldlevel in tactical mode");
01452     Cvar_SetCheckFunction("cl_worldlevel", CL_CvarWorldLevel);
01453     cl_worldlevel->modified = qfalse;
01454 
01455     Cvar_Get("mn_ammoleft", "", 0, "The remaining amount of ammunition in for the left hand weapon");
01456     Cvar_Get("mn_lweapon", "", 0, "The left hand weapon model of the current selected actor - empty if no weapon");
01457     Cvar_RegisterChangeListener("mn_ammoleft", HUD_LeftHandChangeListener);
01458     Cvar_RegisterChangeListener("mn_lweapon", HUD_LeftHandChangeListener);
01459 
01460     Cvar_Get("mn_ammoright", "", 0, "The remaining amount of ammunition in for the right hand weapon");
01461     Cvar_Get("mn_rweapon", "", 0, "The right hand weapon model of the current selected actor - empty if no weapon");
01462     Cvar_RegisterChangeListener("mn_ammoright", HUD_RightHandChangeListener);
01463     Cvar_RegisterChangeListener("mn_rweapon", HUD_RightHandChangeListener);
01464 
01465     Cvar_Get("mn_turemain", "", 0, "Remaining TUs for the current selected actor");
01466     Cvar_RegisterChangeListener("mn_turemain", HUD_TUChangeListener);
01467 
01468     Cvar_RegisterChangeListener("cl_selected", HUD_ActorSelectionChangeListener);
01469 
01470     cl_hud_message_timeout = Cvar_Get("cl_hud_message_timeout", "2000", CVAR_ARCHIVE, "Timeout for HUD messages (milliseconds)");
01471     cl_show_cursor_tooltips = Cvar_Get("cl_show_cursor_tooltips", "1", CVAR_ARCHIVE, "Show cursor tooltips in tactical game mode");
01472 }

Generated by  doxygen 1.6.2