303 lines
6.3 KiB
C
303 lines
6.3 KiB
C
/*
|
|
Copyright (C) 1997-2001 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
// sv_game.c -- interface to the game dll
|
|
|
|
#include <windows.h>
|
|
#include "engine.h"
|
|
#include "server.h"
|
|
|
|
game_export_t *ge;
|
|
HINSTANCE sv_library;
|
|
game_locals_t game;
|
|
|
|
/*
|
|
===============
|
|
PF_dprintf
|
|
|
|
Debug print to server console
|
|
===============
|
|
*/
|
|
void PF_dprintf (char *fmt, ...)
|
|
{
|
|
char msg[1024];
|
|
va_list argptr;
|
|
|
|
va_start (argptr,fmt);
|
|
vsprintf (msg, fmt, argptr);
|
|
va_end (argptr);
|
|
|
|
Msg ("%s", msg);
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
PF_cprintf
|
|
|
|
Print to a single client
|
|
===============
|
|
*/
|
|
void PF_cprintf (edict_t *ent, int level, char *fmt, ...)
|
|
{
|
|
char msg[1024];
|
|
va_list argptr;
|
|
int n;
|
|
|
|
if (ent)
|
|
{
|
|
n = NUM_FOR_EDICT(ent);
|
|
if (n < 1 || n > maxclients->value)
|
|
Com_Error (ERR_DROP, "cprintf to a non-client");
|
|
}
|
|
|
|
va_start (argptr,fmt);
|
|
vsprintf (msg, fmt, argptr);
|
|
va_end (argptr);
|
|
|
|
if (ent)
|
|
SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg);
|
|
else
|
|
Msg ("%s", msg);
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
PF_centerprintf
|
|
|
|
centerprint to a single client
|
|
===============
|
|
*/
|
|
void PF_centerprintf (edict_t *ent, char *fmt, ...)
|
|
{
|
|
char msg[1024];
|
|
va_list argptr;
|
|
int n;
|
|
|
|
n = NUM_FOR_EDICT(ent);
|
|
if (n < 1 || n > maxclients->value)
|
|
return; // Com_Error (ERR_DROP, "centerprintf to a non-client");
|
|
|
|
va_start (argptr,fmt);
|
|
vsprintf (msg, fmt, argptr);
|
|
va_end (argptr);
|
|
|
|
MSG_Begin( svc_centerprint );
|
|
MSG_WriteString (&sv.multicast, msg);
|
|
MSG_Send(MSG_ONE_R, NULL, ent );
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
PF_error
|
|
|
|
Abort the server with a game error
|
|
===============
|
|
*/
|
|
void PF_error (char *fmt, ...)
|
|
{
|
|
char msg[1024];
|
|
va_list argptr;
|
|
|
|
va_start (argptr,fmt);
|
|
vsprintf (msg, fmt, argptr);
|
|
va_end (argptr);
|
|
|
|
Com_Error (ERR_DROP, "Game Error: %s", msg);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
PF_setmodel
|
|
|
|
Also sets mins and maxs for inline bmodels
|
|
=================
|
|
*/
|
|
void PF_setmodel (edict_t *ent, char *name)
|
|
{
|
|
int i;
|
|
cmodel_t *mod;
|
|
|
|
if (!name) Com_Error (ERR_DROP, "PF_setmodel: NULL");
|
|
|
|
i = SV_ModelIndex (name);
|
|
|
|
// ent->model = name;
|
|
ent->s.modelindex = i;
|
|
|
|
mod = CM_LoadModel (name);
|
|
|
|
if(mod) // hull setup
|
|
{
|
|
VectorCopy (mod->mins, ent->mins);
|
|
VectorCopy (mod->maxs, ent->maxs);
|
|
SV_LinkEdict (ent);
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
PF_Configstring
|
|
|
|
===============
|
|
*/
|
|
void PF_Configstring (int index, char *val)
|
|
{
|
|
if (index < 0 || index >= MAX_CONFIGSTRINGS)
|
|
Com_Error (ERR_DROP, "configstring: bad index %i value %s\n", index, val);
|
|
|
|
if (!val) val = "";
|
|
|
|
// change the string in sv
|
|
strcpy (sv.configstrings[index], val);
|
|
|
|
if (sv.state != ss_loading)
|
|
{
|
|
// send the update to everyone
|
|
SZ_Clear (&sv.multicast);
|
|
MSG_Begin(svc_configstring);
|
|
MSG_WriteShort (&sv.multicast, index);
|
|
MSG_WriteString (&sv.multicast, val);
|
|
MSG_Send(MSG_ALL_R, vec3_origin, NULL );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PF_inPVS
|
|
|
|
Also checks portalareas so that doors block sight
|
|
=================
|
|
*/
|
|
bool PF_inPVS (vec3_t p1, vec3_t p2)
|
|
{
|
|
int leafnum;
|
|
int cluster;
|
|
int area1, area2;
|
|
byte *mask;
|
|
|
|
leafnum = CM_PointLeafnum (p1);
|
|
cluster = CM_LeafCluster (leafnum);
|
|
area1 = CM_LeafArea (leafnum);
|
|
mask = CM_ClusterPVS (cluster);
|
|
|
|
leafnum = CM_PointLeafnum (p2);
|
|
cluster = CM_LeafCluster (leafnum);
|
|
area2 = CM_LeafArea (leafnum);
|
|
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
|
return false;
|
|
if (!CM_AreasConnected (area1, area2))
|
|
return false; // a door blocks sight
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
PF_inPHS
|
|
|
|
Also checks portalareas so that doors block sound
|
|
=================
|
|
*/
|
|
bool PF_inPHS (vec3_t p1, vec3_t p2)
|
|
{
|
|
int leafnum;
|
|
int cluster;
|
|
int area1, area2;
|
|
byte *mask;
|
|
|
|
leafnum = CM_PointLeafnum (p1);
|
|
cluster = CM_LeafCluster (leafnum);
|
|
area1 = CM_LeafArea (leafnum);
|
|
mask = CM_ClusterPHS (cluster);
|
|
|
|
leafnum = CM_PointLeafnum (p2);
|
|
cluster = CM_LeafCluster (leafnum);
|
|
area2 = CM_LeafArea (leafnum);
|
|
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
|
return false; // more than one bounce away
|
|
if (!CM_AreasConnected (area1, area2))
|
|
return false; // a door blocks hearing
|
|
|
|
return true;
|
|
}
|
|
|
|
void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume, float attenuation, float timeofs)
|
|
{
|
|
if (!entity) return;
|
|
SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs);
|
|
}
|
|
|
|
//==============================================
|
|
|
|
/*
|
|
===============
|
|
SV_ShutdownGameProgs
|
|
|
|
Called when either the entire server is being killed, or
|
|
it is changing to a different game directory.
|
|
===============
|
|
*/
|
|
void SV_ShutdownGameProgs (void)
|
|
{
|
|
if (!ge) return;
|
|
|
|
Msg("==== ShutdownGame ====\n");
|
|
|
|
//free main memory pools
|
|
Mem_FreePool(&sv.mempool);
|
|
|
|
Mem_Free( ge );
|
|
ge = NULL;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
SV_InitGameProgs
|
|
|
|
Init the game subsystem for a new map
|
|
===============
|
|
*/
|
|
void SCR_DebugGraph (float value, int color);
|
|
|
|
void SV_InitGameProgs (void)
|
|
{
|
|
// unload anything we have now
|
|
if (ge) SV_ShutdownGameProgs ();
|
|
|
|
sv.mempool = Mem_AllocPool("Zone Game");
|
|
ge = Mem_Alloc(sv.mempool, sizeof(game_export_t));
|
|
|
|
// initialize all entities for this game
|
|
game.maxentities = 1024;
|
|
|
|
ge->edict_size = sizeof(edict_t);
|
|
ge->edicts = (edict_t *)Mem_Alloc(sv.mempool, game.maxentities * ge->edict_size);
|
|
ge->max_edicts = game.maxentities;
|
|
|
|
// initialize all clients for this game
|
|
game.maxclients = maxclients->value;
|
|
game.clients = (gclient_t *)Mem_Alloc(sv.mempool, game.maxclients * sizeof(gclient_t));
|
|
ge->num_edicts = game.maxclients + 1; //reserve for world
|
|
}
|
|
|