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