1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 // sv_game.c -- interface to the game dll
23 
24 #include "server.h"
25 
26 #include "../botlib/botlib.h"
27 
28 botlib_export_t	*botlib_export;
29 
SV_GameError(const char * string)30 void SV_GameError( const char *string ) {
31 	Com_Error( ERR_DROP, "%s", string );
32 }
33 
SV_GamePrint(const char * string)34 void SV_GamePrint( const char *string ) {
35 	Com_Printf( "%s", string );
36 }
37 
38 // these functions must be used instead of pointer arithmetic, because
39 // the game allocates gentities with private information after the server shared part
SV_NumForGentity(sharedEntity_t * ent)40 int	SV_NumForGentity( sharedEntity_t *ent ) {
41 	int		num;
42 
43 	num = ( (byte *)ent - (byte *)sv.gentities ) / sv.gentitySize;
44 
45 	return num;
46 }
47 
SV_GentityNum(int num)48 sharedEntity_t *SV_GentityNum( int num ) {
49 	sharedEntity_t *ent;
50 
51 	ent = (sharedEntity_t *)((byte *)sv.gentities + sv.gentitySize*(num));
52 
53 	return ent;
54 }
55 
SV_GameClientNum(int num)56 playerState_t *SV_GameClientNum( int num ) {
57 	playerState_t	*ps;
58 
59 	ps = (playerState_t *)((byte *)sv.gameClients + sv.gameClientSize*(num));
60 
61 	return ps;
62 }
63 
SV_SvEntityForGentity(sharedEntity_t * gEnt)64 svEntity_t	*SV_SvEntityForGentity( sharedEntity_t *gEnt ) {
65 	if ( !gEnt || gEnt->s.number < 0 || gEnt->s.number >= MAX_GENTITIES ) {
66 		Com_Error( ERR_DROP, "SV_SvEntityForGentity: bad gEnt" );
67 	}
68 	return &sv.svEntities[ gEnt->s.number ];
69 }
70 
SV_GEntityForSvEntity(svEntity_t * svEnt)71 sharedEntity_t *SV_GEntityForSvEntity( svEntity_t *svEnt ) {
72 	int		num;
73 
74 	num = svEnt - sv.svEntities;
75 	return SV_GentityNum( num );
76 }
77 
78 /*
79 ===============
80 SV_GameSendServerCommand
81 
82 Sends a command string to a client
83 ===============
84 */
SV_GameSendServerCommand(int clientNum,const char * text)85 void SV_GameSendServerCommand( int clientNum, const char *text ) {
86 	if ( clientNum == -1 ) {
87 		SV_SendServerCommand( NULL, "%s", text );
88 	} else {
89 		if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
90 			return;
91 		}
92 		SV_SendServerCommand( svs.clients + clientNum, "%s", text );
93 	}
94 }
95 
96 
97 /*
98 ===============
99 SV_GameDropClient
100 
101 Disconnects the client with a message
102 ===============
103 */
SV_GameDropClient(int clientNum,const char * reason)104 void SV_GameDropClient( int clientNum, const char *reason ) {
105 	if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
106 		return;
107 	}
108 	SV_DropClient( svs.clients + clientNum, reason );
109 }
110 
111 
112 /*
113 =================
114 SV_SetBrushModel
115 
116 sets mins and maxs for inline bmodels
117 =================
118 */
SV_SetBrushModel(sharedEntity_t * ent,const char * name)119 void SV_SetBrushModel( sharedEntity_t *ent, const char *name ) {
120 	clipHandle_t	h;
121 	vec3_t			mins, maxs;
122 
123 	if (!name) {
124 		Com_Error( ERR_DROP, "SV_SetBrushModel: NULL" );
125 	}
126 
127 	if (name[0] != '*') {
128 		Com_Error( ERR_DROP, "SV_SetBrushModel: %s isn't a brush model", name );
129 	}
130 
131 
132 	ent->s.modelindex = atoi( name + 1 );
133 
134 	h = CM_InlineModel( ent->s.modelindex );
135 	CM_ModelBounds( h, mins, maxs );
136 	VectorCopy (mins, ent->r.mins);
137 	VectorCopy (maxs, ent->r.maxs);
138 	ent->r.bmodel = qtrue;
139 
140 	ent->r.contents = -1;		// we don't know exactly what is in the brushes
141 
142 	SV_LinkEntity( ent );		// FIXME: remove
143 }
144 
145 
146 
147 /*
148 =================
149 SV_inPVS
150 
151 Also checks portalareas so that doors block sight
152 =================
153 */
SV_inPVS(const vec3_t p1,const vec3_t p2)154 qboolean SV_inPVS (const vec3_t p1, const vec3_t p2)
155 {
156 	int		leafnum;
157 	int		cluster;
158 	int		area1, area2;
159 	byte	*mask;
160 
161 	leafnum = CM_PointLeafnum (p1);
162 	cluster = CM_LeafCluster (leafnum);
163 	area1 = CM_LeafArea (leafnum);
164 	mask = CM_ClusterPVS (cluster);
165 
166 	leafnum = CM_PointLeafnum (p2);
167 	cluster = CM_LeafCluster (leafnum);
168 	area2 = CM_LeafArea (leafnum);
169 	if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
170 		return qfalse;
171 	if (!CM_AreasConnected (area1, area2))
172 		return qfalse;		// a door blocks sight
173 	return qtrue;
174 }
175 
176 
177 /*
178 =================
179 SV_inPVSIgnorePortals
180 
181 Does NOT check portalareas
182 =================
183 */
SV_inPVSIgnorePortals(const vec3_t p1,const vec3_t p2)184 qboolean SV_inPVSIgnorePortals( const vec3_t p1, const vec3_t p2)
185 {
186 	int		leafnum;
187 	int		cluster;
188 	int		area1, area2;
189 	byte	*mask;
190 
191 	leafnum = CM_PointLeafnum (p1);
192 	cluster = CM_LeafCluster (leafnum);
193 	area1 = CM_LeafArea (leafnum);
194 	mask = CM_ClusterPVS (cluster);
195 
196 	leafnum = CM_PointLeafnum (p2);
197 	cluster = CM_LeafCluster (leafnum);
198 	area2 = CM_LeafArea (leafnum);
199 
200 	if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
201 		return qfalse;
202 
203 	return qtrue;
204 }
205 
206 
207 /*
208 ========================
209 SV_AdjustAreaPortalState
210 ========================
211 */
SV_AdjustAreaPortalState(sharedEntity_t * ent,qboolean open)212 void SV_AdjustAreaPortalState( sharedEntity_t *ent, qboolean open ) {
213 	svEntity_t	*svEnt;
214 
215 	svEnt = SV_SvEntityForGentity( ent );
216 	if ( svEnt->areanum2 == -1 ) {
217 		return;
218 	}
219 	CM_AdjustAreaPortalState( svEnt->areanum, svEnt->areanum2, open );
220 }
221 
222 
223 /*
224 ==================
225 SV_GameAreaEntities
226 ==================
227 */
SV_EntityContact(vec3_t mins,vec3_t maxs,const sharedEntity_t * gEnt,int capsule)228 qboolean	SV_EntityContact( vec3_t mins, vec3_t maxs, const sharedEntity_t *gEnt, int capsule ) {
229 	const float	*origin, *angles;
230 	clipHandle_t	ch;
231 	trace_t			trace;
232 
233 	// check for exact collision
234 	origin = gEnt->r.currentOrigin;
235 	angles = gEnt->r.currentAngles;
236 
237 	ch = SV_ClipHandleForEntity( gEnt );
238 	CM_TransformedBoxTrace ( &trace, vec3_origin, vec3_origin, mins, maxs,
239 		ch, -1, origin, angles, capsule );
240 
241 	return trace.startsolid;
242 }
243 
244 
245 /*
246 ===============
247 SV_GetServerinfo
248 
249 ===============
250 */
SV_GetServerinfo(char * buffer,int bufferSize)251 void SV_GetServerinfo( char *buffer, int bufferSize ) {
252 	if ( bufferSize < 1 ) {
253 		Com_Error( ERR_DROP, "SV_GetServerinfo: bufferSize == %i", bufferSize );
254 	}
255 	Q_strncpyz( buffer, Cvar_InfoString( CVAR_SERVERINFO ), bufferSize );
256 }
257 
258 /*
259 ===============
260 SV_LocateGameData
261 
262 ===============
263 */
SV_LocateGameData(sharedEntity_t * gEnts,int numGEntities,int sizeofGEntity_t,playerState_t * clients,int sizeofGameClient)264 void SV_LocateGameData( sharedEntity_t *gEnts, int numGEntities, int sizeofGEntity_t,
265 					   playerState_t *clients, int sizeofGameClient ) {
266 	sv.gentities = gEnts;
267 	sv.gentitySize = sizeofGEntity_t;
268 	sv.num_entities = numGEntities;
269 
270 	sv.gameClients = clients;
271 	sv.gameClientSize = sizeofGameClient;
272 }
273 
274 
275 /*
276 ===============
277 SV_GetUsercmd
278 
279 ===============
280 */
SV_GetUsercmd(int clientNum,usercmd_t * cmd)281 void SV_GetUsercmd( int clientNum, usercmd_t *cmd ) {
282 	if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
283 		Com_Error( ERR_DROP, "SV_GetUsercmd: bad clientNum:%i", clientNum );
284 	}
285 	*cmd = svs.clients[clientNum].lastUsercmd;
286 }
287 
288 //==============================================
289 
FloatAsInt(float f)290 static int	FloatAsInt( float f ) {
291 	union
292 	{
293 	    int i;
294 	    float f;
295 	} temp;
296 
297 	temp.f = f;
298 	return temp.i;
299 }
300 
301 /*
302 ====================
303 SV_GameSystemCalls
304 
305 The module is making a system call
306 ====================
307 */
SV_GameSystemCalls(intptr_t * args)308 intptr_t SV_GameSystemCalls( intptr_t *args ) {
309 	switch( args[0] ) {
310 	case G_PRINT:
311 		Com_Printf( "%s", (const char*)VMA(1) );
312 		return 0;
313 	case G_ERROR:
314 		Com_Error( ERR_DROP, "%s", (const char*)VMA(1) );
315 		return 0;
316 	case G_MILLISECONDS:
317 		return Sys_Milliseconds();
318 	case G_CVAR_REGISTER:
319 		Cvar_Register( VMA(1), VMA(2), VMA(3), args[4] );
320 		return 0;
321 	case G_CVAR_UPDATE:
322 		Cvar_Update( VMA(1) );
323 		return 0;
324 	case G_CVAR_SET:
325 		Cvar_Set( (const char *)VMA(1), (const char *)VMA(2) );
326 		return 0;
327 	case G_CVAR_VARIABLE_INTEGER_VALUE:
328 		return Cvar_VariableIntegerValue( (const char *)VMA(1) );
329 	case G_CVAR_VARIABLE_STRING_BUFFER:
330 		Cvar_VariableStringBuffer( VMA(1), VMA(2), args[3] );
331 		return 0;
332 	case G_ARGC:
333 		return Cmd_Argc();
334 	case G_ARGV:
335 		Cmd_ArgvBuffer( args[1], VMA(2), args[3] );
336 		return 0;
337 	case G_SEND_CONSOLE_COMMAND:
338 		Cbuf_ExecuteText( args[1], VMA(2) );
339 		return 0;
340 
341 	case G_FS_FOPEN_FILE:
342 		return FS_FOpenFileByMode( VMA(1), VMA(2), args[3] );
343 	case G_FS_READ:
344 		FS_Read2( VMA(1), args[2], args[3] );
345 		return 0;
346 	case G_FS_WRITE:
347 		FS_Write( VMA(1), args[2], args[3] );
348 		return 0;
349 	case G_FS_FCLOSE_FILE:
350 		FS_FCloseFile( args[1] );
351 		return 0;
352 	case G_FS_GETFILELIST:
353 		return FS_GetFileList( VMA(1), VMA(2), VMA(3), args[4] );
354 	case G_FS_SEEK:
355 		return FS_Seek( args[1], args[2], args[3] );
356 
357 	case G_LOCATE_GAME_DATA:
358 		SV_LocateGameData( VMA(1), args[2], args[3], VMA(4), args[5] );
359 		return 0;
360 	case G_DROP_CLIENT:
361 		SV_GameDropClient( args[1], VMA(2) );
362 		return 0;
363 	case G_SEND_SERVER_COMMAND:
364 		SV_GameSendServerCommand( args[1], VMA(2) );
365 		return 0;
366 	case G_LINKENTITY:
367 		SV_LinkEntity( VMA(1) );
368 		return 0;
369 	case G_UNLINKENTITY:
370 		SV_UnlinkEntity( VMA(1) );
371 		return 0;
372 	case G_ENTITIES_IN_BOX:
373 		return SV_AreaEntities( VMA(1), VMA(2), VMA(3), args[4] );
374 	case G_ENTITY_CONTACT:
375 		return SV_EntityContact( VMA(1), VMA(2), VMA(3), /*int capsule*/ qfalse );
376 	case G_ENTITY_CONTACTCAPSULE:
377 		return SV_EntityContact( VMA(1), VMA(2), VMA(3), /*int capsule*/ qtrue );
378 	case G_TRACE:
379 		SV_Trace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qfalse );
380 		return 0;
381 	case G_TRACECAPSULE:
382 		SV_Trace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qtrue );
383 		return 0;
384 	case G_POINT_CONTENTS:
385 		return SV_PointContents( VMA(1), args[2] );
386 	case G_SET_BRUSH_MODEL:
387 		SV_SetBrushModel( VMA(1), VMA(2) );
388 		return 0;
389 	case G_IN_PVS:
390 		return SV_inPVS( VMA(1), VMA(2) );
391 	case G_IN_PVS_IGNORE_PORTALS:
392 		return SV_inPVSIgnorePortals( VMA(1), VMA(2) );
393 
394 	case G_SET_CONFIGSTRING:
395 		SV_SetConfigstring( args[1], VMA(2) );
396 		return 0;
397 	case G_GET_CONFIGSTRING:
398 		SV_GetConfigstring( args[1], VMA(2), args[3] );
399 		return 0;
400 	case G_SET_USERINFO:
401 		SV_SetUserinfo( args[1], VMA(2) );
402 		return 0;
403 	case G_GET_USERINFO:
404 		SV_GetUserinfo( args[1], VMA(2), args[3] );
405 		return 0;
406 	case G_GET_SERVERINFO:
407 		SV_GetServerinfo( VMA(1), args[2] );
408 		return 0;
409 	case G_ADJUST_AREA_PORTAL_STATE:
410 		SV_AdjustAreaPortalState( VMA(1), args[2] );
411 		return 0;
412 	case G_AREAS_CONNECTED:
413 		return CM_AreasConnected( args[1], args[2] );
414 
415 	case G_BOT_ALLOCATE_CLIENT:
416 		return SV_BotAllocateClient();
417 	case G_BOT_FREE_CLIENT:
418 		SV_BotFreeClient( args[1] );
419 		return 0;
420 
421 	case G_GET_USERCMD:
422 		SV_GetUsercmd( args[1], VMA(2) );
423 		return 0;
424 	case G_GET_ENTITY_TOKEN:
425 		{
426 			const char	*s;
427 
428 			s = Com_Parse( &sv.entityParsePoint );
429 			Q_strncpyz( VMA(1), s, args[2] );
430 			if ( !sv.entityParsePoint && !s[0] ) {
431 				return qfalse;
432 			} else {
433 				return qtrue;
434 			}
435 		}
436 
437 	case G_DEBUG_POLYGON_CREATE:
438 		return BotImport_DebugPolygonCreate( args[1], args[2], VMA(3) );
439 	case G_DEBUG_POLYGON_DELETE:
440 		BotImport_DebugPolygonDelete( args[1] );
441 		return 0;
442 	case G_REAL_TIME:
443 		return Com_RealTime( VMA(1) );
444 	case G_SNAPVECTOR:
445 		Sys_SnapVector( VMA(1) );
446 		return 0;
447 
448 		//====================================
449 
450 	case BOTLIB_SETUP:
451 		return SV_BotLibSetup();
452 	case BOTLIB_SHUTDOWN:
453 		return SV_BotLibShutdown();
454 	case BOTLIB_LIBVAR_SET:
455 		return botlib_export->BotLibVarSet( VMA(1), VMA(2) );
456 	case BOTLIB_LIBVAR_GET:
457 		return botlib_export->BotLibVarGet( VMA(1), VMA(2), args[3] );
458 
459 	case BOTLIB_PC_ADD_GLOBAL_DEFINE:
460 		return botlib_export->PC_AddGlobalDefine( VMA(1) );
461 	case BOTLIB_PC_LOAD_SOURCE:
462 		return botlib_export->PC_LoadSourceHandle( VMA(1) );
463 	case BOTLIB_PC_FREE_SOURCE:
464 		return botlib_export->PC_FreeSourceHandle( args[1] );
465 	case BOTLIB_PC_READ_TOKEN:
466 		return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) );
467 	case BOTLIB_PC_SOURCE_FILE_AND_LINE:
468 		return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) );
469 
470 	case BOTLIB_START_FRAME:
471 		return botlib_export->BotLibStartFrame( VMF(1) );
472 	case BOTLIB_LOAD_MAP:
473 		return botlib_export->BotLibLoadMap( VMA(1) );
474 	case BOTLIB_UPDATENTITY:
475 		return botlib_export->BotLibUpdateEntity( args[1], VMA(2) );
476 	case BOTLIB_TEST:
477 		return botlib_export->Test( args[1], VMA(2), VMA(3), VMA(4) );
478 
479 	case BOTLIB_GET_SNAPSHOT_ENTITY:
480 		return SV_BotGetSnapshotEntity( args[1], args[2] );
481 	case BOTLIB_GET_CONSOLE_MESSAGE:
482 		return SV_BotGetConsoleMessage( args[1], VMA(2), args[3] );
483 	case BOTLIB_USER_COMMAND:
484 		SV_ClientThink( &svs.clients[args[1]], VMA(2) );
485 		return 0;
486 
487 	case BOTLIB_AAS_BBOX_AREAS:
488 		return botlib_export->aas.AAS_BBoxAreas( VMA(1), VMA(2), VMA(3), args[4] );
489 	case BOTLIB_AAS_AREA_INFO:
490 		return botlib_export->aas.AAS_AreaInfo( args[1], VMA(2) );
491 	case BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL:
492 		return botlib_export->aas.AAS_AlternativeRouteGoals( VMA(1), args[2], VMA(3), args[4], args[5], VMA(6), args[7], args[8] );
493 	case BOTLIB_AAS_ENTITY_INFO:
494 		botlib_export->aas.AAS_EntityInfo( args[1], VMA(2) );
495 		return 0;
496 
497 	case BOTLIB_AAS_INITIALIZED:
498 		return botlib_export->aas.AAS_Initialized();
499 	case BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX:
500 		botlib_export->aas.AAS_PresenceTypeBoundingBox( args[1], VMA(2), VMA(3) );
501 		return 0;
502 	case BOTLIB_AAS_TIME:
503 		return FloatAsInt( botlib_export->aas.AAS_Time() );
504 
505 	case BOTLIB_AAS_POINT_AREA_NUM:
506 		return botlib_export->aas.AAS_PointAreaNum( VMA(1) );
507 	case BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX:
508 		return botlib_export->aas.AAS_PointReachabilityAreaIndex( VMA(1) );
509 	case BOTLIB_AAS_TRACE_AREAS:
510 		return botlib_export->aas.AAS_TraceAreas( VMA(1), VMA(2), VMA(3), VMA(4), args[5] );
511 
512 	case BOTLIB_AAS_POINT_CONTENTS:
513 		return botlib_export->aas.AAS_PointContents( VMA(1) );
514 	case BOTLIB_AAS_NEXT_BSP_ENTITY:
515 		return botlib_export->aas.AAS_NextBSPEntity( args[1] );
516 	case BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY:
517 		return botlib_export->aas.AAS_ValueForBSPEpairKey( args[1], VMA(2), VMA(3), args[4] );
518 	case BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY:
519 		return botlib_export->aas.AAS_VectorForBSPEpairKey( args[1], VMA(2), VMA(3) );
520 	case BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY:
521 		return botlib_export->aas.AAS_FloatForBSPEpairKey( args[1], VMA(2), VMA(3) );
522 	case BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY:
523 		return botlib_export->aas.AAS_IntForBSPEpairKey( args[1], VMA(2), VMA(3) );
524 
525 	case BOTLIB_AAS_AREA_REACHABILITY:
526 		return botlib_export->aas.AAS_AreaReachability( args[1] );
527 
528 	case BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA:
529 		return botlib_export->aas.AAS_AreaTravelTimeToGoalArea( args[1], VMA(2), args[3], args[4] );
530 	case BOTLIB_AAS_ENABLE_ROUTING_AREA:
531 		return botlib_export->aas.AAS_EnableRoutingArea( args[1], args[2] );
532 	case BOTLIB_AAS_PREDICT_ROUTE:
533 		return botlib_export->aas.AAS_PredictRoute( VMA(1), args[2], VMA(3), args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11] );
534 
535 	case BOTLIB_AAS_SWIMMING:
536 		return botlib_export->aas.AAS_Swimming( VMA(1) );
537 	case BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT:
538 		return botlib_export->aas.AAS_PredictClientMovement( VMA(1), args[2], VMA(3), args[4], args[5],
539 			VMA(6), VMA(7), args[8], args[9], VMF(10), args[11], args[12], args[13] );
540 
541 	case BOTLIB_EA_SAY:
542 		botlib_export->ea.EA_Say( args[1], VMA(2) );
543 		return 0;
544 	case BOTLIB_EA_SAY_TEAM:
545 		botlib_export->ea.EA_SayTeam( args[1], VMA(2) );
546 		return 0;
547 	case BOTLIB_EA_COMMAND:
548 		botlib_export->ea.EA_Command( args[1], VMA(2) );
549 		return 0;
550 
551 	case BOTLIB_EA_ACTION:
552 		botlib_export->ea.EA_Action( args[1], args[2] );
553 		break;
554 	case BOTLIB_EA_GESTURE:
555 		botlib_export->ea.EA_Gesture( args[1] );
556 		return 0;
557 	case BOTLIB_EA_TALK:
558 		botlib_export->ea.EA_Talk( args[1] );
559 		return 0;
560 	case BOTLIB_EA_ATTACK:
561 		botlib_export->ea.EA_Attack( args[1] );
562 		return 0;
563 	case BOTLIB_EA_USE:
564 		botlib_export->ea.EA_Use( args[1] );
565 		return 0;
566 	case BOTLIB_EA_RESPAWN:
567 		botlib_export->ea.EA_Respawn( args[1] );
568 		return 0;
569 	case BOTLIB_EA_CROUCH:
570 		botlib_export->ea.EA_Crouch( args[1] );
571 		return 0;
572 	case BOTLIB_EA_MOVE_UP:
573 		botlib_export->ea.EA_MoveUp( args[1] );
574 		return 0;
575 	case BOTLIB_EA_MOVE_DOWN:
576 		botlib_export->ea.EA_MoveDown( args[1] );
577 		return 0;
578 	case BOTLIB_EA_MOVE_FORWARD:
579 		botlib_export->ea.EA_MoveForward( args[1] );
580 		return 0;
581 	case BOTLIB_EA_MOVE_BACK:
582 		botlib_export->ea.EA_MoveBack( args[1] );
583 		return 0;
584 	case BOTLIB_EA_MOVE_LEFT:
585 		botlib_export->ea.EA_MoveLeft( args[1] );
586 		return 0;
587 	case BOTLIB_EA_MOVE_RIGHT:
588 		botlib_export->ea.EA_MoveRight( args[1] );
589 		return 0;
590 
591 	case BOTLIB_EA_SELECT_WEAPON:
592 		botlib_export->ea.EA_SelectWeapon( args[1], args[2] );
593 		return 0;
594 	case BOTLIB_EA_JUMP:
595 		botlib_export->ea.EA_Jump( args[1] );
596 		return 0;
597 	case BOTLIB_EA_DELAYED_JUMP:
598 		botlib_export->ea.EA_DelayedJump( args[1] );
599 		return 0;
600 	case BOTLIB_EA_MOVE:
601 		botlib_export->ea.EA_Move( args[1], VMA(2), VMF(3) );
602 		return 0;
603 	case BOTLIB_EA_VIEW:
604 		botlib_export->ea.EA_View( args[1], VMA(2) );
605 		return 0;
606 
607 	case BOTLIB_EA_END_REGULAR:
608 		botlib_export->ea.EA_EndRegular( args[1], VMF(2) );
609 		return 0;
610 	case BOTLIB_EA_GET_INPUT:
611 		botlib_export->ea.EA_GetInput( args[1], VMF(2), VMA(3) );
612 		return 0;
613 	case BOTLIB_EA_RESET_INPUT:
614 		botlib_export->ea.EA_ResetInput( args[1] );
615 		return 0;
616 
617 	case BOTLIB_AI_LOAD_CHARACTER:
618 		return botlib_export->ai.BotLoadCharacter( VMA(1), VMF(2) );
619 	case BOTLIB_AI_FREE_CHARACTER:
620 		botlib_export->ai.BotFreeCharacter( args[1] );
621 		return 0;
622 	case BOTLIB_AI_CHARACTERISTIC_FLOAT:
623 		return FloatAsInt( botlib_export->ai.Characteristic_Float( args[1], args[2] ) );
624 	case BOTLIB_AI_CHARACTERISTIC_BFLOAT:
625 		return FloatAsInt( botlib_export->ai.Characteristic_BFloat( args[1], args[2], VMF(3), VMF(4) ) );
626 	case BOTLIB_AI_CHARACTERISTIC_INTEGER:
627 		return botlib_export->ai.Characteristic_Integer( args[1], args[2] );
628 	case BOTLIB_AI_CHARACTERISTIC_BINTEGER:
629 		return botlib_export->ai.Characteristic_BInteger( args[1], args[2], args[3], args[4] );
630 	case BOTLIB_AI_CHARACTERISTIC_STRING:
631 		botlib_export->ai.Characteristic_String( args[1], args[2], VMA(3), args[4] );
632 		return 0;
633 
634 	case BOTLIB_AI_ALLOC_CHAT_STATE:
635 		return botlib_export->ai.BotAllocChatState();
636 	case BOTLIB_AI_FREE_CHAT_STATE:
637 		botlib_export->ai.BotFreeChatState( args[1] );
638 		return 0;
639 	case BOTLIB_AI_QUEUE_CONSOLE_MESSAGE:
640 		botlib_export->ai.BotQueueConsoleMessage( args[1], args[2], VMA(3) );
641 		return 0;
642 	case BOTLIB_AI_REMOVE_CONSOLE_MESSAGE:
643 		botlib_export->ai.BotRemoveConsoleMessage( args[1], args[2] );
644 		return 0;
645 	case BOTLIB_AI_NEXT_CONSOLE_MESSAGE:
646 		return botlib_export->ai.BotNextConsoleMessage( args[1], VMA(2) );
647 	case BOTLIB_AI_NUM_CONSOLE_MESSAGE:
648 		return botlib_export->ai.BotNumConsoleMessages( args[1] );
649 	case BOTLIB_AI_INITIAL_CHAT:
650 		botlib_export->ai.BotInitialChat( args[1], VMA(2), args[3], VMA(4), VMA(5), VMA(6), VMA(7), VMA(8), VMA(9), VMA(10), VMA(11) );
651 		return 0;
652 	case BOTLIB_AI_NUM_INITIAL_CHATS:
653 		return botlib_export->ai.BotNumInitialChats( args[1], VMA(2) );
654 	case BOTLIB_AI_REPLY_CHAT:
655 		return botlib_export->ai.BotReplyChat( args[1], VMA(2), args[3], args[4], VMA(5), VMA(6), VMA(7), VMA(8), VMA(9), VMA(10), VMA(11), VMA(12) );
656 	case BOTLIB_AI_CHAT_LENGTH:
657 		return botlib_export->ai.BotChatLength( args[1] );
658 	case BOTLIB_AI_ENTER_CHAT:
659 		botlib_export->ai.BotEnterChat( args[1], args[2], args[3] );
660 		return 0;
661 	case BOTLIB_AI_GET_CHAT_MESSAGE:
662 		botlib_export->ai.BotGetChatMessage( args[1], VMA(2), args[3] );
663 		return 0;
664 	case BOTLIB_AI_STRING_CONTAINS:
665 		return botlib_export->ai.StringContains( VMA(1), VMA(2), args[3] );
666 	case BOTLIB_AI_FIND_MATCH:
667 		return botlib_export->ai.BotFindMatch( VMA(1), VMA(2), args[3] );
668 	case BOTLIB_AI_MATCH_VARIABLE:
669 		botlib_export->ai.BotMatchVariable( VMA(1), args[2], VMA(3), args[4] );
670 		return 0;
671 	case BOTLIB_AI_UNIFY_WHITE_SPACES:
672 		botlib_export->ai.UnifyWhiteSpaces( VMA(1) );
673 		return 0;
674 	case BOTLIB_AI_REPLACE_SYNONYMS:
675 		botlib_export->ai.BotReplaceSynonyms( VMA(1), args[2] );
676 		return 0;
677 	case BOTLIB_AI_LOAD_CHAT_FILE:
678 		return botlib_export->ai.BotLoadChatFile( args[1], VMA(2), VMA(3) );
679 	case BOTLIB_AI_SET_CHAT_GENDER:
680 		botlib_export->ai.BotSetChatGender( args[1], args[2] );
681 		return 0;
682 	case BOTLIB_AI_SET_CHAT_NAME:
683 		botlib_export->ai.BotSetChatName( args[1], VMA(2), args[3] );
684 		return 0;
685 
686 	case BOTLIB_AI_RESET_GOAL_STATE:
687 		botlib_export->ai.BotResetGoalState( args[1] );
688 		return 0;
689 	case BOTLIB_AI_RESET_AVOID_GOALS:
690 		botlib_export->ai.BotResetAvoidGoals( args[1] );
691 		return 0;
692 	case BOTLIB_AI_REMOVE_FROM_AVOID_GOALS:
693 		botlib_export->ai.BotRemoveFromAvoidGoals( args[1], args[2] );
694 		return 0;
695 	case BOTLIB_AI_PUSH_GOAL:
696 		botlib_export->ai.BotPushGoal( args[1], VMA(2) );
697 		return 0;
698 	case BOTLIB_AI_POP_GOAL:
699 		botlib_export->ai.BotPopGoal( args[1] );
700 		return 0;
701 	case BOTLIB_AI_EMPTY_GOAL_STACK:
702 		botlib_export->ai.BotEmptyGoalStack( args[1] );
703 		return 0;
704 	case BOTLIB_AI_DUMP_AVOID_GOALS:
705 		botlib_export->ai.BotDumpAvoidGoals( args[1] );
706 		return 0;
707 	case BOTLIB_AI_DUMP_GOAL_STACK:
708 		botlib_export->ai.BotDumpGoalStack( args[1] );
709 		return 0;
710 	case BOTLIB_AI_GOAL_NAME:
711 		botlib_export->ai.BotGoalName( args[1], VMA(2), args[3] );
712 		return 0;
713 	case BOTLIB_AI_GET_TOP_GOAL:
714 		return botlib_export->ai.BotGetTopGoal( args[1], VMA(2) );
715 	case BOTLIB_AI_GET_SECOND_GOAL:
716 		return botlib_export->ai.BotGetSecondGoal( args[1], VMA(2) );
717 	case BOTLIB_AI_CHOOSE_LTG_ITEM:
718 		return botlib_export->ai.BotChooseLTGItem( args[1], VMA(2), VMA(3), args[4] );
719 	case BOTLIB_AI_CHOOSE_NBG_ITEM:
720 		return botlib_export->ai.BotChooseNBGItem( args[1], VMA(2), VMA(3), args[4], VMA(5), VMF(6) );
721 	case BOTLIB_AI_TOUCHING_GOAL:
722 		return botlib_export->ai.BotTouchingGoal( VMA(1), VMA(2) );
723 	case BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE:
724 		return botlib_export->ai.BotItemGoalInVisButNotVisible( args[1], VMA(2), VMA(3), VMA(4) );
725 	case BOTLIB_AI_GET_LEVEL_ITEM_GOAL:
726 		return botlib_export->ai.BotGetLevelItemGoal( args[1], VMA(2), VMA(3) );
727 	case BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL:
728 		return botlib_export->ai.BotGetNextCampSpotGoal( args[1], VMA(2) );
729 	case BOTLIB_AI_GET_MAP_LOCATION_GOAL:
730 		return botlib_export->ai.BotGetMapLocationGoal( VMA(1), VMA(2) );
731 	case BOTLIB_AI_AVOID_GOAL_TIME:
732 		return FloatAsInt( botlib_export->ai.BotAvoidGoalTime( args[1], args[2] ) );
733 	case BOTLIB_AI_SET_AVOID_GOAL_TIME:
734 		botlib_export->ai.BotSetAvoidGoalTime( args[1], args[2], VMF(3));
735 		return 0;
736 	case BOTLIB_AI_INIT_LEVEL_ITEMS:
737 		botlib_export->ai.BotInitLevelItems();
738 		return 0;
739 	case BOTLIB_AI_UPDATE_ENTITY_ITEMS:
740 		botlib_export->ai.BotUpdateEntityItems();
741 		return 0;
742 	case BOTLIB_AI_LOAD_ITEM_WEIGHTS:
743 		return botlib_export->ai.BotLoadItemWeights( args[1], VMA(2) );
744 	case BOTLIB_AI_FREE_ITEM_WEIGHTS:
745 		botlib_export->ai.BotFreeItemWeights( args[1] );
746 		return 0;
747 	case BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC:
748 		botlib_export->ai.BotInterbreedGoalFuzzyLogic( args[1], args[2], args[3] );
749 		return 0;
750 	case BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC:
751 		botlib_export->ai.BotSaveGoalFuzzyLogic( args[1], VMA(2) );
752 		return 0;
753 	case BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC:
754 		botlib_export->ai.BotMutateGoalFuzzyLogic( args[1], VMF(2) );
755 		return 0;
756 	case BOTLIB_AI_ALLOC_GOAL_STATE:
757 		return botlib_export->ai.BotAllocGoalState( args[1] );
758 	case BOTLIB_AI_FREE_GOAL_STATE:
759 		botlib_export->ai.BotFreeGoalState( args[1] );
760 		return 0;
761 
762 	case BOTLIB_AI_RESET_MOVE_STATE:
763 		botlib_export->ai.BotResetMoveState( args[1] );
764 		return 0;
765 	case BOTLIB_AI_ADD_AVOID_SPOT:
766 		botlib_export->ai.BotAddAvoidSpot( args[1], VMA(2), VMF(3), args[4] );
767 		return 0;
768 	case BOTLIB_AI_MOVE_TO_GOAL:
769 		botlib_export->ai.BotMoveToGoal( VMA(1), args[2], VMA(3), args[4] );
770 		return 0;
771 	case BOTLIB_AI_MOVE_IN_DIRECTION:
772 		return botlib_export->ai.BotMoveInDirection( args[1], VMA(2), VMF(3), args[4] );
773 	case BOTLIB_AI_RESET_AVOID_REACH:
774 		botlib_export->ai.BotResetAvoidReach( args[1] );
775 		return 0;
776 	case BOTLIB_AI_RESET_LAST_AVOID_REACH:
777 		botlib_export->ai.BotResetLastAvoidReach( args[1] );
778 		return 0;
779 	case BOTLIB_AI_REACHABILITY_AREA:
780 		return botlib_export->ai.BotReachabilityArea( VMA(1), args[2] );
781 	case BOTLIB_AI_MOVEMENT_VIEW_TARGET:
782 		return botlib_export->ai.BotMovementViewTarget( args[1], VMA(2), args[3], VMF(4), VMA(5) );
783 	case BOTLIB_AI_PREDICT_VISIBLE_POSITION:
784 		return botlib_export->ai.BotPredictVisiblePosition( VMA(1), args[2], VMA(3), args[4], VMA(5) );
785 	case BOTLIB_AI_ALLOC_MOVE_STATE:
786 		return botlib_export->ai.BotAllocMoveState();
787 	case BOTLIB_AI_FREE_MOVE_STATE:
788 		botlib_export->ai.BotFreeMoveState( args[1] );
789 		return 0;
790 	case BOTLIB_AI_INIT_MOVE_STATE:
791 		botlib_export->ai.BotInitMoveState( args[1], VMA(2) );
792 		return 0;
793 
794 	case BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON:
795 		return botlib_export->ai.BotChooseBestFightWeapon( args[1], VMA(2) );
796 	case BOTLIB_AI_GET_WEAPON_INFO:
797 		botlib_export->ai.BotGetWeaponInfo( args[1], args[2], VMA(3) );
798 		return 0;
799 	case BOTLIB_AI_LOAD_WEAPON_WEIGHTS:
800 		return botlib_export->ai.BotLoadWeaponWeights( args[1], VMA(2) );
801 	case BOTLIB_AI_ALLOC_WEAPON_STATE:
802 		return botlib_export->ai.BotAllocWeaponState();
803 	case BOTLIB_AI_FREE_WEAPON_STATE:
804 		botlib_export->ai.BotFreeWeaponState( args[1] );
805 		return 0;
806 	case BOTLIB_AI_RESET_WEAPON_STATE:
807 		botlib_export->ai.BotResetWeaponState( args[1] );
808 		return 0;
809 
810 	case BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION:
811 		return botlib_export->ai.GeneticParentsAndChildSelection(args[1], VMA(2), VMA(3), VMA(4), VMA(5));
812 
813 	case TRAP_MEMSET:
814 		Com_Memset( VMA(1), args[2], args[3] );
815 		return 0;
816 
817 	case TRAP_MEMCPY:
818 		Com_Memcpy( VMA(1), VMA(2), args[3] );
819 		return 0;
820 
821 	case TRAP_STRNCPY:
822 		strncpy( VMA(1), VMA(2), args[3] );
823 		return args[1];
824 
825 	case TRAP_SIN:
826 		return FloatAsInt( sin( VMF(1) ) );
827 
828 	case TRAP_COS:
829 		return FloatAsInt( cos( VMF(1) ) );
830 
831 	case TRAP_ATAN2:
832 		return FloatAsInt( atan2( VMF(1), VMF(2) ) );
833 
834 	case TRAP_SQRT:
835 		return FloatAsInt( sqrt( VMF(1) ) );
836 
837 	case TRAP_MATRIXMULTIPLY:
838 		MatrixMultiply( VMA(1), VMA(2), VMA(3) );
839 		return 0;
840 
841 	case TRAP_ANGLEVECTORS:
842 		AngleVectors( VMA(1), VMA(2), VMA(3), VMA(4) );
843 		return 0;
844 
845 	case TRAP_PERPENDICULARVECTOR:
846 		PerpendicularVector( VMA(1), VMA(2) );
847 		return 0;
848 
849 	case TRAP_FLOOR:
850 		return FloatAsInt( floor( VMF(1) ) );
851 
852 	case TRAP_CEIL:
853 		return FloatAsInt( ceil( VMF(1) ) );
854 
855 
856 	default:
857 		Com_Error( ERR_DROP, "Bad game system trap: %ld", (long int) args[0] );
858 	}
859 	return -1;
860 }
861 
862 /*
863 ===============
864 SV_ShutdownGameProgs
865 
866 Called every time a map changes
867 ===============
868 */
SV_ShutdownGameProgs(void)869 void SV_ShutdownGameProgs( void ) {
870 	if ( !gvm ) {
871 		return;
872 	}
873 	VM_Call( gvm, GAME_SHUTDOWN, qfalse );
874 	VM_Free( gvm );
875 	gvm = NULL;
876 }
877 
878 /*
879 ==================
880 SV_InitGameVM
881 
882 Called for both a full init and a restart
883 ==================
884 */
SV_InitGameVM(qboolean restart)885 static void SV_InitGameVM( qboolean restart ) {
886 	int		i;
887 
888 	// start the entity parsing at the beginning
889 	sv.entityParsePoint = CM_EntityString();
890 
891 	// clear all gentity pointers that might still be set from
892 	// a previous level
893 	// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=522
894 	//   now done before GAME_INIT call
895 	for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
896 		svs.clients[i].gentity = NULL;
897 	}
898 
899 	// use the current msec count for a random seed
900 	// init for this gamestate
901 	VM_Call (gvm, GAME_INIT, sv.time, Com_Milliseconds(), restart);
902 }
903 
904 
905 
906 /*
907 ===================
908 SV_RestartGameProgs
909 
910 Called on a map_restart, but not on a normal map change
911 ===================
912 */
SV_RestartGameProgs(void)913 void SV_RestartGameProgs( void ) {
914 	if ( !gvm ) {
915 		return;
916 	}
917 	VM_Call( gvm, GAME_SHUTDOWN, qtrue );
918 
919 	// do a restart instead of a free
920 	gvm = VM_Restart( gvm );
921 	if ( !gvm ) {
922 		Com_Error( ERR_FATAL, "VM_Restart on game failed" );
923 	}
924 
925 	SV_InitGameVM( qtrue );
926 }
927 
928 
929 /*
930 ===============
931 SV_InitGameProgs
932 
933 Called on a normal map change, not on a map_restart
934 ===============
935 */
SV_InitGameProgs(void)936 void SV_InitGameProgs( void ) {
937 	cvar_t	*var;
938 	//FIXME these are temp while I make bots run in vm
939 	extern int	bot_enable;
940 
941 	var = Cvar_Get( "bot_enable", "1", CVAR_LATCH );
942 	if ( var ) {
943 		bot_enable = var->integer;
944 	}
945 	else {
946 		bot_enable = 0;
947 	}
948 
949 	// load the dll or bytecode
950 	gvm = VM_Create( "qagame", SV_GameSystemCalls, Cvar_VariableValue( "vm_game" ) );
951 	if ( !gvm ) {
952 		Com_Error( ERR_FATAL, "VM_Create on game failed" );
953 	}
954 
955 	SV_InitGameVM( qfalse );
956 }
957 
958 
959 /*
960 ====================
961 SV_GameCommand
962 
963 See if the current console command is claimed by the game
964 ====================
965 */
SV_GameCommand(void)966 qboolean SV_GameCommand( void ) {
967 	if ( sv.state != SS_GAME ) {
968 		return qfalse;
969 	}
970 
971 	return VM_Call( gvm, GAME_CONSOLE_COMMAND );
972 }
973 
974