Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

sv_game.c (8425B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // sv_game.c -- interface to the game dll
     21 
     22 #include "server.h"
     23 
     24 game_export_t	*ge;
     25 
     26 
     27 /*
     28 ===============
     29 PF_Unicast
     30 
     31 Sends the contents of the mutlicast buffer to a single client
     32 ===============
     33 */
     34 void PF_Unicast (edict_t *ent, qboolean reliable)
     35 {
     36 	int		p;
     37 	client_t	*client;
     38 
     39 	if (!ent)
     40 		return;
     41 
     42 	p = NUM_FOR_EDICT(ent);
     43 	if (p < 1 || p > maxclients->value)
     44 		return;
     45 
     46 	client = svs.clients + (p-1);
     47 
     48 	if (reliable)
     49 		SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
     50 	else
     51 		SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
     52 
     53 	SZ_Clear (&sv.multicast);
     54 }
     55 
     56 
     57 /*
     58 ===============
     59 PF_dprintf
     60 
     61 Debug print to server console
     62 ===============
     63 */
     64 void PF_dprintf (char *fmt, ...)
     65 {
     66 	char		msg[1024];
     67 	va_list		argptr;
     68 	
     69 	va_start (argptr,fmt);
     70 	vsprintf (msg, fmt, argptr);
     71 	va_end (argptr);
     72 
     73 	Com_Printf ("%s", msg);
     74 }
     75 
     76 
     77 /*
     78 ===============
     79 PF_cprintf
     80 
     81 Print to a single client
     82 ===============
     83 */
     84 void PF_cprintf (edict_t *ent, int level, char *fmt, ...)
     85 {
     86 	char		msg[1024];
     87 	va_list		argptr;
     88 	int			n;
     89 
     90 	if (ent)
     91 	{
     92 		n = NUM_FOR_EDICT(ent);
     93 		if (n < 1 || n > maxclients->value)
     94 			Com_Error (ERR_DROP, "cprintf to a non-client");
     95 	}
     96 
     97 	va_start (argptr,fmt);
     98 	vsprintf (msg, fmt, argptr);
     99 	va_end (argptr);
    100 
    101 	if (ent)
    102 		SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg);
    103 	else
    104 		Com_Printf ("%s", msg);
    105 }
    106 
    107 
    108 /*
    109 ===============
    110 PF_centerprintf
    111 
    112 centerprint to a single client
    113 ===============
    114 */
    115 void PF_centerprintf (edict_t *ent, char *fmt, ...)
    116 {
    117 	char		msg[1024];
    118 	va_list		argptr;
    119 	int			n;
    120 	
    121 	n = NUM_FOR_EDICT(ent);
    122 	if (n < 1 || n > maxclients->value)
    123 		return;	// Com_Error (ERR_DROP, "centerprintf to a non-client");
    124 
    125 	va_start (argptr,fmt);
    126 	vsprintf (msg, fmt, argptr);
    127 	va_end (argptr);
    128 
    129 	MSG_WriteByte (&sv.multicast,svc_centerprint);
    130 	MSG_WriteString (&sv.multicast,msg);
    131 	PF_Unicast (ent, true);
    132 }
    133 
    134 
    135 /*
    136 ===============
    137 PF_error
    138 
    139 Abort the server with a game error
    140 ===============
    141 */
    142 void PF_error (char *fmt, ...)
    143 {
    144 	char		msg[1024];
    145 	va_list		argptr;
    146 	
    147 	va_start (argptr,fmt);
    148 	vsprintf (msg, fmt, argptr);
    149 	va_end (argptr);
    150 
    151 	Com_Error (ERR_DROP, "Game Error: %s", msg);
    152 }
    153 
    154 
    155 /*
    156 =================
    157 PF_setmodel
    158 
    159 Also sets mins and maxs for inline bmodels
    160 =================
    161 */
    162 void PF_setmodel (edict_t *ent, char *name)
    163 {
    164 	int		i;
    165 	cmodel_t	*mod;
    166 
    167 	if (!name)
    168 		Com_Error (ERR_DROP, "PF_setmodel: NULL");
    169 
    170 	i = SV_ModelIndex (name);
    171 		
    172 //	ent->model = name;
    173 	ent->s.modelindex = i;
    174 
    175 // if it is an inline model, get the size information for it
    176 	if (name[0] == '*')
    177 	{
    178 		mod = CM_InlineModel (name);
    179 		VectorCopy (mod->mins, ent->mins);
    180 		VectorCopy (mod->maxs, ent->maxs);
    181 		SV_LinkEdict (ent);
    182 	}
    183 
    184 }
    185 
    186 /*
    187 ===============
    188 PF_Configstring
    189 
    190 ===============
    191 */
    192 void PF_Configstring (int index, char *val)
    193 {
    194 	if (index < 0 || index >= MAX_CONFIGSTRINGS)
    195 		Com_Error (ERR_DROP, "configstring: bad index %i\n", index);
    196 
    197 	if (!val)
    198 		val = "";
    199 
    200 	// change the string in sv
    201 	strcpy (sv.configstrings[index], val);
    202 	
    203 	if (sv.state != ss_loading)
    204 	{	// send the update to everyone
    205 		SZ_Clear (&sv.multicast);
    206 		MSG_WriteChar (&sv.multicast, svc_configstring);
    207 		MSG_WriteShort (&sv.multicast, index);
    208 		MSG_WriteString (&sv.multicast, val);
    209 
    210 		SV_Multicast (vec3_origin, MULTICAST_ALL_R);
    211 	}
    212 }
    213 
    214 
    215 
    216 void PF_WriteChar (int c) {MSG_WriteChar (&sv.multicast, c);}
    217 void PF_WriteByte (int c) {MSG_WriteByte (&sv.multicast, c);}
    218 void PF_WriteShort (int c) {MSG_WriteShort (&sv.multicast, c);}
    219 void PF_WriteLong (int c) {MSG_WriteLong (&sv.multicast, c);}
    220 void PF_WriteFloat (float f) {MSG_WriteFloat (&sv.multicast, f);}
    221 void PF_WriteString (char *s) {MSG_WriteString (&sv.multicast, s);}
    222 void PF_WritePos (vec3_t pos) {MSG_WritePos (&sv.multicast, pos);}
    223 void PF_WriteDir (vec3_t dir) {MSG_WriteDir (&sv.multicast, dir);}
    224 void PF_WriteAngle (float f) {MSG_WriteAngle (&sv.multicast, f);}
    225 
    226 
    227 /*
    228 =================
    229 PF_inPVS
    230 
    231 Also checks portalareas so that doors block sight
    232 =================
    233 */
    234 qboolean PF_inPVS (vec3_t p1, vec3_t p2)
    235 {
    236 	int		leafnum;
    237 	int		cluster;
    238 	int		area1, area2;
    239 	byte	*mask;
    240 
    241 	leafnum = CM_PointLeafnum (p1);
    242 	cluster = CM_LeafCluster (leafnum);
    243 	area1 = CM_LeafArea (leafnum);
    244 	mask = CM_ClusterPVS (cluster);
    245 
    246 	leafnum = CM_PointLeafnum (p2);
    247 	cluster = CM_LeafCluster (leafnum);
    248 	area2 = CM_LeafArea (leafnum);
    249 	if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
    250 		return false;
    251 	if (!CM_AreasConnected (area1, area2))
    252 		return false;		// a door blocks sight
    253 	return true;
    254 }
    255 
    256 
    257 /*
    258 =================
    259 PF_inPHS
    260 
    261 Also checks portalareas so that doors block sound
    262 =================
    263 */
    264 qboolean PF_inPHS (vec3_t p1, vec3_t p2)
    265 {
    266 	int		leafnum;
    267 	int		cluster;
    268 	int		area1, area2;
    269 	byte	*mask;
    270 
    271 	leafnum = CM_PointLeafnum (p1);
    272 	cluster = CM_LeafCluster (leafnum);
    273 	area1 = CM_LeafArea (leafnum);
    274 	mask = CM_ClusterPHS (cluster);
    275 
    276 	leafnum = CM_PointLeafnum (p2);
    277 	cluster = CM_LeafCluster (leafnum);
    278 	area2 = CM_LeafArea (leafnum);
    279 	if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
    280 		return false;		// more than one bounce away
    281 	if (!CM_AreasConnected (area1, area2))
    282 		return false;		// a door blocks hearing
    283 
    284 	return true;
    285 }
    286 
    287 void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume,
    288     float attenuation, float timeofs)
    289 {
    290 	if (!entity)
    291 		return;
    292 	SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs);
    293 }
    294 
    295 //==============================================
    296 
    297 /*
    298 ===============
    299 SV_ShutdownGameProgs
    300 
    301 Called when either the entire server is being killed, or
    302 it is changing to a different game directory.
    303 ===============
    304 */
    305 void SV_ShutdownGameProgs (void)
    306 {
    307 	if (!ge)
    308 		return;
    309 	ge->Shutdown ();
    310 	Sys_UnloadGame ();
    311 	ge = NULL;
    312 }
    313 
    314 /*
    315 ===============
    316 SV_InitGameProgs
    317 
    318 Init the game subsystem for a new map
    319 ===============
    320 */
    321 void SCR_DebugGraph (float value, int color);
    322 
    323 void SV_InitGameProgs (void)
    324 {
    325 	game_import_t	import;
    326 
    327 	// unload anything we have now
    328 	if (ge)
    329 		SV_ShutdownGameProgs ();
    330 
    331 
    332 	// load a new game dll
    333 	import.multicast = SV_Multicast;
    334 	import.unicast = PF_Unicast;
    335 	import.bprintf = SV_BroadcastPrintf;
    336 	import.dprintf = PF_dprintf;
    337 	import.cprintf = PF_cprintf;
    338 	import.centerprintf = PF_centerprintf;
    339 	import.error = PF_error;
    340 
    341 	import.linkentity = SV_LinkEdict;
    342 	import.unlinkentity = SV_UnlinkEdict;
    343 	import.BoxEdicts = SV_AreaEdicts;
    344 	import.trace = SV_Trace;
    345 	import.pointcontents = SV_PointContents;
    346 	import.setmodel = PF_setmodel;
    347 	import.inPVS = PF_inPVS;
    348 	import.inPHS = PF_inPHS;
    349 	import.Pmove = Pmove;
    350 
    351 	import.modelindex = SV_ModelIndex;
    352 	import.soundindex = SV_SoundIndex;
    353 	import.imageindex = SV_ImageIndex;
    354 
    355 	import.configstring = PF_Configstring;
    356 	import.sound = PF_StartSound;
    357 	import.positioned_sound = SV_StartSound;
    358 
    359 	import.WriteChar = PF_WriteChar;
    360 	import.WriteByte = PF_WriteByte;
    361 	import.WriteShort = PF_WriteShort;
    362 	import.WriteLong = PF_WriteLong;
    363 	import.WriteFloat = PF_WriteFloat;
    364 	import.WriteString = PF_WriteString;
    365 	import.WritePosition = PF_WritePos;
    366 	import.WriteDir = PF_WriteDir;
    367 	import.WriteAngle = PF_WriteAngle;
    368 
    369 	import.TagMalloc = Z_TagMalloc;
    370 	import.TagFree = Z_Free;
    371 	import.FreeTags = Z_FreeTags;
    372 
    373 	import.cvar = Cvar_Get;
    374 	import.cvar_set = Cvar_Set;
    375 	import.cvar_forceset = Cvar_ForceSet;
    376 
    377 	import.argc = Cmd_Argc;
    378 	import.argv = Cmd_Argv;
    379 	import.args = Cmd_Args;
    380 	import.AddCommandString = Cbuf_AddText;
    381 
    382 	import.DebugGraph = SCR_DebugGraph;
    383 	import.SetAreaPortalState = CM_SetAreaPortalState;
    384 	import.AreasConnected = CM_AreasConnected;
    385 
    386 	ge = (game_export_t *)Sys_GetGameAPI (&import);
    387 
    388 	if (!ge)
    389 		Com_Error (ERR_DROP, "failed to load game DLL");
    390 	if (ge->apiversion != GAME_API_VERSION)
    391 		Com_Error (ERR_DROP, "game is version %i, not %i", ge->apiversion,
    392 		GAME_API_VERSION);
    393 
    394 	ge->Init ();
    395 }
    396