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