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 // cl_cgame.c  -- client system interaction with client game
25 
26 // leave this as first line for PCH reasons...
27 //
28 #include "../server/exe_headers.h"
29 #include "../ui/ui_shared.h"
30 
31 #include "client.h"
32 #include "vmachine.h"
33 #include "qcommon/stringed_ingame.h"
34 #include "sys/sys_loadlib.h"
35 
36 vm_t	cgvm;
37 /*
38 Ghoul2 Insert Start
39 */
40 
41 #if !defined(G2_H_INC)
42 	#include "../ghoul2/G2.h"
43 #endif
44 
45 /*
46 Ghoul2 Insert End
47 */
48 
49 //FIXME: Temp
50 extern void S_UpdateAmbientSet ( const char *name, vec3_t origin );
51 extern int S_AddLocalSet( const char *name, vec3_t listener_origin, vec3_t origin, int entID, int time );
52 extern void AS_ParseSets( void );
53 extern sfxHandle_t AS_GetBModelSound( const char *name, int stage );
54 extern void	AS_AddPrecacheEntry( const char *name );
55 extern menuDef_t *Menus_FindByName(const char *p);
56 
57 extern qboolean R_inPVS( vec3_t p1, vec3_t p2 );
58 
59 void UI_SetActiveMenu( const char* menuname,const char *menuID );
60 
CL_InitCGameVM(void * gameLibrary)61 qboolean CL_InitCGameVM( void *gameLibrary )
62 {
63 	typedef intptr_t SyscallProc( intptr_t, ... );
64 	typedef void DllEntryProc( SyscallProc * );
65 
66 	DllEntryProc *dllEntry = (DllEntryProc *)Sys_LoadFunction( gameLibrary, "dllEntry" );
67 	cgvm.entryPoint = (intptr_t (*)(int,...))Sys_LoadFunction( gameLibrary, "vmMain" );
68 
69 	if ( !cgvm.entryPoint || !dllEntry ) {
70 #ifdef JK2_MODE
71 		const char *gamename = "jospgame";
72 #else
73 		const char *gamename = "jagame";
74 #endif
75 
76 		Com_Printf( "CL_InitCGameVM: client game entry point not found in %s" ARCH_STRING DLL_EXT ": %s\n",
77 					gamename, Sys_LibraryError() );
78 		return qfalse;
79 	}
80 
81 	dllEntry( VM_DllSyscall );
82 
83 	return qtrue;
84 }
85 
86 /*
87 ====================
88 CL_GetGameState
89 ====================
90 */
CL_GetGameState(gameState_t * gs)91 void CL_GetGameState( gameState_t *gs ) {
92 	*gs = cl.gameState;
93 }
94 
95 /*
96 ====================
97 CL_GetGlconfig
98 ====================
99 */
CL_GetGlconfig(glconfig_t * glconfig)100 void CL_GetGlconfig( glconfig_t *glconfig ) {
101 	*glconfig = cls.glconfig;
102 }
103 
104 
105 /*
106 ====================
107 CL_GetUserCmd
108 ====================
109 */
CL_GetUserCmd(int cmdNumber,usercmd_t * ucmd)110 qboolean CL_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {
111 	// cmds[cmdNumber] is the last properly generated command
112 
113 	// can't return anything that we haven't created yet
114 	if ( cmdNumber > cl.cmdNumber ) {
115 		Com_Error( ERR_DROP, "CL_GetUserCmd: %i >= %i", cmdNumber, cl.cmdNumber );
116 	}
117 
118 	// the usercmd has been overwritten in the wrapping
119 	// buffer because it is too far out of date
120 	if ( cmdNumber <= cl.cmdNumber - CMD_BACKUP ) {
121 		return qfalse;
122 	}
123 
124 	*ucmd = cl.cmds[ cmdNumber & CMD_MASK ];
125 
126 	return qtrue;
127 }
128 
CL_GetCurrentCmdNumber(void)129 int CL_GetCurrentCmdNumber( void ) {
130 	return cl.cmdNumber;
131 }
132 
133 
134 /*
135 ====================
136 CL_GetParseEntityState
137 ====================
138 */
139 /*
140 qboolean	CL_GetParseEntityState( int parseEntityNumber, entityState_t *state ) {
141 	// can't return anything that hasn't been parsed yet
142 	if ( parseEntityNumber >= cl.parseEntitiesNum ) {
143 		Com_Error( ERR_DROP, "CL_GetParseEntityState: %i >= %i",
144 			parseEntityNumber, cl.parseEntitiesNum );
145 	}
146 
147 	// can't return anything that has been overwritten in the circular buffer
148 	if ( parseEntityNumber <= cl.parseEntitiesNum - MAX_PARSE_ENTITIES ) {
149 		return qfalse;
150 	}
151 
152 	*state = cl.parseEntities[ parseEntityNumber & ( MAX_PARSE_ENTITIES - 1 ) ];
153 	return qtrue;
154 }
155 */
156 
157 /*
158 ====================
159 CL_GetCurrentSnapshotNumber
160 ====================
161 */
CL_GetCurrentSnapshotNumber(int * snapshotNumber,int * serverTime)162 void	CL_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {
163 	*snapshotNumber = cl.frame.messageNum;
164 	*serverTime = cl.frame.serverTime;
165 }
166 
167 /*
168 ====================
169 CL_GetSnapshot
170 ====================
171 */
CL_GetSnapshot(int snapshotNumber,snapshot_t * snapshot)172 qboolean	CL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
173 	clSnapshot_t	*clSnap;
174 	int				i, count;
175 
176 	if ( snapshotNumber > cl.frame.messageNum ) {
177 		Com_Error( ERR_DROP, "CL_GetSnapshot: snapshotNumber > cl.frame.messageNum" );
178 	}
179 
180 	// if the frame has fallen out of the circular buffer, we can't return it
181 	if ( cl.frame.messageNum - snapshotNumber >= PACKET_BACKUP ) {
182 		return qfalse;
183 	}
184 
185 	// if the frame is not valid, we can't return it
186 	clSnap = &cl.frames[snapshotNumber & PACKET_MASK];
187 	if ( !clSnap->valid ) {
188 		return qfalse;
189 	}
190 
191 	// if the entities in the frame have fallen out of their
192 	// circular buffer, we can't return it
193 	if ( cl.parseEntitiesNum - clSnap->parseEntitiesNum >= MAX_PARSE_ENTITIES ) {
194 		return qfalse;
195 	}
196 
197 	// write the snapshot
198 	snapshot->snapFlags = clSnap->snapFlags;
199 	snapshot->serverCommandSequence = clSnap->serverCommandNum;
200 	snapshot->serverTime = clSnap->serverTime;
201 	memcpy( snapshot->areamask, clSnap->areamask, sizeof( snapshot->areamask ) );
202 	snapshot->cmdNum = clSnap->cmdNum;
203 	snapshot->ps = clSnap->ps;
204 	count = clSnap->numEntities;
205 	if ( count > MAX_ENTITIES_IN_SNAPSHOT ) {
206 		Com_DPrintf( "CL_GetSnapshot: truncated %i entities to %i\n", count, MAX_ENTITIES_IN_SNAPSHOT );
207 		count = MAX_ENTITIES_IN_SNAPSHOT;
208 	}
209 	snapshot->numEntities = count;
210 /*
211 Ghoul2 Insert Start
212 */
213  	for ( i = 0 ; i < count ; i++ )
214 	{
215 
216 		int entNum =  ( clSnap->parseEntitiesNum + i ) & (MAX_PARSE_ENTITIES-1) ;
217 		snapshot->entities[i] = cl.parseEntities[ entNum ];
218 	}
219 /*
220 Ghoul2 Insert End
221 */
222 
223 
224 	// FIXME: configstring changes and server commands!!!
225 
226 	return qtrue;
227 }
228 
229 //bg_public.h won't cooperate in here
230 #define EF_PERMANENT   0x00080000
231 
CL_GetDefaultState(int index,entityState_t * state)232 qboolean CL_GetDefaultState(int index, entityState_t *state)
233 {
234 	if (index < 0 || index >= MAX_GENTITIES)
235 	{
236 		return qfalse;
237 	}
238 
239 	// Is this safe? I think so. But it's still ugly as sin.
240 	if (!(sv.svEntities[index].baseline.eFlags & EF_PERMANENT))
241 //	if (!(cl.entityBaselines[index].eFlags & EF_PERMANENT))
242 	{
243 		return qfalse;
244 	}
245 
246 	*state = sv.svEntities[index].baseline;
247 //	*state = cl.entityBaselines[index];
248 
249 	return qtrue;
250 }
251 
252 extern float cl_mPitchOverride;
253 extern float cl_mYawOverride;
CL_SetUserCmdValue(int userCmdValue,float sensitivityScale,float mPitchOverride,float mYawOverride)254 void CL_SetUserCmdValue( int userCmdValue, float sensitivityScale, float mPitchOverride, float mYawOverride ) {
255 	cl.cgameUserCmdValue = userCmdValue;
256 	cl.cgameSensitivity = sensitivityScale;
257 	cl_mPitchOverride = mPitchOverride;
258 	cl_mYawOverride = mYawOverride;
259 }
260 
261 extern vec3_t cl_overriddenAngles;
262 extern qboolean cl_overrideAngles;
CL_SetUserCmdAngles(float pitchOverride,float yawOverride,float rollOverride)263 void CL_SetUserCmdAngles( float pitchOverride, float yawOverride, float rollOverride ) {
264 	cl_overriddenAngles[PITCH] = pitchOverride;
265 	cl_overriddenAngles[YAW] = yawOverride;
266 	cl_overriddenAngles[ROLL] = rollOverride;
267 	cl_overrideAngles = qtrue;
268 }
269 
CL_AddCgameCommand(const char * cmdName)270 void CL_AddCgameCommand( const char *cmdName ) {
271 	Cmd_AddCommand( cmdName, NULL );
272 }
273 
274 /*
275 =====================
276 CL_ConfigstringModified
277 =====================
278 */
CL_ConfigstringModified(void)279 void CL_ConfigstringModified( void ) {
280 	const char *s;
281 	char		*old;
282 	int			i, index;
283 	const char		*dup;
284 	gameState_t	oldGs;
285 	int			len;
286 
287 	index = atoi( Cmd_Argv(1) );
288 	if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
289 		Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
290 	}
291 	s = Cmd_Argv(2);
292 
293 	old = cl.gameState.stringData + cl.gameState.stringOffsets[ index ];
294 	if ( !strcmp( old, s ) ) {
295 		return;		// unchanged
296 	}
297 
298 	// build the new gameState_t
299 	oldGs = cl.gameState;
300 
301 	memset( &cl.gameState, 0, sizeof( cl.gameState ) );
302 
303 	// leave the first 0 for uninitialized strings
304 	cl.gameState.dataCount = 1;
305 
306 	for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
307 		if ( i == index ) {
308 			dup = s;
309 		} else {
310 			dup = oldGs.stringData + oldGs.stringOffsets[ i ];
311 		}
312 		if ( !dup[0] ) {
313 			continue;		// leave with the default empty string
314 		}
315 
316 		len = strlen( dup );
317 
318 		if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
319 			Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
320 		}
321 
322 		// append it to the gameState string buffer
323 		cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
324 		memcpy( cl.gameState.stringData + cl.gameState.dataCount, dup, len + 1 );
325 		cl.gameState.dataCount += len + 1;
326 	}
327 
328 	if ( index == CS_SYSTEMINFO ) {
329 		// parse serverId and other cvars
330 		CL_SystemInfoChanged();
331 	}
332 
333 }
334 
335 
336 /*
337 ===================
338 CL_GetServerCommand
339 
340 Set up argc/argv for the given command
341 ===================
342 */
CL_GetServerCommand(int serverCommandNumber)343 qboolean CL_GetServerCommand( int serverCommandNumber ) {
344 	char	*s;
345 	const char	*cmd;
346 
347 	// if we have irretrievably lost a reliable command, drop the connection
348 	if ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS ) {
349 		Com_Error( ERR_DROP, "CL_GetServerCommand: a reliable command was cycled out" );
350 		return qfalse;
351 	}
352 
353 	if ( serverCommandNumber > clc.serverCommandSequence ) {
354 		Com_Error( ERR_DROP, "CL_GetServerCommand: requested a command not received" );
355 		return qfalse;
356 	}
357 
358 	s = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ];
359 
360 	Com_DPrintf( "serverCommand: %i : %s\n", serverCommandNumber, s );
361 
362 	Cmd_TokenizeString( s );
363 	cmd = Cmd_Argv(0);
364 
365 	if ( !strcmp( cmd, "disconnect" ) ) {
366 		Com_Error (ERR_DISCONNECT,"Server disconnected\n");
367 	}
368 
369 	if ( !strcmp( cmd, "cs" ) ) {
370 		CL_ConfigstringModified();
371 		// reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString()
372 		Cmd_TokenizeString( s );
373 		return qtrue;
374 	}
375 
376 	// the clientLevelShot command is used during development
377 	// to generate 128*128 screenshots from the intermission
378 	// point of levels for the menu system to use
379 	// we pass it along to the cgame to make apropriate adjustments,
380 	// but we also clear the console and notify lines here
381 	if ( !strcmp( cmd, "clientLevelShot" ) ) {
382 		// don't do it if we aren't running the server locally,
383 		// otherwise malicious remote servers could overwrite
384 		// the existing thumbnails
385 		if ( !com_sv_running->integer ) {
386 			return qfalse;
387 		}
388 		// close the console
389 		Con_Close();
390 		// take a special screenshot next frame
391 		Cbuf_AddText( "wait ; wait ; wait ; wait ; screenshot levelshot\n" );
392 		return qtrue;
393 	}
394 
395 	// we may want to put a "connect to other server" command here
396 
397 	// cgame can now act on the command
398 	return qtrue;
399 }
400 
401 
402 /*
403 ====================
404 CL_CM_LoadMap
405 
406 Just adds default parameters that cgame doesn't need to know about
407 ====================
408 */
CL_CM_LoadMap(const char * mapname,qboolean subBSP)409 void CL_CM_LoadMap( const char *mapname, qboolean subBSP ) {
410 	int		checksum;
411 
412 	CM_LoadMap( mapname, qtrue, &checksum, subBSP );
413 }
414 
415 /*
416 ====================
417 CL_ShutdonwCGame
418 
419 ====================
420 */
CL_ShutdownCGame(void)421 void CL_ShutdownCGame( void ) {
422 	cls.cgameStarted = qfalse;
423 
424 	if ( !cgvm.entryPoint) {
425 		return;
426 	}
427 	VM_Call( CG_SHUTDOWN );
428 
429 //	VM_Free( cgvm );
430 //	cgvm = NULL;
431 }
432 
433 #ifdef JK2_MODE
434 /*
435 ====================
436 CL_ConvertJK2SysCall
437 
438 Converts a JK2 syscall to a JKA syscall
439 ====================
440 */
441 
CL_ConvertJK2SysCall(cgameJK2Import_t import)442 cgameImport_t CL_ConvertJK2SysCall( cgameJK2Import_t import )
443 {
444 	// FIXME: This was a 5-minute slap-hack job in order to test if this really works. CLEAN ME UP! --eez
445 	switch(import)
446 	{
447 		case CG_PRINT_JK2:
448 			return CG_PRINT;
449 			break;
450 		case CG_ERROR_JK2:
451 			return CG_ERROR;
452 			break;
453 		case CG_MILLISECONDS_JK2:
454 			return CG_MILLISECONDS;
455 			break;
456 		case CG_CVAR_REGISTER_JK2:
457 			return CG_CVAR_REGISTER;
458 			break;
459 		case CG_CVAR_UPDATE_JK2:
460 			return CG_CVAR_UPDATE;
461 			break;
462 		case CG_CVAR_SET_JK2:
463 			return CG_CVAR_SET;
464 			break;
465 		case CG_ARGC_JK2:
466 			return CG_ARGC;
467 			break;
468 		case CG_ARGV_JK2:
469 			return CG_ARGV;
470 			break;
471 		case CG_ARGS_JK2:
472 			return CG_ARGS;
473 			break;
474 		case CG_FS_FOPENFILE_JK2:
475 			return CG_FS_FOPENFILE;
476 			break;
477 		case CG_FS_READ_JK2:
478 			return CG_FS_READ;
479 			break;
480 		case CG_FS_WRITE_JK2:
481 			return CG_FS_WRITE;
482 			break;
483 		case CG_FS_FCLOSEFILE_JK2:
484 			return CG_FS_FCLOSEFILE;
485 			break;
486 		case CG_SENDCONSOLECOMMAND_JK2:
487 			return CG_SENDCONSOLECOMMAND;
488 			break;
489 		case CG_ADDCOMMAND_JK2:
490 			return CG_ADDCOMMAND;
491 			break;
492 		case CG_SENDCLIENTCOMMAND_JK2:
493 			return CG_SENDCLIENTCOMMAND;
494 			break;
495 		case CG_UPDATESCREEN_JK2:
496 			return CG_UPDATESCREEN;
497 			break;
498 		case CG_CM_LOADMAP_JK2:
499 			return CG_CM_LOADMAP;
500 			break;
501 		case CG_CM_NUMINLINEMODELS_JK2:
502 			return CG_CM_NUMINLINEMODELS;
503 			break;
504 		case CG_CM_INLINEMODEL_JK2:
505 			return CG_CM_INLINEMODEL;
506 			break;
507 		case CG_CM_TEMPBOXMODEL_JK2:
508 			return CG_CM_TEMPBOXMODEL;
509 			break;
510 		case CG_CM_POINTCONTENTS_JK2:
511 			return CG_CM_POINTCONTENTS;
512 			break;
513 		case CG_CM_TRANSFORMEDPOINTCONTENTS_JK2:
514 			return CG_CM_TRANSFORMEDPOINTCONTENTS;
515 			break;
516 		case CG_CM_BOXTRACE_JK2:
517 			return CG_CM_BOXTRACE;
518 			break;
519 		case CG_CM_TRANSFORMEDBOXTRACE_JK2:
520 			return CG_CM_TRANSFORMEDBOXTRACE;
521 			break;
522 		case CG_CM_MARKFRAGMENTS_JK2:
523 			return CG_CM_MARKFRAGMENTS;
524 			break;
525 		case CG_CM_SNAPPVS_JK2:
526 			return CG_CM_SNAPPVS;
527 			break;
528 		case CG_S_STARTSOUND_JK2:
529 			return CG_S_STARTSOUND;
530 			break;
531 		case CG_S_STARTLOCALSOUND_JK2:
532 			return CG_S_STARTLOCALSOUND;
533 			break;
534 		case CG_S_CLEARLOOPINGSOUNDS_JK2:
535 			return CG_S_CLEARLOOPINGSOUNDS;
536 			break;
537 		case CG_S_ADDLOOPINGSOUND_JK2:
538 			return CG_S_ADDLOOPINGSOUND;
539 			break;
540 		case CG_S_UPDATEENTITYPOSITION_JK2:
541 			return CG_S_UPDATEENTITYPOSITION;
542 			break;
543 		case CG_S_RESPATIALIZE_JK2:
544 			return CG_S_RESPATIALIZE;
545 			break;
546 		case CG_S_REGISTERSOUND_JK2:
547 			return CG_S_REGISTERSOUND;
548 			break;
549 		case CG_S_STARTBACKGROUNDTRACK_JK2:
550 			return CG_S_STARTBACKGROUNDTRACK;
551 			break;
552 		case CG_R_LOADWORLDMAP_JK2:
553 			return CG_R_LOADWORLDMAP;
554 			break;
555 		case CG_R_REGISTERMODEL_JK2:
556 			return CG_R_REGISTERMODEL;
557 			break;
558 		case CG_R_REGISTERSKIN_JK2:
559 			return CG_R_REGISTERSKIN;
560 			break;
561 		case CG_R_REGISTERSHADER_JK2:
562 			return CG_R_REGISTERSHADER;
563 			break;
564 		case CG_R_REGISTERSHADERNOMIP_JK2:
565 			return CG_R_REGISTERSHADERNOMIP;
566 			break;
567 		case CG_R_REGISTERFONT_JK2:
568 			return CG_R_REGISTERFONT;
569 			break;
570 		case CG_R_FONTSTRLENPIXELS_JK2:
571 			return CG_R_FONTSTRLENPIXELS;
572 			break;
573 		case CG_R_FONTSTRLENCHARS_JK2:
574 			return CG_R_FONTSTRLENCHARS;
575 			break;
576 		case CG_R_FONTHEIGHTPIXELS_JK2:
577 			return CG_R_FONTHEIGHTPIXELS;
578 			break;
579 		case CG_R_FONTDRAWSTRING_JK2:
580 			return CG_R_FONTDRAWSTRING;
581 			break;
582 		case CG_LANGUAGE_ISASIAN_JK2:
583 			return CG_LANGUAGE_ISASIAN;
584 			break;
585 		case CG_LANGUAGE_USESSPACES_JK2:
586 			return CG_LANGUAGE_USESSPACES;
587 			break;
588 		case CG_ANYLANGUAGE_READFROMSTRING_JK2:
589 			return CG_ANYLANGUAGE_READFROMSTRING;
590 			break;
591 		case CG_R_CLEARSCENE_JK2:
592 			return CG_R_CLEARSCENE;
593 			break;
594 		case CG_R_ADDREFENTITYTOSCENE_JK2:
595 			return CG_R_ADDREFENTITYTOSCENE;
596 			break;
597 		case CG_R_GETLIGHTING_JK2:
598 			return CG_R_GETLIGHTING;
599 			break;
600 		case CG_R_ADDPOLYTOSCENE_JK2:
601 			return CG_R_ADDPOLYTOSCENE;
602 			break;
603 		case CG_R_ADDLIGHTTOSCENE_JK2:
604 			return CG_R_ADDLIGHTTOSCENE;
605 			break;
606 		case CG_R_RENDERSCENE_JK2:
607 			return CG_R_RENDERSCENE;
608 			break;
609 		case CG_R_SETCOLOR_JK2:
610 			return CG_R_SETCOLOR;
611 			break;
612 		case CG_R_DRAWSTRETCHPIC_JK2:
613 			return CG_R_DRAWSTRETCHPIC;
614 			break;
615 		case CG_R_DRAWSCREENSHOT_JK2:
616 			return CG_R_DRAWSCREENSHOT;
617 			break;
618 		case CG_R_MODELBOUNDS_JK2:
619 			return CG_R_MODELBOUNDS;
620 			break;
621 		case CG_R_LERPTAG_JK2:
622 			return CG_R_LERPTAG;
623 			break;
624 		case CG_R_DRAWROTATEPIC_JK2:
625 			return CG_R_DRAWROTATEPIC;
626 			break;
627 		case CG_R_DRAWROTATEPIC2_JK2:
628 			return CG_R_DRAWROTATEPIC2;
629 			break;
630 		case CG_R_LA_GOGGLES_JK2:
631 			return CG_R_LA_GOGGLES;
632 			break;
633 		case CG_R_SCISSOR_JK2:
634 			return CG_R_SCISSOR;
635 			break;
636 		case CG_GETGLCONFIG_JK2:
637 			return CG_GETGLCONFIG;
638 			break;
639 		case CG_GETGAMESTATE_JK2:
640 			return CG_GETGAMESTATE;
641 			break;
642 		case CG_GETCURRENTSNAPSHOTNUMBER_JK2:
643 			return CG_GETCURRENTSNAPSHOTNUMBER;
644 			break;
645 		case CG_GETSNAPSHOT_JK2:
646 			return CG_GETSNAPSHOT;
647 			break;
648 		case CG_GETSERVERCOMMAND_JK2:
649 			return CG_GETSERVERCOMMAND;
650 			break;
651 		case CG_GETCURRENTCMDNUMBER_JK2:
652 			return CG_GETCURRENTCMDNUMBER;
653 			break;
654 		case CG_GETUSERCMD_JK2:
655 			return CG_GETUSERCMD;
656 			break;
657 		case CG_SETUSERCMDVALUE_JK2:
658 			return CG_SETUSERCMDVALUE;
659 			break;
660 		case CG_SETUSERCMDANGLES_JK2:
661 			return CG_SETUSERCMDANGLES;
662 			break;
663 		case CG_S_UPDATEAMBIENTSET_JK2:
664 			return CG_S_UPDATEAMBIENTSET;
665 			break;
666 		case CG_S_ADDLOCALSET_JK2:
667 			return CG_S_ADDLOCALSET;
668 			break;
669 		case CG_AS_PARSESETS_JK2:
670 			return CG_AS_PARSESETS;
671 			break;
672 		case CG_AS_ADDENTRY_JK2:
673 			return CG_AS_ADDENTRY;
674 			break;
675 		case CG_AS_GETBMODELSOUND_JK2:
676 			return CG_AS_GETBMODELSOUND;
677 			break;
678 		case CG_S_GETSAMPLELENGTH_JK2:
679 			return CG_S_GETSAMPLELENGTH;
680 			break;
681 		case COM_SETORGANGLES_JK2:
682 			return COM_SETORGANGLES;
683 			break;
684 /*
685 Ghoul2 Insert Start
686 */
687 		case CG_G2_LISTBONES_JK2:
688 			return CG_G2_LISTBONES;
689 			break;
690 		case CG_G2_LISTSURFACES_JK2:
691 			return CG_G2_LISTSURFACES;
692 			break;
693 		case CG_G2_HAVEWEGHOULMODELS_JK2:
694 			return CG_G2_HAVEWEGHOULMODELS;
695 			break;
696 		case CG_G2_SETMODELS_JK2:
697 			return CG_G2_SETMODELS;
698 			break;
699 /*
700 Ghoul2 Insert End
701 */
702 
703 		case CG_R_GET_LIGHT_STYLE_JK2:
704 			return CG_R_GET_LIGHT_STYLE;
705 			break;
706 		case CG_R_SET_LIGHT_STYLE_JK2:
707 			return CG_R_SET_LIGHT_STYLE;
708 			break;
709 		case CG_R_GET_BMODEL_VERTS_JK2:
710 			return CG_R_GET_BMODEL_VERTS;
711 			break;
712 		case CG_R_WORLD_EFFECT_COMMAND_JK2:
713 			return CG_R_WORLD_EFFECT_COMMAND;
714 			break;
715 
716 		case CG_CIN_PLAYCINEMATIC_JK2:
717 			return CG_CIN_PLAYCINEMATIC;
718 			break;
719 		case CG_CIN_STOPCINEMATIC_JK2:
720 			return CG_CIN_STOPCINEMATIC;
721 			break;
722 		case CG_CIN_RUNCINEMATIC_JK2:
723 			return CG_CIN_RUNCINEMATIC;
724 			break;
725 		case CG_CIN_DRAWCINEMATIC_JK2:
726 			return CG_CIN_DRAWCINEMATIC;
727 			break;
728 		case CG_CIN_SETEXTENTS_JK2:
729 			return CG_CIN_SETEXTENTS;
730 			break;
731 		case CG_Z_MALLOC_JK2:
732 			return CG_Z_MALLOC;
733 			break;
734 		case CG_Z_FREE_JK2:
735 			return CG_Z_FREE;
736 			break;
737 		case CG_UI_MENU_RESET_JK2:
738 			return CG_UI_MENU_RESET;
739 			break;
740 		case CG_UI_MENU_NEW_JK2:
741 			return CG_UI_MENU_NEW;
742 			break;
743 		case CG_UI_PARSE_INT_JK2:
744 			return CG_UI_PARSE_INT;
745 			break;
746 		case CG_UI_PARSE_STRING_JK2:
747 			return CG_UI_PARSE_STRING;
748 			break;
749 		case CG_UI_PARSE_FLOAT_JK2:
750 			return CG_UI_PARSE_FLOAT;
751 			break;
752 		case CG_UI_STARTPARSESESSION_JK2:
753 			return CG_UI_STARTPARSESESSION;
754 			break;
755 		case CG_UI_ENDPARSESESSION_JK2:
756 			return CG_UI_ENDPARSESESSION;
757 			break;
758 		case CG_UI_PARSEEXT_JK2:
759 			return CG_UI_PARSEEXT;
760 			break;
761 		case CG_UI_MENUPAINT_ALL_JK2:
762 			return CG_UI_MENUPAINT_ALL;
763 			break;
764 		case CG_UI_STRING_INIT_JK2:
765 			return CG_UI_STRING_INIT;
766 			break;
767 		case CG_UI_GETMENUINFO_JK2:
768 			return CG_UI_GETMENUINFO;
769 			break;
770 		case CG_SP_REGISTER_JK2:
771 			return CG_SP_REGISTER;
772 			break;
773 		case CG_SP_GETSTRINGTEXT_JK2:
774 			return CG_SP_GETSTRINGTEXT;
775 			break;
776 		case CG_SP_GETSTRINGTEXTSTRING_JK2:
777 			// Both of these do the same thing --eez
778 			return CG_SP_GETSTRINGTEXTSTRING;
779 			break;
780 		case CG_UI_GETITEMTEXT_JK2:
781 			return CG_UI_GETITEMTEXT;
782 			break;
783 		case CG_ANYLANGUAGE_READFROMSTRING2_JK2:
784 			return CG_ANYLANGUAGE_READFROMSTRING2;
785 			break;
786 		case CG_OPENJK_MENU_PAINT_JK2:
787 			return CG_OPENJK_MENU_PAINT;
788 			break;
789 		case CG_OPENJK_GETMENU_BYNAME_JK2:
790 			return CG_OPENJK_GETMENU_BYNAME;
791 			break;
792 	}
793 	return (cgameImport_t)-1;
794 }
795 
796 #endif
797 /*
798 ====================
799 CL_CgameSystemCalls
800 
801 The cgame module is making a system call
802 ====================
803 */
804 void CM_SnapPVS(vec3_t origin,byte *buffer);
805 extern void		Menu_Paint(menuDef_t *menu, qboolean forcePaint);
806 extern menuDef_t *Menus_FindByName(const char *p);
CL_CgameSystemCalls(intptr_t * args)807 intptr_t CL_CgameSystemCalls( intptr_t *args ) {
808 #ifdef JK2_MODE
809 	args[0] = (intptr_t)CL_ConvertJK2SysCall((cgameJK2Import_t)args[0]);
810 #endif
811 	switch( args[0] ) {
812 	case CG_PRINT:
813 		Com_Printf( "%s", VMA(1) );
814 		return 0;
815 	case CG_ERROR:
816 		Com_Error( ERR_DROP, S_COLOR_RED"%s", VMA(1) );
817 		return 0;
818 	case CG_MILLISECONDS:
819 		return Sys_Milliseconds();
820 	case CG_CVAR_REGISTER:
821 		Cvar_Register( (vmCvar_t *) VMA(1), (const char *) VMA(2), (const char *) VMA(3), args[4] );
822 		return 0;
823 	case CG_CVAR_UPDATE:
824 		Cvar_Update( (vmCvar_t *) VMA(1) );
825 		return 0;
826 	case CG_CVAR_SET:
827 		Cvar_Set( (const char *) VMA(1), (const char *) VMA(2) );
828 		return 0;
829 	case CG_ARGC:
830 		return Cmd_Argc();
831 	case CG_ARGV:
832 		Cmd_ArgvBuffer( args[1], (char *) VMA(2), args[3] );
833 		return 0;
834 	case CG_ARGS:
835 		Cmd_ArgsBuffer( (char *) VMA(1), args[2] );
836 		return 0;
837 	case CG_FS_FOPENFILE:
838 		return FS_FOpenFileByMode( (const char *) VMA(1), (int *) VMA(2), (fsMode_t) args[3] );
839 	case CG_FS_READ:
840 		FS_Read( VMA(1), args[2], args[3] );
841 		return 0;
842 	case CG_FS_WRITE:
843 		FS_Write( VMA(1), args[2], args[3] );
844 		return 0;
845 	case CG_FS_FCLOSEFILE:
846 		FS_FCloseFile( args[1] );
847 		return 0;
848 	case CG_SENDCONSOLECOMMAND:
849 		Cbuf_AddText( (const char *) VMA(1) );
850 		return 0;
851 	case CG_ADDCOMMAND:
852 		CL_AddCgameCommand( (const char *) VMA(1) );
853 		return 0;
854 	case CG_SENDCLIENTCOMMAND:
855 		CL_AddReliableCommand( (const char *) VMA(1) );
856 		return 0;
857 	case CG_UPDATESCREEN:
858 		// this is used during lengthy level loading, so pump message loop
859 		Com_EventLoop();	// FIXME: if a server restarts here, BAD THINGS HAPPEN!
860 		SCR_UpdateScreen();
861 		return 0;
862 	case CG_RMG_INIT:
863 		return 0;
864 	case CG_CM_REGISTER_TERRAIN:
865 		return 0;
866 
867 	case CG_RE_INIT_RENDERER_TERRAIN:
868 		return 0;
869 
870 	case CG_CM_LOADMAP:
871 		CL_CM_LoadMap( (const char *) VMA(1), (qboolean)(args[2] != 0) );
872 		return 0;
873 	case CG_CM_NUMINLINEMODELS:
874 		return CM_NumInlineModels();
875 	case CG_CM_INLINEMODEL:
876 		return CM_InlineModel( args[1] );
877 	case CG_CM_TEMPBOXMODEL:
878 		return CM_TempBoxModel( (const float *) VMA(1), (const float *) VMA(2) );//, (int) VMA(3) );
879 	case CG_CM_POINTCONTENTS:
880 		return CM_PointContents( (float *)VMA(1), args[2] );
881 	case CG_CM_TRANSFORMEDPOINTCONTENTS:
882 		return CM_TransformedPointContents( (const float *) VMA(1), args[2], (const float *) VMA(3), (const float *) VMA(4) );
883 	case CG_CM_BOXTRACE:
884 		CM_BoxTrace( (trace_t *) VMA(1), (const float *) VMA(2), (const float *) VMA(3), (const float *) VMA(4), (const float *) VMA(5), args[6], args[7] );
885 		return 0;
886 	case CG_CM_TRANSFORMEDBOXTRACE:
887 		CM_TransformedBoxTrace( (trace_t *) VMA(1), (const float *) VMA(2), (const float *) VMA(3), (const float *) VMA(4), (const float *) VMA(5), args[6], args[7], (const float *) VMA(8), (const float *) VMA(9) );
888 		return 0;
889 	case CG_CM_MARKFRAGMENTS:
890 		return re.MarkFragments( args[1], (float(*)[3]) VMA(2), (const float *) VMA(3), args[4], (float *) VMA(5), args[6], (markFragment_t *) VMA(7) );
891 	case CG_CM_SNAPPVS:
892 		CM_SnapPVS((float(*))VMA(1),(byte *) VMA(2));
893 		return 0;
894 	case CG_S_STOPSOUNDS:
895 		S_StopSounds( );
896 		return 0;
897 
898 	case CG_S_STARTSOUND:
899 		// stops an ERR_DROP internally if called illegally from game side, but note that it also gets here
900 		//	legally during level start where normally the internal s_soundStarted check would return. So ok to hit this.
901 		if (!cls.cgameStarted) {
902 			return 0;
903 		}
904 		S_StartSound( (float *) VMA(1), args[2], (soundChannel_t)args[3], args[4] );
905 		return 0;
906 	case CG_S_UPDATEAMBIENTSET:
907 		// stops an ERR_DROP internally if called illegally from game side, but note that it also gets here
908 		//	legally during level start where normally the internal s_soundStarted check would return. So ok to hit this.
909 		if (!cls.cgameStarted) {
910 			return 0;
911 		}
912 		S_UpdateAmbientSet( (const char *) VMA(1), (float *) VMA(2) );
913 		return 0;
914 	case CG_S_ADDLOCALSET:
915 		return S_AddLocalSet( (const char *) VMA(1), (float *) VMA(2), (float *) VMA(3), args[4], args[5] );
916 	case CG_AS_PARSESETS:
917 		AS_ParseSets();
918 		return 0;
919 	case CG_AS_ADDENTRY:
920 		AS_AddPrecacheEntry( (const char *) VMA(1) );
921 		return 0;
922 	case CG_AS_GETBMODELSOUND:
923 		return AS_GetBModelSound( (const char *) VMA(1), args[2] );
924 	case CG_S_STARTLOCALSOUND:
925 		// stops an ERR_DROP internally if called illegally from game side, but note that it also gets here
926 		//	legally during level start where normally the internal s_soundStarted check would return. So ok to hit this.
927 		if (!cls.cgameStarted) {
928 			return 0;
929 		}
930 		S_StartLocalSound( args[1], args[2] );
931 		return 0;
932 	case CG_S_CLEARLOOPINGSOUNDS:
933 		S_ClearLoopingSounds();
934 		return 0;
935 	case CG_S_ADDLOOPINGSOUND:
936 		// stops an ERR_DROP internally if called illegally from game side, but note that it also gets here
937 		//	legally during level start where normally the internal s_soundStarted check would return. So ok to hit this.
938 		if (!cls.cgameStarted) {
939 			return 0;
940 		}
941 		S_AddLoopingSound( args[1], (const float *) VMA(2), (const float *) VMA(3), args[4], (soundChannel_t)args[5] );
942 		return 0;
943 	case CG_S_UPDATEENTITYPOSITION:
944 		S_UpdateEntityPosition( args[1], (const float *) VMA(2) );
945 		return 0;
946 	case CG_S_RESPATIALIZE:
947 		S_Respatialize( args[1], (const float *) VMA(2), (float(*)[3]) VMA(3), (qboolean)(args[4] != 0) );
948 		return 0;
949 	case CG_S_REGISTERSOUND:
950 		return S_RegisterSound( (const char *) VMA(1) );
951 	case CG_S_STARTBACKGROUNDTRACK:
952 		S_StartBackgroundTrack( (const char *) VMA(1), (const char *) VMA(2), (qboolean)(args[3] != 0) );
953 		return 0;
954 	case CG_S_GETSAMPLELENGTH:
955 		return S_GetSampleLengthInMilliSeconds(  args[1]);
956 	case CG_R_LOADWORLDMAP:
957 		re.LoadWorld( (const char *) VMA(1) );
958 		return 0;
959 	case CG_R_REGISTERMODEL:
960 		return re.RegisterModel( (const char *) VMA(1) );
961 	case CG_R_REGISTERSKIN:
962 		return re.RegisterSkin( (const char *) VMA(1) );
963 	case CG_R_REGISTERSHADER:
964 		return re.RegisterShader( (const char *) VMA(1) );
965 	case CG_R_REGISTERSHADERNOMIP:
966 		return re.RegisterShaderNoMip( (const char *) VMA(1) );
967 	case CG_R_REGISTERFONT:
968 		return re.RegisterFont( (const char *) VMA(1) );
969 	case CG_R_FONTSTRLENPIXELS:
970 		return re.Font_StrLenPixels( (const char *) VMA(1), args[2], VMF(3) );
971 	case CG_R_FONTSTRLENCHARS:
972 		return re.Font_StrLenChars( (const char *) VMA(1) );
973 	case CG_R_FONTHEIGHTPIXELS:
974 		return re.Font_HeightPixels( args[1], VMF(2) );
975 	case CG_R_FONTDRAWSTRING:
976 		re.Font_DrawString(args[1],args[2], (const char *) VMA(3), (float*)args[4], args[5], args[6], VMF(7));
977 		return 0;
978 	case CG_LANGUAGE_ISASIAN:
979 		return re.Language_IsAsian();
980 	case CG_LANGUAGE_USESSPACES:
981 		return re.Language_UsesSpaces();
982 	case CG_ANYLANGUAGE_READFROMSTRING:
983 		return re.AnyLanguage_ReadCharFromString( (char *) VMA(1), (int *) VMA(2), (qboolean *) VMA(3) );
984 	case CG_ANYLANGUAGE_READFROMSTRING2:
985 		return re.AnyLanguage_ReadCharFromString2( (char **) VMA(1), (qboolean *) VMA(3) );
986 	case CG_R_SETREFRACTIONPROP:
987 		*(re.tr_distortionAlpha()) = VMF(1);
988 		*(re.tr_distortionStretch()) = VMF(2);
989 		*(re.tr_distortionPrePost()) = (qboolean)args[3];
990 		*(re.tr_distortionNegate()) = (qboolean)args[4];
991 		return 0;
992 	case CG_R_CLEARSCENE:
993 		re.ClearScene();
994 		return 0;
995 	case CG_R_ADDREFENTITYTOSCENE:
996 		re.AddRefEntityToScene( (const refEntity_t *) VMA(1) );
997 		return 0;
998 
999 	case CG_R_INPVS:
1000 		return re.R_inPVS((float *) VMA(1), (float *) VMA(2));
1001 
1002 	case CG_R_GETLIGHTING:
1003 		return re.GetLighting( (const float * ) VMA(1), (float *) VMA(2), (float *) VMA(3), (float *) VMA(4) );
1004 	case CG_R_ADDPOLYTOSCENE:
1005 		re.AddPolyToScene( args[1], args[2], (const polyVert_t *) VMA(3) );
1006 		return 0;
1007 	case CG_R_ADDLIGHTTOSCENE:
1008 		re.AddLightToScene( (const float *) VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
1009 		return 0;
1010 	case CG_R_RENDERSCENE:
1011 		re.RenderScene( (const refdef_t *) VMA(1) );
1012 		return 0;
1013 	case CG_R_SETCOLOR:
1014 		re.SetColor( (const float *) VMA(1) );
1015 		return 0;
1016 	case CG_R_DRAWSTRETCHPIC:
1017 		re.DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] );
1018 		return 0;
1019 		// The below was commented out for whatever reason... /me shrugs --eez
1020 	case CG_R_DRAWSCREENSHOT:
1021 		re.DrawStretchRaw( VMF(1), VMF(2), VMF(3), VMF(4), SG_SCR_WIDTH, SG_SCR_HEIGHT, SCR_GetScreenshot(0), 0, qtrue);
1022 		return 0;
1023 	case CG_R_MODELBOUNDS:
1024 		re.ModelBounds( args[1], (float *) VMA(2), (float *) VMA(3) );
1025 		return 0;
1026 	case CG_R_LERPTAG:
1027 		re.LerpTag( (orientation_t *) VMA(1), args[2], args[3], args[4], VMF(5), (const char *) VMA(6) );
1028 		return 0;
1029 	case CG_R_DRAWROTATEPIC:
1030 		re.DrawRotatePic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), VMF(9), args[10] );
1031 		return 0;
1032 	case CG_R_DRAWROTATEPIC2:
1033 		re.DrawRotatePic2( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), VMF(9), args[10] );
1034 		return 0;
1035 	case CG_R_SETRANGEFOG:
1036 		re.SetRangedFog( VMF( 1 ) );
1037 		return 0;
1038 	case CG_R_LA_GOGGLES:
1039 		re.LAGoggles();
1040 		return 0;
1041 	case CG_R_SCISSOR:
1042 		re.Scissor( VMF(1), VMF(2), VMF(3), VMF(4));
1043 		return 0;
1044 	case CG_GETGLCONFIG:
1045 		CL_GetGlconfig( (glconfig_t *) VMA(1) );
1046 		return 0;
1047 	case CG_GETGAMESTATE:
1048 		CL_GetGameState( (gameState_t *) VMA(1) );
1049 		return 0;
1050 	case CG_GETCURRENTSNAPSHOTNUMBER:
1051 		CL_GetCurrentSnapshotNumber( (int *) VMA(1), (int *) VMA(2) );
1052 		return 0;
1053 	case CG_GETSNAPSHOT:
1054 		return CL_GetSnapshot( args[1], (snapshot_t *) VMA(2) );
1055 
1056 	case CG_GETDEFAULTSTATE:
1057 		return CL_GetDefaultState(args[1], (entityState_t *)VMA(2));
1058 
1059 	case CG_GETSERVERCOMMAND:
1060 		return CL_GetServerCommand( args[1] );
1061 	case CG_GETCURRENTCMDNUMBER:
1062 		return CL_GetCurrentCmdNumber();
1063 	case CG_GETUSERCMD:
1064 		return CL_GetUserCmd( args[1], (usercmd_s *) VMA(2) );
1065 	case CG_SETUSERCMDVALUE:
1066 		CL_SetUserCmdValue( args[1], VMF(2), VMF(3), VMF(4) );
1067 		return 0;
1068 	case CG_SETUSERCMDANGLES:
1069 		CL_SetUserCmdAngles( VMF(1), VMF(2), VMF(3) );
1070 		return 0;
1071 	case COM_SETORGANGLES:
1072 		Com_SetOrgAngles((float *)VMA(1),(float *)VMA(2));
1073 		return 0;
1074 /*
1075 Ghoul2 Insert Start
1076 */
1077 
1078 	case CG_G2_LISTSURFACES:
1079 		re.G2API_ListSurfaces( (CGhoul2Info *) VMA(1) );
1080 		return 0;
1081 
1082 	case CG_G2_LISTBONES:
1083 		re.G2API_ListBones( (CGhoul2Info *) VMA(1), args[2]);
1084 		return 0;
1085 
1086 	case CG_G2_HAVEWEGHOULMODELS:
1087 		return re.G2API_HaveWeGhoul2Models( *((CGhoul2Info_v *)VMA(1)) );
1088 
1089 	case CG_G2_SETMODELS:
1090 		re.G2API_SetGhoul2ModelIndexes( *((CGhoul2Info_v *)VMA(1)),(qhandle_t *)VMA(2),(qhandle_t *)VMA(3));
1091 		return 0;
1092 
1093 /*
1094 Ghoul2 Insert End
1095 */
1096 
1097 	case CG_R_GET_LIGHT_STYLE:
1098 		re.GetLightStyle(args[1], (byte*) VMA(2) );
1099 		return 0;
1100 	case CG_R_SET_LIGHT_STYLE:
1101 		re.SetLightStyle(args[1], args[2] );
1102 		return 0;
1103 
1104 	case CG_R_GET_BMODEL_VERTS:
1105 		re.GetBModelVerts( args[1], (float (*)[3])VMA(2), (float *)VMA(3) );
1106 		return 0;
1107 
1108 	case CG_R_WORLD_EFFECT_COMMAND:
1109 		re.WorldEffectCommand( (const char *) VMA(1) );
1110 		return 0;
1111 
1112 	case CG_CIN_PLAYCINEMATIC:
1113 	  return CIN_PlayCinematic( (const char *) VMA(1), args[2], args[3], args[4], args[5], args[6], (const char *) VMA(7));
1114 
1115 	case CG_CIN_STOPCINEMATIC:
1116 	  return CIN_StopCinematic(args[1]);
1117 
1118 	case CG_CIN_RUNCINEMATIC:
1119 	  return CIN_RunCinematic(args[1]);
1120 
1121 	case CG_CIN_DRAWCINEMATIC:
1122 	  CIN_DrawCinematic(args[1]);
1123 	  return 0;
1124 
1125 	case CG_CIN_SETEXTENTS:
1126 	  CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]);
1127 	  return 0;
1128 
1129 	case CG_Z_MALLOC:
1130 		return (intptr_t)Z_Malloc(args[1], (memtag_t) args[2], qfalse);
1131 
1132 	case CG_Z_FREE:
1133 		Z_Free((void *) VMA(1));
1134 		return 0;
1135 
1136 	case CG_UI_SETACTIVE_MENU:
1137 		UI_SetActiveMenu((const char *) VMA(1),NULL);
1138 		return 0;
1139 
1140 	case CG_UI_MENU_OPENBYNAME:
1141 		Menus_OpenByName((const char *) VMA(1));
1142 		return 0;
1143 
1144 	case CG_UI_MENU_RESET:
1145 		Menu_Reset();
1146 		return 0;
1147 
1148 	case CG_UI_MENU_NEW:
1149 		Menu_New((char *) VMA(1));
1150 		return 0;
1151 
1152 	case CG_UI_PARSE_INT:
1153 		PC_ParseInt((int *) VMA(1));
1154 		return 0;
1155 
1156 	case CG_UI_PARSE_STRING:
1157 		PC_ParseString((const char **) VMA(1));
1158 		return 0;
1159 
1160 	case CG_UI_PARSE_FLOAT:
1161 		PC_ParseFloat((float *) VMA(1));
1162 		return 0;
1163 
1164 	case CG_UI_STARTPARSESESSION:
1165 		return(PC_StartParseSession((char *) VMA(1),(char **) VMA(2)));
1166 
1167 	case CG_UI_ENDPARSESESSION:
1168 		PC_EndParseSession((char *) VMA(1));
1169 		return 0;
1170 
1171 	case CG_UI_PARSEEXT:
1172 		char **holdPtr;
1173 
1174 		holdPtr = (char **) VMA(1);
1175 
1176 		if(!holdPtr)
1177 		{
1178 			Com_Error(ERR_FATAL, "CG_UI_PARSEEXT: NULL holdPtr");
1179 		}
1180 
1181 		*holdPtr = PC_ParseExt();
1182 		return 0;
1183 
1184 	case CG_UI_MENUCLOSE_ALL:
1185 		Menus_CloseAll();
1186 		return 0;
1187 
1188 	case CG_UI_MENUPAINT_ALL:
1189 		Menu_PaintAll();
1190 		return 0;
1191 
1192 	case CG_OPENJK_MENU_PAINT:
1193 		Menu_Paint( (menuDef_t *)VMA(1), (qboolean)(args[2] != 0) );
1194 		return 0;
1195 
1196 	case CG_OPENJK_GETMENU_BYNAME:
1197 		return (intptr_t)Menus_FindByName( (const char *)VMA(1) );
1198 
1199 	case CG_UI_STRING_INIT:
1200 		String_Init();
1201 		return 0;
1202 
1203 	case CG_UI_GETMENUINFO:
1204 		menuDef_t *menu;
1205 		int		*xPos,*yPos,*w,*h,result;
1206 #ifndef JK2_MODE
1207 		menu = Menus_FindByName((char *) VMA(1));	// Get menu
1208 		if (menu)
1209 		{
1210 			xPos = (int *) VMA(2);
1211 			*xPos = (int) menu->window.rect.x;
1212 			yPos = (int *) VMA(3);
1213 			*yPos = (int) menu->window.rect.y;
1214 			w = (int *) VMA(4);
1215 			*w = (int) menu->window.rect.w;
1216 			h = (int *) VMA(5);
1217 			*h = (int) menu->window.rect.h;
1218 			result = qtrue;
1219 		}
1220 		else
1221 		{
1222 			result = qfalse;
1223 		}
1224 
1225 		return result;
1226 #else
1227 		menu = Menus_FindByName((char *) VMA(1));	// Get menu
1228 		if (menu)
1229 		{
1230 			xPos = (int *) VMA(2);
1231 			*xPos = (int) menu->window.rect.x;
1232 			yPos = (int *) VMA(3);
1233 			*yPos = (int) menu->window.rect.y;
1234 			result = qtrue;
1235 		}
1236 		else
1237 		{
1238 			result = qfalse;
1239 		}
1240 
1241 		return result;
1242 #endif
1243 		break;
1244 
1245 	case CG_UI_GETITEMTEXT:
1246 		itemDef_t *item;
1247 		menu = Menus_FindByName((char *) VMA(1));	// Get menu
1248 
1249 		if (menu)
1250 		{
1251 			item = (itemDef_s *) Menu_FindItemByName((menuDef_t *) menu, (char *) VMA(2));
1252 			if (item)
1253 			{
1254 				Q_strncpyz( (char *) VMA(3), item->text, 256 );
1255 				result = qtrue;
1256 			}
1257 			else
1258 			{
1259 				result = qfalse;
1260 			}
1261 		}
1262 		else
1263 		{
1264 			result = qfalse;
1265 		}
1266 
1267 		return result;
1268 
1269 	case CG_UI_GETITEMINFO:
1270 		menu = Menus_FindByName((char *) VMA(1));	// Get menu
1271 
1272 		if (menu)
1273 		{
1274 			qhandle_t *background;
1275 
1276 			item = (itemDef_s *) Menu_FindItemByName((menuDef_t *) menu, (char *) VMA(2));
1277 			if (item)
1278 			{
1279 				xPos = (int *) VMA(3);
1280 				*xPos = (int) item->window.rect.x;
1281 				yPos = (int *) VMA(4);
1282 				*yPos = (int) item->window.rect.y;
1283 				w = (int *) VMA(5);
1284 				*w = (int) item->window.rect.w;
1285 				h = (int *) VMA(6);
1286 				*h = (int) item->window.rect.h;
1287 
1288 				vec4_t *color;
1289 
1290 				color = (vec4_t *) VMA(7);
1291 				if (!color)
1292 				{
1293 					return qfalse;
1294 				}
1295 
1296 				(*color)[0] = (float) item->window.foreColor[0];
1297 				(*color)[1] = (float) item->window.foreColor[1];
1298 				(*color)[2] = (float) item->window.foreColor[2];
1299 				(*color)[3] = (float) item->window.foreColor[3];
1300 				background = (qhandle_t *) VMA(8);
1301 				if (!background)
1302 				{
1303 					return qfalse;
1304 				}
1305 				*background = item->window.background;
1306 
1307 				result = qtrue;
1308 			}
1309 			else
1310 			{
1311 				result = qfalse;
1312 			}
1313 		}
1314 		else
1315 		{
1316 			result = qfalse;
1317 		}
1318 
1319 		return result;
1320 
1321 #ifdef JK2_MODE
1322 	case CG_SP_GETSTRINGTEXTSTRING:
1323 	case CG_SP_GETSTRINGTEXT:
1324 		const char* text;
1325 
1326 		assert(VMA(1));
1327 //		assert(VMA(2));	// can now pass in NULL to just query the size
1328 
1329 		if (args[0] == CG_SP_GETSTRINGTEXT)
1330 		{
1331 			text = JK2SP_GetStringText( args[1] );
1332 		}
1333 		else
1334 		{
1335 			text = JK2SP_GetStringTextString( (const char *) VMA(1) );
1336 		}
1337 
1338 		if (VMA(2))	// only if dest buffer supplied...
1339 		{
1340 			if ( text[0] )
1341 			{
1342 				Q_strncpyz( (char *) VMA(2), text, args[3] );
1343 			}
1344 			else
1345 			{
1346 				Q_strncpyz( (char *) VMA(2), "??", args[3] );
1347 			}
1348 		}
1349 		return strlen(text);
1350 
1351 	case CG_SP_REGISTER:
1352 		return JK2SP_Register((const char *)VMA(1), args[2] ? (SP_REGISTER_MENU | SP_REGISTER_REQUIRED) : SP_REGISTER_CLIENT);
1353 #else
1354 	case CG_SP_GETSTRINGTEXTSTRING:
1355 		const char* text;
1356 
1357 		assert(VMA(1));
1358 		text = SE_GetString( (const char *) VMA(1) );
1359 
1360 		if (VMA(2))	// only if dest buffer supplied...
1361 		{
1362 			if ( text[0] )
1363 			{
1364 				Q_strncpyz( (char *) VMA(2), text, args[3] );
1365 			}
1366 			else
1367 			{
1368 				Com_sprintf( (char *) VMA(2), args[3], "??%s", VMA(1) );
1369 			}
1370 		}
1371 		return strlen(text);
1372 #endif
1373 
1374 	default:
1375 		Com_Error( ERR_DROP, "Bad cgame system trap: %ld", (long int) args[0] );
1376 	}
1377 	return 0;
1378 }
1379 
1380 
1381 /*
1382 ====================
1383 CL_InitCGame
1384 
1385 Should only be called by CL_StartHunkUsers
1386 ====================
1387 */
1388 extern qboolean Sys_LowPhysicalMemory();
CL_InitCGame(void)1389 void CL_InitCGame( void ) {
1390 	const char			*info;
1391 	const char			*mapname;
1392 	//int		t1, t2;
1393 
1394 	//t1 = Sys_Milliseconds();
1395 
1396 	// put away the console
1397 	Con_Close();
1398 
1399 	// find the current mapname
1400 	info = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];
1401 	mapname = Info_ValueForKey( info, "mapname" );
1402 	Com_sprintf( cl.mapname, sizeof( cl.mapname ), "maps/%s.bsp", mapname );
1403 
1404 	cls.state = CA_LOADING;
1405 
1406 	// init for this gamestate
1407 	VM_Call( CG_INIT, clc.serverCommandSequence );
1408 
1409 	// reset any CVAR_CHEAT cvars registered by cgame
1410 	if ( !cl_connectedToCheatServer )
1411 		Cvar_SetCheatState();
1412 
1413 	// we will send a usercmd this frame, which
1414 	// will cause the server to send us the first snapshot
1415 	cls.state = CA_PRIMED;
1416 
1417 	//t2 = Sys_Milliseconds();
1418 
1419 	//Com_Printf( "CL_InitCGame: %5.2f seconds\n", (t2-t1)/1000.0 );
1420 	// have the renderer touch all its images, so they are present
1421 	// on the card even if the driver does deferred loading
1422 	re.EndRegistration();
1423 
1424 	// make sure everything is paged in
1425 //	if (!Sys_LowPhysicalMemory())
1426 	{
1427 		Com_TouchMemory();
1428 	}
1429 
1430 	// clear anything that got printed
1431 	Con_ClearNotify ();
1432 }
1433 
1434 
1435 /*
1436 ====================
1437 CL_GameCommand
1438 
1439 See if the current console command is claimed by the cgame
1440 ====================
1441 */
CL_GameCommand(void)1442 qboolean CL_GameCommand( void ) {
1443 	if ( cls.state != CA_ACTIVE ) {
1444 		return qfalse;
1445 	}
1446 
1447 	return (qboolean)(VM_Call( CG_CONSOLE_COMMAND ) != 0);
1448 }
1449 
1450 
1451 
1452 /*
1453 =====================
1454 CL_CGameRendering
1455 =====================
1456 */
CL_CGameRendering(stereoFrame_t stereo)1457 void CL_CGameRendering( stereoFrame_t stereo ) {
1458 #if 0
1459 	if ( cls.state == CA_ACTIVE ) {
1460 		static int counter;
1461 
1462 		if ( ++counter == 40 ) {
1463 			VM_Debug( 2 );
1464 		}
1465 	}
1466 #endif
1467 	int timei=cl.serverTime;
1468 	if (timei>60)
1469 	{
1470 		timei-=0;
1471 	}
1472 	re.G2API_SetTime(cl.serverTime,G2T_CG_TIME);
1473 	VM_Call( CG_DRAW_ACTIVE_FRAME,timei, stereo, qfalse );
1474 //	VM_Debug( 0 );
1475 }
1476 
1477 
1478 /*
1479 =================
1480 CL_AdjustTimeDelta
1481 
1482 Adjust the clients view of server time.
1483 
1484 We attempt to have cl.serverTime exactly equal the server's view
1485 of time plus the timeNudge, but with variable latencies over
1486 the internet it will often need to drift a bit to match conditions.
1487 
1488 Our ideal time would be to have the adjusted time aproach, but not pass,
1489 the very latest snapshot.
1490 
1491 Adjustments are only made when a new snapshot arrives, which keeps the
1492 adjustment process framerate independent and prevents massive overadjustment
1493 during times of significant packet loss.
1494 =================
1495 */
1496 
1497 #define	RESET_TIME	300
1498 
CL_AdjustTimeDelta(void)1499 void CL_AdjustTimeDelta( void ) {
1500 /*
1501 	cl.newSnapshots = qfalse;
1502 	// if the current time is WAY off, just correct to the current value
1503 	if ( cls.realtime + cl.serverTimeDelta < cl.frame.serverTime - RESET_TIME
1504 		|| cls.realtime + cl.serverTimeDelta > cl.frame.serverTime + RESET_TIME  ) {
1505 		cl.serverTimeDelta = cl.frame.serverTime - cls.realtime;
1506 		cl.oldServerTime = cl.frame.serverTime;
1507 		if ( cl_showTimeDelta->integer ) {
1508 			Com_Printf( "<RESET> " );
1509 		}
1510 	}
1511 
1512 	// if any of the frames between this and the previous snapshot
1513 	// had to be extrapolated, nudge our sense of time back a little
1514 	if ( cl.extrapolatedSnapshot ) {
1515 		cl.extrapolatedSnapshot = qfalse;
1516 		cl.serverTimeDelta -= 2;
1517 	} else {
1518 		// otherwise, move our sense of time forward to minimize total latency
1519 		cl.serverTimeDelta++;
1520 	}
1521 
1522 	if ( cl_showTimeDelta->integer ) {
1523 		Com_Printf( "%i ", cl.serverTimeDelta );
1524 	}
1525 */
1526 	int		newDelta;
1527 	int		deltaDelta;
1528 
1529 	cl.newSnapshots = qfalse;
1530 
1531 	newDelta = cl.frame.serverTime - cls.realtime;
1532 	deltaDelta = abs( newDelta - cl.serverTimeDelta );
1533 
1534 	if ( deltaDelta > RESET_TIME ) {
1535 		cl.serverTimeDelta = newDelta;
1536 		cl.oldServerTime = cl.frame.serverTime;	// FIXME: is this a problem for cgame?
1537 		cl.serverTime = cl.frame.serverTime;
1538 		if ( cl_showTimeDelta->integer ) {
1539 			Com_Printf( "<RESET> " );
1540 		}
1541 	} else if ( deltaDelta > 100 ) {
1542 		// fast adjust, cut the difference in half
1543 		if ( cl_showTimeDelta->integer ) {
1544 			Com_Printf( "<FAST> " );
1545 		}
1546 		cl.serverTimeDelta = ( cl.serverTimeDelta + newDelta ) >> 1;
1547 	} else {
1548 		// slow drift adjust, only move 1 or 2 msec
1549 
1550 		// if any of the frames between this and the previous snapshot
1551 		// had to be extrapolated, nudge our sense of time back a little
1552 		// the granularity of +1 / -2 is too high for timescale modified frametimes
1553 		if ( com_timescale->value == 0 || com_timescale->value == 1 ) {
1554 			if ( cl.extrapolatedSnapshot ) {
1555 				cl.extrapolatedSnapshot = qfalse;
1556 				cl.serverTimeDelta -= 2;
1557 			} else {
1558 				// otherwise, move our sense of time forward to minimize total latency
1559 				cl.serverTimeDelta++;
1560 			}
1561 		}
1562 	}
1563 
1564 	if ( cl_showTimeDelta->integer ) {
1565 		Com_Printf( "%i ", cl.serverTimeDelta );
1566 	}
1567 }
1568 
1569 
1570 /*
1571 ==================
1572 CL_FirstSnapshot
1573 ==================
1574 */
CL_FirstSnapshot(void)1575 void CL_FirstSnapshot( void ) {
1576 
1577 	re.RegisterMedia_LevelLoadEnd();
1578 
1579 	cls.state = CA_ACTIVE;
1580 
1581 	// set the timedelta so we are exactly on this first frame
1582 	cl.serverTimeDelta = cl.frame.serverTime - cls.realtime;
1583 	cl.oldServerTime = cl.frame.serverTime;
1584 
1585 	// if this is the first frame of active play,
1586 	// execute the contents of activeAction now
1587 	// this is to allow scripting a timedemo to start right
1588 	// after loading
1589 	if ( cl_activeAction->string[0] ) {
1590 		Cbuf_AddText( cl_activeAction->string );
1591 		Cvar_Set( "activeAction", "" );
1592 	}
1593 }
1594 
1595 /*
1596 ==================
1597 CL_SetCGameTime
1598 ==================
1599 */
CL_SetCGameTime(void)1600 void CL_SetCGameTime( void ) {
1601 
1602 	// getting a valid frame message ends the connection process
1603 	if ( cls.state != CA_ACTIVE ) {
1604 		if ( cls.state != CA_PRIMED ) {
1605 			return;
1606 		}
1607 		if ( cl.newSnapshots ) {
1608 			cl.newSnapshots = qfalse;
1609 			CL_FirstSnapshot();
1610 		}
1611 
1612 		if ( cls.state != CA_ACTIVE ) {
1613 			return;
1614 		}
1615 	}
1616 
1617 	// if we have gotten to this point, cl.frame is guaranteed to be valid
1618 	if ( !cl.frame.valid ) {
1619 		Com_Error( ERR_DROP, "CL_SetCGameTime: !cl.snap.valid" );
1620 	}
1621 
1622 	// allow pause in single player
1623 	if ( sv_paused->integer && CL_CheckPaused() && com_sv_running->integer ) {
1624 		// paused
1625 		return;
1626 	}
1627 
1628 	if ( cl.frame.serverTime < cl.oldFrameServerTime ) {
1629 		Com_Error( ERR_DROP, "cl.frame.serverTime < cl.oldFrameServerTime" );
1630 	}
1631 	cl.oldFrameServerTime = cl.frame.serverTime;
1632 
1633 
1634 	// get our current view of time
1635 
1636 	// cl_timeNudge is a user adjustable cvar that allows more
1637 	// or less latency to be added in the interest of better
1638 	// smoothness or better responsiveness.
1639 	cl.serverTime = cls.realtime + cl.serverTimeDelta - cl_timeNudge->integer;
1640 
1641 	// guarantee that time will never flow backwards, even if
1642 	// serverTimeDelta made an adjustment or cl_timeNudge was changed
1643 	if ( cl.serverTime < cl.oldServerTime ) {
1644 		cl.serverTime = cl.oldServerTime;
1645 	}
1646 	cl.oldServerTime = cl.serverTime;
1647 
1648 	// note if we are almost past the latest frame (without timeNudge),
1649 	// so we will try and adjust back a bit when the next snapshot arrives
1650 	if ( cls.realtime + cl.serverTimeDelta >= cl.frame.serverTime - 5 ) {
1651 		cl.extrapolatedSnapshot = qtrue;
1652 	}
1653 
1654 	// if we have gotten new snapshots, drift serverTimeDelta
1655 	// don't do this every frame, or a period of packet loss would
1656 	// make a huge adjustment
1657 	if ( cl.newSnapshots ) {
1658 		CL_AdjustTimeDelta();
1659 	}
1660 }
1661 
1662