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