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