PageRenderTime 68ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 2ms

/codemp/cgame/cg_draw.c

https://github.com/Stoiss/jaMME
C | 8534 lines | 6389 code | 1213 blank | 932 comment | 1635 complexity | ae3b1e5de7cae0e92a46aa7392141981 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. // cg_draw.c -- draw all of the graphical elements during
  4. // active (after loading) gameplay
  5. #include "cg_local.h"
  6. #include "game/bg_saga.h"
  7. #include "ui/ui_shared.h"
  8. #include "ui/ui_public.h"
  9. extern float CG_RadiusForCent( centity_t *cent );
  10. qboolean CG_WorldCoordToScreenCoordFloat(vec3_t worldCoord, float *x, float *y);
  11. qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle );
  12. static void CG_DrawSiegeTimer(int timeRemaining, qboolean isMyTeam);
  13. static void CG_DrawSiegeDeathTimer( int timeRemaining );
  14. // nmckenzie: DUEL_HEALTH
  15. void CG_DrawDuelistHealth ( float x, float y, float w, float h, int duelist );
  16. // used for scoreboard
  17. extern displayContextDef_t cgDC;
  18. menuDef_t *menuScoreboard = NULL;
  19. int sortedTeamPlayers[TEAM_MAXOVERLAY];
  20. int numSortedTeamPlayers;
  21. float lastvalidlockdif;
  22. extern float zoomFov; //this has to be global client-side
  23. char systemChat[256];
  24. char teamChat1[256];
  25. char teamChat2[256];
  26. // The time at which you died and the time it will take for you to rejoin game.
  27. int cg_siegeDeathTime = 0;
  28. #define MAX_HUD_TICS 4
  29. const char *armorTicName[MAX_HUD_TICS] =
  30. {
  31. "armor_tic1",
  32. "armor_tic2",
  33. "armor_tic3",
  34. "armor_tic4",
  35. };
  36. const char *healthTicName[MAX_HUD_TICS] =
  37. {
  38. "health_tic1",
  39. "health_tic2",
  40. "health_tic3",
  41. "health_tic4",
  42. };
  43. const char *forceTicName[MAX_HUD_TICS] =
  44. {
  45. "force_tic1",
  46. "force_tic2",
  47. "force_tic3",
  48. "force_tic4",
  49. };
  50. const char *ammoTicName[MAX_HUD_TICS] =
  51. {
  52. "ammo_tic1",
  53. "ammo_tic2",
  54. "ammo_tic3",
  55. "ammo_tic4",
  56. };
  57. char *showPowersName[] =
  58. {
  59. "HEAL2",//FP_HEAL
  60. "JUMP2",//FP_LEVITATION
  61. "SPEED2",//FP_SPEED
  62. "PUSH2",//FP_PUSH
  63. "PULL2",//FP_PULL
  64. "MINDTRICK2",//FP_TELEPTAHY
  65. "GRIP2",//FP_GRIP
  66. "LIGHTNING2",//FP_LIGHTNING
  67. "DARK_RAGE2",//FP_RAGE
  68. "PROTECT2",//FP_PROTECT
  69. "ABSORB2",//FP_ABSORB
  70. "TEAM_HEAL2",//FP_TEAM_HEAL
  71. "TEAM_REPLENISH2",//FP_TEAM_FORCE
  72. "DRAIN2",//FP_DRAIN
  73. "SEEING2",//FP_SEE
  74. "SABER_OFFENSE2",//FP_SABER_OFFENSE
  75. "SABER_DEFENSE2",//FP_SABER_DEFENSE
  76. "SABER_THROW2",//FP_SABERTHROW
  77. NULL
  78. };
  79. //Called from UI shared code. For now we'll just redirect to the normal anim load function.
  80. int UI_ParseAnimationFile(const char *filename, animation_t *animset, qboolean isHumanoid)
  81. {
  82. return BG_ParseAnimationFile(filename, animset, isHumanoid);
  83. }
  84. int MenuFontToHandle(int iMenuFont)
  85. {
  86. switch (iMenuFont)
  87. {
  88. case FONT_SMALL: return cgDC.Assets.qhSmallFont;
  89. case FONT_SMALL2: return cgDC.Assets.qhSmall2Font;
  90. case FONT_MEDIUM: return cgDC.Assets.qhMediumFont;
  91. case FONT_LARGE: return cgDC.Assets.qhMediumFont;//cgDC.Assets.qhBigFont;
  92. //fixme? Big fonr isn't registered...?
  93. }
  94. return cgDC.Assets.qhMediumFont;
  95. }
  96. int CG_Text_Width(const char *text, float scale, int iMenuFont)
  97. {
  98. int iFontIndex = MenuFontToHandle(iMenuFont);
  99. return trap_R_Font_StrLenPixels(text, iFontIndex, scale);
  100. }
  101. int CG_Text_Height(const char *text, float scale, int iMenuFont)
  102. {
  103. int iFontIndex = MenuFontToHandle(iMenuFont);
  104. return trap_R_Font_HeightPixels(iFontIndex, scale);
  105. }
  106. #include "qcommon/qfiles.h" // for STYLE_BLINK etc
  107. void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style, int iMenuFont)
  108. {
  109. int iStyleOR = 0;
  110. int iFontIndex = MenuFontToHandle(iMenuFont);
  111. switch (style)
  112. {
  113. case ITEM_TEXTSTYLE_NORMAL: iStyleOR = 0;break; // JK2 normal text
  114. case ITEM_TEXTSTYLE_BLINK: iStyleOR = STYLE_BLINK;break; // JK2 fast blinking
  115. case ITEM_TEXTSTYLE_PULSE: iStyleOR = STYLE_BLINK;break; // JK2 slow pulsing
  116. case ITEM_TEXTSTYLE_SHADOWED: iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this )
  117. case ITEM_TEXTSTYLE_OUTLINED: iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this )
  118. case ITEM_TEXTSTYLE_OUTLINESHADOWED: iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this )
  119. case ITEM_TEXTSTYLE_SHADOWEDMORE: iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this )
  120. }
  121. trap_R_Font_DrawString( x, // int ox
  122. y, // int oy
  123. text, // const char *text
  124. color, // paletteRGBA_c c
  125. iStyleOR | iFontIndex, // const int iFontHandle
  126. !limit?-1:limit, // iCharLimit (-1 = none)
  127. scale // const float scale = 1.0f
  128. );
  129. }
  130. /*
  131. qboolean CG_WorldCoordToScreenCoord(vec3_t worldCoord, int *x, int *y)
  132. Take any world coord and convert it to a 2D virtual 640x480 screen coord
  133. */
  134. /*
  135. qboolean CG_WorldCoordToScreenCoordFloat(vec3_t worldCoord, float *x, float *y)
  136. {
  137. int xcenter, ycenter;
  138. vec3_t local, transformed;
  139. // xcenter = cg.refdef.width / 2;//gives screen coords adjusted for resolution
  140. // ycenter = cg.refdef.height / 2;//gives screen coords adjusted for resolution
  141. //NOTE: did it this way because most draw functions expect virtual 640x480 coords
  142. // and adjust them for current resolution
  143. xcenter = 640 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn
  144. ycenter = 480 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn
  145. VectorSubtract (worldCoord, cg.refdef.vieworg, local);
  146. transformed[0] = DotProduct(local,vright);
  147. transformed[1] = DotProduct(local,vup);
  148. transformed[2] = DotProduct(local,vfwd);
  149. // Make sure Z is not negative.
  150. if(transformed[2] < 0.01)
  151. {
  152. return qfalse;
  153. }
  154. // Simple convert to screen coords.
  155. float xzi = xcenter / transformed[2] * (90.0/cg.refdef.fov_x);
  156. float yzi = ycenter / transformed[2] * (90.0/cg.refdef.fov_y);
  157. *x = xcenter + xzi * transformed[0];
  158. *y = ycenter - yzi * transformed[1];
  159. return qtrue;
  160. }
  161. qboolean CG_WorldCoordToScreenCoord( vec3_t worldCoord, int *x, int *y )
  162. {
  163. float xF, yF;
  164. qboolean retVal = CG_WorldCoordToScreenCoordFloat( worldCoord, &xF, &yF );
  165. *x = (int)xF;
  166. *y = (int)yF;
  167. return retVal;
  168. }
  169. */
  170. /*
  171. ================
  172. CG_DrawZoomMask
  173. ================
  174. */
  175. static void CG_DrawZoomMask( void )
  176. {
  177. vec4_t color1;
  178. float level;
  179. static qboolean flip = qtrue;
  180. // int ammo = cg_entities[0].gent->client->ps.ammo[weaponData[cent->currentState.weapon].ammoIndex];
  181. float cx, cy;
  182. // int val[5];
  183. float max, fi;
  184. // Check for Binocular specific zooming since we'll want to render different bits in each case
  185. if ( cg.predictedPlayerState.zoomMode == 2 )
  186. {
  187. int val, i;
  188. float off;
  189. // zoom level
  190. level = (float)(80.0f - cg.predictedPlayerState.zoomFov) / 80.0f;
  191. // ...so we'll clamp it
  192. if ( level < 0.0f )
  193. {
  194. level = 0.0f;
  195. }
  196. else if ( level > 1.0f )
  197. {
  198. level = 1.0f;
  199. }
  200. // Using a magic number to convert the zoom level to scale amount
  201. level *= 162.0f;
  202. // draw blue tinted distortion mask, trying to make it as small as is necessary to fill in the viewable area
  203. trap_R_SetColor( colorTable[CT_WHITE] );
  204. CG_DrawPic( 34, 48, 570, 362, cgs.media.binocularStatic );
  205. // Black out the area behind the numbers
  206. trap_R_SetColor( colorTable[CT_BLACK]);
  207. CG_DrawPic( 212, 367, 200, 40, cgs.media.whiteShader );
  208. // Numbers should be kind of greenish
  209. color1[0] = 0.2f;
  210. color1[1] = 0.4f;
  211. color1[2] = 0.2f;
  212. color1[3] = 0.3f;
  213. trap_R_SetColor( color1 );
  214. // Draw scrolling numbers, use intervals 10 units apart--sorry, this section of code is just kind of hacked
  215. // up with a bunch of magic numbers.....
  216. val = ((int)((cg.refdef.viewangles[YAW] + 180) / 10)) * 10;
  217. off = (cg.refdef.viewangles[YAW] + 180) - val;
  218. for ( i = -10; i < 30; i += 10 )
  219. {
  220. val -= 10;
  221. if ( val < 0 )
  222. {
  223. val += 360;
  224. }
  225. // we only want to draw the very far left one some of the time, if it's too far to the left it will
  226. // poke outside the mask.
  227. if (( off > 3.0f && i == -10 ) || i > -10 )
  228. {
  229. // draw the value, but add 200 just to bump the range up...arbitrary, so change it if you like
  230. CG_DrawNumField( 155 + i * 10 + off * 10, 374, 3, val + 200, 24, 14, NUM_FONT_CHUNKY, qtrue );
  231. CG_DrawPic( 245 + (i-1) * 10 + off * 10, 376, 6, 6, cgs.media.whiteShader );
  232. }
  233. }
  234. CG_DrawPic( 212, 367, 200, 28, cgs.media.binocularOverlay );
  235. color1[0] = sin( cg.time * 0.01 + cg.timeFraction * 0.01 ) * 0.5f + 0.5f;
  236. color1[0] = color1[0] * color1[0];
  237. color1[1] = color1[0];
  238. color1[2] = color1[0];
  239. color1[3] = 1.0f;
  240. trap_R_SetColor( color1 );
  241. CG_DrawPic( 82, 94, 16, 16, cgs.media.binocularCircle );
  242. // Flickery color
  243. color1[0] = 0.7f + crandom() * 0.1f;
  244. color1[1] = 0.8f + crandom() * 0.1f;
  245. color1[2] = 0.7f + crandom() * 0.1f;
  246. color1[3] = 1.0f;
  247. trap_R_SetColor( color1 );
  248. CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, cgs.media.binocularMask );
  249. CG_DrawPic( 4, 282 - level, 16, 16, cgs.media.binocularArrow );
  250. // The top triangle bit randomly flips
  251. if ( flip )
  252. {
  253. CG_DrawPic( 330, 60, -26, -30, cgs.media.binocularTri );
  254. }
  255. else
  256. {
  257. CG_DrawPic( 307, 40, 26, 30, cgs.media.binocularTri );
  258. }
  259. if ( random() > 0.98f && ( cg.time & 1024 ))
  260. {
  261. flip = !flip;
  262. }
  263. }
  264. else if (cg.zoomMode)
  265. {
  266. // disruptor zoom mode
  267. level = (float)(50.0f - zoomFov) / 50.0f;//(float)(80.0f - zoomFov) / 80.0f;
  268. // ...so we'll clamp it
  269. if ( level < 0.0f )
  270. {
  271. level = 0.0f;
  272. }
  273. else if ( level > 1.0f )
  274. {
  275. level = 1.0f;
  276. }
  277. if (!cg.playerPredicted)
  278. level = 0.46f;
  279. // Using a magic number to convert the zoom level to a rotation amount that correlates more or less with the zoom artwork.
  280. level *= 103.0f;
  281. // Draw target mask
  282. trap_R_SetColor( colorTable[CT_WHITE] );
  283. CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, cgs.media.disruptorMask );
  284. // apparently 99.0f is the full zoom level
  285. if ( level >= 99 )
  286. {
  287. // Fully zoomed, so make the rotating insert pulse
  288. color1[0] = 1.0f;
  289. color1[1] = 1.0f;
  290. color1[2] = 1.0f;
  291. color1[3] = 0.7f + sin( cg.time * 0.01 + cg.timeFraction * 0.01 ) * 0.3f;
  292. trap_R_SetColor( color1 );
  293. }
  294. // Draw rotating insert
  295. CG_DrawRotatePic2( SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT, -level, cgs.media.disruptorInsert );
  296. // Increase the light levels under the center of the target
  297. // CG_DrawPic( 198, 118, 246, 246, cgs.media.disruptorLight );
  298. // weirdness.....converting ammo to a base five number scale just to be geeky.
  299. /* val[0] = ammo % 5;
  300. val[1] = (ammo / 5) % 5;
  301. val[2] = (ammo / 25) % 5;
  302. val[3] = (ammo / 125) % 5;
  303. val[4] = (ammo / 625) % 5;
  304. color1[0] = 0.2f;
  305. color1[1] = 0.55f + crandom() * 0.1f;
  306. color1[2] = 0.5f + crandom() * 0.1f;
  307. color1[3] = 1.0f;
  308. trap_R_SetColor( color1 );
  309. for ( int t = 0; t < 5; t++ )
  310. {
  311. cx = 320 + sin( (t*10+45)/57.296f ) * 192;
  312. cy = 240 + cos( (t*10+45)/57.296f ) * 192;
  313. CG_DrawRotatePic2( cx, cy, 24, 38, 45 - t * 10, trap_R_RegisterShader( va("gfx/2d/char%d",val[4-t] )));
  314. }
  315. */
  316. //max = ( cg_entities[0].gent->health / 100.0f );
  317. if (cg.playerPredicted) {
  318. if ( (cg.snap->ps.eFlags & EF_DOUBLE_AMMO) )
  319. max = cg.snap->ps.ammo[weaponData[WP_DISRUPTOR].ammoIndex] / ((float)ammoData[weaponData[WP_DISRUPTOR].ammoIndex].max*2.0f);
  320. else
  321. max = cg.snap->ps.ammo[weaponData[WP_DISRUPTOR].ammoIndex] / (float)ammoData[weaponData[WP_DISRUPTOR].ammoIndex].max;
  322. if ( max > 1.0f )
  323. max = 1.0f;
  324. } else {
  325. max = 0.5f; // let it be half
  326. }
  327. color1[0] = (1.0f - max) * 2.0f;
  328. color1[1] = max * 1.5f;
  329. color1[2] = 0.0f;
  330. color1[3] = 1.0f;
  331. // If we are low on health, make us flash
  332. if ( max < 0.15f && ( cg.time & 512 ))
  333. {
  334. VectorClear( color1 );
  335. }
  336. if ( color1[0] > 1.0f )
  337. {
  338. color1[0] = 1.0f;
  339. }
  340. if ( color1[1] > 1.0f )
  341. {
  342. color1[1] = 1.0f;
  343. }
  344. trap_R_SetColor( color1 );
  345. max *= 58.0f;
  346. for (fi = 18.5f; fi <= 18.5f + max; fi+= 3 ) // going from 15 to 45 degrees, with 5 degree increments
  347. {
  348. cx = SCREEN_WIDTH / 2 + sin( (fi+90.0f)/57.296f ) * 190;
  349. cy = SCREEN_HEIGHT / 2 + cos( (fi+90.0f)/57.296f ) * 190;
  350. CG_DrawRotatePic2( cx, cy, 12, 24, 90 - fi, cgs.media.disruptorInsertTick );
  351. }
  352. if ((cg.playerPredicted && cg.predictedPlayerState.weaponstate == WEAPON_CHARGING_ALT)
  353. || (!cg.playerPredicted && cg.charging && cg.chargeTime && cg.time > cg.chargeTime))
  354. {
  355. trap_R_SetColor( colorTable[CT_WHITE] );
  356. // draw the charge level
  357. if (cg.playerPredicted)
  358. max = ((cg.time - cg.predictedPlayerState.weaponChargeTime) + cg.timeFraction) / (50.0f * 30.0f); // bad hardcodedness 50 is disruptor charge unit and 30 is max charge units allowed.
  359. else
  360. max = ((cg.time - cg.chargeTime) + cg.timeFraction) / (50.0f * 30.0f);
  361. if ( max > 1.0f )
  362. {
  363. max = 1.0f;
  364. }
  365. trap_R_DrawStretchPic(257, 435, 134*max, 34, 0, 0, max, 1, cgs.media.disruptorChargeShader);
  366. }
  367. // trap_R_SetColor( colorTable[CT_WHITE] );
  368. // CG_DrawPic( 0, 0, 640, 480, cgs.media.disruptorMask );
  369. }
  370. }
  371. /*
  372. ================
  373. CG_Draw3DModel
  374. ================
  375. */
  376. void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, void *ghoul2, int g2radius, qhandle_t skin, vec3_t origin, vec3_t angles ) {
  377. refdef_t refdef;
  378. refEntity_t ent;
  379. if ( !cg_draw3DIcons.integer || !cg_drawIcons.integer ) {
  380. return;
  381. }
  382. memset( &refdef, 0, sizeof( refdef ) );
  383. memset( &ent, 0, sizeof( ent ) );
  384. AnglesToAxis( angles, ent.axis );
  385. VectorCopy( origin, ent.origin );
  386. ent.hModel = model;
  387. ent.ghoul2 = ghoul2;
  388. ent.radius = g2radius;
  389. ent.customSkin = skin;
  390. ent.renderfx = RF_NOSHADOW; // no stencil shadows
  391. refdef.rdflags = RDF_NOWORLDMODEL;
  392. AxisClear( refdef.viewaxis );
  393. refdef.fov_x = 30;
  394. refdef.fov_y = 30;
  395. refdef.x = x;
  396. refdef.y = y;
  397. refdef.width = w;
  398. refdef.height = h;
  399. refdef.time = cg.time;
  400. trap_R_ClearScene();
  401. trap_R_AddRefEntityToScene( &ent );
  402. trap_R_RenderScene( &refdef );
  403. }
  404. /*
  405. ================
  406. CG_DrawHead
  407. Used for both the status bar and the scoreboard
  408. ================
  409. */
  410. void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles )
  411. {
  412. clientInfo_t *ci;
  413. if (clientNum >= MAX_CLIENTS)
  414. { //npc?
  415. return;
  416. }
  417. ci = &cgs.clientinfo[ clientNum ];
  418. CG_DrawPic( x, y, w, h, ci->modelIcon );
  419. // if they are deferred, draw a cross out
  420. if ( ci->deferred )
  421. {
  422. CG_DrawPic( x, y, w, h, cgs.media.deferShader );
  423. }
  424. }
  425. /*
  426. ================
  427. CG_DrawFlagModel
  428. Used for both the status bar and the scoreboard
  429. ================
  430. */
  431. void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) {
  432. qhandle_t cm;
  433. float len;
  434. vec3_t origin, angles;
  435. vec3_t mins, maxs;
  436. qhandle_t handle;
  437. if ( !force2D && cg_draw3DIcons.integer ) {
  438. //Raz: need to adjust the coords only for 3d models
  439. // 2d icons use virtual screen coords
  440. x *= cgs.screenXScale;
  441. y *= cgs.screenYScale;
  442. w *= cgs.screenXScale;
  443. h *= cgs.screenYScale;
  444. VectorClear( angles );
  445. cm = cgs.media.redFlagModel;
  446. // offset the origin y and z to center the flag
  447. trap_R_ModelBounds( cm, mins, maxs );
  448. origin[2] = -0.5 * ( mins[2] + maxs[2] );
  449. origin[1] = 0.5 * ( mins[1] + maxs[1] );
  450. // calculate distance so the flag nearly fills the box
  451. // assume heads are taller than wide
  452. len = 0.5 * ( maxs[2] - mins[2] );
  453. origin[0] = len / 0.268; // len / tan( fov/2 )
  454. angles[YAW] = 60 * sin((double)((double)cg.time + cg.timeFraction) / 2000.0);;
  455. if( team == TEAM_RED ) {
  456. handle = cgs.media.redFlagModel;
  457. } else if( team == TEAM_BLUE ) {
  458. handle = cgs.media.blueFlagModel;
  459. } else if( team == TEAM_FREE ) {
  460. handle = 0;//cgs.media.neutralFlagModel;
  461. } else {
  462. return;
  463. }
  464. CG_Draw3DModel( x, y, w, h, handle, NULL, 0, 0, origin, angles );
  465. } else if ( cg_drawIcons.integer ) {
  466. gitem_t *item;
  467. if( team == TEAM_RED ) {
  468. item = BG_FindItemForPowerup( PW_REDFLAG );
  469. } else if( team == TEAM_BLUE ) {
  470. item = BG_FindItemForPowerup( PW_BLUEFLAG );
  471. } else if( team == TEAM_FREE ) {
  472. item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
  473. } else {
  474. return;
  475. }
  476. if (item) {
  477. CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );
  478. }
  479. }
  480. }
  481. /*
  482. ================
  483. CG_DrawHealth
  484. ================
  485. */
  486. void CG_DrawHealth( menuDef_t *menuHUD )
  487. {
  488. vec4_t calcColor;
  489. playerState_t *ps;
  490. int healthAmt;
  491. int i,currValue,inc;
  492. itemDef_t *focusItem;
  493. float percent;
  494. // Can we find the menu?
  495. if (!menuHUD)
  496. {
  497. return;
  498. }
  499. ps = &cg.snap->ps;
  500. // What's the health?
  501. healthAmt = ps->stats[STAT_HEALTH];
  502. if (healthAmt > ps->stats[STAT_MAX_HEALTH])
  503. {
  504. healthAmt = ps->stats[STAT_MAX_HEALTH];
  505. }
  506. inc = (float) ps->stats[STAT_MAX_HEALTH] / MAX_HUD_TICS;
  507. currValue = healthAmt;
  508. // Print the health tics, fading out the one which is partial health
  509. for (i=(MAX_HUD_TICS-1);i>=0;i--)
  510. {
  511. focusItem = Menu_FindItemByName(menuHUD, healthTicName[i]);
  512. if (!focusItem) // This is bad
  513. {
  514. continue;
  515. }
  516. memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t));
  517. if (currValue <= 0) // don't show tic
  518. {
  519. break;
  520. }
  521. else if (currValue < inc) // partial tic (alpha it out)
  522. {
  523. percent = (float) currValue / inc;
  524. calcColor[3] *= percent; // Fade it out
  525. }
  526. trap_R_SetColor( calcColor);
  527. CG_DrawPic(
  528. focusItem->window.rect.x*cgs.widthRatioCoef,
  529. focusItem->window.rect.y,
  530. focusItem->window.rect.w*cgs.widthRatioCoef,
  531. focusItem->window.rect.h,
  532. focusItem->window.background
  533. );
  534. currValue -= inc;
  535. }
  536. // Print the mueric amount
  537. focusItem = Menu_FindItemByName(menuHUD, "healthamount");
  538. if (focusItem)
  539. {
  540. // Print health amount
  541. trap_R_SetColor( focusItem->window.foreColor );
  542. CG_DrawNumField (
  543. focusItem->window.rect.x*cgs.widthRatioCoef,
  544. focusItem->window.rect.y,
  545. 3,
  546. ps->stats[STAT_HEALTH],
  547. focusItem->window.rect.w*cgs.widthRatioCoef,
  548. focusItem->window.rect.h,
  549. NUM_FONT_SMALL,
  550. qfalse);
  551. }
  552. }
  553. /*
  554. ================
  555. CG_DrawArmor
  556. ================
  557. */
  558. void CG_DrawArmor( menuDef_t *menuHUD )
  559. {
  560. vec4_t calcColor;
  561. playerState_t *ps;
  562. int maxArmor;
  563. itemDef_t *focusItem;
  564. float percent,quarterArmor;
  565. int i,currValue,inc;
  566. //ps = &cg.snap->ps;
  567. ps = &cg.predictedPlayerState;
  568. // Can we find the menu?
  569. if (!menuHUD)
  570. {
  571. return;
  572. }
  573. maxArmor = ps->stats[STAT_MAX_HEALTH];
  574. currValue = ps->stats[STAT_ARMOR];
  575. inc = (float) maxArmor / MAX_HUD_TICS;
  576. memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t));
  577. for (i=(MAX_HUD_TICS-1);i>=0;i--)
  578. {
  579. focusItem = Menu_FindItemByName(menuHUD, armorTicName[i]);
  580. if (!focusItem) // This is bad
  581. {
  582. continue;
  583. }
  584. memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t));
  585. if (currValue <= 0) // don't show tic
  586. {
  587. break;
  588. }
  589. else if (currValue < inc) // partial tic (alpha it out)
  590. {
  591. percent = (float) currValue / inc;
  592. calcColor[3] *= percent;
  593. }
  594. trap_R_SetColor( calcColor);
  595. if ((i==(MAX_HUD_TICS-1)) && (currValue < inc))
  596. {
  597. if (cg.HUDArmorFlag)
  598. {
  599. CG_DrawPic(
  600. focusItem->window.rect.x*cgs.widthRatioCoef,
  601. focusItem->window.rect.y,
  602. focusItem->window.rect.w*cgs.widthRatioCoef,
  603. focusItem->window.rect.h,
  604. focusItem->window.background
  605. );
  606. }
  607. }
  608. else
  609. {
  610. CG_DrawPic(
  611. focusItem->window.rect.x*cgs.widthRatioCoef,
  612. focusItem->window.rect.y,
  613. focusItem->window.rect.w*cgs.widthRatioCoef,
  614. focusItem->window.rect.h,
  615. focusItem->window.background
  616. );
  617. }
  618. currValue -= inc;
  619. }
  620. focusItem = Menu_FindItemByName(menuHUD, "armoramount");
  621. if (focusItem)
  622. {
  623. // Print armor amount
  624. trap_R_SetColor( focusItem->window.foreColor );
  625. CG_DrawNumField (
  626. focusItem->window.rect.x*cgs.widthRatioCoef,
  627. focusItem->window.rect.y,
  628. 3,
  629. ps->stats[STAT_ARMOR],
  630. focusItem->window.rect.w*cgs.widthRatioCoef,
  631. focusItem->window.rect.h,
  632. NUM_FONT_SMALL,
  633. qfalse);
  634. }
  635. // If armor is low, flash a graphic to warn the player
  636. if (ps->stats[STAT_ARMOR]) // Is there armor? Draw the HUD Armor TIC
  637. {
  638. quarterArmor = (float) (ps->stats[STAT_MAX_HEALTH] / 4.0f);
  639. // Make tic flash if armor is at 25% of full armor
  640. if (ps->stats[STAT_ARMOR] < quarterArmor) // Do whatever the flash timer says
  641. {
  642. if (cg.HUDTickFlashTime < cg.time) // Flip at the same time
  643. {
  644. cg.HUDTickFlashTime = cg.time + 400;
  645. if (cg.HUDArmorFlag)
  646. {
  647. cg.HUDArmorFlag = qfalse;
  648. }
  649. else
  650. {
  651. cg.HUDArmorFlag = qtrue;
  652. }
  653. }
  654. }
  655. else
  656. {
  657. cg.HUDArmorFlag=qtrue;
  658. }
  659. }
  660. else // No armor? Don't show it.
  661. {
  662. cg.HUDArmorFlag=qfalse;
  663. }
  664. }
  665. /*
  666. ================
  667. CG_DrawSaberStyle
  668. If the weapon is a light saber (which needs no ammo) then draw a graphic showing
  669. the saber style (fast, medium, strong)
  670. ================
  671. */
  672. static void CG_DrawSaberStyle( centity_t *cent, menuDef_t *menuHUD)
  673. {
  674. itemDef_t *focusItem;
  675. if (!cent->currentState.weapon ) // We don't have a weapon right now
  676. {
  677. return;
  678. }
  679. if ( cent->currentState.weapon != WP_SABER )
  680. {
  681. return;
  682. }
  683. // Can we find the menu?
  684. if (!menuHUD)
  685. {
  686. return;
  687. }
  688. // draw the current saber style in this window
  689. switch ( cg.predictedPlayerState.fd.saberDrawAnimLevel )
  690. {
  691. case 1://FORCE_LEVEL_1:
  692. case 5://FORCE_LEVEL_5://Tavion
  693. focusItem = Menu_FindItemByName(menuHUD, "saberstyle_fast");
  694. if (focusItem)
  695. {
  696. trap_R_SetColor( colorTable[CT_WHITE] );
  697. CG_DrawPic(
  698. SCREEN_WIDTH - (SCREEN_WIDTH - focusItem->window.rect.x)*cgs.widthRatioCoef,
  699. focusItem->window.rect.y,
  700. focusItem->window.rect.w*cgs.widthRatioCoef,
  701. focusItem->window.rect.h,
  702. focusItem->window.background
  703. );
  704. }
  705. break;
  706. case 2://FORCE_LEVEL_2:
  707. case 6://SS_DUAL
  708. case 7://SS_STAFF
  709. focusItem = Menu_FindItemByName(menuHUD, "saberstyle_medium");
  710. if (focusItem)
  711. {
  712. trap_R_SetColor( colorTable[CT_WHITE] );
  713. CG_DrawPic(
  714. SCREEN_WIDTH - (SCREEN_WIDTH - focusItem->window.rect.x)*cgs.widthRatioCoef,
  715. focusItem->window.rect.y,
  716. focusItem->window.rect.w*cgs.widthRatioCoef,
  717. focusItem->window.rect.h,
  718. focusItem->window.background
  719. );
  720. }
  721. break;
  722. case 3://FORCE_LEVEL_3:
  723. case 4://FORCE_LEVEL_4://Desann
  724. focusItem = Menu_FindItemByName(menuHUD, "saberstyle_strong");
  725. if (focusItem)
  726. {
  727. trap_R_SetColor( colorTable[CT_WHITE] );
  728. CG_DrawPic(
  729. SCREEN_WIDTH - (SCREEN_WIDTH - focusItem->window.rect.x)*cgs.widthRatioCoef,
  730. focusItem->window.rect.y,
  731. focusItem->window.rect.w*cgs.widthRatioCoef,
  732. focusItem->window.rect.h,
  733. focusItem->window.background
  734. );
  735. }
  736. break;
  737. }
  738. }
  739. /*
  740. ================
  741. CG_DrawAmmo
  742. ================
  743. */
  744. static void CG_DrawAmmo( centity_t *cent,menuDef_t *menuHUD)
  745. {
  746. playerState_t *ps;
  747. int i;
  748. vec4_t calcColor;
  749. float value=0.0f,inc = 0.0f,percent;
  750. itemDef_t *focusItem;
  751. ps = &cg.snap->ps;
  752. // Can we find the menu?
  753. if (!menuHUD)
  754. {
  755. return;
  756. }
  757. if (!cent->currentState.weapon ) // We don't have a weapon right now
  758. {
  759. return;
  760. }
  761. value = ps->ammo[weaponData[cent->currentState.weapon].ammoIndex];
  762. if (value < 0) // No ammo
  763. {
  764. return;
  765. }
  766. //
  767. // ammo
  768. //
  769. if (cg.oldammo < value)
  770. {
  771. cg.oldAmmoTime = cg.time + 200;
  772. }
  773. cg.oldammo = value;
  774. focusItem = Menu_FindItemByName(menuHUD, "ammoamount");
  775. if (weaponData[cent->currentState.weapon].energyPerShot == 0 &&
  776. weaponData[cent->currentState.weapon].altEnergyPerShot == 0)
  777. { //just draw "infinite"
  778. inc = 8 / MAX_HUD_TICS;
  779. value = 8;
  780. focusItem = Menu_FindItemByName(menuHUD, "ammoinfinite");
  781. trap_R_SetColor( colorTable[CT_YELLOW] );
  782. if (focusItem)
  783. {
  784. UI_DrawProportionalString(SCREEN_WIDTH - (SCREEN_WIDTH - focusItem->window.rect.x)*cgs.widthRatioCoef, focusItem->window.rect.y, "--", NUM_FONT_SMALL, focusItem->window.foreColor);
  785. }
  786. }
  787. else
  788. {
  789. focusItem = Menu_FindItemByName(menuHUD, "ammoamount");
  790. // Firing or reloading?
  791. if (( cg.predictedPlayerState.weaponstate == WEAPON_FIRING
  792. && cg.predictedPlayerState.weaponTime > 100 ))
  793. {
  794. memcpy(calcColor, colorTable[CT_LTGREY], sizeof(vec4_t));
  795. }
  796. else
  797. {
  798. if ( value > 0 )
  799. {
  800. if (cg.oldAmmoTime > cg.time)
  801. {
  802. memcpy(calcColor, colorTable[CT_YELLOW], sizeof(vec4_t));
  803. }
  804. else
  805. {
  806. memcpy(calcColor, focusItem->window.foreColor, sizeof(vec4_t));
  807. }
  808. }
  809. else
  810. {
  811. memcpy(calcColor, colorTable[CT_RED], sizeof(vec4_t));
  812. }
  813. }
  814. trap_R_SetColor( calcColor );
  815. if (focusItem)
  816. {
  817. if ( (cent->currentState.eFlags & EF_DOUBLE_AMMO) )
  818. {
  819. inc = (float) (ammoData[weaponData[cent->currentState.weapon].ammoIndex].max*2.0f) / MAX_HUD_TICS;
  820. }
  821. else
  822. {
  823. inc = (float) ammoData[weaponData[cent->currentState.weapon].ammoIndex].max / MAX_HUD_TICS;
  824. }
  825. value =ps->ammo[weaponData[cent->currentState.weapon].ammoIndex];
  826. CG_DrawNumField (
  827. SCREEN_WIDTH - (SCREEN_WIDTH - focusItem->window.rect.x)*cgs.widthRatioCoef,
  828. focusItem->window.rect.y,
  829. 3,
  830. value,
  831. focusItem->window.rect.w*cgs.widthRatioCoef,
  832. focusItem->window.rect.h,
  833. NUM_FONT_SMALL,
  834. qfalse);
  835. }
  836. }
  837. trap_R_SetColor( colorTable[CT_WHITE] );
  838. // Draw tics
  839. for (i=MAX_HUD_TICS-1;i>=0;i--)
  840. {
  841. focusItem = Menu_FindItemByName(menuHUD, ammoTicName[i]);
  842. if (!focusItem)
  843. {
  844. continue;
  845. }
  846. memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t));
  847. if ( value <= 0 ) // done
  848. {
  849. break;
  850. }
  851. else if (value < inc) // partial tic
  852. {
  853. percent = value / inc;
  854. calcColor[3] = percent;
  855. }
  856. trap_R_SetColor( calcColor);
  857. CG_DrawPic(
  858. SCREEN_WIDTH - (SCREEN_WIDTH - focusItem->window.rect.x)*cgs.widthRatioCoef,
  859. focusItem->window.rect.y,
  860. focusItem->window.rect.w*cgs.widthRatioCoef,
  861. focusItem->window.rect.h,
  862. focusItem->window.background
  863. );
  864. value -= inc;
  865. }
  866. }
  867. /*
  868. ================
  869. CG_DrawForcePower
  870. ================
  871. */
  872. void CG_DrawForcePower( menuDef_t *menuHUD )
  873. {
  874. int i;
  875. vec4_t calcColor;
  876. float value,inc,percent;
  877. itemDef_t *focusItem;
  878. const int maxForcePower = 100;
  879. qboolean flash=qfalse;
  880. // Can we find the menu?
  881. if (!menuHUD)
  882. {
  883. return;
  884. }
  885. if (cg.forceHUDTotalFlashTime < cg.time) {
  886. cg.forceHUDTotalFlashTime = 0;
  887. cg.forceHUDNextFlashTime = 0;
  888. }// else {
  889. // cg.forceHUDTotalFlashTime = cg.time + 1000;
  890. // }
  891. // Make the hud flash by setting forceHUDTotalFlashTime above cg.time
  892. if (cg.forceHUDTotalFlashTime > cg.time )
  893. {
  894. flash = qtrue;
  895. if (cg.forceHUDNextFlashTime < cg.time)
  896. {
  897. cg.forceHUDNextFlashTime = cg.time + 400;
  898. trap_S_StartSound (NULL, 0, CHAN_LOCAL, cgs.media.noforceSound );
  899. if (cg.forceHUDActive)
  900. {
  901. cg.forceHUDActive = qfalse;
  902. }
  903. else
  904. {
  905. cg.forceHUDActive = qtrue;
  906. }
  907. }
  908. }
  909. else // turn HUD back on if it had just finished flashing time.
  910. {
  911. cg.forceHUDNextFlashTime = 0;
  912. cg.forceHUDActive = qtrue;
  913. }
  914. // if (!cg.forceHUDActive)
  915. // {
  916. // return;
  917. // }
  918. inc = (float) maxForcePower / MAX_HUD_TICS;
  919. value = cg.snap->ps.fd.forcePower;
  920. for (i=MAX_HUD_TICS-1;i>=0;i--)
  921. {
  922. focusItem = Menu_FindItemByName(menuHUD, forceTicName[i]);
  923. if (!focusItem)
  924. {
  925. continue;
  926. }
  927. // memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t));
  928. if ( value <= 0 ) // done
  929. {
  930. break;
  931. }
  932. else if (value < inc) // partial tic
  933. {
  934. if (flash)
  935. {
  936. memcpy(calcColor, colorTable[CT_RED], sizeof(vec4_t));
  937. }
  938. else
  939. {
  940. memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t));
  941. }
  942. percent = value / inc;
  943. calcColor[3] = percent;
  944. }
  945. else
  946. {
  947. if (flash)
  948. {
  949. memcpy(calcColor, colorTable[CT_RED], sizeof(vec4_t));
  950. }
  951. else
  952. {
  953. memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t));
  954. }
  955. }
  956. trap_R_SetColor( calcColor);
  957. CG_DrawPic(
  958. SCREEN_WIDTH - (SCREEN_WIDTH - (float)focusItem->window.rect.x)*cgs.widthRatioCoef,
  959. focusItem->window.rect.y,
  960. focusItem->window.rect.w*cgs.widthRatioCoef,
  961. focusItem->window.rect.h,
  962. focusItem->window.background
  963. );
  964. value -= inc;
  965. }
  966. focusItem = Menu_FindItemByName(menuHUD, "forceamount");
  967. if (focusItem)
  968. {
  969. // Print force amount
  970. trap_R_SetColor( focusItem->window.foreColor );
  971. CG_DrawNumField (
  972. SCREEN_WIDTH - (SCREEN_WIDTH - focusItem->window.rect.x)*cgs.widthRatioCoef,
  973. focusItem->window.rect.y,
  974. 3,
  975. cg.snap->ps.fd.forcePower,
  976. focusItem->window.rect.w*cgs.widthRatioCoef,
  977. focusItem->window.rect.h,
  978. NUM_FONT_SMALL,
  979. qfalse);
  980. }
  981. }
  982. /*
  983. ================
  984. CG_DrawHUD
  985. ================
  986. */
  987. void CG_DrawHUD(centity_t *cent)
  988. {
  989. menuDef_t *menuHUD = NULL;
  990. itemDef_t *focusItem = NULL;
  991. const char *scoreStr = NULL;
  992. int scoreBias;
  993. char scoreBiasStr[16];
  994. if (cg_hudFiles.integer)
  995. {
  996. int x = 0;
  997. int y = SCREEN_HEIGHT-80;
  998. char ammoString[64];
  999. int weapX = x;
  1000. if (cg.predictedPlayerState.pm_type != PM_SPECTATOR)
  1001. {
  1002. UI_DrawProportionalString( (x+16)*cgs.widthRatioCoef, y+40, va( "%i", cg.snap->ps.stats[STAT_HEALTH] ),
  1003. UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_RED] );
  1004. UI_DrawProportionalString( (x+18+14)*cgs.widthRatioCoef, y+40+14, va( "%i", cg.snap->ps.stats[STAT_ARMOR] ),
  1005. UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_GREEN] );
  1006. if (cg.snap->ps.weapon == WP_SABER)
  1007. {
  1008. if (cg.snap->ps.fd.saberDrawAnimLevel == SS_DUAL)
  1009. {
  1010. Com_sprintf(ammoString, sizeof(ammoString), "AKIMBO");
  1011. weapX += 16;
  1012. }
  1013. else if (cg.snap->ps.fd.saberDrawAnimLevel == SS_STAFF)
  1014. {
  1015. Com_sprintf(ammoString, sizeof(ammoString), "STAFF");
  1016. weapX += 16;
  1017. }
  1018. else if (cg.snap->ps.fd.saberDrawAnimLevel == FORCE_LEVEL_3)
  1019. {
  1020. Com_sprintf(ammoString, sizeof(ammoString), "STRONG");
  1021. weapX += 16;
  1022. }
  1023. else if (cg.snap->ps.fd.saberDrawAnimLevel == FORCE_LEVEL_2)
  1024. {
  1025. Com_sprintf(ammoString, sizeof(ammoString), "MEDIUM");
  1026. weapX += 16;
  1027. }
  1028. else
  1029. {
  1030. Com_sprintf(ammoString, sizeof(ammoString), "FAST");
  1031. }
  1032. }
  1033. else if (weaponData[cent->currentState.weapon].energyPerShot == 0 && weaponData[cent->currentState.weapon].altEnergyPerShot == 0)
  1034. {
  1035. Q_strncpyz(ammoString, "--", sizeof(ammoString));
  1036. }
  1037. else
  1038. {
  1039. Com_sprintf(ammoString, sizeof(ammoString), "%i", cg.snap->ps.ammo[weaponData[cent->currentState.weapon].ammoIndex]);
  1040. }
  1041. UI_DrawProportionalString( SCREEN_WIDTH-(weapX+16+32), y+40, va( "%s", ammoString ),
  1042. UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_ORANGE] );
  1043. UI_DrawProportionalString( SCREEN_WIDTH-(x+18+14+32), y+40+14, va( "%i", cg.snap->ps.fd.forcePower),
  1044. UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_ICON_BLUE] );
  1045. }
  1046. return;
  1047. }
  1048. if (cg.predictedPlayerState.pm_type != PM_SPECTATOR)
  1049. {
  1050. // Draw the left HUD
  1051. menuHUD = Menus_FindByName("lefthud");
  1052. Menu_Paint( menuHUD, qtrue );
  1053. if (menuHUD)
  1054. {
  1055. itemDef_t *focusItem;
  1056. // Print scanline
  1057. focusItem = Menu_FindItemByName(menuHUD, "scanline");
  1058. if (focusItem)
  1059. {
  1060. trap_R_SetColor( colorTable[CT_WHITE] );
  1061. CG_DrawPic(
  1062. focusItem->window.rect.x,
  1063. focusItem->window.rect.y,
  1064. focusItem->window.rect.w*cgs.widthRatioCoef,
  1065. focusItem->window.rect.h,
  1066. focusItem->window.background
  1067. );
  1068. }
  1069. // Print frame
  1070. focusItem = Menu_FindItemByName(menuHUD, "frame");
  1071. if (focusItem)
  1072. {
  1073. trap_R_SetColor( colorTable[CT_WHITE] );
  1074. CG_DrawPic(
  1075. focusItem->window.rect.x,
  1076. focusItem->window.rect.y,
  1077. focusItem->window.rect.w*cgs.widthRatioCoef,
  1078. focusItem->window.rect.h,
  1079. focusItem->window.background
  1080. );
  1081. }
  1082. CG_DrawArmor(menuHUD);
  1083. CG_DrawHealth(menuHUD);
  1084. }
  1085. else
  1086. {
  1087. //CG_Error("CG_ChatBox_ArrayInsert: unable to locate HUD menu file ");
  1088. }
  1089. //scoreStr = va("Score: %i", cgs.clientinfo[cg.snap->ps.clientNum].score);
  1090. if ( cgs.gametype == GT_DUEL )
  1091. {//A duel that requires more than one kill to knock the current enemy back to the queue
  1092. //show current kills out of how many needed
  1093. scoreStr = va("%s: %i/%i", CG_GetStringEdString("MP_INGAME", "SCORE"), cg.snap->ps.persistant[PERS_SCORE], cgs.fraglimit);
  1094. }
  1095. else if (0 && cgs.gametype < GT_TEAM )
  1096. { // This is a teamless mode, draw the score bias.
  1097. scoreBias = cg.snap->ps.persistant[PERS_SCORE] - cgs.scores1;
  1098. if (scoreBias == 0)
  1099. { // We are the leader!
  1100. if (cgs.scores2 <= 0)
  1101. { // Nobody to be ahead of yet.
  1102. Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), "");
  1103. }
  1104. else
  1105. {
  1106. scoreBias = cg.snap->ps.persistant[PERS_SCORE] - cgs.scores2;
  1107. if (scoreBias == 0)
  1108. {
  1109. Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (Tie)");
  1110. }
  1111. else
  1112. {
  1113. Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (+%d)", scoreBias);
  1114. }
  1115. }
  1116. }
  1117. else // if (scoreBias < 0)
  1118. { // We are behind!
  1119. Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (%d)", scoreBias);
  1120. }
  1121. scoreStr = va("%s: %i%s", CG_GetStringEdString("MP_INGAME", "SCORE"), cg.snap->ps.persistant[PERS_SCORE], scoreBiasStr);
  1122. }
  1123. else
  1124. { // Don't draw a bias.
  1125. scoreStr = va("%s: %i", CG_GetStringEdString("MP_INGAME", "SCORE"), cg.snap->ps.persistant[PERS_SCORE]);
  1126. }
  1127. menuHUD = Menus_FindByName("righthud");
  1128. Menu_Paint( menuHUD, qtrue );
  1129. if (menuHUD)
  1130. {
  1131. if (cgs.gametype != GT_POWERDUEL)
  1132. {
  1133. focusItem = Menu_FindItemByName(menuHUD, "score_line");
  1134. if (focusItem)
  1135. {
  1136. UI_DrawScaledProportionalString(
  1137. SCREEN_WIDTH - (SCREEN_WIDTH - focusItem->window.rect.x)*cgs.widthRatioCoef - 17,
  1138. focusItem->window.rect.y,
  1139. scoreStr,
  1140. UI_RIGHT|UI_DROPSHADOW,
  1141. focusItem->window.foreColor,
  1142. 0.7f);
  1143. }
  1144. }
  1145. // Print scanline
  1146. focusItem = Menu_FindItemByName(menuHUD, "scanline");
  1147. if (focusItem)
  1148. {
  1149. trap_R_SetColor( colorTable[CT_WHITE] );
  1150. CG_DrawPic(
  1151. focusItem->window.rect.x,
  1152. focusItem->window.rect.y,
  1153. focusItem->window.rect.w*cgs.widthRatioCoef,
  1154. focusItem->window.rect.h,
  1155. focusItem->window.background
  1156. );
  1157. }
  1158. focusItem = Menu_FindItemByName(menuHUD, "frame");
  1159. if (focusItem)
  1160. {
  1161. trap_R_SetColor( colorTable[CT_WHITE] );
  1162. CG_DrawPic(
  1163. focusItem->window.rect.x,
  1164. focusItem->window.rect.y,
  1165. focusItem->window.rect.w*cgs.widthRatioCoef,
  1166. focusItem->window.rect.h,
  1167. focusItem->window.background
  1168. );
  1169. }
  1170. CG_DrawForcePower(menuHUD);
  1171. // Draw ammo tics or saber style
  1172. if ( cent->currentState.weapon == WP_SABER )
  1173. {
  1174. CG_DrawSaberStyle(cent,menuHUD);
  1175. }
  1176. else
  1177. {
  1178. CG_DrawAmmo(cent,menuHUD);
  1179. }
  1180. }
  1181. else
  1182. {
  1183. //CG_Error("CG_ChatBox_ArrayInsert: unable to locate HUD menu file ");
  1184. }
  1185. }
  1186. }
  1187. #define MAX_SHOWPOWERS NUM_FORCE_POWERS
  1188. qboolean ForcePower_Valid(int i)
  1189. {
  1190. if (i == FP_LEVITATION ||
  1191. i == FP_SABER_OFFENSE ||
  1192. i == FP_SABER_DEFENSE ||
  1193. i == FP_SABERTHROW)
  1194. {
  1195. return qfalse;
  1196. }
  1197. if (cg.snap->ps.fd.forcePowersKnown & (1 << i))
  1198. {
  1199. return qtrue;
  1200. }
  1201. return qfalse;
  1202. }
  1203. /*
  1204. ===================
  1205. CG_DrawForceSelect
  1206. ===================
  1207. */
  1208. void CG_DrawForceSelect( void )
  1209. {
  1210. int i;
  1211. int count;
  1212. int smallIconSize,bigIconSize;
  1213. int holdX,x,y,x2,y2,pad,length;
  1214. int sideLeftIconCnt,sideRightIconCnt;
  1215. int sideMax,holdCount,iconCnt;
  1216. int yOffset = 0;
  1217. x2 = 0;
  1218. y2 = 0;
  1219. // don't display if dead
  1220. if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 )
  1221. {
  1222. return;
  1223. }
  1224. if ((cg.forceSelectTime+WEAPON_SELECT_TIME)<cg.time) // Time is up for the HUD to display
  1225. {
  1226. cg.forceSelect = cg.snap->ps.fd.forcePowerSelected;
  1227. return;
  1228. }
  1229. if (!cg.snap->ps.fd.forcePowersKnown)
  1230. {
  1231. return;
  1232. }
  1233. // count the number of powers owned
  1234. count = 0;
  1235. for (i=0;i < NUM_FORCE_POWERS;++i)
  1236. {
  1237. if (ForcePower_Valid(i))
  1238. {
  1239. count++;
  1240. }
  1241. }
  1242. if (count == 0) // If no force powers, don't display
  1243. {
  1244. return;
  1245. }
  1246. sideMax = 3; // Max number of icons on the side
  1247. // Calculate how many icons will appear to either side of the center one
  1248. holdCount = count - 1; // -1 for the center icon
  1249. if (holdCount == 0) // No icons to either side
  1250. {
  1251. sideLeftIconCnt = 0;
  1252. sideRightIconCnt = 0;
  1253. }
  1254. else if (count > (2*sideMax)) // Go to the max on each side
  1255. {
  1256. sideLeftIconCnt = sideMax;
  1257. sideRightIconCnt = sideMax;
  1258. }
  1259. else // Less than max, so do the calc
  1260. {
  1261. sideLeftIconCnt = holdCount/2;
  1262. sideRightIconCnt = holdCount - sideLeftIconCnt;
  1263. }
  1264. smallIconSize = 30;
  1265. bigIconSize = 60;
  1266. pad = 12;
  1267. x = 320;
  1268. y = 425;
  1269. // Background
  1270. length = (sideLeftIconCnt * smallIconSize) + (sideLeftIconCnt*pad) +
  1271. bigIconSize + (sideRightIconCnt * smallIconSize) + (sideRightIconCnt*pad) + 12;
  1272. i = BG_ProperForceIndex(cg.forceSelect) - 1;
  1273. if (i < 0)
  1274. {
  1275. i = MAX_SHOWPOWERS;
  1276. }
  1277. trap_R_SetColor(NULL);
  1278. // Work backwards from current icon
  1279. holdX = x - ((bigIconSize/2) + pad + smallIconSize)*cgs.widthRatioCoef;
  1280. for (iconCnt=1;iconCnt<(sideLeftIconCnt+1);i--)
  1281. {
  1282. if (i < 0)
  1283. {
  1284. i = MAX_SHOWPOWERS;
  1285. }
  1286. if (!ForcePower_Valid(forcePowerSorted[i])) // Does he have this power?
  1287. {
  1288. continue;
  1289. }
  1290. ++iconCnt; // Good icon
  1291. if (cgs.media.forcePowerIcons[forcePowerSorted[i]])
  1292. {
  1293. CG_DrawPic( holdX, y + yOffset, smallIconSize*cgs.widthRatioCoef, smallIconSize, cgs.media.forcePowerIcons[forcePowerSorted[i]] );
  1294. holdX -= (smallIconSize+pad)*cgs.widthRatioCoef;
  1295. }
  1296. }
  1297. if (ForcePower_Valid(cg.forceSelect))
  1298. {
  1299. // Current Center Icon
  1300. if (cgs.media.forcePowerIcons[cg.forceSelect])
  1301. {
  1302. CG_DrawPic( x-(bigIconSize/2)*cgs.widthRatioCoef, (y-((bigIconSize-smallIconSize)/2)) + yOffset, bigIconSize*cgs.widthRatioCoef, bigIconSize, cgs.media.forcePowerIcons[cg.forceSelect] ); //only cache the icon for display
  1303. }
  1304. }
  1305. i = BG_ProperForceIndex(cg.forceSelect) + 1;
  1306. if (i>MAX_SHOWPOWERS)
  1307. {
  1308. i = 0;
  1309. }
  1310. // Work forwards from current icon
  1311. holdX = x + ((bigIconSize/2) + pad)*cgs.widthRatioCoef;
  1312. for (iconCnt=1;iconCnt<(sideRightIconCnt+1);i++)
  1313. {
  1314. if (i>MAX_SHOWPOWERS)
  1315. {
  1316. i = 0;
  1317. }
  1318. if (!ForcePower_Valid(forcePowerSorted[i])) // Does he have this power?
  1319. {
  1320. continue;
  1321. }
  1322. ++iconCnt; // Good icon
  1323. if (cgs.media.forcePowerIcons[forcePowerSorted[i]])
  1324. {
  1325. CG_DrawPic( holdX, y + yOffset, smallIconSize*cgs.widthRatioCoef, smallIconSize, cgs.media.forcePowerIcons[forcePowerSorted[i]] ); //only cache the icon for display
  1326. holdX += (smallIconSize+pad)*cgs.widthRatioCoef;
  1327. }
  1328. }
  1329. if ( showPowersName[cg.forceSelect] )
  1330. {
  1331. UI_DrawProportionalString(320, y + 30 + yOffset, CG_GetStringEdString("SP_INGAME", showPowersName[cg.forceSelect]), UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]);
  1332. }
  1333. }
  1334. /*
  1335. ===================
  1336. CG_DrawInventorySelect
  1337. ===================
  1338. */
  1339. void CG_DrawInvenSelect( void )
  1340. {
  1341. int i;
  1342. int sideMax,holdCount,iconCnt;
  1343. int smallIconSize,bigIconSize;
  1344. int sideLeftIconCnt,sideRightIconCnt;
  1345. int count;
  1346. int holdX,x,y,y2,pad;
  1347. int height;
  1348. float addX;
  1349. // don't display if dead
  1350. if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 )
  1351. {
  1352. return;
  1353. }
  1354. if ((cg.invenSelectTime+WEAPON_SELECT_TIME)<cg.time) // Time is up for the HUD to display
  1355. {
  1356. return;
  1357. }
  1358. if (!cg.snap->ps.stats[STAT_HOLDABLE_ITEM] || !cg.snap->ps.stats[STAT_HOLDABLE_ITEMS])
  1359. {
  1360. return;
  1361. }
  1362. if (cg.itemSelect == -1)
  1363. {
  1364. cg.itemSelect = bg_itemlist[cg.snap->ps.stats[STAT_HOLDABLE_ITEM]].giTag;
  1365. }
  1366. //const int bits = cg.snap->ps.stats[ STAT_ITEMS ];
  1367. // count the number of items owned
  1368. count = 0;
  1369. for ( i = 0 ; i < HI_NUM_HOLDABLE ; i++ )
  1370. {
  1371. if (/*CG_InventorySelectable(i) && inv_icons[i]*/
  1372. (cg.snap->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << i)) )
  1373. {
  1374. count++;
  1375. }
  1376. }
  1377. if (!count)
  1378. {
  1379. y2 = 0; //err?
  1380. UI_DrawProportionalString(320, y2 + 22, "EMPTY INVENTORY", UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]);
  1381. return;
  1382. }
  1383. sideMax = 3; // Max number of icons on the side
  1384. // Calculate how many icons will appear to either side of the center one
  1385. holdCount = count - 1; // -1 for the center icon
  1386. if (holdCount == 0) // No icons to either side
  1387. {
  1388. sideLeftIconCnt = 0;
  1389. sideRightIconCnt = 0;
  1390. }
  1391. else if (count > (2*sideMax)) // Go to the max on each side
  1392. {
  1393. sideLeftIconCnt = sideMax;
  1394. sideRightIconCnt = sideMax;
  1395. }
  1396. else // Less than max, so do the calc
  1397. {
  1398. sideLeftIconCnt = holdCount/2;
  1399. sideRightIconCnt = holdCount - sideLeftIconCnt;
  1400. }
  1401. i = cg.itemSelect - 1;
  1402. if (i<0)
  1403. {
  1404. i = HI_NUM_HOLDABLE-1;
  1405. }
  1406. smallIconSize = 40;
  1407. bigIconSize = 80;
  1408. pad = 16;
  1409. x = 320;
  1410. y = 410;
  1411. // Left side ICONS
  1412. // Work backwards from current icon
  1413. holdX = x - ((bigIconSize/2) + pad + smallIconSize)*cgs.widthRatioCoef;
  1414. height = smallIconSize * cg.iconHUDPercent;
  1415. addX = (float) smallIconSize * .75;
  1416. for (iconCnt=0;iconCnt<sideLeftIconCnt;i--)
  1417. {
  1418. if (i<0)
  1419. {
  1420. i = HI_NUM_HOLDABLE-1;
  1421. }
  1422. if ( !(cg.snap->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << i)) || i == cg.itemSelect )
  1423. {
  1424. continue;
  1425. }
  1426. ++iconCnt; // Good icon
  1427. if (!BG_IsItemSelectable(&cg.predictedPlayerState, i))
  1428. {
  1429. continue;
  1430. }
  1431. if (cgs.media.invenIcons[i])
  1432. {
  1433. trap_R_SetColor(NULL);
  1434. CG_DrawPic( holdX, y+10, smallIconSize*cgs.widthRatioCoef, smallIconSize, cgs.media.invenIcons[i] );
  1435. trap_R_SetColor(colorTable[CT_ICON_BLUE]);
  1436. /*CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12,
  1437. NUM_FONT_SMALL,qfalse);
  1438. */
  1439. holdX -= (smallIconSize+pad)*cgs.widthRatioCoef;
  1440. }
  1441. }
  1442. // Current Center Icon
  1443. height = bigIconSize * cg.iconHUDPercent;
  1444. if (cgs.media.invenIcons[cg.itemSelect] && BG_IsItemSelectable(&cg.predictedPlayerState, cg.itemSelect))
  1445. {
  1446. int itemNdex;
  1447. trap_R_SetColor(NULL);
  1448. CG_DrawPic( x-(bigIconSize/2)*cgs.widthRatioCoef, (y-((bigIconSize-smallIconSize)/2))+10, bigIconSize*cgs.widthRatioCoef, bigIconSize, cgs.media.invenIcons[cg.itemSelect] );
  1449. addX = (float) bigIconSize * .75;
  1450. trap_R_SetColor(colorTable[CT_ICON_BLUE]);
  1451. /*CG_DrawNumField ((x-(bigIconSize/2)) + addX, y, 2, cg.snap->ps.inventory[cg.inventorySelect], 6, 12,
  1452. NUM_FONT_SMALL,qfalse);*/
  1453. itemNdex = BG_GetItemIndexByTag(cg.itemSelect, IT_HOLDABLE);
  1454. if (bg_itemlist[itemNdex].classname)
  1455. {
  1456. vec4_t textColor = { .312f, .75f, .621f, 1.0f };
  1457. char text[1024];
  1458. char upperKey[1024];
  1459. strcpy(upperKey, bg_itemlist[itemNdex].classname);
  1460. if ( trap_SP_GetStringTextString( va("SP_INGAME_%s",Q_strupr(upperKey)), text, sizeof( text )))
  1461. {
  1462. UI_DrawProportionalString(320, y+45, text, UI_CENTER | UI_SMALLFONT, textColor);
  1463. }
  1464. else
  1465. {
  1466. UI_DrawProportionalString(320, y+45, bg_itemlist[itemNdex].classname, UI_CENTER | UI_SMALLFONT, textColor);
  1467. }
  1468. }
  1469. }
  1470. i = cg.itemSelect + 1;
  1471. if (i> HI_NUM_HOLDABLE-1)
  1472. {
  1473. i = 0;
  1474. }
  1475. // Right side ICONS
  1476. // Work forwards from current icon
  1477. holdX = x + ((bigIconSize/2) + pad)*cgs.widthRatioCoef;
  1478. height = smallIconSize * cg.iconHUDPercent;
  1479. addX = (float) smallIconSize * .75;
  1480. for (iconCnt=0;iconCnt<sideRightIconCnt;i++)
  1481. {
  1482. if (i> HI_NUM_HOLDABLE-1)
  1483. {
  1484. i = 0;
  1485. }
  1486. if ( !(cg.snap->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << i)) || i == cg.itemSelect )
  1487. {
  1488. continue;
  1489. }
  1490. ++iconCnt; // Good icon
  1491. if (!BG_IsItemSelectable(&cg.predictedPlayerState, i))
  1492. {
  1493. continue;
  1494. }
  1495. if (cgs.media.invenIcons[i])
  1496. {
  1497. trap_R_SetColor(NULL);
  1498. CG_DrawPic( holdX, y+10, smallIconSize*cgs.widthRatioCoef, smallIconSize, cgs.media.invenIcons[i] );
  1499. trap_R_SetColor(colorTable[CT_ICON_BLUE]);
  1500. /*CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12,
  1501. NUM_FONT_SMALL,qfalse);*/
  1502. holdX += (smallIconSize+pad)*cgs.widthRatioCoef;
  1503. }
  1504. }
  1505. }
  1506. int cg_targVeh = ENTITYNUM_NONE;
  1507. int cg_targVehLastTime = 0;
  1508. qboolean CG_CheckTargetVehicle( centity_t **pTargetVeh, float *alpha )
  1509. {
  1510. int targetNum = ENTITYNUM_NONE;
  1511. centity_t *targetVeh = NULL;
  1512. if ( !pTargetVeh || !alpha )
  1513. {//hey, where are my pointers?
  1514. return qfalse;
  1515. }
  1516. *alpha = 1.0f;
  1517. //FIXME: need to clear all of these when you die?
  1518. if ( cg.predictedPlayerState.rocketLockIndex < ENTITYNUM_WORLD )
  1519. {
  1520. targetNum = cg.predictedPlayerState.rocketLockIndex;
  1521. }
  1522. else if ( cg.crosshairVehNum < ENTITYNUM_WORLD
  1523. && cg.time - cg.crosshairVehTime < 3000 )
  1524. {//crosshair was on a vehicle in the last 3 seconds
  1525. targetNum = cg.crosshairVehNum;
  1526. }
  1527. else if ( cg.crosshairClientNum < ENTITYNUM_WORLD )
  1528. {
  1529. targetNum = cg.crosshairClientNum;
  1530. }
  1531. if ( targetNum < MAX_CLIENTS )
  1532. {//real client
  1533. if ( cg_entities[targetNum].currentState.m_iVehicleNum >= MAX_CLIENTS )
  1534. {//in a vehicle
  1535. targetNum = cg_entities[targetNum].currentState.m_iVehicleNum;
  1536. }
  1537. }
  1538. if ( targetNum < ENTITYNUM_WORLD
  1539. && targetNum >= MAX_CLIENTS )
  1540. {
  1541. //centity_t *targetVeh = &cg_entities[targetNum];
  1542. targetVeh = &cg_entities[targetNum];
  1543. if ( targetVeh->currentState.NPC_class == CLASS_VEHICLE
  1544. && targetVeh->m_pVehicle
  1545. && targetVeh->m_pVehicle->m_pVehicleInfo
  1546. && targetVeh->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
  1547. {//it's a vehicle
  1548. cg_targVeh = targetNum;
  1549. cg_targVehLastTime = cg.time;
  1550. *alpha = 1.0f;
  1551. }
  1552. else
  1553. {
  1554. targetVeh = NULL;
  1555. }
  1556. }
  1557. if ( targetVeh )
  1558. {
  1559. *pTargetVeh = targetVeh;
  1560. return qtrue;
  1561. }
  1562. if ( cg_targVehLastTime && cg.time - cg_targVehLastTime < 3000 )
  1563. {
  1564. targetVeh = &cg_entities[cg_targVeh];
  1565. //stay at full alpha for 1 sec after lose them from crosshair
  1566. if ( cg.time-cg_targVehLastTime < 1000 )
  1567. *alpha = 1.0f;
  1568. else //fade out over 2 secs
  1569. *alpha = 1.0f-(((cg.time-cg_targVehLastTime)+cg.timeFraction-1000)/2000.0f);
  1570. }
  1571. return qfalse;
  1572. }
  1573. #define MAX_VHUD_SHIELD_TICS 12
  1574. #define MAX_VHUD_SPEED_TICS 5
  1575. #define MAX_VHUD_ARMOR_TICS 5
  1576. #define MAX_VHUD_AMMO_TICS 5
  1577. float CG_DrawVehicleShields( const menuDef_t *menuHUD, const centity_t *veh )
  1578. {
  1579. int i;
  1580. char itemName[64];
  1581. float inc, currValue,maxShields;
  1582. vec4_t calcColor;
  1583. itemDef_t *item;
  1584. float percShields;
  1585. item = Menu_FindItemByName((menuDef_t *) menuHUD, "armorbackground");
  1586. if (item)
  1587. {
  1588. trap_R_SetColor( item->window.foreColor );
  1589. CG_DrawPic(
  1590. item->window.rect.x,
  1591. item->window.rect.y,
  1592. item->window.rect.w,
  1593. item->window.rect.h,
  1594. item->window.background );
  1595. }
  1596. maxShields = veh->m_pVehicle->m_pVehicleInfo->shields;
  1597. currValue = cg.predictedVehicleState.stats[STAT_ARMOR];
  1598. percShields = (float)currValue/(float)maxShields;
  1599. // Print all the tics of the shield graphic
  1600. // Look at the amount of health left and show only as much of the graphic as there is health.
  1601. // Use alpha to fade out partial section of health
  1602. inc = (float) maxShields / MAX_VHUD_ARMOR_TICS;
  1603. for (i=1;i<=MAX_VHUD_ARMOR_TICS;i++)
  1604. {
  1605. sprintf( itemName, "armor_tic%d", i );
  1606. item = Menu_FindItemByName((menuDef_t *) menuHUD, itemName);
  1607. if (!item)
  1608. {
  1609. continue;
  1610. }
  1611. memcpy(calcColor, item->window.foreColor, sizeof(vec4_t));
  1612. if (currValue <= 0) // don't show tic
  1613. {
  1614. break;
  1615. }
  1616. else if (currValue < inc) // partial tic (alpha it out)
  1617. {
  1618. float percent = currValue / inc;
  1619. calcColor[3] *= percent; // Fade it out
  1620. }
  1621. trap_R_SetColor( calcColor);
  1622. CG_DrawPic(
  1623. item->window.rect.x,
  1624. item->window.rect.y,
  1625. item->window.rect.w,
  1626. item->window.rect.h,
  1627. item->window.background );
  1628. currValue -= inc;
  1629. }
  1630. return percShields;
  1631. }
  1632. int cg_vehicleAmmoWarning = 0;
  1633. int cg_vehicleAmmoWarningTime = 0;
  1634. void CG_DrawVehicleAmmo( const menuDef_t *menuHUD, const centity_t *veh )
  1635. {
  1636. int i;
  1637. char itemName[64];
  1638. float inc, currValue,maxAmmo;
  1639. vec4_t calcColor;
  1640. itemDef_t *item;
  1641. item = Menu_FindItemByName((menuDef_t *) menuHUD, "ammobackground");
  1642. if (item)
  1643. {
  1644. trap_R_SetColor( item->window.foreColor );
  1645. CG_DrawPic(
  1646. item->window.rect.x,
  1647. item->window.rect.y,
  1648. item->window.rect.w,
  1649. item->window.rect.h,
  1650. item->window.background );
  1651. }
  1652. maxAmmo = veh->m_pVehicle->m_pVehicleInfo->weapon[0].ammoMax;
  1653. currValue = cg.predictedVehicleState.ammo[0];
  1654. inc = (float) maxAmmo / MAX_VHUD_AMMO_TICS;
  1655. for (i=1;i<=MAX_VHUD_AMMO_TICS;i++)
  1656. {
  1657. sprintf( itemName, "ammo_tic%d", i );
  1658. item = Menu_FindItemByName((menuDef_t *)menuHUD, itemName);
  1659. if (!item)
  1660. {
  1661. continue;
  1662. }
  1663. if ( cg_vehicleAmmoWarningTime > cg.time
  1664. && cg_vehicleAmmoWarning == 0 )
  1665. {
  1666. memcpy(calcColor, g_color_table[ColorIndex(COLOR_RED)], sizeof(vec4_t));
  1667. calcColor[3] = sin(cg.time*0.005+cg.timeFraction*0.005)*0.5f+0.5f;
  1668. }
  1669. else
  1670. {
  1671. memcpy(calcColor, item->window.foreColor, sizeof(vec4_t));
  1672. if (currValue <= 0) // don't show tic
  1673. {
  1674. break;
  1675. }
  1676. else if (currValue < inc) // partial tic (alpha it out)
  1677. {
  1678. float percent = currValue / inc;
  1679. calcColor[3] *= percent; // Fade it out
  1680. }
  1681. }
  1682. trap_R_SetColor( calcColor);
  1683. CG_DrawPic(
  1684. item->window.rect.x,
  1685. item->window.rect.y,
  1686. item->window.rect.w,
  1687. item->window.rect.h,
  1688. item->window.background );
  1689. currValue -= inc;
  1690. }
  1691. }
  1692. void CG_DrawVehicleAmmoUpper( const menuDef_t *menuHUD, const centity_t *veh )
  1693. {
  1694. int i;
  1695. char itemName[64];
  1696. float inc, currValue,maxAmmo;
  1697. vec4_t calcColor;
  1698. itemDef_t *item;
  1699. item = Menu_FindItemByName((menuDef_t *)menuHUD, "ammoupperbackground");
  1700. if (item)
  1701. {
  1702. trap_R_SetColor( item->window.foreColor );
  1703. CG_DrawPic(
  1704. item->window.rect.x,
  1705. item->window.rect.y,
  1706. item->window.rect.w,
  1707. item->window.rect.h,
  1708. item->window.background );
  1709. }
  1710. maxAmmo = veh->m_pVehicle->m_pVehicleInfo->weapon[0].ammoMax;
  1711. currValue = cg.predictedVehicleState.ammo[0];
  1712. inc = (float) maxAmmo / MAX_VHUD_AMMO_TICS;
  1713. for (i=1;i<MAX_VHUD_AMMO_TICS;i++)
  1714. {
  1715. sprintf( itemName, "ammoupper_tic%d", i );
  1716. // Com_sprintf(itemName, sizeof(itemName), "ammoupper_tic%d", i );
  1717. item = Menu_FindItemByName((menuDef_t *)menuHUD, itemName);
  1718. if (!item)
  1719. {
  1720. continue;
  1721. }
  1722. if ( cg_vehicleAmmoWarningTime > cg.time
  1723. && cg_vehicleAmmoWarning == 0 )
  1724. {
  1725. memcpy(calcColor, g_color_table[ColorIndex(COLOR_RED)], sizeof(vec4_t));
  1726. calcColor[3] = sin(cg.time*0.005+cg.timeFraction*0.005)*0.5f+0.5f;
  1727. }
  1728. else
  1729. {
  1730. memcpy(calcColor, item->window.foreColor, sizeof(vec4_t));
  1731. if (currValue <= 0) // don't show tic
  1732. {
  1733. break;
  1734. }
  1735. else if (currValue < inc) // partial tic (alpha it out)
  1736. {
  1737. float percent = currValue / inc;
  1738. calcColor[3] *= percent; // Fade it out
  1739. }
  1740. }
  1741. trap_R_SetColor( calcColor);
  1742. CG_DrawPic(
  1743. item->window.rect.x,
  1744. item->window.rect.y,
  1745. item->window.rect.w,
  1746. item->window.rect.h,
  1747. item->window.background );
  1748. currValue -= inc;
  1749. }
  1750. }
  1751. void CG_DrawVehicleAmmoLower( const menuDef_t *menuHUD, const centity_t *veh )
  1752. {
  1753. int i;
  1754. char itemName[64];
  1755. float inc, currValue,maxAmmo;
  1756. vec4_t calcColor;
  1757. itemDef_t *item;
  1758. item = Menu_FindItemByName((menuDef_t *)menuHUD, "ammolowerbackground");
  1759. if (item)
  1760. {
  1761. trap_R_SetColor( item->window.foreColor );
  1762. CG_DrawPic(
  1763. item->window.rect.x,
  1764. item->window.rect.y,
  1765. item->window.rect.w,
  1766. item->window.rect.h,

Large files files are truncated, but you can click here to view the full file