1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7 
8 This file is part of the OpenJK source code.
9 
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23 
24 #include "cg_local.h"
25 #include "cg_media.h"
26 #include "FxScheduler.h"
27 
28 #include "../../code/client/vmachine.h"
29 
30 #include "../../code/qcommon/sstring.h"
31 #include "../code/qcommon/ojk_saved_game_helper.h"
32 
33 //NOTENOTE: Be sure to change the mirrored code in g_shared.h
34 typedef std::map< sstring_t, unsigned char, std::less<sstring_t> >	namePrecache_m;
35 extern namePrecache_m	*as_preCacheMap;
36 extern void CG_RegisterNPCCustomSounds( clientInfo_t *ci );
37 extern qboolean G_AddSexToMunroString ( char *string, qboolean qDoBoth );
38 extern void CG_RegisterNPCEffects( team_t team );
39 extern qboolean G_ParseAnimFileSet( const char *filename, const char *animCFG, int *animFileIndex );
40 extern void CG_DrawDataPadInventorySelect( void );
41 
42 void CG_Init( int serverCommandSequence );
43 qboolean CG_ConsoleCommand( void );
44 void CG_Shutdown( void );
45 int CG_GetCameraPos( vec3_t camerapos );
46 void UseItem(int itemNum);
47 const char *CG_DisplayBoxedText(int iBoxX, int iBoxY, int iBoxWidth, int iBoxHeight,
48 								const char *psText, int iFontHandle, float fScale,
49 								const vec4_t v4Color);
50 
51 #define NUM_CHUNKS		6
52 /*
53 Ghoul2 Insert Start
54 */
55 
56 void CG_ResizeG2Bolt(boltInfo_v *bolt, int newCount);
57 void CG_ResizeG2Surface(surfaceInfo_v *surface, int newCount);
58 void CG_ResizeG2Bone(boneInfo_v *bone, int newCount);
59 void CG_ResizeG2(CGhoul2Info_v *ghoul2, int newCount);
60 void CG_ResizeG2TempBone(mdxaBone_v *tempBone, int newCount);
61 /*
62 Ghoul2 Insert End
63 */
64 
65 
66 void CG_LoadHudMenu(void);
67 int inv_icons[INV_MAX];
68 const char *inv_names[] =
69 {
70 "ELECTROBINOCULARS",
71 "BACTA CANISTER",
72 "SEEKER",
73 "LIGHT AMP GOGGLES",
74 "ASSAULT SENTRY",
75 "GOODIE KEY",
76 "GOODIE KEY",
77 "GOODIE KEY",
78 "GOODIE KEY",
79 "GOODIE KEY",
80 "SECURITY KEY",
81 "SECURITY KEY",
82 "SECURITY KEY",
83 "SECURITY KEY",
84 "SECURITY KEY",
85 };
86 
87 int	force_icons[NUM_FORCE_POWERS];
88 
89 
90 int cgi_UI_GetMenuInfo(char *menuFile,int *x,int *y);
91 void CG_DrawDataPadHUD( centity_t *cent );
92 void MissionInformation_Draw( centity_t *cent );
93 void CG_DrawIconBackground(void);
94 void CG_DrawDataPadIconBackground(int backgroundType);
95 void CG_DrawDataPadWeaponSelect( void );
96 void CG_DrawDataPadForceSelect( void );
97 
98 /*
99 ================
100 vmMain
101 
102 This is the only way control passes into the cgame module.
103 This must be the very first function compiled into the .q3vm file
104 ================
105 */
vmMain(intptr_t command,intptr_t arg0,intptr_t arg1,intptr_t arg2,intptr_t arg3,intptr_t arg4,intptr_t arg5,intptr_t arg6,intptr_t arg7)106 extern "C" Q_EXPORT intptr_t vmMain( intptr_t command, intptr_t arg0, intptr_t arg1, intptr_t arg2, intptr_t arg3, intptr_t arg4, intptr_t arg5, intptr_t arg6, intptr_t arg7 ) {
107 	centity_t		*cent;
108 
109 	switch ( command ) {
110 	case CG_INIT:
111 		CG_Init( arg0 );
112 		return 0;
113 	case CG_SHUTDOWN:
114 		CG_Shutdown();
115 		return 0;
116 	case CG_CONSOLE_COMMAND:
117 		return CG_ConsoleCommand();
118 	case CG_DRAW_ACTIVE_FRAME:
119 		CG_DrawActiveFrame( arg0, (stereoFrame_t) arg1 );
120 		return 0;
121 	case CG_CROSSHAIR_PLAYER:
122 		return CG_CrosshairPlayer();
123 	case CG_CAMERA_POS:
124 		return CG_GetCameraPos( (float*)arg0);
125 /*
126 Ghoul2 Insert Start
127 */
128 	case CG_RESIZE_G2:
129 		CG_ResizeG2((CGhoul2Info_v *)arg0, arg1);
130 		return 0;
131 	case CG_RESIZE_G2_BOLT:
132 		CG_ResizeG2Bolt((boltInfo_v *)arg0, arg1);
133 		return 0;
134 	case CG_RESIZE_G2_BONE:
135 		CG_ResizeG2Bone((boneInfo_v *)arg0, arg1);
136 		return 0;
137 	case CG_RESIZE_G2_SURFACE:
138 		CG_ResizeG2Surface((surfaceInfo_v *)arg0, arg1);
139 		return 0;
140 	case CG_RESIZE_G2_TEMPBONE:
141 		CG_ResizeG2TempBone((mdxaBone_v *)arg0, arg1);
142 		return 0;
143 
144 /*
145 Ghoul2 Insert End
146 */
147 	case CG_DRAW_DATAPAD_HUD:
148 		if (cg.snap)
149 		{
150 			cent = &cg_entities[cg.snap->ps.clientNum];
151 			CG_DrawDataPadHUD(cent);
152 		}
153 		return 0;
154 
155 	case CG_DRAW_DATAPAD_OBJECTIVES:
156 		if (cg.snap)
157 		{
158 			cent = &cg_entities[cg.snap->ps.clientNum];
159 			MissionInformation_Draw(cent);
160 		}
161 		return 0;
162 
163 	case CG_DRAW_DATAPAD_WEAPONS:
164 		if (cg.snap)
165 		{
166 			CG_DrawDataPadIconBackground(ICON_WEAPONS);
167 			CG_DrawDataPadWeaponSelect();
168 		}
169 		return 0;
170 	case CG_DRAW_DATAPAD_INVENTORY:
171 		if (cg.snap)
172 		{
173 			CG_DrawDataPadIconBackground(ICON_INVENTORY);
174 			CG_DrawDataPadInventorySelect();
175 		}
176 		return 0;
177 	case CG_DRAW_DATAPAD_FORCEPOWERS:
178 		if (cg.snap)
179 		{
180 			CG_DrawDataPadIconBackground(ICON_FORCE);
181 			CG_DrawDataPadForceSelect();
182 		}
183 		return 0;
184 	}
185 	return -1;
186 }
187 
188 /*
189 Ghoul2 Insert Start
190 */
191 
CG_ResizeG2Bolt(boltInfo_v * bolt,int newCount)192 void CG_ResizeG2Bolt(boltInfo_v *bolt, int newCount)
193 {
194 	bolt->resize(newCount);
195 }
196 
CG_ResizeG2Surface(surfaceInfo_v * surface,int newCount)197 void CG_ResizeG2Surface(surfaceInfo_v *surface, int newCount)
198 {
199 	surface->resize(newCount);
200 }
201 
CG_ResizeG2Bone(boneInfo_v * bone,int newCount)202 void CG_ResizeG2Bone(boneInfo_v *bone, int newCount)
203 {
204 	bone->resize(newCount);
205 }
206 
CG_ResizeG2(CGhoul2Info_v * ghoul2,int newCount)207 void CG_ResizeG2(CGhoul2Info_v *ghoul2, int newCount)
208 {
209 	ghoul2->resize(newCount);
210 }
211 
CG_ResizeG2TempBone(mdxaBone_v * tempBone,int newCount)212 void CG_ResizeG2TempBone(mdxaBone_v *tempBone, int newCount)
213 {
214 	tempBone->resize(newCount);
215 }
216 /*
217 Ghoul2 Insert End
218 */
219 
220 cg_t				cg;
221 cgs_t				cgs;
222 centity_t			cg_entities[MAX_GENTITIES];
223 weaponInfo_t		cg_weapons[MAX_WEAPONS];
224 itemInfo_t			cg_items[MAX_ITEMS];
225 
226 typedef struct {
227 	qboolean		registered;		// Has the player picked it up
228 	qboolean		active;			// Is it the chosen inventory item
229 	int				count;			// Count of items.
230 	char			description[128];
231 } inventoryInfo_t;
232 
233 inventoryInfo_t		cg_inventory[INV_MAX];
234 
235 
236 vmCvar_t	cg_centertime;
237 vmCvar_t	cg_runpitch;
238 vmCvar_t	cg_runroll;
239 vmCvar_t	cg_bobup;
240 vmCvar_t	cg_bobpitch;
241 vmCvar_t	cg_bobroll;
242 vmCvar_t	cg_swingSpeed;
243 vmCvar_t	cg_shadows;
244 vmCvar_t	cg_paused;
245 vmCvar_t	cg_drawTimer;
246 vmCvar_t	cg_drawFPS;
247 vmCvar_t	cg_drawSnapshot;
248 vmCvar_t	cg_drawAmmoWarning;
249 vmCvar_t	cg_drawCrosshair;
250 vmCvar_t	cg_crosshairIdentifyTarget;
251 vmCvar_t	cg_dynamicCrosshair;
252 vmCvar_t	cg_crosshairForceHint;
253 vmCvar_t	cg_crosshairX;
254 vmCvar_t	cg_crosshairY;
255 vmCvar_t	cg_crosshairSize;
256 vmCvar_t	cg_draw2D;
257 vmCvar_t	cg_drawStatus;
258 vmCvar_t	cg_drawHUD;
259 vmCvar_t	cg_animSpeed;
260 vmCvar_t	cg_debugAnim;
261 vmCvar_t	cg_debugSaber;
262 vmCvar_t	cg_debugPosition;
263 vmCvar_t	cg_debugEvents;
264 vmCvar_t	cg_errorDecay;
265 vmCvar_t	cg_noPlayerAnims;
266 vmCvar_t	cg_footsteps;
267 vmCvar_t	cg_addMarks;
268 vmCvar_t	cg_drawGun;
269 vmCvar_t	cg_gun_frame;
270 vmCvar_t	cg_gun_x;
271 vmCvar_t	cg_gun_y;
272 vmCvar_t	cg_gun_z;
273 vmCvar_t	cg_fovViewmodel;
274 vmCvar_t	cg_fovViewmodelAdjust;
275 vmCvar_t	cg_autoswitch;
276 vmCvar_t	cg_simpleItems;
277 vmCvar_t	cg_fov;
278 vmCvar_t	cg_fovAspectAdjust;
279 vmCvar_t	cg_missionstatusscreen;
280 vmCvar_t	cg_endcredits;
281 vmCvar_t	cg_updatedDataPadForcePower1;
282 vmCvar_t	cg_updatedDataPadForcePower2;
283 vmCvar_t	cg_updatedDataPadForcePower3;
284 vmCvar_t	cg_updatedDataPadObjective;
285 
286 vmCvar_t	cg_thirdPerson;
287 vmCvar_t	cg_thirdPersonRange;
288 vmCvar_t	cg_thirdPersonMaxRange;
289 vmCvar_t	cg_thirdPersonAngle;
290 vmCvar_t	cg_thirdPersonPitchOffset;
291 vmCvar_t	cg_thirdPersonVertOffset;
292 vmCvar_t	cg_thirdPersonCameraDamp;
293 vmCvar_t	cg_thirdPersonTargetDamp;
294 vmCvar_t	cg_saberAutoThird;
295 vmCvar_t	cg_gunAutoFirst;
296 
297 vmCvar_t	cg_thirdPersonAlpha;
298 vmCvar_t	cg_thirdPersonAutoAlpha;
299 vmCvar_t	cg_thirdPersonHorzOffset;
300 
301 vmCvar_t	cg_stereoSeparation;
302 vmCvar_t 	cg_developer;
303 vmCvar_t 	cg_timescale;
304 vmCvar_t	cg_skippingcin;
305 
306 vmCvar_t	cg_pano;
307 vmCvar_t	cg_panoNumShots;
308 
309 vmCvar_t	fx_freeze;
310 vmCvar_t	fx_debug;
311 
312 vmCvar_t	cg_missionInfoCentered;
313 vmCvar_t	cg_missionInfoFlashTime;
314 vmCvar_t	cg_hudFiles;
315 
316 /*
317 Ghoul2 Insert Start
318 */
319 vmCvar_t	cg_debugBB;
320 /*
321 Ghoul2 Insert End
322 */
323 
324 vmCvar_t	cg_VariantSoundCap;	// 0 = no capping, else cap to (n) max (typically just 1, but allows more)
325 vmCvar_t	cg_turnAnims;
326 vmCvar_t	cg_motionBoneComp;
327 vmCvar_t	cg_reliableAnimSounds;
328 
329 vmCvar_t	cg_smoothPlayerPos;
330 vmCvar_t	cg_smoothPlayerPlat;
331 vmCvar_t	cg_smoothPlayerPlatAccel;
332 
333 typedef struct {
334 	vmCvar_t	*vmCvar;
335 	const char	*cvarName;
336 	const char	*defaultString;
337 	int			cvarFlags;
338 } cvarTable_t;
339 
340 static cvarTable_t cvarTable[] = {
341 	{ &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE },
342 	{ &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE },
343 	{ &cg_fov, "cg_fov", "80", CVAR_ARCHIVE },
344 	{ &cg_fovAspectAdjust, "cg_fovAspectAdjust", "0", CVAR_ARCHIVE },
345 	{ &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE  },
346 	{ &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE  },
347 
348 	{ &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE  },
349 	{ &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE  },
350 	{ &cg_drawHUD, "cg_drawHUD", "1", 0  },
351 	{ &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE  },
352 	{ &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE  },
353 	{ &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE  },
354 	{ &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE  },
355 	{ &cg_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE },
356 	{ &cg_dynamicCrosshair, "cg_dynamicCrosshair", "1", CVAR_ARCHIVE },
357 	{ &cg_crosshairIdentifyTarget, "cg_crosshairIdentifyTarget", "1", CVAR_ARCHIVE },
358 	{ &cg_crosshairForceHint, "cg_crosshairForceHint", "1", CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART },
359 	{ &cg_missionstatusscreen, "cg_missionstatusscreen", "0", CVAR_ROM},
360 	{ &cg_endcredits, "cg_endcredits", "0", 0},
361 	{ &cg_updatedDataPadForcePower1, "cg_updatedDataPadForcePower1", "0", 0},
362 	{ &cg_updatedDataPadForcePower2, "cg_updatedDataPadForcePower2", "0", 0},
363 	{ &cg_updatedDataPadForcePower3, "cg_updatedDataPadForcePower3", "0", 0},
364 	{ &cg_updatedDataPadObjective, "cg_updatedDataPadObjective", "0", 0},
365 
366 	{ &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE },
367 	{ &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE },
368 	{ &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE },
369 	{ &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE },
370 	{ &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE },
371 
372 	{ &cg_gun_frame, "gun_frame", "0", CVAR_CHEAT },
373 	{ &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT },
374 	{ &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT },
375 	{ &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT },
376 	{ &cg_centertime, "cg_centertime", "3", CVAR_CHEAT },
377 	{ &cg_fovViewmodel, "cg_fovViewModel", "0", CVAR_ARCHIVE },
378 	{ &cg_fovViewmodelAdjust, "cg_fovViewmodelAdjust", "1", CVAR_ARCHIVE },
379 
380 	{ &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE},
381 	{ &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE },
382 	{ &cg_bobup , "cg_bobup", "0.005", CVAR_ARCHIVE },
383 	{ &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
384 	{ &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE },
385 
386 	{ &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
387 	{ &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
388 	{ &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT },
389 	{ &cg_debugSaber, "cg_debugsaber", "0", CVAR_CHEAT },
390 	{ &cg_debugPosition, "cg_debugposition", "0", CVAR_CHEAT },
391 	{ &cg_debugEvents, "cg_debugevents", "0", CVAR_CHEAT },
392 	{ &cg_errorDecay, "cg_errordecay", "100", 0 },
393 	{ &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT },
394 	{ &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT },
395 
396 	{ &cg_thirdPerson, "cg_thirdPerson", "0", CVAR_SAVEGAME },
397 	{ &cg_thirdPersonRange, "cg_thirdPersonRange", "80", CVAR_ARCHIVE },
398 	{ &cg_thirdPersonMaxRange, "cg_thirdPersonMaxRange", "150", 0 },
399 	{ &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", 0 },
400 	{ &cg_thirdPersonPitchOffset, "cg_thirdPersonPitchOffset", "0", 0 },
401 	{ &cg_thirdPersonVertOffset, "cg_thirdPersonVertOffset", "16", 0},
402 	{ &cg_thirdPersonCameraDamp, "cg_thirdPersonCameraDamp", "0.3", 0},
403 	{ &cg_thirdPersonTargetDamp, "cg_thirdPersonTargetDamp", "0.5", 0},
404 
405 	{ &cg_thirdPersonHorzOffset, "cg_thirdPersonHorzOffset", "0", 0},
406 	{ &cg_thirdPersonAlpha,	"cg_thirdPersonAlpha",	"1.0", CVAR_CHEAT },
407 	{ &cg_thirdPersonAutoAlpha,	"cg_thirdPersonAutoAlpha",	"0", 0 },
408 
409 	{ &cg_saberAutoThird, "cg_saberAutoThird", "1", CVAR_ARCHIVE },
410 	{ &cg_gunAutoFirst, "cg_gunAutoFirst", "1", CVAR_ARCHIVE },
411 
412 	{ &cg_pano, "pano", "0", 0 },
413 	{ &cg_panoNumShots, "panoNumShots", "10", 0 },
414 
415 	{ &fx_freeze, "fx_freeze", "0", 0 },
416 	{ &fx_debug, "fx_debug", "0", 0 },
417 	// the following variables are created in other parts of the system,
418 	// but we also reference them here
419 
420 	{ &cg_paused, "cl_paused", "0", CVAR_ROM },
421 	{ &cg_developer, "developer", "", 0 },
422 	{ &cg_timescale, "timescale", "1", 0 },
423 	{ &cg_skippingcin, "skippingCinematic", "0", CVAR_ROM},
424 	{ &cg_missionInfoCentered, "cg_missionInfoCentered", "1", CVAR_ARCHIVE },
425 	{ &cg_missionInfoFlashTime, "cg_missionInfoFlashTime", "10000", 0  },
426 	{ &cg_hudFiles, "cg_hudFiles", "ui/jk2hud.txt", CVAR_ARCHIVE},
427 /*
428 Ghoul2 Insert Start
429 */
430 	{ &cg_debugBB, "debugBB", "0", 0},
431 /*
432 Ghoul2 Insert End
433 */
434 	{ &cg_VariantSoundCap, "cg_VariantSoundCap", "0", 0 },
435 	{ &cg_turnAnims, "cg_turnAnims", "0", 0 },
436 	{ &cg_motionBoneComp, "cg_motionBoneComp", "2", 0 },
437 	{ &cg_reliableAnimSounds, "cg_reliableAnimSounds", "1", CVAR_ARCHIVE },
438 	{ &cg_smoothPlayerPos, "cg_smoothPlayerPos", "0.5", 0},
439 	{ &cg_smoothPlayerPlat, "cg_smoothPlayerPlat", "0.75", 0},
440 	{ &cg_smoothPlayerPlatAccel, "cg_smoothPlayerPlatAccel", "3.25", 0},
441 };
442 
443 static const size_t cvarTableSize = ARRAY_LEN( cvarTable );
444 
445 /*
446 =================
447 CG_RegisterCvars
448 =================
449 */
CG_RegisterCvars(void)450 void CG_RegisterCvars( void ) {
451 	size_t		i;
452 	cvarTable_t	*cv;
453 
454 	for ( i=0, cv=cvarTable; i<cvarTableSize; i++, cv++ ) {
455 		cgi_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
456 	}
457 }
458 
459 /*
460 =================
461 CG_UpdateCvars
462 =================
463 */
CG_UpdateCvars(void)464 void CG_UpdateCvars( void ) {
465 	size_t		i;
466 	cvarTable_t	*cv;
467 
468 	for ( i=0, cv=cvarTable; i<cvarTableSize; i++, cv++ ) {
469 		if ( cv->vmCvar ) {
470 			cgi_Cvar_Update( cv->vmCvar );
471 		}
472 	}
473 }
474 
CG_CrosshairPlayer(void)475 int CG_CrosshairPlayer( void )
476 {
477 	if ( cg.time > ( cg.crosshairClientTime + 1000 ) )
478 	{
479 		return -1;
480 	}
481 	return cg.crosshairClientNum;
482 }
483 
484 
CG_GetCameraPos(vec3_t camerapos)485 int CG_GetCameraPos( vec3_t camerapos ) {
486 	if ( in_camera) {
487 		VectorCopy(client_camera.origin, camerapos);
488 		return 1;
489 	}
490 	else if ( cg_entities[0].gent && cg_entities[0].gent->client && cg_entities[0].gent->client->ps.viewEntity > 0 && cg_entities[0].gent->client->ps.viewEntity < ENTITYNUM_WORLD )
491 	//else if ( cg.snap && cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD )
492 	{//in an entity camera view
493 		if ( g_entities[cg_entities[0].gent->client->ps.viewEntity].client && cg.renderingThirdPerson )
494 		{
495 			VectorCopy( g_entities[cg_entities[0].gent->client->ps.viewEntity].client->renderInfo.eyePoint, camerapos );
496 		}
497 		else
498 		{
499 			VectorCopy( g_entities[cg_entities[0].gent->client->ps.viewEntity].currentOrigin, camerapos );
500 		}
501 		//VectorCopy( cg_entities[cg_entities[0].gent->client->ps.viewEntity].lerpOrigin, camerapos );
502 		/*
503 		if ( g_entities[cg.snap->ps.viewEntity].client && cg.renderingThirdPerson )
504 		{
505 			VectorCopy( g_entities[cg.snap->ps.viewEntity].client->renderInfo.eyePoint, camerapos );
506 		}
507 		else
508 		{//use the g_ent because it may not have gotten over to the client yet...
509 			VectorCopy( g_entities[cg.snap->ps.viewEntity].currentOrigin, camerapos );
510 		}
511 		*/
512 		return 1;
513 	}
514 	else if ( cg.renderingThirdPerson )
515 	{//in third person
516 		//FIXME: what about hacks that render in third person regardless of this value?
517 		VectorCopy( cg.refdef.vieworg, camerapos );
518 		return 1;
519 	}
520 	else if (cg.snap && (cg.snap->ps.weapon == WP_SABER||cg.snap->ps.weapon == WP_MELEE) )//implied: !cg.renderingThirdPerson
521 	{//first person saber hack
522 		VectorCopy( cg.refdef.vieworg, camerapos );
523 		return 1;
524 	}
525 	return 0;
526 }
527 
CG_Printf(const char * msg,...)528 void CG_Printf( const char *msg, ... ) {
529 	va_list		argptr;
530 	char		text[1024];
531 
532 	va_start (argptr, msg);
533 	Q_vsnprintf (text, sizeof(text), msg, argptr);
534 	va_end (argptr);
535 
536 	cgi_Printf( text );
537 }
538 
CG_Error(const char * msg,...)539 NORETURN void CG_Error( const char *msg, ... ) {
540 	va_list		argptr;
541 	char		text[1024];
542 
543 	va_start (argptr, msg);
544 	Q_vsnprintf (text, sizeof(text), msg, argptr);
545 	va_end (argptr);
546 
547 	cgi_Error( text );
548 }
549 
550 
551 /*
552 ================
553 CG_Argv
554 ================
555 */
CG_Argv(int arg)556 const char *CG_Argv( int arg ) {
557 	static char	buffer[MAX_STRING_CHARS];
558 
559 	cgi_Argv( arg, buffer, sizeof( buffer ) );
560 
561 	return buffer;
562 }
563 
564 
565 //========================================================================
566 
567 /*
568 =================
569 CG_RegisterItemSounds
570 
571 The server says this item is used on this level
572 =================
573 */
CG_RegisterItemSounds(int itemNum)574 void CG_RegisterItemSounds( int itemNum ) {
575 	gitem_t			*item;
576 	char			data[MAX_QPATH];
577 	char			*s, *start;
578 	int				len;
579 
580 	item = &bg_itemlist[ itemNum ];
581 
582 	if (item->pickup_sound)
583 	{
584 		cgi_S_RegisterSound( item->pickup_sound );
585 	}
586 
587 	// parse the space seperated precache string for other media
588 	s = item->sounds;
589 	if (!s || !s[0])
590 		return;
591 
592 	while (*s) {
593 		start = s;
594 		while (*s && *s != ' ') {
595 			s++;
596 		}
597 
598 		len = s-start;
599 		if (len >= MAX_QPATH || len < 5) {
600 			CG_Error( "PrecacheItem: %s has bad precache string",
601 				item->classname);
602 			return;
603 		}
604 		memcpy (data, start, len);
605 		data[len] = 0;
606 		if ( *s ) {
607 			s++;
608 		}
609 
610 		if ( !strcmp(data+len-3, "wav" )) {
611 			cgi_S_RegisterSound( data );
612 		}
613 	}
614 }
615 
616 /*
617 ======================
618 CG_LoadingString
619 
620 ======================
621 */
CG_LoadingString(const char * s)622 void CG_LoadingString( const char *s ) {
623 	Q_strncpyz( cg.infoScreenText, s, sizeof( cg.infoScreenText ) );
624 	cgi_UpdateScreen();
625 }
626 
627 
CG_AS_Register(void)628 static void CG_AS_Register(void)
629 {
630 	CG_LoadingString( "ambient sound sets" );
631 
632 	//Load the ambient sets
633 
634 	cgi_AS_AddPrecacheEntry( "#clear" );	// ;-)
635 	//FIXME: Don't ask... I had to get around a really nasty MS error in the templates with this...
636 	namePrecache_m::iterator	pi;
637 	STL_ITERATE( pi, (*as_preCacheMap) )
638 	{
639 		cgi_AS_AddPrecacheEntry( ((*pi).first).c_str() );
640 	}
641 
642 	cgi_AS_ParseSets();
643 }
644 
645 
646 /*
647 =================
648 CG_RegisterSounds
649 
650 called during a precache command
651 =================
652 */
CG_RegisterSounds(void)653 static void CG_RegisterSounds( void ) {
654 	int		i;
655 	char	name[MAX_QPATH];
656 	const char	*soundName;
657 
658 	CG_AS_Register();
659 
660 	CG_LoadingString( "general sounds" );
661 
662 	//FIXME: add to cg.media?
663 	cgi_S_RegisterSound( "sound/player/fallsplat.wav" );
664 
665 	cgs.media.selectSound = cgi_S_RegisterSound( "sound/weapons/change.wav" );
666 	cgs.media.selectSound2 = cgi_S_RegisterSound( "sound/interface/button1.wav" );
667 //	cgs.media.useNothingSound = cgi_S_RegisterSound( "sound/items/use_nothing.wav" );
668 
669 	cgs.media.noAmmoSound = cgi_S_RegisterSound( "sound/weapons/noammo.wav" );
670 //	cgs.media.talkSound = 	cgi_S_RegisterSound( "sound/interface/communicator.wav" );
671 	cgs.media.landSound =	cgi_S_RegisterSound( "sound/player/land1.wav");
672 	cgs.media.rollSound =	cgi_S_RegisterSound( "sound/player/roll1.wav");
673 
674 	cgs.media.overchargeFastSound	= cgi_S_RegisterSound("sound/weapons/overchargeFast.wav" );
675 	cgs.media.overchargeSlowSound	= cgi_S_RegisterSound("sound/weapons/overchargeSlow.wav" );
676 	cgs.media.overchargeLoopSound	= cgi_S_RegisterSound("sound/weapons/overchargeLoop.wav");
677 	cgs.media.overchargeEndSound	= cgi_S_RegisterSound("sound/weapons/overchargeEnd.wav");
678 
679 	cgs.media.batteryChargeSound	= cgi_S_RegisterSound( "sound/interface/pickup_battery.wav" );
680 
681 //	cgs.media.tedTextSound = cgi_S_RegisterSound( "sound/interface/tedtext.wav" );
682 	cgs.media.messageLitSound = cgi_S_RegisterSound( "sound/interface/update" );
683 	cg.messageLitActive = qfalse;
684 
685 //	cgs.media.interfaceSnd1 = cgi_S_RegisterSound( "sound/interface/button4.wav" );
686 //	cgs.media.interfaceSnd2 = cgi_S_RegisterSound( "sound/interface/button2.wav" );
687 //	cgs.media.interfaceSnd3 = cgi_S_RegisterSound( "sound/interface/button1.wav" );
688 
689 	cgs.media.watrInSound = cgi_S_RegisterSound ("sound/player/watr_in.wav");
690 	cgs.media.watrOutSound = cgi_S_RegisterSound ("sound/player/watr_out.wav");
691 	cgs.media.watrUnSound = cgi_S_RegisterSound ("sound/player/watr_un.wav");
692 
693 	// Zoom
694 	cgs.media.zoomStart = cgi_S_RegisterSound( "sound/interface/zoomstart.wav" );
695 	cgs.media.zoomLoop = cgi_S_RegisterSound( "sound/interface/zoomloop.wav" );
696 	cgs.media.zoomEnd = cgi_S_RegisterSound( "sound/interface/zoomend.wav" );
697 
698 	cgi_S_RegisterSound( "sound/chars/turret/startup.wav" );
699 	cgi_S_RegisterSound( "sound/chars/turret/shutdown.wav" );
700 	cgi_S_RegisterSound( "sound/chars/turret/ping.wav" );
701 	cgi_S_RegisterSound( "sound/chars/turret/move.wav" );
702 	cgi_S_RegisterSound( "sound/player/use_sentry" );
703 	cgi_R_RegisterModel( "models/items/psgun.glm" );
704 	theFxScheduler.RegisterEffect( "turret/explode" );
705 	theFxScheduler.RegisterEffect( "spark_exp_nosnd" );
706 
707 	for (i=0 ; i<4 ; i++) {
708 		Com_sprintf (name, sizeof(name), "sound/player/footsteps/stone_step%i.wav", i+1);
709 		cgs.media.footsteps[FOOTSTEP_NORMAL][i] = cgi_S_RegisterSound (name);
710 
711 		Com_sprintf (name, sizeof(name), "sound/player/footsteps/metal_step%i.wav", i+1);
712 		cgs.media.footsteps[FOOTSTEP_METAL][i] = cgi_S_RegisterSound (name);
713 
714 		Com_sprintf (name, sizeof(name), "sound/player/footsteps/water_run%i.wav", i+1);
715 		cgs.media.footsteps[FOOTSTEP_SPLASH][i] = cgi_S_RegisterSound (name);
716 
717 		Com_sprintf (name, sizeof(name), "sound/player/footsteps/water_walk%i.wav", i+1);
718 		cgs.media.footsteps[FOOTSTEP_WADE][i] = cgi_S_RegisterSound (name);
719 
720 		Com_sprintf (name, sizeof(name), "sound/player/footsteps/water_wade_0%i.wav", i+1);
721 		cgs.media.footsteps[FOOTSTEP_SWIM][i] = cgi_S_RegisterSound (name);
722 
723 		// should these always be registered??
724 		Com_sprintf (name, sizeof(name), "sound/player/footsteps/boot%i.wav", i+1);
725 		cgi_S_RegisterSound (name);
726 	}
727 	theFxScheduler.RegisterEffect( "water_impact" );
728 
729 	cg.loadLCARSStage = 1;
730 	CG_LoadingString( "item sounds" );
731 
732 	// only register the items that the server says we need
733 	char	items[MAX_ITEMS+1];
734 	//Raz: Fixed buffer overflow
735 	Q_strncpyz(items, CG_ConfigString(CS_ITEMS), sizeof(items));
736 
737 	for ( i = 1 ; i < bg_numItems ; i++ ) {
738 		if ( items[ i ] == '1' )	//even with sound pooling, don't clutter it for low end machines
739 		{
740 			CG_RegisterItemSounds( i );
741 		}
742 	}
743 
744 	cg.loadLCARSStage = 2;
745 	CG_LoadingString( "preregistered sounds" );
746 
747 	for ( i = 1 ; i < MAX_SOUNDS ; i++ ) {
748 		soundName = CG_ConfigString( CS_SOUNDS+i );
749 		if ( !soundName[0] ) {
750 			break;
751 		}
752 		if ( soundName[0] == '*' ) {
753 			continue;	// custom sound
754 		}
755 		if (i&31) {
756 			CG_LoadingString( soundName );
757 		}
758 		cgs.sound_precache[i] = cgi_S_RegisterSound( soundName );
759 	}
760 }
761 
762 /*
763 =============================================================================
764 
765 CLIENT INFO
766 
767 =============================================================================
768 */
769 
CG_RegisterHeadSkin(const char * headModelName,const char * headSkinName,qboolean * extensions)770 qhandle_t CG_RegisterHeadSkin( const char *headModelName, const char *headSkinName, qboolean *extensions )
771 {
772 	char		hfilename[MAX_QPATH];
773 	qhandle_t	headSkin;
774 
775 	Com_sprintf( hfilename, sizeof( hfilename ), "models/players/%s/head_%s.skin", headModelName, headSkinName );
776 	headSkin = cgi_R_RegisterSkin( hfilename );
777 	if ( headSkin < 0 )
778 	{	//have extensions
779 		*extensions = qtrue;
780 		headSkin = -headSkin;
781 	}
782 	else
783 	{
784 		*extensions = qfalse;	//just to be sure.
785 	}
786 
787 	if ( !headSkin )
788 	{
789 		Com_Printf( "Failed to load skin file: %s : %s\n", headModelName, headSkinName );
790 	}
791 	return headSkin;
792 }
793 
794 /*
795 ==========================
796 CG_RegisterClientSkin
797 ==========================
798 */
CG_RegisterClientSkin(clientInfo_t * ci,const char * headModelName,const char * headSkinName,const char * torsoModelName,const char * torsoSkinName,const char * legsModelName,const char * legsSkinName)799 qboolean	CG_RegisterClientSkin( clientInfo_t *ci,
800 								  const char *headModelName, const char *headSkinName,
801 								  const char *torsoModelName, const char *torsoSkinName,
802 								  const char *legsModelName, const char *legsSkinName)
803 {
804 	char		hfilename[MAX_QPATH];
805 	char		tfilename[MAX_QPATH];
806 	char		lfilename[MAX_QPATH];
807 
808 	Com_sprintf( lfilename, sizeof( lfilename ), "models/players/%s/lower_%s.skin", legsModelName, legsSkinName );
809 	ci->legsSkin = cgi_R_RegisterSkin( lfilename );
810 
811 	if ( !ci->legsSkin )
812 	{
813 //		Com_Printf( "Failed to load skin file: %s : %s\n", legsModelName, legsSkinName );
814 		//return qfalse;
815 	}
816 
817 	if(torsoModelName && torsoSkinName && torsoModelName[0] && torsoSkinName[0])
818 	{
819 		Com_sprintf( tfilename, sizeof( tfilename ), "models/players/%s/upper_%s.skin", torsoModelName, torsoSkinName );
820 		ci->torsoSkin = cgi_R_RegisterSkin( tfilename );
821 
822 		if ( !ci->torsoSkin )
823 		{
824 			Com_Printf( "Failed to load skin file: %s : %s\n", torsoModelName, torsoSkinName );
825 			return qfalse;
826 		}
827 	}
828 
829 	if(headModelName && headSkinName && headModelName[0] && headSkinName[0])
830 	{
831 		Com_sprintf( hfilename, sizeof( hfilename ), "models/players/%s/head_%s.skin", headModelName, headSkinName );
832 		ci->headSkin = cgi_R_RegisterSkin( hfilename );
833 		if (ci->headSkin <0) {	//have extensions
834 			ci->extensions = qtrue;
835 			ci->headSkin = -ci->headSkin;
836 		} else {
837 			ci->extensions = qfalse;	//just to be sure.
838 		}
839 
840 		if ( !ci->headSkin )
841 		{
842 			Com_Printf( "Failed to load skin file: %s : %s\n", headModelName, headSkinName );
843 			return qfalse;
844 		}
845 	}
846 
847 	return qtrue;
848 }
849 
850 /*
851 ==========================
852 CG_RegisterClientModelname
853 ==========================
854 */
CG_RegisterClientModelname(clientInfo_t * ci,const char * headModelName,const char * headSkinName,const char * torsoModelName,const char * torsoSkinName,const char * legsModelName,const char * legsSkinName)855 qboolean CG_RegisterClientModelname( clientInfo_t *ci,
856 									const char *headModelName, const char *headSkinName,
857 									const char *torsoModelName, const char *torsoSkinName,
858 									const char *legsModelName, const char *legsSkinName )
859 {
860 /*
861 Ghoul2 Insert Start
862 */
863 #if 1
864 	char		filename[MAX_QPATH];
865 
866 
867 	if ( !legsModelName || !legsModelName[0] )
868 	{
869 		return qtrue;
870 	}
871 	Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.mdr", legsModelName );
872 	ci->legsModel = cgi_R_RegisterModel( filename );
873 	if ( !ci->legsModel )
874 	{//he's not skeletal, try the old way
875 		Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", legsModelName );
876 		ci->legsModel = cgi_R_RegisterModel( filename );
877 		if ( !ci->legsModel )
878 		{
879 			Com_Printf( S_COLOR_RED"Failed to load model file %s\n", filename );
880 			return qfalse;
881 		}
882 	}
883 
884 	if(torsoModelName && torsoModelName[0])
885 	{//You are trying to set one
886 		Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.mdr", torsoModelName );
887 		ci->torsoModel = cgi_R_RegisterModel( filename );
888 		if ( !ci->torsoModel )
889 		{//he's not skeletal, try the old way
890 			Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", torsoModelName );
891 			ci->torsoModel = cgi_R_RegisterModel( filename );
892 			if ( !ci->torsoModel )
893 			{
894 				Com_Printf( S_COLOR_RED"Failed to load model file %s\n", filename );
895 				return qfalse;
896 			}
897 		}
898 	}
899 	else
900 	{
901 		ci->torsoModel = 0;
902 	}
903 
904 	if(headModelName && headModelName[0])
905 	{//You are trying to set one
906 		Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headModelName );
907 		ci->headModel = cgi_R_RegisterModel( filename );
908 		if ( !ci->headModel )
909 		{
910 			Com_Printf( S_COLOR_RED"Failed to load model file %s\n", filename );
911 			return qfalse;
912 		}
913 	}
914 	else
915 	{
916 		ci->headModel = 0;
917 	}
918 
919 
920 	// if any skins failed to load, return failure
921 	if ( !CG_RegisterClientSkin( ci, headModelName, headSkinName, torsoModelName, torsoSkinName, legsModelName, legsSkinName ) )
922 	{
923 		//Com_Printf( "Failed to load skin file: %s : %s/%s : %s/%s : %s\n", headModelName, headSkinName, torsoModelName, torsoSkinName, legsModelName, legsSkinName );
924 		return qfalse;
925 	}
926 
927 	//FIXME: for now, uses the legs model dir for anim cfg, but should we set this in some sort of NPCs.cfg?
928 	// load the animation file set
929 	if ( !G_ParseAnimFileSet( legsModelName, legsModelName, &ci->animFileIndex ) )
930 	{
931 		Com_Printf( S_COLOR_RED"Failed to load animation file set models/players/%s\n", legsModelName );
932 		return qfalse;
933 	}
934 #endif
935 /*
936 Ghoul2 Insert End
937 */
938 	return qtrue;
939 }
940 
941 
CG_RegisterClientRenderInfo(clientInfo_t * ci,renderInfo_t * ri)942 void CG_RegisterClientRenderInfo(clientInfo_t *ci, renderInfo_t *ri)
943 {
944 	char			*slash;
945 	char			headModelName[MAX_QPATH];
946 	char			torsoModelName[MAX_QPATH];
947 	char			legsModelName[MAX_QPATH];
948 	char			headSkinName[MAX_QPATH];
949 	char			torsoSkinName[MAX_QPATH];
950 	char			legsSkinName[MAX_QPATH];
951 
952 	if(!ri->legsModelName[0])
953 	{//Must have at LEAST a legs model
954 		return;
955 	}
956 
957 	Q_strncpyz( legsModelName, ri->legsModelName, sizeof( legsModelName ) );
958 	//Legs skin
959 	slash = strchr( legsModelName, '/' );
960 	if ( !slash )
961 	{
962 		// modelName didn not include a skin name
963 		Q_strncpyz( legsSkinName, "default", sizeof( legsSkinName ) );
964 	}
965 	else
966 	{
967 		Q_strncpyz( legsSkinName, slash + 1, sizeof( legsSkinName ) );
968 		// truncate modelName
969 		*slash = 0;
970 	}
971 
972 	if(ri->torsoModelName[0])
973 	{
974 		Q_strncpyz( torsoModelName, ri->torsoModelName, sizeof( torsoModelName ) );
975 		//Torso skin
976 		slash = strchr( torsoModelName, '/' );
977 		if ( !slash )
978 		{
979 			// modelName didn't include a skin name
980 			Q_strncpyz( torsoSkinName, "default", sizeof( torsoSkinName ) );
981 		}
982 		else
983 		{
984 			Q_strncpyz( torsoSkinName, slash + 1, sizeof( torsoSkinName ) );
985 			// truncate modelName
986 			*slash = 0;
987 		}
988 	}
989 	else
990 	{
991 		torsoModelName[0] = 0;
992 	}
993 
994 	//Head
995 	if(ri->headModelName[0])
996 	{
997 		Q_strncpyz( headModelName, ri->headModelName, sizeof( headModelName ) );
998 		//Head skin
999 		slash = strchr( headModelName, '/' );
1000 		if ( !slash )
1001 		{
1002 			// modelName didn not include a skin name
1003 			Q_strncpyz( headSkinName, "default", sizeof( headSkinName ) );
1004 		}
1005 		else
1006 		{
1007 			Q_strncpyz( headSkinName, slash + 1, sizeof( headSkinName ) );
1008 			// truncate modelName
1009 			*slash = 0;
1010 		}
1011 	}
1012 	else
1013 	{
1014 		headModelName[0] = 0;
1015 	}
1016 
1017 	if ( !CG_RegisterClientModelname( ci, headModelName, headSkinName, torsoModelName, torsoSkinName, legsModelName, legsSkinName) )
1018 	{
1019 		if ( !CG_RegisterClientModelname( ci, DEFAULT_HEADMODEL, "default", DEFAULT_TORSOMODEL, "default", DEFAULT_LEGSMODEL, "default" ) )
1020 		{
1021 			CG_Error( "DEFAULT_MODELS failed to register");
1022 		}
1023 	}
1024 }
1025 
1026 //-------------------------------------
1027 // CG_RegisterEffects
1028 //
1029 // Handles precaching all effect files
1030 //	and any shader, model, or sound
1031 //	files an effect may use.
1032 //-------------------------------------
1033 extern void CG_InitGlass( void );
1034 extern void	cgi_R_WorldEffectCommand( const char *command );
1035 
CG_RegisterEffects(void)1036 static void CG_RegisterEffects( void )
1037 {
1038 	char	*effectName;
1039 	int		i;
1040 
1041 	// Register external effects
1042 	for ( i = 1 ; i < MAX_FX ; i++ )
1043 	{
1044 		effectName = ( char *)CG_ConfigString( CS_EFFECTS + i );
1045 
1046 		if ( !effectName[0] )
1047 		{
1048 			break;
1049 		}
1050 
1051 		theFxScheduler.RegisterEffect( (const char*)effectName );
1052 	}
1053 
1054 	// Start world effects
1055 	for ( i = 1 ; i < MAX_WORLD_FX ; i++ )
1056 	{
1057 		effectName = ( char *)CG_ConfigString( CS_WORLD_FX + i );
1058 
1059 		if ( !effectName[0] )
1060 		{
1061 			break;
1062 		}
1063 
1064 		cgi_R_WorldEffectCommand( effectName );
1065 	}
1066 
1067 	// Set up the glass effects mini-system.
1068 	CG_InitGlass();
1069 }
1070 
1071 /*
1072 void CG_RegisterClientModels (int entityNum)
1073 
1074 Only call if clientInfo->infoValid is not true
1075 
1076 For players and NPCs to register their models
1077 */
CG_RegisterClientModels(int entityNum)1078 void CG_RegisterClientModels (int entityNum)
1079 {
1080 	gentity_t		*ent;
1081 
1082 	if(entityNum < 0 || entityNum > ENTITYNUM_WORLD)
1083 	{
1084 		return;
1085 	}
1086 
1087 	ent = &g_entities[entityNum];
1088 
1089 	if(!ent->client)
1090 	{
1091 		return;
1092 	}
1093 
1094 	ent->client->clientInfo.infoValid = qtrue;
1095 
1096 	if ( ent->playerModel != -1 && ent->ghoul2.size() )
1097 	{
1098 		return;
1099 	}
1100 
1101 	CG_RegisterClientRenderInfo(&ent->client->clientInfo, &ent->client->renderInfo);
1102 
1103 	ent->client->clientInfo.infoValid = qtrue;
1104 
1105 	if(entityNum < MAX_CLIENTS)
1106 	{
1107 		memcpy(&cgs.clientinfo[entityNum], &ent->client->clientInfo, sizeof(clientInfo_t));
1108 	}
1109 }
1110 
1111 //===================================================================================
1112 
1113 forceTicPos_t forceTicPos[] =
1114 {
1115 	{ 11, 41, 20, 10, "gfx/hud/force_tick1", NULL_HANDLE },		// Left Top
1116 	{ 12, 45, 20, 10, "gfx/hud/force_tick2", NULL_HANDLE },
1117 	{ 14, 49, 20, 10, "gfx/hud/force_tick3", NULL_HANDLE },
1118 	{ 17, 52, 20, 10, "gfx/hud/force_tick4", NULL_HANDLE },
1119 	{ 22, 55, 10, 10, "gfx/hud/force_tick5", NULL_HANDLE },
1120 	{ 28, 57, 10, 20, "gfx/hud/force_tick6", NULL_HANDLE },
1121 	{ 34, 59, 10, 10, "gfx/hud/force_tick7", NULL_HANDLE },		// Left bottom
1122 
1123 	{ 46, 59, -10, 10, "gfx/hud/force_tick7", NULL_HANDLE },		// Right bottom
1124 	{ 52, 57, -10, 20, "gfx/hud/force_tick6", NULL_HANDLE },
1125 	{ 58, 55, -10, 10, "gfx/hud/force_tick5", NULL_HANDLE },
1126 	{ 63, 52, -20, 10, "gfx/hud/force_tick4", NULL_HANDLE },
1127 	{ 66, 49, -20, 10, "gfx/hud/force_tick3", NULL_HANDLE },
1128 	{ 68, 45, -20, 10, "gfx/hud/force_tick2", NULL_HANDLE },
1129 	{ 69, 41, -20, 10, "gfx/hud/force_tick1", NULL_HANDLE },		// Right top
1130 };
1131 
1132 forceTicPos_t ammoTicPos[] =
1133 {
1134 	{ 12, 34, 10, 10, "gfx/hud/ammo_tick7-l", NULL_HANDLE }, 	// Bottom
1135 	{ 13, 28, 10, 10, "gfx/hud/ammo_tick6-l", NULL_HANDLE },
1136 	{ 15, 23, 10, 10, "gfx/hud/ammo_tick5-l", NULL_HANDLE },
1137 	{ 19, 19, 10, 10, "gfx/hud/ammo_tick4-l", NULL_HANDLE },
1138 	{ 23, 15, 10, 10, "gfx/hud/ammo_tick3-l", NULL_HANDLE },
1139 	{ 29, 12, 10, 10, "gfx/hud/ammo_tick2-l", NULL_HANDLE },
1140 	{ 34, 11, 10, 10, "gfx/hud/ammo_tick1-l", NULL_HANDLE },
1141 
1142 	{ 47, 11, -10, 10, "gfx/hud/ammo_tick1-r", NULL_HANDLE },
1143 	{ 52, 12, -10, 10, "gfx/hud/ammo_tick2-r", NULL_HANDLE },
1144 	{ 58, 15, -10, 10, "gfx/hud/ammo_tick3-r", NULL_HANDLE },
1145 	{ 62, 19, -10, 10, "gfx/hud/ammo_tick4-r", NULL_HANDLE },
1146 	{ 66, 23, -10, 10, "gfx/hud/ammo_tick5-r", NULL_HANDLE },
1147 	{ 68, 28, -10, 10, "gfx/hud/ammo_tick6-r", NULL_HANDLE },
1148 	{ 69, 34, -10, 10, "gfx/hud/ammo_tick7-r", NULL_HANDLE },
1149 };
1150 
1151 
1152 extern void NPC_Precache ( gentity_t *spawner );
1153 qboolean NPCsPrecached = qfalse;
1154 /*
1155 =================
1156 CG_PrepRefresh
1157 
1158 Call before entering a new level, or after changing renderers
1159 This function may execute for a couple of minutes with a slow disk.
1160 =================
1161 */
CG_RegisterGraphics(void)1162 static void CG_RegisterGraphics( void ) {
1163 	int			i;
1164 	char		items[MAX_ITEMS+1];
1165 	static char		*sb_nums[11] = {
1166 		"gfx/2d/numbers/zero",
1167 		"gfx/2d/numbers/one",
1168 		"gfx/2d/numbers/two",
1169 		"gfx/2d/numbers/three",
1170 		"gfx/2d/numbers/four",
1171 		"gfx/2d/numbers/five",
1172 		"gfx/2d/numbers/six",
1173 		"gfx/2d/numbers/seven",
1174 		"gfx/2d/numbers/eight",
1175 		"gfx/2d/numbers/nine",
1176 		"gfx/2d/numbers/minus",
1177 	};
1178 
1179 	static char		*sb_t_nums[11] = {
1180 		"gfx/2d/numbers/t_zero",
1181 		"gfx/2d/numbers/t_one",
1182 		"gfx/2d/numbers/t_two",
1183 		"gfx/2d/numbers/t_three",
1184 		"gfx/2d/numbers/t_four",
1185 		"gfx/2d/numbers/t_five",
1186 		"gfx/2d/numbers/t_six",
1187 		"gfx/2d/numbers/t_seven",
1188 		"gfx/2d/numbers/t_eight",
1189 		"gfx/2d/numbers/t_nine",
1190 		"gfx/2d/numbers/t_minus",
1191 	};
1192 
1193 	static char		*sb_c_nums[11] = {
1194 		"gfx/2d/numbers/c_zero",
1195 		"gfx/2d/numbers/c_one",
1196 		"gfx/2d/numbers/c_two",
1197 		"gfx/2d/numbers/c_three",
1198 		"gfx/2d/numbers/c_four",
1199 		"gfx/2d/numbers/c_five",
1200 		"gfx/2d/numbers/c_six",
1201 		"gfx/2d/numbers/c_seven",
1202 		"gfx/2d/numbers/c_eight",
1203 		"gfx/2d/numbers/c_nine",
1204 		"gfx/2d/numbers/t_minus", //?????
1205 	};
1206 
1207 	// Clean, then register...rinse...repeat...
1208 	CG_LoadingString( "effects" );
1209 	FX_Init();
1210 	CG_RegisterEffects();
1211 
1212 	// clear any references to old media
1213 	memset( &cg.refdef, 0, sizeof( cg.refdef ) );
1214 	cgi_R_ClearScene();
1215 
1216 	cg.loadLCARSStage = 3;
1217 	CG_LoadingString( cgs.mapname );
1218 
1219 	cgi_R_LoadWorldMap( cgs.mapname );
1220 
1221 	cg.loadLCARSStage = 4;
1222 	CG_LoadingString( "game media shaders" );
1223 
1224 	for ( i=0; i < 11; i++ )
1225 	{
1226 		cgs.media.numberShaders[i]			= cgi_R_RegisterShaderNoMip( sb_nums[i] );
1227 		cgs.media.smallnumberShaders[i]		= cgi_R_RegisterShaderNoMip( sb_t_nums[i] );
1228 		cgs.media.chunkyNumberShaders[i]	= cgi_R_RegisterShaderNoMip( sb_c_nums[i] );
1229 	}
1230 
1231 	// FIXME: conditionally do this??  Something must be wrong with inventory item caching..?
1232 	cgi_R_RegisterModel( "models/items/remote.md3" );
1233 
1234 	cgs.media.explosionModel				= cgi_R_RegisterModel ( "models/weaphits/explosion.md3" );
1235 	cgs.media.surfaceExplosionShader		= cgi_R_RegisterShader( "surfaceExplosion" );
1236 
1237 	cgs.media.solidWhiteShader			= cgi_R_RegisterShader( "gfx/effects/solidWhite" );
1238 
1239 	//on players
1240 	cgs.media.personalShieldShader		= cgi_R_RegisterShader( "gfx/misc/personalshield" );
1241 	cgs.media.cloakedShader				= cgi_R_RegisterShader( "gfx/effects/cloakedShader" );
1242 											cgi_R_RegisterShader( "gfx/misc/ion_shield" );
1243 
1244 	cgs.media.boltShader			= cgi_R_RegisterShader( "gfx/misc/blueLine" );
1245 
1246 	// FIXME: do these conditionally
1247 	cgi_R_RegisterShader( "gfx/2d/workingCamera" );
1248 	cgi_R_RegisterShader( "gfx/2d/brokenCamera" );
1249 	cgi_R_RegisterShader( "gfx/effects/irid_shield" ); // for galak, but he doesn't have his own weapon so I can't register the shader there.
1250 
1251 	//interface
1252 	for ( i = 0 ; i < NUM_CROSSHAIRS ; i++ ) {
1253 		cgs.media.crosshairShader[i] = cgi_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a'+i) );
1254 	}
1255 	cgs.media.backTileShader		= cgi_R_RegisterShader( "gfx/2d/backtile" );
1256 	cgs.media.noammoShader			= cgi_R_RegisterShaderNoMip( "gfx/hud/noammo");
1257 	cgs.media.weaponIconBackground	= cgi_R_RegisterShaderNoMip( "gfx/hud/background");
1258 	cgs.media.weaponProngsOn		= cgi_R_RegisterShaderNoMip( "gfx/hud/prong_on_w");
1259 	cgs.media.weaponProngsOff		= cgi_R_RegisterShaderNoMip( "gfx/hud/prong_off");
1260 	cgs.media.forceProngsOn			= cgi_R_RegisterShaderNoMip( "gfx/hud/prong_on_f");
1261 	cgs.media.forceIconBackground	= cgi_R_RegisterShaderNoMip( "gfx/hud/background_f");
1262 	cgs.media.inventoryIconBackground= cgi_R_RegisterShaderNoMip( "gfx/hud/background_i");
1263 	cgs.media.inventoryProngsOn		= cgi_R_RegisterShaderNoMip( "gfx/hud/prong_on_i");
1264 	cgs.media.dataPadFrame			= cgi_R_RegisterShaderNoMip( "gfx/hud/datapad2");
1265 
1266 	cg.loadLCARSStage = 5;
1267 	CG_LoadingString( "game media models" );
1268 
1269 	// Chunk models
1270 	//FIXME: jfm:? bother to conditionally load these if an ent has this material type?
1271 	for ( i = 0; i < NUM_CHUNK_MODELS; i++ )
1272 	{
1273 		cgs.media.chunkModels[CHUNK_METAL2][i]	= cgi_R_RegisterModel( va( "models/chunks/metal/metal1_%i.md3", i+1 ) ); //_ /switched\ _
1274 		cgs.media.chunkModels[CHUNK_METAL1][i]	= cgi_R_RegisterModel( va( "models/chunks/metal/metal2_%i.md3", i+1 ) ); //  \switched/
1275 		cgs.media.chunkModels[CHUNK_ROCK1][i]	= cgi_R_RegisterModel( va( "models/chunks/rock/rock1_%i.md3", i+1 ) );
1276 		cgs.media.chunkModels[CHUNK_ROCK2][i]	= cgi_R_RegisterModel( va( "models/chunks/rock/rock2_%i.md3", i+1 ) );
1277 		cgs.media.chunkModels[CHUNK_ROCK3][i]	= cgi_R_RegisterModel( va( "models/chunks/rock/rock3_%i.md3", i+1 ) );
1278 		cgs.media.chunkModels[CHUNK_CRATE1][i]	= cgi_R_RegisterModel( va( "models/chunks/crate/crate1_%i.md3", i+1 ) );
1279 		cgs.media.chunkModels[CHUNK_CRATE2][i]	= cgi_R_RegisterModel( va( "models/chunks/crate/crate2_%i.md3", i+1 ) );
1280 		cgs.media.chunkModels[CHUNK_WHITE_METAL][i]	= cgi_R_RegisterModel( va( "models/chunks/metal/wmetal1_%i.md3", i+1 ) );
1281 	}
1282 
1283 	cgs.media.chunkSound			= cgi_S_RegisterSound("sound/weapons/explosions/glasslcar");
1284 	cgs.media.grateSound			= cgi_S_RegisterSound( "sound/effects/grate_destroy" );
1285 	cgs.media.rockBreakSound		= cgi_S_RegisterSound("sound/effects/wall_smash");
1286 	cgs.media.rockBounceSound[0]	= cgi_S_RegisterSound("sound/effects/stone_bounce");
1287 	cgs.media.rockBounceSound[1]	= cgi_S_RegisterSound("sound/effects/stone_bounce2");
1288 	cgs.media.metalBounceSound[0]	= cgi_S_RegisterSound("sound/effects/metal_bounce");
1289 	cgs.media.metalBounceSound[1]	= cgi_S_RegisterSound("sound/effects/metal_bounce2");
1290 	cgs.media.glassChunkSound		= cgi_S_RegisterSound("sound/weapons/explosions/glassbreak1");
1291 	cgs.media.crateBreakSound[0]	= cgi_S_RegisterSound("sound/weapons/explosions/crateBust1" );
1292 	cgs.media.crateBreakSound[1]	= cgi_S_RegisterSound("sound/weapons/explosions/crateBust2" );
1293 
1294 	cgs.media.weaponbox	 = cgi_R_RegisterShaderNoMip( "gfx/interface/weapon_box");
1295 
1296 	//Models & Shaders
1297 	cgs.media.damageBlendBlobShader	= cgi_R_RegisterShader( "gfx/misc/borgeyeflare" );
1298 
1299 	cg.loadLCARSStage = 6;
1300 
1301 //	cgs.media.HUDLeftFrame= cgi_R_RegisterShaderNoMip( "gfx/hud/hudleftframe" );
1302 	cgs.media.HUDLeftFrame= cgi_R_RegisterShaderNoMip( "gfx/hud/static_test" );
1303 	cgs.media.HUDInnerLeft = cgi_R_RegisterShaderNoMip( "gfx/hud/hudleft_innerframe" );
1304 	cgs.media.HUDArmor1= cgi_R_RegisterShaderNoMip( "gfx/hud/armor1" );
1305 	cgs.media.HUDArmor2= cgi_R_RegisterShaderNoMip( "gfx/hud/armor2" );
1306 	cgs.media.HUDHealth= cgi_R_RegisterShaderNoMip( "gfx/hud/health" );
1307 	cgs.media.HUDHealthTic= cgi_R_RegisterShaderNoMip( "gfx/hud/health_tic" );
1308 //	cgs.media.HUDArmorTic= cgi_R_RegisterShaderNoMip( "gfx/hud/armor_tic" );
1309 
1310 	cgs.media.HUDRightFrame= cgi_R_RegisterShaderNoMip( "gfx/hud/hudrightframe" );
1311 	cgs.media.HUDInnerRight = cgi_R_RegisterShaderNoMip( "gfx/hud/hudright_innerframe" );
1312 
1313 	cgs.media.messageLitOn = cgi_R_RegisterShaderNoMip( "gfx/hud/message_on" );
1314 	cgs.media.messageLitOff = cgi_R_RegisterShaderNoMip( "gfx/hud/message_off" );
1315 	cgs.media.messageObjCircle = cgi_R_RegisterShaderNoMip( "gfx/hud/objective_circle" );
1316 
1317 	cgs.media.DPForcePowerOverlay = cgi_R_RegisterShader( "gfx/hud/force_swirl" );
1318 
1319 	// battery charge shader when using a gonk
1320 	cgs.media.batteryChargeShader = cgi_R_RegisterShader( "gfx/2d/battery" );
1321 	cgi_R_RegisterShader( "gfx/2d/droid_view" );
1322 
1323 	// Load force tics
1324 	for (i=0;i<MAX_TICS;i++)
1325 	{
1326 		forceTicPos[i].tic = cgi_R_RegisterShaderNoMip( forceTicPos[i].file );
1327 		ammoTicPos[i].tic = cgi_R_RegisterShaderNoMip( ammoTicPos[i].file );
1328 	}
1329 
1330 	memset( cg_items, 0, sizeof( cg_items ) );
1331 	memset( cg_weapons, 0, sizeof( cg_weapons ) );
1332 
1333 	// only register the items that the server says we need
1334 	Q_strncpyz( items, CG_ConfigString( CS_ITEMS ), sizeof(items) );
1335 
1336 	for ( i = 1 ; i < bg_numItems ; i++ ) {
1337 		if ( items[ i ] == '1' )
1338 		{
1339 			if (bg_itemlist[i].classname)
1340 			{
1341 				CG_LoadingString( bg_itemlist[i].classname );
1342 				CG_RegisterItemVisuals( i );
1343 			}
1344 		}
1345 		if (bg_itemlist[i].giType == IT_HOLDABLE)
1346 		{
1347 			if (bg_itemlist[i].giTag < INV_MAX)
1348 			{
1349 				inv_icons[bg_itemlist[i].giTag] = cgi_R_RegisterShaderNoMip( bg_itemlist[i].icon );
1350 			}
1351 		}
1352 	}
1353 
1354 	cgi_R_RegisterShader( "gfx/misc/test_crackle" );
1355 
1356 	// wall marks
1357 	cgs.media.phaserMarkShader				= cgi_R_RegisterShader( "gfx/damage/burnmark3" );
1358 	cgs.media.scavMarkShader				= cgi_R_RegisterShader( "gfx/damage/burnmark4" );
1359 //	cgs.media.bulletmarksShader				= cgi_R_RegisterShader( "textures/decals/bulletmark4" );
1360 	cgs.media.rivetMarkShader				= cgi_R_RegisterShader( "gfx/damage/rivetmark" );
1361 
1362 	// doing one shader just makes it look like a shell.  By using two shaders with different bulge offsets and different texture scales, it has a much more chaotic look
1363 	cgs.media.electricBodyShader			= cgi_R_RegisterShader( "gfx/misc/electric" );
1364 	cgs.media.electricBody2Shader			= cgi_R_RegisterShader( "gfx/misc/fullbodyelectric2" );
1365 
1366 	cgs.media.shadowMarkShader	= cgi_R_RegisterShader( "markShadow" );
1367 	cgs.media.wakeMarkShader	= cgi_R_RegisterShader( "wake" );
1368 	cgi_S_RegisterSound( "sound/effects/energy_crackle.wav" );
1369 
1370 
1371 	CG_LoadingString("map brushes");
1372 	// register the inline models
1373 	cgs.numInlineModels = cgi_CM_NumInlineModels();
1374 	assert( cgs.numInlineModels < (int)ARRAY_LEN( cgs.inlineDrawModel ) );
1375 	for ( i = 1 ; i < cgs.numInlineModels ; i++ ) {
1376 		char	name[10];
1377 		vec3_t			mins, maxs;
1378 		int				j;
1379 
1380 		Com_sprintf( name, sizeof(name), "*%i", i );
1381 		cgs.inlineDrawModel[i] = cgi_R_RegisterModel( name );
1382 		cgi_R_ModelBounds( cgs.inlineDrawModel[i], mins, maxs );
1383 		for ( j = 0 ; j < 3 ; j++ ) {
1384 			cgs.inlineModelMidpoints[i][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] );
1385 		}
1386 	}
1387 
1388 	cg.loadLCARSStage = 7;
1389 	CG_LoadingString("map models");
1390 	// register all the server specified models
1391 	for (i=1 ; i<MAX_MODELS ; i++) {
1392 		const char		*modelName;
1393 
1394 		modelName = CG_ConfigString( CS_MODELS+i );
1395 		if ( !modelName[0] ) {
1396 			break;
1397 		}
1398 		cgs.model_draw[i] = cgi_R_RegisterModel( modelName );
1399 //		OutputDebugString(va("### CG_RegisterGraphics(): cgs.model_draw[%d] = \"%s\"\n",i,modelName));
1400 	}
1401 
1402 	cg.loadLCARSStage = 8;
1403 
1404 /*
1405 Ghoul2 Insert Start
1406 */
1407 	CG_LoadingString("skins");
1408 	// register all the server specified models
1409 	for (i=1 ; i<MAX_CHARSKINS ; i++) {
1410 		const char		*modelName;
1411 
1412 		modelName = CG_ConfigString( CS_CHARSKINS+i );
1413 		if ( !modelName[0] ) {
1414 			break;
1415 		}
1416 		cgs.skins[i] = cgi_R_RegisterSkin( modelName );
1417 	}
1418 
1419 /*
1420 Ghoul2 Insert End
1421 */
1422 
1423 	for (i=0 ; i<MAX_CLIENTS ; i++)
1424 	{
1425 		const char		*clientInfo;
1426 
1427 		clientInfo = CG_ConfigString( CS_PLAYERS+i );
1428 		if ( !clientInfo[0] )
1429 		{
1430 			continue;
1431 		}
1432 
1433 		//feedback( va("client %i", i ) );
1434 		CG_NewClientinfo( i );
1435 	}
1436 
1437 	for (i=0 ; i < ENTITYNUM_WORLD ; i++)
1438 	{
1439 		if(&g_entities[i])
1440 		{
1441 			if(g_entities[i].client)
1442 			{
1443 				//if(!g_entities[i].client->clientInfo.infoValid)
1444 				//We presume this
1445 				{
1446 					CG_LoadingString( va("client %s", g_entities[i].client->clientInfo.name ) );
1447 					CG_RegisterClientModels(i);
1448 					if ( i != 0 )
1449 					{//Client weapons already precached
1450 						CG_RegisterWeapon( g_entities[i].client->ps.weapon );
1451 						CG_RegisterNPCCustomSounds( &g_entities[i].client->clientInfo );
1452 						CG_RegisterNPCEffects( g_entities[i].client->playerTeam );
1453 					}
1454 				}
1455 			}
1456 			else if ( g_entities[i].svFlags & SVF_NPC_PRECACHE && g_entities[i].NPC_type && g_entities[i].NPC_type[0] )
1457 			{//Precache the NPC_type
1458 				//FIXME: make sure we didn't precache this NPC_type already
1459 				CG_LoadingString( va("NPC %s", g_entities[i].NPC_type ) );
1460 				NPC_Precache( &g_entities[i] );
1461 			}
1462 		}
1463 	}
1464 
1465 
1466 	cg.loadLCARSStage = 9;
1467 
1468 	NPCsPrecached = qtrue;
1469 
1470 	extern	cvar_t	*com_buildScript;
1471 
1472 	if (com_buildScript->integer) {
1473 		cgi_R_RegisterShader( "gfx/misc/nav_cpoint" );
1474 		cgi_R_RegisterShader( "gfx/misc/nav_line" );
1475 		cgi_R_RegisterShader( "gfx/misc/nav_arrow" );
1476 		cgi_R_RegisterShader( "gfx/misc/nav_node" );
1477 	}
1478 }
1479 
1480 //===========================================================================
1481 
1482 /*
1483 =================
1484 CG_ConfigString
1485 =================
1486 */
CG_ConfigString(int index)1487 const char *CG_ConfigString( int index ) {
1488 	if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
1489 		CG_Error( "CG_ConfigString: bad index: %i", index );
1490 	}
1491 	return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ];
1492 }
1493 
1494 //==================================================================
1495 
CG_LinkCentsToGents(void)1496 void CG_LinkCentsToGents(void)
1497 {
1498 	int	i;
1499 
1500 	for(i = 0; i < MAX_GENTITIES; i++)
1501 	{
1502 		cg_entities[i].gent = &g_entities[i];
1503 	}
1504 }
1505 
1506 /*
1507 ======================
1508 CG_StartMusic
1509 
1510 ======================
1511 */
CG_StartMusic(qboolean bForceStart)1512 void CG_StartMusic( qboolean bForceStart ) {
1513 	const char	*s;
1514 	char	parm1[MAX_QPATH], parm2[MAX_QPATH];
1515 
1516 	// start the background music
1517 	s = (char *)CG_ConfigString( CS_MUSIC );
1518 	COM_BeginParseSession();
1519 	Q_strncpyz( parm1, COM_Parse( &s ), sizeof( parm1 ) );
1520 	Q_strncpyz( parm2, COM_Parse( &s ), sizeof( parm2 ) );
1521 	COM_EndParseSession();
1522 
1523 	cgi_S_StartBackgroundTrack( parm1, parm2, (qboolean)!bForceStart );
1524 }
1525 
1526 /*
1527 ======================
1528 CG_GameStateReceived
1529 
1530 Displays the info screen while loading media
1531 ======================
1532 */
1533 
1534 int iCGResetCount=0;
1535 qboolean qbVidRestartOccured = qfalse;
1536 
1537 //===================
1538 qboolean gbUseTheseValuesFromLoadSave = qfalse;	// MUST default to this
1539 int gi_cg_forcepowerSelect;
1540 int gi_cg_inventorySelect;
1541 //===================
1542 
1543 
CG_GameStateReceived(void)1544 static void CG_GameStateReceived( void ) {
1545 	// clear everything
1546 
1547 	extern void CG_ClearAnimSndCache( void );
1548 	CG_ClearAnimSndCache();	// else sound handles wrong after vid_restart
1549 
1550 	qbVidRestartOccured = qtrue;
1551 	iCGResetCount++;
1552 	if (iCGResetCount == 1)	// this will only equal 1 first time, after each vid_restart it just gets higher.
1553 	{						//	This non-clear is so the user can vid_restart during scrolling text without losing it.
1554 		qbVidRestartOccured = qfalse;
1555 	}
1556 
1557 	if (!qbVidRestartOccured)
1558 	{
1559 /*
1560 Ghoul2 Insert Start
1561 */
1562 
1563 // this is a No-No now we have stl vector classes in here.
1564 //		memset( &cg, 0, sizeof( cg ) );
1565 		CG_Init_CG();
1566 /*
1567 Ghoul2 Insert End
1568 */
1569 
1570 	}
1571 /*
1572 Ghoul2 Insert Start
1573 */
1574 
1575 //	memset( cg_entities, 0, sizeof(cg_entities) );
1576 	CG_Init_CGents();
1577 /*
1578 Ghoul2 Insert End
1579 */
1580 
1581 	memset( cg_weapons, 0, sizeof(cg_weapons) );
1582 	memset( cg_items, 0, sizeof(cg_items) );
1583 
1584 	CG_LinkCentsToGents();
1585 
1586 	cg.weaponSelect = WP_BRYAR_PISTOL;
1587 	cg.forcepowerSelect = FP_HEAL;
1588 
1589 	if (gbUseTheseValuesFromLoadSave)
1590 	{
1591 		gbUseTheseValuesFromLoadSave = qfalse;	// ack
1592 		cg.forcepowerSelect = gi_cg_forcepowerSelect;
1593 		cg.inventorySelect	= gi_cg_inventorySelect;
1594 	}
1595 
1596 
1597 	// get the rendering configuration from the client system
1598 	cgi_GetGlconfig( &cgs.glconfig );
1599 
1600 /*	cgs.charScale = cgs.glconfig.vidHeight * (1.0/480.0);
1601 	if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
1602 		// wide screen
1603 		cgs.bias = 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * (640.0/480.0) ) );
1604 	}
1605 	else {
1606 		// no wide screen
1607 		cgs.bias = 0;
1608 	}
1609 */
1610 	// get the gamestate from the client system
1611 	cgi_GetGameState( &cgs.gameState );
1612 
1613 	CG_ParseServerinfo();
1614 
1615 	// load the new map
1616 	cgs.media.levelLoad = cgi_R_RegisterShaderNoMip( "gfx/hud/mp_levelload" );
1617 	CG_LoadingString( "collision map" );
1618 
1619 	cgi_CM_LoadMap( cgs.mapname, qfalse );
1620 
1621 	CG_RegisterSounds();
1622 
1623 	CG_RegisterGraphics();
1624 
1625 
1626 	//jfm: moved down to preinit
1627 //	CG_InitLocalEntities();
1628 //	CG_InitMarkPolys();
1629 
1630 	CG_StartMusic( qfalse );
1631 
1632 	// remove the last loading update
1633 	cg.infoScreenText[0] = 0;
1634 
1635 	CGCam_Init();
1636 
1637 	CG_ClearLightStyles();
1638 
1639 }
1640 
CG_WriteTheEvilCGHackStuff(void)1641 void CG_WriteTheEvilCGHackStuff(void)
1642 {
1643 	ojk::SavedGameHelper saved_game(
1644 		::gi.saved_game);
1645 
1646 	saved_game.write_chunk<int32_t>(
1647 		INT_ID('F', 'P', 'S', 'L'),
1648 		::cg.forcepowerSelect);
1649 
1650 	saved_game.write_chunk<int32_t>(
1651 		INT_ID('I', 'V', 'S', 'L'),
1652 		::cg.inventorySelect);
1653 }
1654 
CG_ReadTheEvilCGHackStuff(void)1655 void CG_ReadTheEvilCGHackStuff(void)
1656 {
1657 	ojk::SavedGameHelper saved_game(
1658 		::gi.saved_game);
1659 
1660 	saved_game.read_chunk<int32_t>(
1661 		INT_ID('F', 'P', 'S', 'L'),
1662 		::gi_cg_forcepowerSelect);
1663 
1664 	saved_game.read_chunk<int32_t>(
1665 		INT_ID('I', 'V', 'S', 'L'),
1666 		::gi_cg_inventorySelect);
1667 
1668 	gbUseTheseValuesFromLoadSave = qtrue;
1669 }
1670 
1671 /*
1672 Ghoul2 Insert Start
1673 */
1674 
1675 // initialise the cg_entities structure - take into account the ghoul2 stl stuff in the active snap shots
CG_Init_CG(void)1676 void CG_Init_CG(void)
1677 {
1678 	memset( &cg, 0, sizeof(cg));
1679 }
1680 
1681 // initialise the cg_entities structure - take into account the ghoul2 stl stuff
CG_Init_CGents(void)1682 void CG_Init_CGents(void)
1683 {
1684 	memset( cg_entities, 0, sizeof(cg_entities) );
1685 }
1686 
1687 /*
1688 Ghoul2 Insert End
1689 */
1690 
1691 
1692 /*
1693 =================
1694 CG_PreInit
1695 
1696 Called when DLL loads (after subsystem restart, but before gamestate is received)
1697 =================
1698 */
CG_PreInit()1699 void CG_PreInit() {
1700 /*
1701 Ghoul2 Insert Start
1702 */
1703 
1704 // this is a No-No now we have stl vector classes in here.
1705 //	memset( &cg, 0, sizeof( cg ) );
1706 	CG_Init_CG();
1707 /*
1708 Ghoul2 Insert End
1709 */
1710 
1711 	memset( &cgs, 0, sizeof( cgs ) );
1712 	iCGResetCount = 0;
1713 
1714 	CG_RegisterCvars();
1715 
1716 //moved from CG_GameStateReceived because it's loaded sooner now
1717 	CG_InitLocalEntities();
1718 
1719 	CG_InitMarkPolys();
1720 }
1721 
1722 /*
1723 =================
1724 CG_Init
1725 
1726 Called after every level change or subsystem restart
1727 =================
1728 */
CG_Init(int serverCommandSequence)1729 void CG_Init( int serverCommandSequence ) {
1730 	cgs.serverCommandSequence = serverCommandSequence;
1731 
1732 	cgi_Cvar_Set( "cg_drawHUD", "1" );
1733 
1734 	// fonts...
1735 	//
1736 	cgs.media.charsetShader = cgi_R_RegisterShaderNoMip("gfx/2d/charsgrid_med");
1737 
1738 	cgs.media.qhFontSmall = cgi_R_RegisterFont("ocr_a");
1739 	cgs.media.qhFontMedium= cgi_R_RegisterFont("ergoec");
1740 
1741 	cgs.media.whiteShader   = cgi_R_RegisterShader( "white" );
1742 	cgs.media.loadTick		= cgi_R_RegisterShaderNoMip( "gfx/hud/load_tick" );
1743 	cgs.media.loadTickCap	= cgi_R_RegisterShaderNoMip( "gfx/hud/load_tick_cap" );
1744 
1745 	static char		*force_icon_files[NUM_FORCE_POWERS] =
1746 	{
1747 		"gfx/hud/f_icon_heal",
1748 		"gfx/hud/f_icon_levitation",
1749 		"gfx/hud/f_icon_speed",
1750 		"gfx/hud/f_icon_push",
1751 		"gfx/hud/f_icon_pull",
1752 		"gfx/hud/f_icon_telepathy",
1753 		"gfx/hud/f_icon_grip",
1754 		"gfx/hud/f_icon_l1",
1755 		"gfx/hud/f_icon_saber_throw",
1756 		"gfx/hud/f_icon_saber_defend",
1757 		"gfx/hud/f_icon_saber_attack",
1758 	};
1759 
1760 	// Precache inventory icons
1761 	for ( int i=0;i<NUM_FORCE_POWERS;i++)
1762 	{
1763 		if (force_icon_files[i])
1764 		{
1765 			force_icons[i] = cgi_R_RegisterShaderNoMip( force_icon_files[i] );
1766 		}
1767 	}
1768 
1769 	cgi_SP_Register("SP_INGAME", qtrue);	//require load and keep around
1770 	cgi_SP_Register("OBJECTIVES", qtrue);	//require load and keep around
1771 
1772 	CG_LoadHudMenu();      // load new hud stuff
1773 
1774 	cg.loadLCARSStage		= 0;
1775 
1776 	CG_GameStateReceived();
1777 
1778 	CG_InitConsoleCommands();
1779 
1780 	cg.missionInfoFlashTime = 0;
1781 	cg.missionStatusShow = qfalse;
1782 
1783 }
1784 
1785 /*
1786 =================
1787 CG_Shutdown
1788 
1789 Called before every level change or subsystem restart
1790 =================
1791 */
CG_Shutdown(void)1792 void CG_Shutdown( void )
1793 {
1794 	in_camera = false;
1795 	FX_Free();
1796 }
1797 
1798 //// DEBUG STUFF
1799 /*
1800 -------------------------
1801 CG_DrawNode
1802 -------------------------
1803 */
CG_DrawNode(vec3_t origin,int type)1804 void CG_DrawNode( vec3_t origin, int type )
1805 {
1806 	localEntity_t	*ex;
1807 
1808 	ex = CG_AllocLocalEntity();
1809 
1810 	ex->leType = LE_SPRITE;
1811 	ex->startTime = cg.time;
1812 	ex->endTime = ex->startTime + 51;
1813 	VectorCopy( origin, ex->refEntity.origin );
1814 
1815 	ex->refEntity.customShader = cgi_R_RegisterShader( "gfx/misc/nav_node" );
1816 
1817 	float	scale = 16.0f;
1818 
1819 	switch ( type )
1820 	{
1821 	case NODE_NORMAL:
1822 		ex->color[0] = 255;
1823 		ex->color[1] = 0;
1824 		ex->color[2] = 0;
1825 		break;
1826 
1827 	case NODE_START:
1828 		ex->color[0] = 0;
1829 		ex->color[1] = 0;
1830 		ex->color[2] = 255;
1831 		scale += 16.0f;
1832 		break;
1833 
1834 	case NODE_GOAL:
1835 		ex->color[0] = 0;
1836 		ex->color[1] = 255;
1837 		ex->color[2] = 0;
1838 		scale += 16.0f;
1839 		break;
1840 
1841 	case NODE_NAVGOAL:
1842 		ex->color[0] = 255;
1843 		ex->color[1] = 255;
1844 		ex->color[2] = 0;
1845 		break;
1846 	}
1847 
1848 	ex->radius = scale;
1849 }
1850 
1851 /*
1852 -------------------------
1853 CG_DrawRadius
1854 -------------------------
1855 */
1856 
CG_DrawRadius(vec3_t origin,unsigned int radius,int type)1857 void CG_DrawRadius( vec3_t origin, unsigned int radius, int type )
1858 {
1859 	localEntity_t	*ex;
1860 
1861 	ex = CG_AllocLocalEntity();
1862 
1863 	ex->leType = LE_QUAD;
1864 	ex->radius = radius;
1865 	ex->startTime = cg.time;
1866 	ex->endTime = ex->startTime + 51;
1867 	VectorCopy( origin, ex->refEntity.origin );
1868 
1869 	ex->refEntity.customShader = cgi_R_RegisterShader( "gfx/misc/nav_radius" );
1870 
1871 	switch ( type )
1872 	{
1873 	case NODE_NORMAL:
1874 		ex->color[0] = 255;
1875 		ex->color[1] = 0;
1876 		ex->color[2] = 0;
1877 		break;
1878 
1879 	case NODE_START:
1880 		ex->color[0] = 0;
1881 		ex->color[1] = 0;
1882 		ex->color[2] = 255;
1883 		break;
1884 
1885 	case NODE_GOAL:
1886 		ex->color[0] = 0;
1887 		ex->color[1] = 255;
1888 		ex->color[2] = 0;
1889 		break;
1890 
1891 	case NODE_NAVGOAL:
1892 		ex->color[0] = 255;
1893 		ex->color[1] = 255;
1894 		ex->color[2] = 0;
1895 		break;
1896 	}
1897 }
1898 
1899 /*
1900 -------------------------
1901 CG_DrawEdge
1902 -------------------------
1903 */
1904 
CG_DrawEdge(vec3_t start,vec3_t end,int type)1905 void CG_DrawEdge( vec3_t start, vec3_t end, int type )
1906 {
1907 	switch ( type )
1908 	{
1909 	case EDGE_PATH:
1910 		FX_AddLine( start, end, 4.0f, 4.0f, 0.0f, 1.0f, 1.0f, 51, cgi_R_RegisterShader( "gfx/misc/nav_arrow" ), 0 );
1911 		break;
1912 
1913 	case EDGE_NORMAL:
1914 		FX_AddLine( start, end, 8.0f, 4.0f, 0.0f, 0.5f, 0.5f, 51, cgi_R_RegisterShader( "gfx/misc/nav_line" ), 0 );
1915 		break;
1916 
1917 	case EDGE_BLOCKED:
1918 		{
1919 			vec3_t	color = { 255, 255, 0 };
1920 
1921 			FX_AddLine( start, end, 8.0f, 4.0f, 0.0f, 0.5f, 0.5f, color, color, 51, cgi_R_RegisterShader( "gfx/misc/nav_line" ), 0 );
1922 		}
1923 		break;
1924 	case EDGE_FAILED:
1925 		{
1926 			vec3_t	color = { 255, 0, 0 };
1927 
1928 			FX_AddLine( start, end, 8.0f, 4.0f, 0.0f, 0.5f, 0.5f, color, color, 51, cgi_R_RegisterShader( "gfx/misc/nav_line" ), 0 );
1929 		}
1930 		break;
1931 	case EDGE_MOVEDIR:
1932 		{
1933 			vec3_t	color = { 0, 255, 0 };
1934 
1935 			FX_AddLine( start, end, 8.0f, 4.0f, 0.0f, 0.5f, 0.5f, color, color, 51, cgi_R_RegisterShader( "gfx/misc/nav_line" ), 0 );
1936 		}
1937 		break;
1938 	default:
1939 		break;
1940 	}
1941 }
1942 
1943 /*
1944 -------------------------
1945 CG_DrawCombatPoint
1946 -------------------------
1947 */
1948 
CG_DrawCombatPoint(vec3_t origin,int type)1949 void CG_DrawCombatPoint( vec3_t origin, int type )
1950 {
1951 	localEntity_t	*ex;
1952 
1953 	ex = CG_AllocLocalEntity();
1954 
1955 	ex->leType = LE_SPRITE;
1956 	ex->startTime = cg.time;
1957 	ex->radius = 8;
1958 	ex->endTime = ex->startTime + 51;
1959 	VectorCopy( origin, ex->refEntity.origin );
1960 
1961 	ex->refEntity.customShader = cgi_R_RegisterShader( "gfx/misc/nav_cpoint" );
1962 
1963 	ex->color[0] = 0;
1964 	ex->color[1] = 255;
1965 	ex->color[2] = 255;
1966 
1967 /*
1968 	switch( type )
1969 	{
1970 	case 0:	//FIXME: To shut up the compiler warning (more will be added here later of course)
1971 	default:
1972 		FX_AddSprite( origin, NULL, NULL, 8.0f, 0.0f, 1.0f, 1.0f, color, color, 0.0f, 0.0f, 51, cgi_R_RegisterShader( "gfx/misc/nav_cpoint" ) );
1973 		break;
1974 	}
1975 */
1976 }
1977 
1978 /*
1979 -------------------------
1980 CG_DrawAlert
1981 -------------------------
1982 */
1983 
CG_DrawAlert(vec3_t origin,float rating)1984 void CG_DrawAlert( vec3_t origin, float rating )
1985 {
1986 	vec3_t	drawPos;
1987 
1988 	VectorCopy( origin, drawPos );
1989 	drawPos[2] += 48;
1990 
1991 	vec3_t	startRGB;
1992 
1993 	//Fades from green at 0, to red at 1
1994 	startRGB[0] = rating;
1995 	startRGB[1] = 1 - rating;
1996 	startRGB[2] = 0;
1997 
1998 	FX_AddSprite( drawPos, NULL, NULL, 16, 0.0f, 1.0f, 1.0f, startRGB, startRGB, 0, 0, 50, cgs.media.whiteShader );
1999 }
2000 
2001 
2002 #define MAX_MENUDEFFILE				4096
2003 
2004 //
2005 // ==============================
2006 // new hud stuff ( mission pack )
2007 // ==============================
2008 //
CG_Asset_Parse(const char ** p)2009 qboolean CG_Asset_Parse(const char **p)
2010 {
2011 	const char *token;
2012 	const char *tempStr;
2013 	int pointSize;
2014 
2015 	token = COM_ParseExt(p, qtrue);
2016 
2017 	if (!token)
2018 	{
2019 		return qfalse;
2020 	}
2021 
2022 	if (Q_stricmp(token, "{") != 0)
2023 	{
2024 		return qfalse;
2025 	}
2026 
2027 	while ( 1 )
2028 	{
2029 		token = COM_ParseExt(p, qtrue);
2030 		if (!token)
2031 		{
2032 			return qfalse;
2033 		}
2034 
2035 		if (Q_stricmp(token, "}") == 0)
2036 		{
2037 			return qtrue;
2038 		}
2039 
2040 		// font
2041 		if (Q_stricmp(token, "font") == 0)
2042 		{
2043 /*
2044 			int pointSize;
2045 
2046 			cgi_UI_Parse_String(tempStr);
2047 			cgi_UI_Parse_Int(&pointSize);
2048 
2049 			if (!tempStr || !pointSize)
2050 			{
2051 				return qfalse;
2052 			}
2053 */
2054 //			cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.textFont);
2055 			continue;
2056 		}
2057 
2058 		// smallFont
2059 		if (Q_stricmp(token, "smallFont") == 0)
2060 		{
2061 			if (!COM_ParseString(p, &tempStr) || !COM_ParseInt(p, &pointSize))
2062 			{
2063 				return qfalse;
2064 			}
2065 //			cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.smallFont);
2066 			continue;
2067 		}
2068 
2069 		// font
2070 		if (Q_stricmp(token, "bigfont") == 0)
2071 		{
2072 			int pointSize;
2073 			if (!COM_ParseString(p, &tempStr) || !COM_ParseInt(p, &pointSize))
2074 			{
2075 				return qfalse;
2076 			}
2077 //			cgDC.registerFont(tempStr, pointSize, &cgDC.Assets.bigFont);
2078 			continue;
2079 		}
2080 
2081 		// gradientbar
2082 		if (Q_stricmp(token, "gradientbar") == 0)
2083 		{
2084 			if (!COM_ParseString(p, &tempStr))
2085 			{
2086 				return qfalse;
2087 			}
2088 //			cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
2089 			continue;
2090 		}
2091 
2092 		// enterMenuSound
2093 		if (Q_stricmp(token, "menuEnterSound") == 0)
2094 		{
2095 			if (!COM_ParseString(p, &tempStr))
2096 			{
2097 				return qfalse;
2098 			}
2099 //			cgDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr );
2100 			continue;
2101 		}
2102 
2103 		// exitMenuSound
2104 		if (Q_stricmp(token, "menuExitSound") == 0)
2105 		{
2106 			if (!COM_ParseString(p, &tempStr))
2107 			{
2108 				return qfalse;
2109 			}
2110 //			cgDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr );
2111 			continue;
2112 		}
2113 
2114 		// itemFocusSound
2115 		if (Q_stricmp(token, "itemFocusSound") == 0)
2116 		{
2117 			if (!COM_ParseString(p, &tempStr))
2118 			{
2119 				return qfalse;
2120 			}
2121 //			cgDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr );
2122 			continue;
2123 		}
2124 
2125 		// menuBuzzSound
2126 		if (Q_stricmp(token, "menuBuzzSound") == 0)
2127 		{
2128 			if (!COM_ParseString(p, &tempStr))
2129 			{
2130 				return qfalse;
2131 			}
2132 //			cgDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr );
2133 			continue;
2134 		}
2135 
2136 		if (Q_stricmp(token, "cursor") == 0)
2137 		{
2138 //			if (!COM_ParseString(p, &cgDC.Assets.cursorStr))
2139 //			{
2140 //				return qfalse;
2141 //			}
2142 //			cgDC.Assets.cursor = trap_R_RegisterShaderNoMip( cgDC.Assets.cursorStr);
2143 			continue;
2144 		}
2145 
2146 		if (Q_stricmp(token, "fadeClamp") == 0)
2147 		{
2148 //			if (!COM_ParseFloat(p, &cgDC.Assets.fadeClamp))
2149 //			{
2150 //				return qfalse;
2151 //			}
2152 			continue;
2153 		}
2154 
2155 		if (Q_stricmp(token, "fadeCycle") == 0)
2156 		{
2157 //			if (!COM_ParseInt(p, &cgDC.Assets.fadeCycle))
2158 //			{
2159 //				return qfalse;
2160 //			}
2161 			continue;
2162 		}
2163 
2164 		if (Q_stricmp(token, "fadeAmount") == 0)
2165 		{
2166 //			if (!COM_ParseFloat(p, &cgDC.Assets.fadeAmount))
2167 //			{
2168 //				return qfalse;
2169 //			}
2170 			continue;
2171 		}
2172 
2173 		if (Q_stricmp(token, "shadowX") == 0)
2174 		{
2175 //			if (!COM_ParseFloat(p, &cgDC.Assets.shadowX))
2176 //			{
2177 //				return qfalse;
2178 //			}
2179 			continue;
2180 		}
2181 
2182 		if (Q_stricmp(token, "shadowY") == 0)
2183 		{
2184 //			if (!COM_ParseFloat(p, &cgDC.Assets.shadowY))
2185 //			{
2186 //				return qfalse;
2187 //			}
2188 			continue;
2189 		}
2190 
2191 		if (Q_stricmp(token, "shadowColor") == 0)
2192 		{
2193 			/*
2194 			if (!PC_Color_Parse(handle, &cgDC.Assets.shadowColor))
2195 			{
2196 				return qfalse;
2197 			}
2198 			cgDC.Assets.shadowFadeClamp = cgDC.Assets.shadowColor[3];
2199 			*/
2200 			continue;
2201 		}
2202 	}
2203 	return qfalse; // bk001204 - why not?
2204 }
2205 
2206 void cgi_UI_EndParseSession(char *buf);
2207 
2208 /*
2209 =================
2210 CG_ParseMenu();
2211 =================
2212 */
CG_ParseMenu(const char * menuFile)2213 void CG_ParseMenu(const char *menuFile)
2214 {
2215 	char			*token;
2216 	int				result;
2217 	char			*buf,*p;
2218 
2219 	Com_Printf("Parsing menu file: %s\n", menuFile);
2220 
2221 	result = cgi_UI_StartParseSession((char *) menuFile,&buf);
2222 
2223 	if (!result)
2224 	{
2225 		Com_Printf("Unable to load hud menu file: %s. Using default ui/testhud.menu.\n", menuFile);
2226 		result = cgi_UI_StartParseSession("ui/testhud.menu",&buf);
2227 		if (!result)
2228 		{
2229 			Com_Printf("Unable to load default ui/testhud.menu.\n");
2230 			return;
2231 		}
2232 	}
2233 
2234 	p = buf;
2235 	while ( 1 )
2236 	{
2237 		cgi_UI_ParseExt(&token);
2238 
2239 		if(!token)
2240 		{
2241 			// NULL checking is the best kind of checking --eez
2242 			Com_Error(ERR_FATAL, "cgi_UI_ParseExt: NULL token parameter");
2243 		}
2244 
2245 		if (!*token)	// All done?
2246 		{
2247 			break;
2248 		}
2249 
2250 		//if ( Q_stricmp( token, "{" ) ) {
2251 		//	Com_Printf( "Missing { in menu file\n" );
2252 		//	break;
2253 		//}
2254 
2255 		//if ( menuCount == MAX_MENUS ) {
2256 		//	Com_Printf( "Too many menus!\n" );
2257 		//	break;
2258 		//}
2259 
2260 //		if ( *token == '}' )
2261 //		{
2262 //			break;
2263 //		}
2264 
2265 		if (Q_stricmp(token, "assetGlobalDef") == 0)
2266 		{
2267 			/*
2268 			if (CG_Asset_Parse(handle))
2269 			{
2270 				continue;
2271 			}
2272 			else
2273 			{
2274 				break;
2275 			}
2276 			*/
2277 		}
2278 
2279 
2280 		if (Q_stricmp(token, "menudef") == 0)
2281 		{
2282 			// start a new menu
2283 			cgi_UI_Menu_New(p);
2284 		}
2285 	}
2286 
2287 	cgi_UI_EndParseSession(buf);
2288 
2289 }
2290 
2291 /*
2292 =================
2293 CG_Load_Menu();
2294 
2295 =================
2296 */
CG_Load_Menu(const char ** p)2297 qboolean CG_Load_Menu( const char **p)
2298 {
2299 	const char *token;
2300 
2301 	token = COM_ParseExt(p, qtrue);
2302 
2303 	if (token[0] != '{')
2304 	{
2305 		return qfalse;
2306 	}
2307 
2308 	while ( 1 )
2309 	{
2310 
2311 		token = COM_ParseExt(p, qtrue);
2312 
2313 		if (Q_stricmp(token, "}") == 0)
2314 		{
2315 			return qtrue;
2316 		}
2317 
2318 		if ( !token || token[0] == 0 )
2319 		{
2320 			return qfalse;
2321 		}
2322 
2323 		CG_ParseMenu(token);
2324 	}
2325 	return qfalse;
2326 }
2327 
2328 /*
2329 =================
2330 CG_LoadMenus();
2331 
2332 =================
2333 */
CG_LoadMenus(const char * menuFile)2334 void CG_LoadMenus(const char *menuFile)
2335 {
2336 	const char	*token;
2337 	const char	*p;
2338 	int	len, start;
2339 	fileHandle_t	f;
2340 	static char buf[MAX_MENUDEFFILE];
2341 
2342 	start = cgi_Milliseconds();
2343 
2344 	len = cgi_FS_FOpenFile( menuFile, &f, FS_READ );
2345 	if ( !f )
2346 	{
2347 		//cgi_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );	// what. this would not run
2348 		cgi_Printf( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );	// the rest at all.. --eez
2349 		len = cgi_FS_FOpenFile( "ui/jk2hud.txt", &f, FS_READ );
2350 		if (!f)
2351 		{
2352 			cgi_Error( va( S_COLOR_RED "default menu file not found: ui/hud.txt, unable to continue!\n", menuFile ) );
2353 		}
2354 	}
2355 
2356 	if ( len >= MAX_MENUDEFFILE )
2357 	{
2358 		cgi_FS_FCloseFile( f );
2359 		cgi_Error( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", menuFile, len, MAX_MENUDEFFILE ) );
2360 		return;
2361 	}
2362 
2363 	cgi_FS_Read( buf, len, f );
2364 	buf[len] = 0;
2365 	cgi_FS_FCloseFile( f );
2366 
2367 //	COM_Compress(buf);
2368 
2369 //	cgi_UI_Menu_Reset();
2370 
2371 	p = buf;
2372 
2373 	COM_BeginParseSession();
2374 	while ( 1 )
2375 	{
2376 		token = COM_ParseExt( &p, qtrue );
2377 		if( !token || token[0] == 0 || token[0] == '}')
2378 		{
2379 			break;
2380 		}
2381 
2382 		if ( Q_stricmp( token, "}" ) == 0 )
2383 		{
2384 			break;
2385 		}
2386 
2387 		if (Q_stricmp(token, "loadmenu") == 0)
2388 		{
2389 			if (CG_Load_Menu(&p))
2390 			{
2391 				continue;
2392 			}
2393 			else
2394 			{
2395 				break;
2396 			}
2397 		}
2398 	}
2399 	COM_EndParseSession();
2400 
2401 	Com_Printf("UI menu load time = %d milli seconds\n", cgi_Milliseconds() - start);
2402 }
2403 
2404 /*
2405 =================
2406 CG_LoadHudMenu();
2407 
2408 =================
2409 */
CG_LoadHudMenu(void)2410 void CG_LoadHudMenu(void)
2411 {
2412 	const char *hudSet;
2413 /*
2414 	cgDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
2415 	cgDC.setColor = &trap_R_SetColor;
2416 	cgDC.drawHandlePic = &CG_DrawPic;
2417 	cgDC.drawStretchPic = &trap_R_DrawStretchPic;
2418 	cgDC.drawText = &CG_Text_Paint;
2419 	cgDC.textWidth = &CG_Text_Width;
2420 	cgDC.textHeight = &CG_Text_Height;
2421 	cgDC.registerModel = &trap_R_RegisterModel;
2422 	cgDC.modelBounds = &trap_R_ModelBounds;
2423 	cgDC.fillRect = &CG_FillRect;
2424 	cgDC.drawRect = &CG_DrawRect;
2425 	cgDC.drawSides = &CG_DrawSides;
2426 	cgDC.drawTopBottom = &CG_DrawTopBottom;
2427 	cgDC.clearScene = &trap_R_ClearScene;
2428 	cgDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
2429 	cgDC.renderScene = &trap_R_RenderScene;
2430 	cgDC.registerFont = &trap_R_RegisterFont;
2431 	cgDC.ownerDrawItem = &CG_OwnerDraw;
2432 	cgDC.getValue = &CG_GetValue;
2433 	cgDC.ownerDrawVisible = &CG_OwnerDrawVisible;
2434 	cgDC.runScript = &CG_RunMenuScript;
2435 	cgDC.getTeamColor = &CG_GetTeamColor;
2436 	cgDC.setCVar = trap_Cvar_Set;
2437 	cgDC.getCVarString = trap_Cvar_VariableStringBuffer;
2438 	cgDC.getCVarValue = CG_Cvar_Get;
2439 	cgDC.drawTextWithCursor = &CG_Text_PaintWithCursor;
2440 	cgDC.startLocalSound = &trap_S_StartLocalSound;
2441 	cgDC.ownerDrawHandleKey = &CG_OwnerDrawHandleKey;
2442 	cgDC.feederCount = &CG_FeederCount;
2443 	cgDC.feederItemImage = &CG_FeederItemImage;
2444 	cgDC.feederItemText = &CG_FeederItemText;
2445 	cgDC.feederSelection = &CG_FeederSelection;
2446 	cgDC.Error = &Com_Error;
2447 	cgDC.Print = &Com_Printf;
2448 	cgDC.ownerDrawWidth = &CG_OwnerDrawWidth;
2449 	cgDC.registerSound = &trap_S_RegisterSound;
2450 	cgDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
2451 	cgDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
2452 	cgDC.playCinematic = &CG_PlayCinematic;
2453 	cgDC.stopCinematic = &CG_StopCinematic;
2454 	cgDC.drawCinematic = &CG_DrawCinematic;
2455 	cgDC.runCinematicFrame = &CG_RunCinematicFrame;
2456 */
2457 //	Init_Display(&cgDC);
2458 
2459 //	cgi_UI_String_Init();
2460 
2461 //	cgi_UI_Menu_Reset();
2462 
2463 	hudSet = cg_hudFiles.string;
2464 	if (hudSet[0] == '\0')
2465 	{
2466 		hudSet = "ui/jk2hud.txt";
2467 	}
2468 
2469 	CG_LoadMenus(hudSet);
2470 }
2471 
2472 
2473 /*
2474 ==============================================================================
2475 
2476 INVENTORY SELECTION
2477 
2478 ==============================================================================
2479 */
2480 
2481 /*
2482 ===============
2483 CG_InventorySelectable
2484 ===============
2485 */
CG_InventorySelectable(int index)2486 static qboolean CG_InventorySelectable( int index)
2487 {
2488 	if (cg.snap->ps.inventory[index])	// Is there any in the inventory?
2489 	{
2490 		return qtrue;
2491 	}
2492 
2493 	return qfalse;
2494 }
2495 
2496 
2497 /*
2498 ===============
2499 SetInventoryTime
2500 ===============
2501 */
SetInventoryTime(void)2502 static void SetInventoryTime(void)
2503 {
2504 	if (((cg.weaponSelectTime + WEAPON_SELECT_TIME) > cg.time) ||	// The Weapon HUD was currently active to just swap it out with Force HUD
2505 		((cg.forcepowerSelectTime + WEAPON_SELECT_TIME) > cg.time))	// The Force HUD was currently active to just swap it out with Force HUD
2506 	{
2507 		cg.weaponSelectTime = 0;
2508 		cg.forcepowerSelectTime = 0;
2509 		cg.inventorySelectTime = cg.time + 130.0f;
2510 	}
2511 	else
2512 	{
2513 		cg.inventorySelectTime = cg.time;
2514 	}
2515 }
2516 
2517 /*
2518 ===============
2519 CG_DPPrevInventory_f
2520 ===============
2521 */
CG_DPPrevInventory_f(void)2522 void CG_DPPrevInventory_f( void )
2523 {
2524 	int		i;
2525 
2526 	if ( !cg.snap )
2527 	{
2528 		return;
2529 	}
2530 
2531 	const int original = cg.DataPadInventorySelect;
2532 
2533 	for ( i = 0 ; i < INV_MAX ; i++ )
2534 	{
2535 		cg.DataPadInventorySelect--;
2536 
2537 		if ((cg.DataPadInventorySelect < INV_ELECTROBINOCULARS) || (cg.DataPadInventorySelect >= INV_MAX))
2538 		{
2539 			cg.DataPadInventorySelect = (INV_MAX - 1);
2540 		}
2541 
2542 		if ( CG_InventorySelectable( cg.DataPadInventorySelect ) )
2543 		{
2544 			return;
2545 		}
2546 	}
2547 
2548 	cg.DataPadInventorySelect = original;
2549 }
2550 /*
2551 ===============
2552 CG_DPNextInventory_f
2553 ===============
2554 */
CG_DPNextInventory_f(void)2555 void CG_DPNextInventory_f( void )
2556 {
2557 	int		i;
2558 
2559 	if ( !cg.snap )
2560 	{
2561 		return;
2562 	}
2563 
2564 	const int original = cg.DataPadInventorySelect;
2565 
2566 	for ( i = 0 ; i < INV_MAX ; i++ )
2567 	{
2568 		cg.DataPadInventorySelect++;
2569 
2570 		if ((cg.DataPadInventorySelect < INV_ELECTROBINOCULARS) || (cg.DataPadInventorySelect >= INV_MAX))
2571 		{
2572 			cg.DataPadInventorySelect = INV_ELECTROBINOCULARS;
2573 		}
2574 
2575 		if ( CG_InventorySelectable( cg.DataPadInventorySelect ) && (inv_icons[cg.DataPadInventorySelect]))
2576 		{
2577 			return;
2578 		}
2579 	}
2580 
2581 	cg.DataPadInventorySelect = original;
2582 }
2583 
2584 /*
2585 ===============
2586 CG_NextInventory_f
2587 ===============
2588 */
CG_NextInventory_f(void)2589 void CG_NextInventory_f( void )
2590 {
2591 	int		i;
2592 	float	*color;
2593 
2594 	if ( !cg.snap )
2595 	{
2596 		return;
2597 	}
2598 
2599 	// The first time it's been hit so just show inventory but don't advance in inventory.
2600 	color = CG_FadeColor( cg.inventorySelectTime, WEAPON_SELECT_TIME );
2601 	if ( !color )
2602 	{
2603 		SetInventoryTime();
2604 		return;
2605 	}
2606 
2607 	const int original = cg.inventorySelect;
2608 
2609 	for ( i = 0 ; i < INV_MAX ; i++ )
2610 	{
2611 		cg.inventorySelect++;
2612 
2613 		if ((cg.inventorySelect < INV_ELECTROBINOCULARS) || (cg.inventorySelect >= INV_MAX))
2614 		{
2615 			cg.inventorySelect = INV_ELECTROBINOCULARS;
2616 		}
2617 
2618 		if ( CG_InventorySelectable( cg.inventorySelect ) && (inv_icons[cg.inventorySelect]))
2619 		{
2620 			cgi_S_StartSound (NULL, 0, CHAN_AUTO, cgs.media.selectSound2 );
2621 			SetInventoryTime();
2622 			return;
2623 		}
2624 	}
2625 
2626 	cg.inventorySelect = original;
2627 }
2628 
2629 /*
2630 ===============
2631 CG_UseInventory_f
2632 ===============
2633 */
2634 /*
2635 this func was moved to Cmd_UseInventory_f in g_cmds.cpp
2636 */
2637 
2638 /*
2639 ===============
2640 CG_PrevInventory_f
2641 ===============
2642 */
CG_PrevInventory_f(void)2643 void CG_PrevInventory_f( void )
2644 {
2645 	int		i;
2646 	float	*color;
2647 
2648 	if ( !cg.snap )
2649 	{
2650 		return;
2651 	}
2652 
2653 	// The first time it's been hit so just show inventory but don't advance in inventory.
2654 	color = CG_FadeColor( cg.inventorySelectTime, WEAPON_SELECT_TIME );
2655 	if ( !color )
2656 	{
2657 		SetInventoryTime();
2658 		return;
2659 	}
2660 
2661 	const int original = cg.inventorySelect;
2662 
2663 	for ( i = 0 ; i < INV_MAX ; i++ )
2664 	{
2665 		cg.inventorySelect--;
2666 
2667 		if ((cg.inventorySelect < INV_ELECTROBINOCULARS) || (cg.inventorySelect >= INV_MAX))
2668 		{
2669 			cg.inventorySelect = (INV_MAX - 1);
2670 		}
2671 
2672 		if ( CG_InventorySelectable( cg.inventorySelect ) && (inv_icons[cg.inventorySelect]))
2673 		{
2674 			cgi_S_StartSound (NULL, 0, CHAN_AUTO, cgs.media.selectSound2 );
2675 			SetInventoryTime();
2676 			return;
2677 		}
2678 	}
2679 
2680 	cg.inventorySelect = original;
2681 }
2682 
2683 
2684 /*
2685 ===================
2686 FindInventoryItemTag
2687 ===================
2688 */
FindInventoryItemTag(int tag)2689 gitem_t *FindInventoryItemTag(int tag)
2690 {
2691 	int		i;
2692 
2693 /*	if (!Q_stricmp(tokenStr,"INV_ELECTROBINOCULARS")
2694 	{
2695 		tag = INV_ELECTROBINOCULARS;
2696 	}
2697 	else if (!Q_stricmp(tokenStr,"INV_BACTA_CANISTER")
2698 	{
2699 		tag = INV_BACTA_CANISTER;
2700 	}
2701 	else if (!Q_stricmp(tokenStr,"INV_SEEKER")
2702 	{
2703 		tag = INV_SEEKER;
2704 	}
2705 	else if (!Q_stricmp(tokenStr,"INV_LIGHTAMP_GOGGLES")
2706 	{
2707 		tag = INV_LIGHTAMP_GOGGLES;
2708 	}
2709 	else if (!Q_stricmp(tokenStr,"INV_SENTRY")
2710 	{
2711 		tag = INV_SENTRY;
2712 	}
2713 	else if (!Q_stricmp(tokenStr,"INV_GOODIE_KEY")
2714 	{
2715 		tag = INV_GOODIE_KEY;
2716 	}
2717 	else if (!Q_stricmp(tokenStr,"INV_SECURITY_KEY")
2718 	{
2719 		tag = INV_SECURITY_KEY;
2720 	}
2721 */
2722 
2723 	for ( i = 1 ; i < bg_numItems ; i++ )
2724 	{
2725 		if ( bg_itemlist[i].giTag == tag && bg_itemlist[i].giType == IT_HOLDABLE ) // I guess giTag's aren't unique amongst items..must also make sure it's a holdable
2726 		{
2727 			return &bg_itemlist[i];
2728 		}
2729 	}
2730 
2731 	return (0);
2732 }
2733 
2734 
2735 
2736 
2737 /*
2738 ===================
2739 CG_DrawInventorySelect
2740 ===================
2741 */
CG_DrawInventorySelect(void)2742 void CG_DrawInventorySelect( void )
2743 {
2744 	int				i;
2745 	int				sideMax,holdCount,iconCnt;
2746 	int				smallIconSize,bigIconSize;
2747 	int				sideLeftIconCnt,sideRightIconCnt;
2748 	int				count;
2749 	int				holdX,x,y,pad;
2750 	//int				height;
2751 //	int				tag;
2752 	float			addX;
2753 	vec4_t			textColor = { .312f, .75f, .621f, 1.0f };
2754 	char			text[1024]={0};
2755 
2756 	// don't display if dead
2757 	if ( cg.predicted_player_state.stats[STAT_HEALTH] <= 0 || ( cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD ))
2758 	{
2759 		return;
2760 	}
2761 
2762 	if ((cg.inventorySelectTime+WEAPON_SELECT_TIME)<cg.time)	// Time is up for the HUD to display
2763 	{
2764 		return;
2765 	}
2766 
2767 	int x2,y2;
2768 	if (!cgi_UI_GetMenuInfo("inventoryselecthud",&x2,&y2))
2769 	{
2770 		return;
2771 	}
2772 
2773 	cg.iconSelectTime = cg.inventorySelectTime;
2774 
2775 	// showing weapon select clears pickup item display, but not the blend blob
2776 	cg.itemPickupTime = 0;
2777 
2778 //const int bits = cg.snap->ps.stats[ STAT_ITEMS ];
2779 
2780 	// count the number of items owned
2781 	count = 0;
2782 	for ( i = 0 ; i < INV_MAX ; i++ )
2783 	{
2784 		if (CG_InventorySelectable(i) && inv_icons[i])
2785 		{
2786 			count++;
2787 		}
2788 	}
2789 
2790 	if (!count)
2791 	{
2792 		cgi_SP_GetStringTextString("INGAME_EMPTY_INV",text, sizeof(text) );
2793 		int w = cgi_R_Font_StrLenPixels( text, cgs.media.qhFontSmall, 1.0f );
2794 		x = ( SCREEN_WIDTH - w ) / 2;
2795 		CG_DrawProportionalString(x, y2 + 22, text, CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]);
2796 		return;
2797 	}
2798 
2799 	sideMax = 3;	// Max number of icons on the side
2800 
2801 	// Calculate how many icons will appear to either side of the center one
2802 	holdCount = count - 1;	// -1 for the center icon
2803 	if (holdCount == 0)			// No icons to either side
2804 	{
2805 		sideLeftIconCnt = 0;
2806 		sideRightIconCnt = 0;
2807 	}
2808 	else if (count > (2*sideMax))	// Go to the max on each side
2809 	{
2810 		sideLeftIconCnt = sideMax;
2811 		sideRightIconCnt = sideMax;
2812 	}
2813 	else							// Less than max, so do the calc
2814 	{
2815 		sideLeftIconCnt = holdCount/2;
2816 		sideRightIconCnt = holdCount - sideLeftIconCnt;
2817 	}
2818 
2819 	i = cg.inventorySelect - 1;
2820 	if (i<0)
2821 	{
2822 		i = INV_MAX-1;
2823 	}
2824 
2825 	smallIconSize = 40;
2826 	bigIconSize = 80;
2827 	pad = 16;
2828 
2829 	x = 320;
2830 	y = 410;
2831 
2832 	// Left side ICONS
2833 	// Work backwards from current icon
2834 	holdX = x - ((bigIconSize/2) + pad + smallIconSize);
2835 	//height = smallIconSize * cg.iconHUDPercent;
2836 	addX = (float) smallIconSize * .75;
2837 
2838 	for (iconCnt=0;iconCnt<sideLeftIconCnt;i--)
2839 	{
2840 		if (i<0)
2841 		{
2842 			i = INV_MAX-1;
2843 		}
2844 
2845 		if ((!CG_InventorySelectable(i)) || (!inv_icons[i]))
2846 		{
2847 			continue;
2848 		}
2849 
2850 		++iconCnt;					// Good icon
2851 
2852 		if (inv_icons[i])
2853 		{
2854 			cgi_R_SetColor(NULL);
2855 			CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, inv_icons[i] );
2856 
2857 			cgi_R_SetColor(colorTable[CT_ICON_BLUE]);
2858 			CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12,
2859 				NUM_FONT_SMALL,qfalse);
2860 
2861 			holdX -= (smallIconSize+pad);
2862 		}
2863 	}
2864 
2865 	// Current Center Icon
2866 	//height = bigIconSize * cg.iconHUDPercent;
2867 	if (inv_icons[cg.inventorySelect])
2868 	{
2869 		cgi_R_SetColor(NULL);
2870 		CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10, bigIconSize, bigIconSize, inv_icons[cg.inventorySelect] );
2871 		addX = (float) bigIconSize * .75;
2872 		cgi_R_SetColor(colorTable[CT_ICON_BLUE]);
2873 		CG_DrawNumField ((x-(bigIconSize/2)) + addX, y, 2, cg.snap->ps.inventory[cg.inventorySelect], 6, 12,
2874 			NUM_FONT_SMALL,qfalse);
2875 
2876 		if (inv_names[cg.inventorySelect])
2877 		{
2878 			// FIXME: This is ONLY a temp solution, the icon stuff, etc, should all just use items.dat for everything
2879 			gitem_t *item = FindInventoryItemTag( cg.inventorySelect );
2880 
2881 			if ( item && item->classname && item->classname[0] )
2882 			{
2883 				char itemName[256], data[1024]; // FIXME: do these really need to be this large??  does it matter?
2884 
2885 				sprintf( itemName, "INGAME_%s",	item->classname );
2886 
2887 				if ( cgi_SP_GetStringTextString( itemName, data, sizeof( data )))
2888 				{
2889 					int w = cgi_R_Font_StrLenPixels( data, cgs.media.qhFontSmall, 1.0f );
2890 					int x = ( SCREEN_WIDTH - w ) / 2;
2891 
2892 					cgi_R_Font_DrawString( x, (SCREEN_HEIGHT - 24), data, textColor, cgs.media.qhFontSmall, -1, 1.0f);
2893 				}
2894 			}
2895 //			if (tag)
2896 //			{
2897 //				CG_DrawProportionalString(320, y + 53, inv_names[cg.inventorySelect], CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]);
2898 //				CG_DrawProportionalString(320, y + 53, bg_itemlist[i].pickup_name, CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]);
2899 //			}
2900 		}
2901 	}
2902 
2903 	i = cg.inventorySelect + 1;
2904 	if (i> INV_MAX-1)
2905 	{
2906 		i = 0;
2907 	}
2908 
2909 	// Right side ICONS
2910 	// Work forwards from current icon
2911 	holdX = x + (bigIconSize/2) + pad;
2912 	//height = smallIconSize * cg.iconHUDPercent;
2913 	addX = (float) smallIconSize * .75;
2914 	for (iconCnt=0;iconCnt<sideRightIconCnt;i++)
2915 	{
2916 		if (i> INV_MAX-1)
2917 		{
2918 			i = 0;
2919 		}
2920 
2921 		if ((!CG_InventorySelectable(i)) || (!inv_icons[i]))
2922 		{
2923 			continue;
2924 		}
2925 
2926 		++iconCnt;					// Good icon
2927 
2928 		if (inv_icons[i])
2929 		{
2930 			cgi_R_SetColor(NULL);
2931 			CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, inv_icons[i] );
2932 
2933 			cgi_R_SetColor(colorTable[CT_ICON_BLUE]);
2934 			CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12,
2935 				NUM_FONT_SMALL,qfalse);
2936 
2937 			holdX += (smallIconSize+pad);
2938 		}
2939 	}
2940 }
2941 
2942 int cgi_UI_GetItemText(char *menuFile,char *itemName, char *text);
2943 
2944 char *inventoryDesc[15] =
2945 {
2946 "NEURO_SAAV_DESC",
2947 "BACTA_DESC",
2948 "INQUISITOR_DESC",
2949 "LA_GOGGLES_DESC",
2950 "PORTABLE_SENTRY_DESC",
2951 "GOODIE_KEY_DESC",
2952 "SECURITY_KEY_DP_DESC",
2953 };
2954 
2955 
2956 /*
2957 ===================
2958 CG_DrawDataPadInventorySelect
2959 ===================
2960 */
CG_DrawDataPadInventorySelect(void)2961 void CG_DrawDataPadInventorySelect( void )
2962 {
2963 	int				i;
2964 	int				sideMax,holdCount,iconCnt;
2965 	int				smallIconSize,bigIconSize;
2966 	int				sideLeftIconCnt,sideRightIconCnt;
2967 	int				count;
2968 	int				holdX,x,y,pad;
2969 	//int				height;
2970 	float			addX;
2971 	char			text[1024]={0};
2972 	vec4_t			textColor = { .312f, .75f, .621f, 1.0f };
2973 
2974 
2975 	// count the number of items owned
2976 	count = 0;
2977 	for ( i = 0 ; i < INV_MAX ; i++ )
2978 	{
2979 		if (CG_InventorySelectable(i) && inv_icons[i])
2980 		{
2981 			count++;
2982 		}
2983 	}
2984 
2985 
2986 	if (!count)
2987 	{
2988 		cgi_SP_GetStringTextString("INGAME_EMPTY_INV",text, sizeof(text) );
2989 		int w = cgi_R_Font_StrLenPixels( text, cgs.media.qhFontSmall, 1.0f );
2990 		x = ( SCREEN_WIDTH - w ) / 2;
2991 		CG_DrawProportionalString(x, 300 + 22, text, CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]);
2992 		return;
2993 	}
2994 
2995 	sideMax = 3;	// Max number of icons on the side
2996 
2997 	// Calculate how many icons will appear to either side of the center one
2998 	holdCount = count - 1;	// -1 for the center icon
2999 	if (holdCount == 0)			// No icons to either side
3000 	{
3001 		sideLeftIconCnt = 0;
3002 		sideRightIconCnt = 0;
3003 	}
3004 	else if (count > (2*sideMax))	// Go to the max on each side
3005 	{
3006 		sideLeftIconCnt = sideMax;
3007 		sideRightIconCnt = sideMax;
3008 	}
3009 	else							// Less than max, so do the calc
3010 	{
3011 		sideLeftIconCnt = holdCount/2;
3012 		sideRightIconCnt = holdCount - sideLeftIconCnt;
3013 	}
3014 
3015 //	char buffer[256];
3016 //	cgi_UI_GetItemText("datapadInventoryMenu",va("invdesc%d",cg.DataPadInventorySelect+1),buffer);
3017 
3018 	i = cg.DataPadInventorySelect - 1;
3019 	if (i<0)
3020 	{
3021 		i = INV_MAX-1;
3022 	}
3023 
3024 	smallIconSize = 40;
3025 	bigIconSize = 80;
3026 	pad = 8;
3027 
3028 	x = 320;
3029 	y = 300;
3030 
3031 	// Left side ICONS
3032 	// Work backwards from current icon
3033 	holdX = x - ((bigIconSize/2) + pad + smallIconSize);
3034 	//height = smallIconSize * cg.iconHUDPercent;
3035 	addX = (float) smallIconSize * .75;
3036 
3037 	for (iconCnt=0;iconCnt<sideLeftIconCnt;i--)
3038 	{
3039 		if (i<0)
3040 		{
3041 			i = INV_MAX-1;
3042 		}
3043 
3044 		if ((!CG_InventorySelectable(i)) || (!inv_icons[i]))
3045 		{
3046 			continue;
3047 		}
3048 
3049 		++iconCnt;					// Good icon
3050 
3051 		if (inv_icons[i])
3052 		{
3053 			cgi_R_SetColor(NULL);
3054 			CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, inv_icons[i] );
3055 
3056 			cgi_R_SetColor(colorTable[CT_ICON_BLUE]);
3057 			CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12,
3058 				NUM_FONT_SMALL,qfalse);
3059 
3060 			holdX -= (smallIconSize+pad);
3061 		}
3062 	}
3063 
3064 	// Current Center Icon
3065 	//height = bigIconSize * cg.iconHUDPercent;
3066 	if (inv_icons[cg.DataPadInventorySelect])
3067 	{
3068 		cgi_R_SetColor(NULL);
3069 		CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10, bigIconSize, bigIconSize, inv_icons[cg.DataPadInventorySelect] );
3070 		addX = (float) bigIconSize * .75;
3071 		cgi_R_SetColor(colorTable[CT_ICON_BLUE]);
3072 		CG_DrawNumField ((x-(bigIconSize/2)) + addX, y, 2, cg.snap->ps.inventory[cg.DataPadInventorySelect], 6, 12,
3073 			NUM_FONT_SMALL,qfalse);
3074 
3075 		if (inv_names[cg.DataPadInventorySelect])
3076 		{
3077 			// FIXME :this has to use the bg_itemlist pickup name
3078 //			tag = FindInventoryItemTag(cg.inventorySelect);
3079 
3080 //			if (tag)
3081 //			{
3082 //				CG_DrawProportionalString(320, y + 53, inv_names[cg.inventorySelect], CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]);
3083 //				CG_DrawProportionalString(320, y + 53, bg_itemlist[i].pickup_name, CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]);
3084 //			}
3085 		}
3086 	}
3087 
3088 	i = cg.DataPadInventorySelect + 1;
3089 	if (i> INV_MAX-1)
3090 	{
3091 		i = 0;
3092 	}
3093 
3094 	// Right side ICONS
3095 	// Work forwards from current icon
3096 	holdX = x + (bigIconSize/2) + pad;
3097 	//height = smallIconSize * cg.iconHUDPercent;
3098 	addX = (float) smallIconSize * .75;
3099 	for (iconCnt=0;iconCnt<sideRightIconCnt;i++)
3100 	{
3101 		if (i> INV_MAX-1)
3102 		{
3103 			i = 0;
3104 		}
3105 
3106 		if ((!CG_InventorySelectable(i)) || (!inv_icons[i]))
3107 		{
3108 			continue;
3109 		}
3110 
3111 		++iconCnt;					// Good icon
3112 
3113 		if (inv_icons[i])
3114 		{
3115 			cgi_R_SetColor(NULL);
3116 			CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, inv_icons[i] );
3117 
3118 			cgi_R_SetColor(colorTable[CT_ICON_BLUE]);
3119 			CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12,
3120 				NUM_FONT_SMALL,qfalse);
3121 
3122 			holdX += (smallIconSize+pad);
3123 		}
3124 	}
3125 
3126 	// draw the weapon description
3127 	x= 40;
3128 	y= 70;
3129 
3130 	if ((cg.DataPadInventorySelect>=0) && (cg.DataPadInventorySelect<13))
3131 	{
3132 		cgi_SP_GetStringTextString( va("INGAME_%s",inventoryDesc[cg.DataPadInventorySelect]), text, sizeof(text) );
3133 
3134 		if (text[0])
3135 		{
3136 			CG_DisplayBoxedText(70,50,500,300,text,
3137 														cgs.media.qhFontSmall,
3138 														0.7f,
3139 														textColor
3140 														);
3141 		}
3142 	}
3143 }
3144 
3145 /*
3146 ===============
3147 SetForcePowerTime
3148 ===============
3149 */
SetForcePowerTime(void)3150 void SetForcePowerTime(void)
3151 {
3152 	if (((cg.weaponSelectTime + WEAPON_SELECT_TIME) > cg.time) ||	// The Weapon HUD was currently active to just swap it out with Force HUD
3153 		((cg.inventorySelectTime + WEAPON_SELECT_TIME) > cg.time))	// The Inventory HUD was currently active to just swap it out with Force HUD
3154 	{
3155 		cg.weaponSelectTime = 0;
3156 		cg.inventorySelectTime = 0;
3157 		cg.forcepowerSelectTime = cg.time + 130.0f;
3158 	}
3159 	else
3160 	{
3161 		cg.forcepowerSelectTime = cg.time;
3162 	}
3163 }
3164 
3165 int showPowers[MAX_SHOWPOWERS] =
3166 {
3167 	FP_HEAL,
3168 	FP_SPEED,
3169 	FP_PUSH,
3170 	FP_PULL,
3171 	FP_TELEPATHY,
3172 	FP_GRIP,
3173 	FP_LIGHTNING
3174 };
3175 char *showPowersName[MAX_SHOWPOWERS] =
3176 {
3177 	"HEAL2",
3178 	"SPEED2",
3179 	"PUSH2",
3180 	"PULL2",
3181 	"MINDTRICK2",
3182 	"GRIP2",
3183 	"LIGHTNING2",
3184 };
3185 
3186 int showDataPadPowers[MAX_DPSHOWPOWERS] =
3187 {
3188 	FP_HEAL,
3189 	FP_LEVITATION,
3190 	FP_SPEED,
3191 	FP_PUSH,
3192 	FP_PULL,
3193 	FP_TELEPATHY,
3194 	FP_GRIP,
3195 	FP_LIGHTNING,
3196 	FP_SABERTHROW,
3197 	FP_SABER_DEFENSE,
3198 	FP_SABER_OFFENSE,
3199 };
3200 
3201 /*char *showDataPadPowersName[MAX_DPSHOWPOWERS] =
3202 {
3203 	"HEAL2",
3204 	"JUMP2",
3205 	"SPEED2",
3206 	"PUSH2",
3207 	"PULL2",
3208 	"MINDTRICK2",
3209 	"GRIP2",
3210 	"LIGHTNING2",
3211 	"SABER_THROW2",
3212 	"SABER_DEFENSE2",
3213 	"SABER_OFFENSE2",
3214 };
3215 /*
3216 
3217 /*
3218 ===============
3219 ForcePower_Valid
3220 ===============
3221 */
ForcePower_Valid(int index)3222 qboolean ForcePower_Valid(int index)
3223 {
3224 	gentity_t	*player = &g_entities[0];
3225 
3226 	assert (MAX_SHOWPOWERS == ( sizeof(showPowers)/sizeof(showPowers[0]) ));
3227 	assert (index < MAX_SHOWPOWERS );	//is this a valid index?
3228 	if (player->client->ps.forcePowersKnown & (1 << showPowers[index]) &&
3229 		player->client->ps.forcePowerLevel[showPowers[index]])	// Does he have the force power?
3230 	{
3231 		return qtrue;
3232 	}
3233 
3234 	return qfalse;
3235 }
3236 
3237 /*
3238 ===============
3239 CG_NextForcePower_f
3240 ===============
3241 */
CG_NextForcePower_f(void)3242 void CG_NextForcePower_f( void )
3243 {
3244 	int		i;
3245 
3246 	if ( !cg.snap )
3247 	{
3248 		return;
3249 	}
3250 
3251 	SetForcePowerTime();
3252 
3253 	if ((cg.forcepowerSelectTime + WEAPON_SELECT_TIME) < cg.time)
3254 	{
3255 		return;
3256 	}
3257 
3258 	const int original = cg.forcepowerSelect;
3259 
3260 	for ( i = 0; i < MAX_SHOWPOWERS; i++ )
3261 	{
3262 		cg.forcepowerSelect++;
3263 
3264 		if (cg.forcepowerSelect >= MAX_SHOWPOWERS)
3265 		{
3266 			cg.forcepowerSelect = 0;
3267 		}
3268 
3269 		if (ForcePower_Valid(cg.forcepowerSelect))	// Does he have the force power?
3270 		{
3271 			cgi_S_StartSound (NULL, 0, CHAN_AUTO, cgs.media.selectSound2 );
3272 			return;
3273 		}
3274 	}
3275 
3276 	cg.forcepowerSelect = original;
3277 }
3278 
3279 /*
3280 ===============
3281 CG_PrevForcePower_f
3282 ===============
3283 */
CG_PrevForcePower_f(void)3284 void CG_PrevForcePower_f( void )
3285 {
3286 	int		i;
3287 
3288 	if ( !cg.snap )
3289 	{
3290 		return;
3291 	}
3292 
3293 	SetForcePowerTime();
3294 
3295 	if ((cg.forcepowerSelectTime + WEAPON_SELECT_TIME) < cg.time)
3296 	{
3297 		return;
3298 	}
3299 
3300 	const int original = cg.forcepowerSelect;
3301 
3302 	for ( i = 0; i < MAX_SHOWPOWERS; i++ )
3303 	{
3304 		cg.forcepowerSelect--;
3305 
3306 		if (cg.forcepowerSelect < 0)
3307 		{
3308 			cg.forcepowerSelect = MAX_SHOWPOWERS - 1;
3309 		}
3310 
3311 		if (ForcePower_Valid(cg.forcepowerSelect))	// Does he have the force power?
3312 		{
3313 			cgi_S_StartSound (NULL, 0, CHAN_AUTO, cgs.media.selectSound2 );
3314 			return;
3315 		}
3316 	}
3317 
3318 
3319 	cg.forcepowerSelect = original;
3320 }
3321 
3322 /*
3323 ===================
3324 CG_DrawForceSelect
3325 ===================
3326 */
CG_DrawForceSelect(void)3327 void CG_DrawForceSelect( void )
3328 {
3329 	int		i;
3330 	int		count;
3331 	int		smallIconSize,bigIconSize;
3332 	int		holdX,x,y,pad;
3333 	int		sideLeftIconCnt,sideRightIconCnt;
3334 	int		sideMax,holdCount,iconCnt;
3335 	char	text[1024]={0};
3336 
3337 
3338 	// don't display if dead
3339 	if ( cg.predicted_player_state.stats[STAT_HEALTH] <= 0 || ( cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD ))
3340 	{
3341 		return;
3342 	}
3343 
3344 	if ((cg.forcepowerSelectTime+WEAPON_SELECT_TIME)<cg.time)	// Time is up for the HUD to display
3345 	{
3346 		return;
3347 	}
3348 
3349 	// count the number of powers owned
3350 	count = 0;
3351 
3352 	for (i=0; i<MAX_SHOWPOWERS; ++i)
3353 	{
3354 		if (ForcePower_Valid(i))
3355 		{
3356 			count++;
3357 		}
3358 	}
3359 
3360 	if (count == 0)	// If no force powers, don't display
3361 	{
3362 		return;
3363 	}
3364 
3365 /*
3366 	int x2,y2;
3367 	if (!cgi_UI_GetMenuInfo("forceselecthud",&x2,&y2))
3368 	{
3369 		return;
3370 	}
3371 */
3372 	cg.iconSelectTime = cg.forcepowerSelectTime;
3373 
3374 	// showing weapon select clears pickup item display, but not the blend blob
3375 	cg.itemPickupTime = 0;
3376 
3377 	sideMax = 3;	// Max number of icons on the side
3378 
3379 	// Calculate how many icons will appear to either side of the center one
3380 	holdCount = count - 1;	// -1 for the center icon
3381 	if (holdCount == 0)			// No icons to either side
3382 	{
3383 		sideLeftIconCnt = 0;
3384 		sideRightIconCnt = 0;
3385 	}
3386 	else if (count > (2*sideMax))	// Go to the max on each side
3387 	{
3388 		sideLeftIconCnt = sideMax;
3389 		sideRightIconCnt = sideMax;
3390 	}
3391 	else							// Less than max, so do the calc
3392 	{
3393 		sideLeftIconCnt = holdCount/2;
3394 		sideRightIconCnt = holdCount - sideLeftIconCnt;
3395 	}
3396 
3397 	smallIconSize = 30;
3398 	bigIconSize = 60;
3399 	pad = 12;
3400 
3401 	x = 320;
3402 	y = 425;
3403 
3404 	i = cg.forcepowerSelect - 1;
3405 	if (i < 0)
3406 	{
3407 		i = MAX_SHOWPOWERS-1;
3408 	}
3409 
3410 	cgi_R_SetColor(NULL);
3411 	// Work backwards from current icon
3412 	holdX = x - ((bigIconSize/2) + pad + smallIconSize);
3413 	for (iconCnt=1;iconCnt<(sideLeftIconCnt+1);i--)
3414 	{
3415 		if (i < 0)
3416 		{
3417 			i = MAX_SHOWPOWERS-1;
3418 		}
3419 
3420 		if (!ForcePower_Valid(i))	// Does he have this power?
3421 		{
3422 			continue;
3423 		}
3424 
3425 		++iconCnt;					// Good icon
3426 
3427 		if (force_icons[showPowers[i]])
3428 		{
3429 			CG_DrawPic( holdX, y, smallIconSize, smallIconSize, force_icons[showPowers[i]] );
3430 			holdX -= (smallIconSize+pad);
3431 		}
3432 	}
3433 
3434 	// Current Center Icon
3435 	if (force_icons[showPowers[cg.forcepowerSelect]])
3436 	{
3437 		CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2)), bigIconSize, bigIconSize, force_icons[showPowers[cg.forcepowerSelect]] ); //only cache the icon for display
3438 	}
3439 
3440 
3441 	i = cg.forcepowerSelect + 1;
3442 	if (i>=MAX_SHOWPOWERS)
3443 	{
3444 		i = 0;
3445 	}
3446 
3447 	// Work forwards from current icon
3448 	holdX = x + (bigIconSize/2) + pad;
3449 	for (iconCnt=1;iconCnt<(sideRightIconCnt+1);i++)
3450 	{
3451 		if (i>=MAX_SHOWPOWERS)
3452 		{
3453 			i = 0;
3454 		}
3455 
3456 		if (!ForcePower_Valid(i))	// Does he have this power?
3457 		{
3458 			continue;
3459 		}
3460 
3461 		++iconCnt;					// Good icon
3462 
3463 		if (force_icons[showPowers[i]])
3464 		{
3465 			CG_DrawPic( holdX, y, smallIconSize, smallIconSize, force_icons[showPowers[i]] ); //only cache the icon for display
3466 			holdX += (smallIconSize+pad);
3467 		}
3468 	}
3469 
3470 	// This only a temp solution.
3471 	if (cgi_SP_GetStringTextString( va("INGAME_%s",showPowersName[cg.forcepowerSelect]), text, sizeof(text) ))
3472 	{
3473 			int w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 1.0f);
3474 			int x = ( SCREEN_WIDTH - w ) / 2;
3475 			cgi_R_Font_DrawString(x, (SCREEN_HEIGHT - 24), text, colorTable[CT_ICON_BLUE], cgs.media.qhFontSmall, -1, 1.0f);
3476 	}
3477 }
3478 
3479 /*
3480 ===============
3481 ForcePowerDataPad_Valid
3482 ===============
3483 */
ForcePowerDataPad_Valid(int index)3484 qboolean ForcePowerDataPad_Valid(int index)
3485 {
3486 	gentity_t	*player = &g_entities[0];
3487 
3488 	assert (index < MAX_DPSHOWPOWERS);
3489 	if (player->client->ps.forcePowersKnown & (1 << showDataPadPowers[index]) &&
3490 		player->client->ps.forcePowerLevel[showDataPadPowers[index]])	// Does he have the force power?
3491 	{
3492 		return qtrue;
3493 	}
3494 
3495 	return qfalse;
3496 }
3497 
3498 /*
3499 ===============
3500 CG_DPNextForcePower_f
3501 ===============
3502 */
CG_DPNextForcePower_f(void)3503 void CG_DPNextForcePower_f( void )
3504 {
3505 	int		i;
3506 	int		original;
3507 
3508 	if ( !cg.snap )
3509 	{
3510 		return;
3511 	}
3512 
3513 	original = cg.DataPadforcepowerSelect;
3514 
3515 	for ( i = 0; i<MAX_DPSHOWPOWERS; i++ )
3516 	{
3517 		cg.DataPadforcepowerSelect++;
3518 
3519 		if (cg.DataPadforcepowerSelect >= MAX_DPSHOWPOWERS)
3520 		{
3521 			cg.DataPadforcepowerSelect = 0;
3522 		}
3523 
3524 		if (ForcePowerDataPad_Valid(cg.DataPadforcepowerSelect))	// Does he have the force power?
3525 		{
3526 			return;
3527 		}
3528 	}
3529 
3530 	cg.DataPadforcepowerSelect = original;
3531 }
3532 
3533 /*
3534 ===============
3535 CG_DPPrevForcePower_f
3536 ===============
3537 */
CG_DPPrevForcePower_f(void)3538 void CG_DPPrevForcePower_f( void )
3539 {
3540 	int		i;
3541 	int		original;
3542 
3543 	if ( !cg.snap )
3544 	{
3545 		return;
3546 	}
3547 
3548 	original = cg.DataPadforcepowerSelect;
3549 
3550 	for ( i = 0; i<MAX_DPSHOWPOWERS; i++ )
3551 	{
3552 		cg.DataPadforcepowerSelect--;
3553 
3554 		if (cg.DataPadforcepowerSelect < 0)
3555 		{
3556 			cg.DataPadforcepowerSelect = MAX_DPSHOWPOWERS-1;
3557 		}
3558 
3559 		if (ForcePowerDataPad_Valid(cg.DataPadforcepowerSelect))	// Does he have the force power?
3560 		{
3561 			return;
3562 		}
3563 	}
3564 
3565 
3566 	cg.DataPadforcepowerSelect = original;
3567 }
3568 
3569 char *forcepowerDesc[NUM_FORCE_POWERS] =
3570 {
3571 "FORCE_HEAL_DESC",
3572 "FORCE_JUMP_DESC",
3573 "FORCE_SPEED_DESC",
3574 "FORCE_PUSH_DESC",
3575 "FORCE_PULL_DESC",
3576 "FORCE_MIND_TRICK_DESC",
3577 "FORCE_GRIP_DESC",
3578 "FORCE_LIGHTNING_DESC",
3579 "FORCE_SABER_THROW_DESC",
3580 "FORCE_SABER_DEFENSE_DESC",
3581 "FORCE_SABER_OFFENSE_DESC",
3582 };
3583 
3584 char *forcepowerLvl1Desc[NUM_FORCE_POWERS] =
3585 {
3586 "FORCE_HEAL_LVL1_DESC",
3587 "FORCE_JUMP_LVL1_DESC",
3588 "FORCE_SPEED_LVL1_DESC",
3589 "FORCE_PUSH_LVL1_DESC",
3590 "FORCE_PULL_LVL1_DESC",
3591 "FORCE_MIND_TRICK_LVL1_DESC",
3592 "FORCE_GRIP_LVL1_DESC",
3593 "FORCE_LIGHTNING_LVL1_DESC",
3594 "FORCE_SABER_THROW_LVL1_DESC",
3595 "FORCE_SABER_DEFENSE_LVL1_DESC",
3596 "FORCE_SABER_OFFENSE_LVL1_DESC",
3597 };
3598 
3599 char *forcepowerLvl2Desc[NUM_FORCE_POWERS] =
3600 {
3601 "FORCE_HEAL_LVL2_DESC",
3602 "FORCE_JUMP_LVL2_DESC",
3603 "FORCE_SPEED_LVL2_DESC",
3604 "FORCE_PUSH_LVL2_DESC",
3605 "FORCE_PULL_LVL2_DESC",
3606 "FORCE_MIND_TRICK_LVL2_DESC",
3607 "FORCE_GRIP_LVL2_DESC",
3608 "FORCE_LIGHTNING_LVL2_DESC",
3609 "FORCE_SABER_THROW_LVL2_DESC",
3610 "FORCE_SABER_DEFENSE_LVL2_DESC",
3611 "FORCE_SABER_OFFENSE_LVL2_DESC",
3612 };
3613 
3614 char *forcepowerLvl3Desc[NUM_FORCE_POWERS] =
3615 {
3616 "FORCE_HEAL_LVL3_DESC",
3617 "FORCE_JUMP_LVL3_DESC",
3618 "FORCE_SPEED_LVL3_DESC",
3619 "FORCE_PUSH_LVL3_DESC",
3620 "FORCE_PULL_LVL3_DESC",
3621 "FORCE_MIND_TRICK_LVL3_DESC",
3622 "FORCE_GRIP_LVL3_DESC",
3623 "FORCE_LIGHTNING_LVL3_DESC",
3624 "FORCE_SABER_THROW_LVL3_DESC",
3625 "FORCE_SABER_DEFENSE_LVL3_DESC",
3626 "FORCE_SABER_OFFENSE_LVL3_DESC",
3627 };
3628 
3629 /*
3630 ===================
3631 CG_DrawDataPadForceSelect
3632 ===================
3633 */
CG_DrawDataPadForceSelect(void)3634 void CG_DrawDataPadForceSelect( void )
3635 {
3636   	gentity_t	*player = &g_entities[0];
3637 	int		i;
3638 	int		count;
3639 	int		smallIconSize,bigIconSize;
3640 	int		holdX,x,y,pad;
3641 	int		sideLeftIconCnt,sideRightIconCnt;
3642 	int		sideMax,holdCount,iconCnt;
3643 	char	text[1024]={0};
3644 	char	text2[1024]={0};
3645 
3646 	// count the number of powers owned
3647 	count = 0;
3648 
3649 	for (i=0;i<MAX_DPSHOWPOWERS;++i)
3650 	{
3651 		if (ForcePowerDataPad_Valid(i))
3652 		{
3653 			count++;
3654 		}
3655 	}
3656 
3657 	if (count == 0)	// If no force powers, don't display
3658 	{
3659 		return;
3660 	}
3661 
3662 
3663 	// Time to switch new icon colors
3664 	cgi_R_SetColor(colorTable[CT_WHITE]);
3665 
3666 	cg.iconSelectTime = cg.forcepowerSelectTime;
3667 
3668 	sideMax = 3;	// Max number of icons on the side
3669 
3670 	// Calculate how many icons will appear to either side of the center one
3671 	holdCount = count - 1;	// -1 for the center icon
3672 	if (holdCount == 0)			// No icons to either side
3673 	{
3674 		sideLeftIconCnt = 0;
3675 		sideRightIconCnt = 0;
3676 	}
3677 	else if (count > (2*sideMax))	// Go to the max on each side
3678 	{
3679 		sideLeftIconCnt = sideMax;
3680 		sideRightIconCnt = sideMax;
3681 	}
3682 	else							// Less than max, so do the calc
3683 	{
3684 		sideLeftIconCnt = holdCount/2;
3685 		sideRightIconCnt = holdCount - sideLeftIconCnt;
3686 	}
3687 
3688 
3689 	smallIconSize = 30;
3690 	bigIconSize = 60;
3691 	pad = 8;
3692 
3693 	x = 320;
3694 	y = 310;
3695 
3696 	i = cg.DataPadforcepowerSelect - 1;
3697 	if (i < 0)
3698 	{
3699 		i = MAX_DPSHOWPOWERS-1;
3700 	}
3701 
3702 	cgi_R_SetColor(NULL);
3703 	// Work backwards from current icon
3704 	holdX = x - ((bigIconSize/2) + pad + smallIconSize);
3705 	for (iconCnt=1;iconCnt<(sideLeftIconCnt+1);i--)
3706 	{
3707 		if (i < 0)
3708 		{
3709 			i = MAX_DPSHOWPOWERS-1;
3710 		}
3711 
3712 		if (!ForcePowerDataPad_Valid(i))	// Does he have this power?
3713 		{
3714 			continue;
3715 		}
3716 
3717 		++iconCnt;					// Good icon
3718 
3719 		if (force_icons[showDataPadPowers[i]])
3720 		{
3721 			CG_DrawPic( holdX, y, smallIconSize, smallIconSize, force_icons[showDataPadPowers[i]] );
3722 		}
3723 
3724 		// A new force power
3725 		if (((cg_updatedDataPadForcePower1.integer - 1) == showDataPadPowers[i]) ||
3726 			((cg_updatedDataPadForcePower2.integer - 1) == showDataPadPowers[i]) ||
3727 			((cg_updatedDataPadForcePower3.integer - 1) == showDataPadPowers[i]))
3728 		{
3729 			CG_DrawPic( holdX, y, smallIconSize, smallIconSize, cgs.media.DPForcePowerOverlay );
3730 		}
3731 
3732 		if (force_icons[showDataPadPowers[i]])
3733 		{
3734 			holdX -= (smallIconSize+pad);
3735 		}
3736 	}
3737 
3738 	// Current Center Icon
3739 	if (force_icons[showDataPadPowers[cg.DataPadforcepowerSelect]])
3740 	{
3741 
3742 		CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2)), bigIconSize, bigIconSize, force_icons[showDataPadPowers[cg.DataPadforcepowerSelect]] ); //only cache the icon for display
3743 
3744 		// New force power
3745 		if (((cg_updatedDataPadForcePower1.integer - 1) == showDataPadPowers[cg.DataPadforcepowerSelect]) ||
3746 			((cg_updatedDataPadForcePower2.integer - 1) == showDataPadPowers[cg.DataPadforcepowerSelect]) ||
3747 			((cg_updatedDataPadForcePower3.integer - 1) == showDataPadPowers[cg.DataPadforcepowerSelect]))
3748 		{
3749 			CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2)), bigIconSize, bigIconSize, cgs.media.DPForcePowerOverlay );
3750 		}
3751 	}
3752 
3753 
3754 	i = cg.DataPadforcepowerSelect + 1;
3755 	if (i>=MAX_DPSHOWPOWERS)
3756 	{
3757 		i = 0;
3758 	}
3759 
3760 	// Work forwards from current icon
3761 	holdX = x + (bigIconSize/2) + pad;
3762 	for (iconCnt=1;iconCnt<(sideRightIconCnt+1);i++)
3763 	{
3764 		if (i>=MAX_DPSHOWPOWERS)
3765 		{
3766 			i = 0;
3767 		}
3768 
3769 		if (!ForcePowerDataPad_Valid(i))	// Does he have this power?
3770 		{
3771 			continue;
3772 		}
3773 
3774 		++iconCnt;					// Good icon
3775 
3776 		if (force_icons[showDataPadPowers[i]])
3777 		{
3778 			CG_DrawPic( holdX, y, smallIconSize, smallIconSize, force_icons[showDataPadPowers[i]] ); //only cache the icon for display
3779 		}
3780 
3781 		// A new force power
3782 		if (((cg_updatedDataPadForcePower1.integer - 1) == showDataPadPowers[i]) ||
3783 			((cg_updatedDataPadForcePower2.integer - 1) == showDataPadPowers[i]) ||
3784 			((cg_updatedDataPadForcePower3.integer - 1) == showDataPadPowers[i]))
3785 		{
3786 			CG_DrawPic( holdX, y, smallIconSize, smallIconSize, cgs.media.DPForcePowerOverlay ); //only cache the icon for display
3787 		}
3788 
3789 		if (force_icons[showDataPadPowers[i]])
3790 		{
3791 			holdX += (smallIconSize+pad);
3792 		}
3793 	}
3794 
3795 	cgi_SP_GetStringTextString( va("INGAME_%s",forcepowerDesc[cg.DataPadforcepowerSelect]), text, sizeof(text) );
3796 
3797 	if (player->client->ps.forcePowerLevel[cg.DataPadforcepowerSelect]==1)
3798 	{
3799 		cgi_SP_GetStringTextString( va("INGAME_%s",forcepowerLvl1Desc[cg.DataPadforcepowerSelect]), text2, sizeof(text2) );
3800 	}
3801 	else if (player->client->ps.forcePowerLevel[cg.DataPadforcepowerSelect]==2)
3802 	{
3803 		cgi_SP_GetStringTextString( va("INGAME_%s",forcepowerLvl2Desc[cg.DataPadforcepowerSelect]), text2, sizeof(text2) );
3804 	}
3805 	else
3806 	{
3807 		cgi_SP_GetStringTextString( va("INGAME_%s",forcepowerLvl3Desc[cg.DataPadforcepowerSelect]), text2, sizeof(text2) );
3808 	}
3809 
3810 	if (text[0])
3811 	{
3812 
3813 		CG_DisplayBoxedText(70,50,500,300,va("%s%s",text,text2),
3814 													cgs.media.qhFontSmall,
3815 													0.7f,
3816 													colorTable[CT_ICON_BLUE]
3817 													);
3818 	}
3819 }
3820 
3821 // actually, these are pretty pointless so far in CHC, since in TA codebase they were used only so init some HUD
3822 //	function ptrs to allow cinematics in onscreen displays. So far, we don't use those, but here they are anyway...
3823 //
3824 /*	These stupid pragmas don't work, they still give the warning. Forget it, REM the lot.
3825 
3826 #pragma warning ( disable : 4505)		// unreferenced local function has been removed
3827 static int CG_PlayCinematic(const char *name, float x, float y, float w, float h) {
3828   return trap_CIN_PlayCinematic(name, x, y, w, h, CIN_loop);
3829 }
3830 
3831 static void CG_StopCinematic(int handle) {
3832   trap_CIN_StopCinematic(handle);
3833 }
3834 
3835 static void CG_DrawCinematic(int handle, float x, float y, float w, float h) {
3836   trap_CIN_SetExtents(handle, x, y, w, h);
3837   trap_CIN_DrawCinematic(handle);
3838 }
3839 
3840 static void CG_RunCinematicFrame(int handle) {
3841   trap_CIN_RunCinematic(handle);
3842 }
3843 #pragma warning ( default : 4505)
3844 */
3845 
3846 
3847 
3848 
3849