2019-11-24 20:45:15 -08:00
/*
Copyright ( C ) 1996 - 2001 Id Software , Inc .
Copyright ( C ) 2002 - 2009 John Fitzgibbons and others
Copyright ( C ) 2010 - 2014 QuakeSpasm developers
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_edict.c -- entity dictionary
# include "quakedef.h"
2019-11-25 17:40:18 -08:00
dprograms_t * progs ;
dfunction_t * pr_functions ;
static char * pr_strings ;
static int32_t pr_stringssize ;
static const char * * pr_knownstrings ;
static int32_t pr_maxknownstrings ;
static int32_t pr_numknownstrings ;
static ddef_t * pr_fielddefs ;
static ddef_t * pr_globaldefs ;
bool pr_alpha_supported ; //johnfitz
dstatement_t * pr_statements ;
globalvars_t * pr_global_struct ;
float * pr_globals ; // same as pr_global_struct
int32_t pr_edict_size ; // in bytes
uint16_t pr_crc ;
int32_t type_size [ 8 ] =
{
1 , // ev_void
1 , // sizeof(string_t) / 4 // ev_string
1 , // ev_float
3 , // ev_vector
1 , // ev_entity
1 , // ev_field
1 , // sizeof(func_t) / 4 // ev_function
1 // sizeof(void *) / 4 // ev_pointer
2019-11-24 20:45:15 -08:00
} ;
2019-11-25 17:40:18 -08:00
static ddef_t * ED_FieldAtOfs ( int32_t ofs ) ;
static bool ED_ParseEpair ( void * base , ddef_t * key , const char * s ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
# define MAX_FIELD_LEN 64
# define GEFV_CACHESIZE 2
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
typedef struct
{
ddef_t * pcache ;
char field [ MAX_FIELD_LEN ] ;
2019-11-24 20:45:15 -08:00
} gefv_cache ;
2019-11-25 17:40:18 -08:00
static gefv_cache gefvCache [ GEFV_CACHESIZE ] =
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
{ NULL , " " } ,
{ NULL , " " }
2019-11-24 20:45:15 -08:00
} ;
2019-11-25 17:40:18 -08:00
cvar_t nomonsters = { " nomonsters " , " 0 " , CVAR_NONE } ;
cvar_t gamecfg = { " gamecfg " , " 0 " , CVAR_NONE } ;
cvar_t scratch1 = { " scratch1 " , " 0 " , CVAR_NONE } ;
cvar_t scratch2 = { " scratch2 " , " 0 " , CVAR_NONE } ;
cvar_t scratch3 = { " scratch3 " , " 0 " , CVAR_NONE } ;
cvar_t scratch4 = { " scratch4 " , " 0 " , CVAR_NONE } ;
cvar_t savedgamecfg = { " savedgamecfg " , " 0 " , CVAR_ARCHIVE } ;
cvar_t saved1 = { " saved1 " , " 0 " , CVAR_ARCHIVE } ;
cvar_t saved2 = { " saved2 " , " 0 " , CVAR_ARCHIVE } ;
cvar_t saved3 = { " saved3 " , " 0 " , CVAR_ARCHIVE } ;
cvar_t saved4 = { " saved4 " , " 0 " , CVAR_ARCHIVE } ;
2019-11-24 20:45:15 -08:00
/*
= = = = = = = = = = = = = = = = =
ED_ClearEdict
Sets everything to NULL
= = = = = = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
void ED_ClearEdict ( edict_t * e )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
memset ( & e - > v , 0 , progs - > entityfields * 4 ) ;
2019-11-24 20:45:15 -08:00
e - > free = false ;
}
/*
= = = = = = = = = = = = = = = = =
ED_Alloc
Either finds a free edict , or allocates a new one .
Try to avoid reusing an entity that was recently freed , because it
can cause the client to think the entity morphed into something else
instead of being removed and recreated , which can cause interpolated
angles and bad trails .
= = = = = = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
edict_t * ED_Alloc ( void )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i ;
edict_t * e ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for ( i = svs . maxclients + 1 ; i < sv . num_edicts ; i + + )
2019-11-24 20:45:15 -08:00
{
e = EDICT_NUM ( i ) ;
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
2019-11-25 17:40:18 -08:00
if ( e - > free & & ( e - > freetime < 2 | | sv . time - e - > freetime > 0.5 ) )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ED_ClearEdict ( e ) ;
2019-11-24 20:45:15 -08:00
return e ;
}
}
2019-11-25 17:40:18 -08:00
if ( i = = sv . max_edicts ) //johnfitz -- use sv.max_edicts instead of MAX_EDICTS
Host_Error ( " ED_Alloc: no free edicts (max_edicts is % " PRIi32 " ) " , sv . max_edicts ) ;
2019-11-24 20:45:15 -08:00
sv . num_edicts + + ;
e = EDICT_NUM ( i ) ;
memset ( e , 0 , pr_edict_size ) ; // ericw -- switched sv.edicts to malloc(), so we are accessing uninitialized memory and must fully zero it, not just ED_ClearEdict
return e ;
}
/*
= = = = = = = = = = = = = = = = =
ED_Free
Marks the edict as free
FIXME : walk all entities and NULL out references to this entity
= = = = = = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
void ED_Free ( edict_t * ed )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
SV_UnlinkEdict ( ed ) ; // unlink from world bsp
2019-11-24 20:45:15 -08:00
ed - > free = true ;
ed - > v . model = 0 ;
ed - > v . takedamage = 0 ;
ed - > v . modelindex = 0 ;
ed - > v . colormap = 0 ;
ed - > v . skin = 0 ;
ed - > v . frame = 0 ;
2019-11-25 17:40:18 -08:00
VectorCopy ( vec3_origin , ed - > v . origin ) ;
VectorCopy ( vec3_origin , ed - > v . angles ) ;
2019-11-24 20:45:15 -08:00
ed - > v . nextthink = - 1 ;
ed - > v . solid = 0 ;
ed - > alpha = ENTALPHA_DEFAULT ; //johnfitz -- reset alpha for next entity
ed - > freetime = sv . time ;
}
//===========================================================================
/*
= = = = = = = = = = = =
ED_GlobalAtOfs
= = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static ddef_t * ED_GlobalAtOfs ( int32_t ofs )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ddef_t * def ;
int32_t i ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < progs - > numglobaldefs ; i + + )
2019-11-24 20:45:15 -08:00
{
def = & pr_globaldefs [ i ] ;
2019-11-25 17:40:18 -08:00
if ( def - > ofs = = ofs )
2019-11-24 20:45:15 -08:00
return def ;
}
return NULL ;
}
/*
= = = = = = = = = = = =
ED_FieldAtOfs
= = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static ddef_t * ED_FieldAtOfs ( int32_t ofs )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ddef_t * def ;
int32_t i ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < progs - > numfielddefs ; i + + )
2019-11-24 20:45:15 -08:00
{
def = & pr_fielddefs [ i ] ;
2019-11-25 17:40:18 -08:00
if ( def - > ofs = = ofs )
2019-11-24 20:45:15 -08:00
return def ;
}
return NULL ;
}
/*
= = = = = = = = = = = =
ED_FindField
= = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static ddef_t * ED_FindField ( const char * name )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ddef_t * def ;
int32_t i ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < progs - > numfielddefs ; i + + )
2019-11-24 20:45:15 -08:00
{
def = & pr_fielddefs [ i ] ;
2019-11-25 17:40:18 -08:00
if ( ! strcmp ( PR_GetString ( def - > s_name ) , name ) )
2019-11-24 20:45:15 -08:00
return def ;
}
return NULL ;
}
/*
= = = = = = = = = = = =
ED_FindGlobal
= = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static ddef_t * ED_FindGlobal ( const char * name )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ddef_t * def ;
int32_t i ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < progs - > numglobaldefs ; i + + )
2019-11-24 20:45:15 -08:00
{
def = & pr_globaldefs [ i ] ;
2019-11-25 17:40:18 -08:00
if ( ! strcmp ( PR_GetString ( def - > s_name ) , name ) )
2019-11-24 20:45:15 -08:00
return def ;
}
return NULL ;
}
/*
= = = = = = = = = = = =
ED_FindFunction
= = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static dfunction_t * ED_FindFunction ( const char * fn_name )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
dfunction_t * func ;
int32_t i ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < progs - > numfunctions ; i + + )
2019-11-24 20:45:15 -08:00
{
func = & pr_functions [ i ] ;
2019-11-25 17:40:18 -08:00
if ( ! strcmp ( PR_GetString ( func - > s_name ) , fn_name ) )
2019-11-24 20:45:15 -08:00
return func ;
}
return NULL ;
}
/*
= = = = = = = = = = = =
GetEdictFieldValue
= = = = = = = = = = = =
*/
eval_t * GetEdictFieldValue ( edict_t * ed , const char * field )
{
2019-11-25 17:40:18 -08:00
ddef_t * def = NULL ;
int32_t i ;
static int32_t rep = 0 ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < GEFV_CACHESIZE ; i + + )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( ! strcmp ( field , gefvCache [ i ] . field ) )
2019-11-24 20:45:15 -08:00
{
def = gefvCache [ i ] . pcache ;
goto Done ;
}
}
2019-11-25 17:40:18 -08:00
def = ED_FindField ( field ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( strlen ( field ) < MAX_FIELD_LEN )
2019-11-24 20:45:15 -08:00
{
gefvCache [ rep ] . pcache = def ;
2019-11-25 17:40:18 -08:00
strcpy ( gefvCache [ rep ] . field , field ) ;
2019-11-24 20:45:15 -08:00
rep ^ = 1 ;
}
Done :
2019-11-25 17:40:18 -08:00
if ( ! def )
2019-11-24 20:45:15 -08:00
return NULL ;
2019-11-25 17:40:18 -08:00
return ( eval_t * ) ( ( char * ) & ed - > v + def - > ofs * 4 ) ;
2019-11-24 20:45:15 -08:00
}
/*
= = = = = = = = = = = =
PR_ValueString
( etype_t type , eval_t * val )
Returns a string describing * data in a type specific manner
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static const char * PR_ValueString ( int32_t type , eval_t * val )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
static char line [ 512 ] ;
ddef_t * def ;
dfunction_t * f ;
2019-11-24 20:45:15 -08:00
type & = ~ DEF_SAVEGLOBAL ;
2019-11-25 17:40:18 -08:00
switch ( type )
2019-11-24 20:45:15 -08:00
{
case ev_string :
2019-11-25 17:40:18 -08:00
sprintf ( line , " %s " , PR_GetString ( val - > string ) ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_entity :
2019-11-25 17:40:18 -08:00
sprintf ( line , " entity % " PRIi32 " " , NUM_FOR_EDICT ( PROG_TO_EDICT ( val - > edict ) ) ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_function :
f = pr_functions + val - > function ;
2019-11-25 17:40:18 -08:00
sprintf ( line , " %s() " , PR_GetString ( f - > s_name ) ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_field :
2019-11-25 17:40:18 -08:00
def = ED_FieldAtOfs ( val - > _int ) ;
sprintf ( line , " .%s " , PR_GetString ( def - > s_name ) ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_void :
2019-11-25 17:40:18 -08:00
sprintf ( line , " void " ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_float :
2019-11-25 17:40:18 -08:00
sprintf ( line , " %5.1f " , val - > _float ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_vector :
2019-11-25 17:40:18 -08:00
sprintf ( line , " '%5.1f %5.1f %5.1f' " , val - > vector [ 0 ] , val - > vector [ 1 ] , val - > vector [ 2 ] ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_pointer :
2019-11-25 17:40:18 -08:00
sprintf ( line , " pointer " ) ;
2019-11-24 20:45:15 -08:00
break ;
default :
2019-11-25 17:40:18 -08:00
sprintf ( line , " bad type % " PRIi32 " " , type ) ;
2019-11-24 20:45:15 -08:00
break ;
}
return line ;
}
/*
= = = = = = = = = = = =
PR_UglyValueString
( etype_t type , eval_t * val )
Returns a string describing * data in a type specific manner
Easier to parse than PR_ValueString
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static const char * PR_UglyValueString ( int32_t type , eval_t * val )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
static char line [ 512 ] ;
ddef_t * def ;
dfunction_t * f ;
2019-11-24 20:45:15 -08:00
type & = ~ DEF_SAVEGLOBAL ;
2019-11-25 17:40:18 -08:00
switch ( type )
2019-11-24 20:45:15 -08:00
{
case ev_string :
2019-11-25 17:40:18 -08:00
sprintf ( line , " %s " , PR_GetString ( val - > string ) ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_entity :
2019-11-25 17:40:18 -08:00
sprintf ( line , " % " PRIi32 " " , NUM_FOR_EDICT ( PROG_TO_EDICT ( val - > edict ) ) ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_function :
f = pr_functions + val - > function ;
2019-11-25 17:40:18 -08:00
sprintf ( line , " %s " , PR_GetString ( f - > s_name ) ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_field :
2019-11-25 17:40:18 -08:00
def = ED_FieldAtOfs ( val - > _int ) ;
sprintf ( line , " %s " , PR_GetString ( def - > s_name ) ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_void :
2019-11-25 17:40:18 -08:00
sprintf ( line , " void " ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_float :
2019-11-25 17:40:18 -08:00
sprintf ( line , " %f " , val - > _float ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_vector :
2019-11-25 17:40:18 -08:00
sprintf ( line , " %f %f %f " , val - > vector [ 0 ] , val - > vector [ 1 ] , val - > vector [ 2 ] ) ;
2019-11-24 20:45:15 -08:00
break ;
default :
2019-11-25 17:40:18 -08:00
sprintf ( line , " bad type % " PRIi32 " " , type ) ;
2019-11-24 20:45:15 -08:00
break ;
}
return line ;
}
/*
= = = = = = = = = = = =
PR_GlobalString
Returns a string with a description and the contents of a global ,
padded to 20 field width
= = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
const char * PR_GlobalString ( int32_t ofs )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
static char line [ 512 ] ;
const char * s ;
int32_t i ;
ddef_t * def ;
void * val ;
2019-11-24 20:45:15 -08:00
val = ( void * ) & pr_globals [ ofs ] ;
def = ED_GlobalAtOfs ( ofs ) ;
2019-11-25 17:40:18 -08:00
if ( ! def )
sprintf ( line , " % " PRIi32 " (?) " , ofs ) ;
2019-11-24 20:45:15 -08:00
else
{
2019-11-25 17:40:18 -08:00
s = PR_ValueString ( def - > type , ( eval_t * ) val ) ;
sprintf ( line , " % " PRIi32 " (%s)%s " , ofs , PR_GetString ( def - > s_name ) , s ) ;
2019-11-24 20:45:15 -08:00
}
i = strlen ( line ) ;
2019-11-25 17:40:18 -08:00
for ( ; i < 20 ; i + + )
strcat ( line , " " ) ;
strcat ( line , " " ) ;
2019-11-24 20:45:15 -08:00
return line ;
}
2019-11-25 17:40:18 -08:00
const char * PR_GlobalStringNoContents ( int32_t ofs )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
static char line [ 512 ] ;
int32_t i ;
ddef_t * def ;
2019-11-24 20:45:15 -08:00
def = ED_GlobalAtOfs ( ofs ) ;
2019-11-25 17:40:18 -08:00
if ( ! def )
sprintf ( line , " % " PRIi32 " (?) " , ofs ) ;
2019-11-24 20:45:15 -08:00
else
2019-11-25 17:40:18 -08:00
sprintf ( line , " % " PRIi32 " (%s) " , ofs , PR_GetString ( def - > s_name ) ) ;
2019-11-24 20:45:15 -08:00
i = strlen ( line ) ;
2019-11-25 17:40:18 -08:00
for ( ; i < 20 ; i + + )
strcat ( line , " " ) ;
strcat ( line , " " ) ;
2019-11-24 20:45:15 -08:00
return line ;
}
/*
= = = = = = = = = = = = =
ED_Print
For debugging
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
void ED_Print ( edict_t * ed )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ddef_t * d ;
int32_t * v ;
int32_t i , j , l ;
const char * name ;
int32_t type ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( ed - > free )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_Printf ( " FREE \n " ) ;
2019-11-24 20:45:15 -08:00
return ;
}
2019-11-25 16:56:15 -08:00
Con_SafePrintf ( " \n EDICT % " PRIi32 " : \n " , NUM_FOR_EDICT ( ed ) ) ; //johnfitz -- was Con_Printf
2019-11-25 17:40:18 -08:00
for ( i = 1 ; i < progs - > numfielddefs ; i + + )
2019-11-24 20:45:15 -08:00
{
d = & pr_fielddefs [ i ] ;
name = PR_GetString ( d - > s_name ) ;
2019-11-25 17:40:18 -08:00
l = strlen ( name ) ;
if ( l > 1 & & name [ l - 2 ] = = ' _ ' )
continue ; // skip _x, _y, _z vars
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
v = ( int32_t * ) ( ( char * ) & ed - > v + d - > ofs * 4 ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
// if the value is still all 0, skip the field
2019-11-24 20:45:15 -08:00
type = d - > type & ~ DEF_SAVEGLOBAL ;
2019-11-25 17:40:18 -08:00
for ( j = 0 ; j < type_size [ type ] ; j + + )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( v [ j ] )
2019-11-24 20:45:15 -08:00
break ;
}
2019-11-25 17:40:18 -08:00
if ( j = = type_size [ type ] )
2019-11-24 20:45:15 -08:00
continue ;
2019-11-25 17:40:18 -08:00
Con_SafePrintf ( " %s " , name ) ; //johnfitz -- was Con_Printf
while ( l + + < 15 )
Con_SafePrintf ( " " ) ; //johnfitz -- was Con_Printf
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
Con_SafePrintf ( " %s \n " , PR_ValueString ( d - > type , ( eval_t * ) v ) ) ; //johnfitz -- was Con_Printf
2019-11-24 20:45:15 -08:00
}
}
/*
= = = = = = = = = = = = =
ED_Write
For savegames
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
void ED_Write ( FILE * f , edict_t * ed )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ddef_t * d ;
int32_t * v ;
int32_t i , j ;
const char * name ;
int32_t type ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
fprintf ( f , " { \n " ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( ed - > free )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
fprintf ( f , " } \n " ) ;
2019-11-24 20:45:15 -08:00
return ;
}
2019-11-25 17:40:18 -08:00
for ( i = 1 ; i < progs - > numfielddefs ; i + + )
2019-11-24 20:45:15 -08:00
{
d = & pr_fielddefs [ i ] ;
name = PR_GetString ( d - > s_name ) ;
2019-11-25 17:40:18 -08:00
j = strlen ( name ) ;
if ( j > 1 & & name [ j - 2 ] = = ' _ ' )
continue ; // skip _x, _y, _z vars
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
v = ( int32_t * ) ( ( char * ) & ed - > v + d - > ofs * 4 ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
// if the value is still all 0, skip the field
2019-11-24 20:45:15 -08:00
type = d - > type & ~ DEF_SAVEGLOBAL ;
2019-11-25 17:40:18 -08:00
for ( j = 0 ; j < type_size [ type ] ; j + + )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( v [ j ] )
2019-11-24 20:45:15 -08:00
break ;
}
2019-11-25 17:40:18 -08:00
if ( j = = type_size [ type ] )
2019-11-24 20:45:15 -08:00
continue ;
2019-11-25 17:40:18 -08:00
fprintf ( f , " \" %s \" " , name ) ;
fprintf ( f , " \" %s \" \n " , PR_UglyValueString ( d - > type , ( eval_t * ) v ) ) ;
2019-11-24 20:45:15 -08:00
}
//johnfitz -- save entity alpha manually when progs.dat doesn't know about alpha
2019-11-25 17:40:18 -08:00
if ( ! pr_alpha_supported & & ed - > alpha ! = ENTALPHA_DEFAULT )
fprintf ( f , " \" alpha \" \" %f \" \n " , ENTALPHA_TOSAVE ( ed - > alpha ) ) ;
2019-11-24 20:45:15 -08:00
//johnfitz
2019-11-25 17:40:18 -08:00
fprintf ( f , " } \n " ) ;
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
void ED_PrintNum ( int32_t ent )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ED_Print ( EDICT_NUM ( ent ) ) ;
2019-11-24 20:45:15 -08:00
}
/*
= = = = = = = = = = = = =
ED_PrintEdicts
For debugging , prints all the entities in the current server
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
void ED_PrintEdicts ( void )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( ! sv . active )
2019-11-24 20:45:15 -08:00
return ;
2019-11-25 17:40:18 -08:00
Con_Printf ( " % " PRIi32 " entities \n " , sv . num_edicts ) ;
for ( i = 0 ; i < sv . num_edicts ; i + + )
ED_PrintNum ( i ) ;
2019-11-24 20:45:15 -08:00
}
/*
= = = = = = = = = = = = =
ED_PrintEdict_f
For debugging , prints a single edicy
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static void ED_PrintEdict_f ( void )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( ! sv . active )
2019-11-24 20:45:15 -08:00
return ;
2019-11-25 17:40:18 -08:00
i = Q_atoi ( Cmd_Argv ( 1 ) ) ;
if ( i < 0 | | i > = sv . num_edicts )
2019-11-24 20:45:15 -08:00
{
Con_Printf ( " Bad edict number \n " ) ;
return ;
}
2019-11-25 17:40:18 -08:00
ED_PrintNum ( i ) ;
2019-11-24 20:45:15 -08:00
}
/*
= = = = = = = = = = = = =
ED_Count
For debugging
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static void ED_Count ( void )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
edict_t * ent ;
int32_t i , active , models , solid , step ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( ! sv . active )
2019-11-24 20:45:15 -08:00
return ;
active = models = solid = step = 0 ;
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < sv . num_edicts ; i + + )
2019-11-24 20:45:15 -08:00
{
ent = EDICT_NUM ( i ) ;
2019-11-25 17:40:18 -08:00
if ( ent - > free )
2019-11-24 20:45:15 -08:00
continue ;
active + + ;
2019-11-25 17:40:18 -08:00
if ( ent - > v . solid )
2019-11-24 20:45:15 -08:00
solid + + ;
2019-11-25 17:40:18 -08:00
if ( ent - > v . model )
2019-11-24 20:45:15 -08:00
models + + ;
2019-11-25 17:40:18 -08:00
if ( ent - > v . movetype = = MOVETYPE_STEP )
2019-11-24 20:45:15 -08:00
step + + ;
}
2019-11-25 17:40:18 -08:00
Con_Printf ( " num_edicts:%3 " PRIi32 " \n " , sv . num_edicts ) ;
Con_Printf ( " active :%3 " PRIi32 " \n " , active ) ;
Con_Printf ( " view :%3 " PRIi32 " \n " , models ) ;
Con_Printf ( " touch :%3 " PRIi32 " \n " , solid ) ;
Con_Printf ( " step :%3 " PRIi32 " \n " , step ) ;
2019-11-24 20:45:15 -08:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ARCHIVING GLOBALS
FIXME : need to tag constants , doesn ' t really work
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = =
ED_WriteGlobals
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
void ED_WriteGlobals ( FILE * f )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ddef_t * def ;
int32_t i ;
const char * name ;
int32_t type ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
fprintf ( f , " { \n " ) ;
for ( i = 0 ; i < progs - > numglobaldefs ; i + + )
2019-11-24 20:45:15 -08:00
{
def = & pr_globaldefs [ i ] ;
type = def - > type ;
2019-11-25 17:40:18 -08:00
if ( ! ( def - > type & DEF_SAVEGLOBAL ) )
2019-11-24 20:45:15 -08:00
continue ;
type & = ~ DEF_SAVEGLOBAL ;
2019-11-25 17:40:18 -08:00
if ( type ! = ev_string & & type ! = ev_float & & type ! = ev_entity )
2019-11-24 20:45:15 -08:00
continue ;
name = PR_GetString ( def - > s_name ) ;
2019-11-25 17:40:18 -08:00
fprintf ( f , " \" %s \" " , name ) ;
fprintf ( f , " \" %s \" \n " , PR_UglyValueString ( type , ( eval_t * ) & pr_globals [ def - > ofs ] ) ) ;
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
fprintf ( f , " } \n " ) ;
2019-11-24 20:45:15 -08:00
}
/*
= = = = = = = = = = = = =
ED_ParseGlobals
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
const char * ED_ParseGlobals ( const char * data )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
char keyname [ 64 ] ;
ddef_t * key ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
while ( 1 )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
// parse key
data = COM_Parse ( data ) ;
if ( com_token [ 0 ] = = ' } ' )
2019-11-24 20:45:15 -08:00
break ;
2019-11-25 17:40:18 -08:00
if ( ! data )
Host_Error ( " ED_ParseEntity: EOF without closing brace " ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
q_strlcpy ( keyname , com_token , sizeof ( keyname ) ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
// parse value
data = COM_Parse ( data ) ;
if ( ! data )
Host_Error ( " ED_ParseEntity: EOF without closing brace " ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( com_token [ 0 ] = = ' } ' )
Host_Error ( " ED_ParseEntity: closing brace without data " ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
key = ED_FindGlobal ( keyname ) ;
if ( ! key )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_Printf ( " '%s' is not a global \n " , keyname ) ;
2019-11-24 20:45:15 -08:00
continue ;
}
2019-11-25 17:40:18 -08:00
if ( ! ED_ParseEpair ( ( void * ) pr_globals , key , com_token ) )
Host_Error ( " ED_ParseGlobals: parse error " ) ;
2019-11-24 20:45:15 -08:00
}
return data ;
}
//============================================================================
/*
= = = = = = = = = = = = =
ED_NewString
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static string_t ED_NewString ( const char * string )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
char * new_p ;
int32_t i , l ;
string_t num ;
2019-11-24 20:45:15 -08:00
l = strlen ( string ) + 1 ;
2019-11-25 17:40:18 -08:00
num = PR_AllocString ( l , & new_p ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < l ; i + + )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( string [ i ] = = ' \\ ' & & i < l - 1 )
2019-11-24 20:45:15 -08:00
{
i + + ;
2019-11-25 17:40:18 -08:00
if ( string [ i ] = = ' n ' )
2019-11-24 20:45:15 -08:00
* new_p + + = ' \n ' ;
else
* new_p + + = ' \\ ' ;
}
else
* new_p + + = string [ i ] ;
}
return num ;
}
/*
= = = = = = = = = = = = =
ED_ParseEval
Can parse either fields or globals
returns false if error
= = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
static bool ED_ParseEpair ( void * base , ddef_t * key , const char * s )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i ;
char string [ 128 ] ;
ddef_t * def ;
char * v , * w ;
char * end ;
void * d ;
dfunction_t * func ;
2019-11-24 20:45:15 -08:00
2019-11-25 16:49:58 -08:00
d = ( void * ) ( ( int32_t * ) base + key - > ofs ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
switch ( key - > type & ~ DEF_SAVEGLOBAL )
2019-11-24 20:45:15 -08:00
{
case ev_string :
* ( string_t * ) d = ED_NewString ( s ) ;
break ;
case ev_float :
2019-11-25 17:40:18 -08:00
* ( float * ) d = atof ( s ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_vector :
2019-11-25 17:40:18 -08:00
q_strlcpy ( string , s , sizeof ( string ) ) ;
2019-11-24 20:45:15 -08:00
end = ( char * ) string + strlen ( string ) ;
v = string ;
w = string ;
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < 3 & & ( w < = end ) ; i + + ) // ericw -- added (w <= end) check
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
// set v to the next space (or 0 byte), and change that char to a 0 byte
while ( * v & & * v ! = ' ' )
2019-11-24 20:45:15 -08:00
v + + ;
* v = 0 ;
2019-11-25 17:40:18 -08:00
( ( float * ) d ) [ i ] = atof ( w ) ;
w = v = v + 1 ;
2019-11-24 20:45:15 -08:00
}
// ericw -- fill remaining elements to 0 in case we hit the end of string
// before reading 3 floats.
2019-11-25 17:40:18 -08:00
if ( i < 3 )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_DWarning ( " Avoided reading garbage for \" %s \" \" %s \" \n " , PR_GetString ( key - > s_name ) , s ) ;
for ( ; i < 3 ; i + + )
2019-11-24 20:45:15 -08:00
( ( float * ) d ) [ i ] = 0.0f ;
}
break ;
case ev_entity :
2019-11-25 17:40:18 -08:00
* ( int32_t * ) d = EDICT_TO_PROG ( EDICT_NUM ( atoi ( s ) ) ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_field :
2019-11-25 17:40:18 -08:00
def = ED_FindField ( s ) ;
if ( ! def )
2019-11-24 20:45:15 -08:00
{
//johnfitz -- HACK -- suppress error becuase fog/sky fields might not be mentioned in defs.qc
2019-11-25 17:40:18 -08:00
if ( strncmp ( s , " sky " , 3 ) & & strcmp ( s , " fog " ) )
Con_DPrintf ( " Can't find field %s \n " , s ) ;
2019-11-24 20:45:15 -08:00
return false ;
}
2019-11-25 16:49:58 -08:00
* ( int32_t * ) d = G_INT ( def - > ofs ) ;
2019-11-24 20:45:15 -08:00
break ;
case ev_function :
2019-11-25 17:40:18 -08:00
func = ED_FindFunction ( s ) ;
if ( ! func )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_Printf ( " Can't find function %s \n " , s ) ;
2019-11-24 20:45:15 -08:00
return false ;
}
* ( func_t * ) d = func - pr_functions ;
break ;
default :
break ;
}
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = =
ED_ParseEdict
Parses an edict out of the given string , returning the new position
ed should be a properly initialized empty edict .
Used for initial level load and for savegames .
= = = = = = = = = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
const char * ED_ParseEdict ( const char * data , edict_t * ent )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ddef_t * key ;
char keyname [ 256 ] ;
bool anglehack , init ;
int32_t n ;
2019-11-24 20:45:15 -08:00
init = false ;
// clear it
2019-11-25 17:40:18 -08:00
if ( ent ! = sv . edicts ) // hack
memset ( & ent - > v , 0 , progs - > entityfields * 4 ) ;
2019-11-24 20:45:15 -08:00
// go through all the dictionary pairs
2019-11-25 17:40:18 -08:00
while ( 1 )
2019-11-24 20:45:15 -08:00
{
// parse key
2019-11-25 17:40:18 -08:00
data = COM_Parse ( data ) ;
if ( com_token [ 0 ] = = ' } ' )
2019-11-24 20:45:15 -08:00
break ;
2019-11-25 17:40:18 -08:00
if ( ! data )
Host_Error ( " ED_ParseEntity: EOF without closing brace " ) ;
2019-11-24 20:45:15 -08:00
// anglehack is to allow QuakeEd to write single scalar angles
// and allow them to be turned into vectors. (FIXME...)
2019-11-25 17:40:18 -08:00
if ( ! strcmp ( com_token , " angle " ) )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
strcpy ( com_token , " angles " ) ;
2019-11-24 20:45:15 -08:00
anglehack = true ;
}
else
anglehack = false ;
// FIXME: change light to _light to get rid of this hack
2019-11-25 17:40:18 -08:00
if ( ! strcmp ( com_token , " light " ) )
strcpy ( com_token , " light_lev " ) ; // hack for single light def
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
q_strlcpy ( keyname , com_token , sizeof ( keyname ) ) ;
2019-11-24 20:45:15 -08:00
// another hack to fix keynames with trailing spaces
n = strlen ( keyname ) ;
2019-11-25 17:40:18 -08:00
while ( n & & keyname [ n - 1 ] = = ' ' )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
keyname [ n - 1 ] = 0 ;
2019-11-24 20:45:15 -08:00
n - - ;
}
// parse value
2019-11-25 17:40:18 -08:00
data = COM_Parse ( data ) ;
if ( ! data )
Host_Error ( " ED_ParseEntity: EOF without closing brace " ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( com_token [ 0 ] = = ' } ' )
Host_Error ( " ED_ParseEntity: closing brace without data " ) ;
2019-11-24 20:45:15 -08:00
init = true ;
// keynames with a leading underscore are used for utility comments,
// and are immediately discarded by quake
2019-11-25 17:40:18 -08:00
if ( keyname [ 0 ] = = ' _ ' )
2019-11-24 20:45:15 -08:00
continue ;
//johnfitz -- hack to support .alpha even when progs.dat doesn't know about it
2019-11-25 17:40:18 -08:00
if ( ! strcmp ( keyname , " alpha " ) )
2019-11-24 20:45:15 -08:00
ent - > alpha = ENTALPHA_ENCODE ( atof ( com_token ) ) ;
//johnfitz
2019-11-25 17:40:18 -08:00
key = ED_FindField ( keyname ) ;
if ( ! key )
2019-11-24 20:45:15 -08:00
{
//johnfitz -- HACK -- suppress error becuase fog/sky/alpha fields might not be mentioned in defs.qc
2019-11-25 17:40:18 -08:00
if ( strncmp ( keyname , " sky " , 3 ) & & strcmp ( keyname , " fog " ) & & strcmp ( keyname , " alpha " ) )
Con_DPrintf ( " \" %s \" is not a field \n " , keyname ) ; //johnfitz -- was Con_Printf
2019-11-24 20:45:15 -08:00
continue ;
}
2019-11-25 17:40:18 -08:00
if ( anglehack )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
char temp [ 32 ] ;
strcpy ( temp , com_token ) ;
sprintf ( com_token , " 0 %s 0 " , temp ) ;
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
if ( ! ED_ParseEpair ( ( void * ) & ent - > v , key , com_token ) )
Host_Error ( " ED_ParseEdict: parse error " ) ;
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
if ( ! init )
2019-11-24 20:45:15 -08:00
ent - > free = true ;
return data ;
}
/*
= = = = = = = = = = = = = = = =
ED_LoadFromFile
The entities are directly placed in the array , rather than allocated with
ED_Alloc , because otherwise an error loading the map would have entity
number references out of order .
Creates a server ' s entity / program execution context by
parsing textual entity definitions out of an ent file .
Used for both fresh maps and savegame loads . A fresh map would also need
to call ED_CallSpawnFunctions ( ) to let the objects initialize themselves .
= = = = = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
void ED_LoadFromFile ( const char * data )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
dfunction_t * func ;
edict_t * ent = NULL ;
int32_t inhibit = 0 ;
2019-11-24 20:45:15 -08:00
pr_global_struct - > time = sv . time ;
// parse ents
2019-11-25 17:40:18 -08:00
while ( 1 )
2019-11-24 20:45:15 -08:00
{
// parse the opening brace
2019-11-25 17:40:18 -08:00
data = COM_Parse ( data ) ;
if ( ! data )
2019-11-24 20:45:15 -08:00
break ;
2019-11-25 17:40:18 -08:00
if ( com_token [ 0 ] ! = ' { ' )
Host_Error ( " ED_LoadFromFile: found %s when expecting { " , com_token ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( ! ent )
2019-11-24 20:45:15 -08:00
ent = EDICT_NUM ( 0 ) ;
else
2019-11-25 17:40:18 -08:00
ent = ED_Alloc ( ) ;
data = ED_ParseEdict ( data , ent ) ;
2019-11-24 20:45:15 -08:00
// remove things from different skill levels or deathmatch
2019-11-25 17:40:18 -08:00
if ( deathmatch . value )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( ( ( int32_t ) ent - > v . spawnflags & SPAWNFLAG_NOT_DEATHMATCH ) )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ED_Free ( ent ) ;
2019-11-24 20:45:15 -08:00
inhibit + + ;
continue ;
}
}
2019-11-25 17:40:18 -08:00
else if ( ( current_skill = = 0 & & ( ( int32_t ) ent - > v . spawnflags & SPAWNFLAG_NOT_EASY ) )
| | ( current_skill = = 1 & & ( ( int32_t ) ent - > v . spawnflags & SPAWNFLAG_NOT_MEDIUM ) )
| | ( current_skill > = 2 & & ( ( int32_t ) ent - > v . spawnflags & SPAWNFLAG_NOT_HARD ) ) )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
ED_Free ( ent ) ;
2019-11-24 20:45:15 -08:00
inhibit + + ;
continue ;
}
//
// immediately call spawn function
//
2019-11-25 17:40:18 -08:00
if ( ! ent - > v . classname )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_SafePrintf ( " No classname for: \n " ) ; //johnfitz -- was Con_Printf
ED_Print ( ent ) ;
ED_Free ( ent ) ;
2019-11-24 20:45:15 -08:00
continue ;
}
2019-11-25 17:40:18 -08:00
// look for the spawn function
func = ED_FindFunction ( PR_GetString ( ent - > v . classname ) ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( ! func )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_SafePrintf ( " No spawn function for: \n " ) ; //johnfitz -- was Con_Printf
ED_Print ( ent ) ;
ED_Free ( ent ) ;
2019-11-24 20:45:15 -08:00
continue ;
}
pr_global_struct - > self = EDICT_TO_PROG ( ent ) ;
2019-11-25 17:40:18 -08:00
PR_ExecuteProgram ( func - pr_functions ) ;
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
Con_DPrintf ( " % " PRIi32 " entities inhibited \n " , inhibit ) ;
2019-11-24 20:45:15 -08:00
}
/*
= = = = = = = = = = = = = = =
PR_LoadProgs
= = = = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
void PR_LoadProgs ( void )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i ;
2019-11-24 20:45:15 -08:00
// flush the non-C variable lookup cache
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < GEFV_CACHESIZE ; i + + )
2019-11-24 20:45:15 -08:00
gefvCache [ i ] . field [ 0 ] = 0 ;
2019-11-25 17:40:18 -08:00
CRC_Init ( & pr_crc ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
progs = ( dprograms_t * ) COM_LoadHunkFile ( " progs.dat " , NULL ) ;
if ( ! progs )
Host_Error ( " PR_LoadProgs: couldn't load progs.dat " ) ;
Con_DPrintf ( " Programs occupy % " PRIi32 " K. \n " , com_filesize / 1024 ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < com_filesize ; i + + )
CRC_ProcessByte ( & pr_crc , ( ( byte * ) progs ) [ i ] ) ;
2019-11-24 20:45:15 -08:00
// byte swap the header
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < ( int32_t ) sizeof ( * progs ) / 4 ; i + + )
( ( int32_t * ) progs ) [ i ] = LittleLong ( ( ( int32_t * ) progs ) [ i ] ) ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( progs - > version ! = PROG_VERSION )
Host_Error ( " progs.dat has wrong version number (% " PRIi32 " should be % " PRIi32 " ) " , progs - > version , PROG_VERSION ) ;
if ( progs - > crc ! = PROGHEADER_CRC )
Host_Error ( " progs.dat system vars have been modified, progdefs.h is out of date " ) ;
2019-11-24 20:45:15 -08:00
pr_functions = ( dfunction_t * ) ( ( byte * ) progs + progs - > ofs_functions ) ;
pr_strings = ( char * ) progs + progs - > ofs_strings ;
2019-11-25 17:40:18 -08:00
if ( progs - > ofs_strings + progs - > numstrings > = com_filesize )
Host_Error ( " progs.dat strings go past end of file \n " ) ;
2019-11-24 20:45:15 -08:00
// initialize the strings
pr_numknownstrings = 0 ;
pr_maxknownstrings = 0 ;
pr_stringssize = progs - > numstrings ;
2019-11-25 17:40:18 -08:00
if ( pr_knownstrings )
Z_Free ( ( void * ) pr_knownstrings ) ;
2019-11-24 20:45:15 -08:00
pr_knownstrings = NULL ;
PR_SetEngineString ( " " ) ;
pr_globaldefs = ( ddef_t * ) ( ( byte * ) progs + progs - > ofs_globaldefs ) ;
pr_fielddefs = ( ddef_t * ) ( ( byte * ) progs + progs - > ofs_fielddefs ) ;
pr_statements = ( dstatement_t * ) ( ( byte * ) progs + progs - > ofs_statements ) ;
pr_global_struct = ( globalvars_t * ) ( ( byte * ) progs + progs - > ofs_globals ) ;
pr_globals = ( float * ) pr_global_struct ;
// byte swap the lumps
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < progs - > numstatements ; i + + )
2019-11-24 20:45:15 -08:00
{
pr_statements [ i ] . op = LittleShort ( pr_statements [ i ] . op ) ;
pr_statements [ i ] . a = LittleShort ( pr_statements [ i ] . a ) ;
pr_statements [ i ] . b = LittleShort ( pr_statements [ i ] . b ) ;
pr_statements [ i ] . c = LittleShort ( pr_statements [ i ] . c ) ;
}
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < progs - > numfunctions ; i + + )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
pr_functions [ i ] . first_statement = LittleLong ( pr_functions [ i ] . first_statement ) ;
pr_functions [ i ] . parm_start = LittleLong ( pr_functions [ i ] . parm_start ) ;
pr_functions [ i ] . s_name = LittleLong ( pr_functions [ i ] . s_name ) ;
pr_functions [ i ] . s_file = LittleLong ( pr_functions [ i ] . s_file ) ;
pr_functions [ i ] . numparms = LittleLong ( pr_functions [ i ] . numparms ) ;
pr_functions [ i ] . locals = LittleLong ( pr_functions [ i ] . locals ) ;
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < progs - > numglobaldefs ; i + + )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
pr_globaldefs [ i ] . type = LittleShort ( pr_globaldefs [ i ] . type ) ;
pr_globaldefs [ i ] . ofs = LittleShort ( pr_globaldefs [ i ] . ofs ) ;
pr_globaldefs [ i ] . s_name = LittleLong ( pr_globaldefs [ i ] . s_name ) ;
2019-11-24 20:45:15 -08:00
}
pr_alpha_supported = false ; //johnfitz
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < progs - > numfielddefs ; i + + )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
pr_fielddefs [ i ] . type = LittleShort ( pr_fielddefs [ i ] . type ) ;
if ( pr_fielddefs [ i ] . type & DEF_SAVEGLOBAL )
Host_Error ( " PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL " ) ;
pr_fielddefs [ i ] . ofs = LittleShort ( pr_fielddefs [ i ] . ofs ) ;
pr_fielddefs [ i ] . s_name = LittleLong ( pr_fielddefs [ i ] . s_name ) ;
2019-11-24 20:45:15 -08:00
//johnfitz -- detect alpha support in progs.dat
2019-11-25 17:40:18 -08:00
if ( ! strcmp ( pr_strings + pr_fielddefs [ i ] . s_name , " alpha " ) )
2019-11-24 20:45:15 -08:00
pr_alpha_supported = true ;
//johnfitz
}
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < progs - > numglobals ; i + + )
( ( int32_t * ) pr_globals ) [ i ] = LittleLong ( ( ( int32_t * ) pr_globals ) [ i ] ) ;
2019-11-24 20:45:15 -08:00
pr_edict_size = progs - > entityfields * 4 + sizeof ( edict_t ) - sizeof ( entvars_t ) ;
// round off to next highest whole word address (esp for Alpha)
// this ensures that pointers in the engine data area are always
// properly aligned
pr_edict_size + = sizeof ( void * ) - 1 ;
pr_edict_size & = ~ ( sizeof ( void * ) - 1 ) ;
}
/*
= = = = = = = = = = = = = = =
PR_Init
= = = = = = = = = = = = = = =
*/
2019-11-25 17:40:18 -08:00
void PR_Init ( void )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Cmd_AddCommand ( " edict " , ED_PrintEdict_f ) ;
Cmd_AddCommand ( " edicts " , ED_PrintEdicts ) ;
Cmd_AddCommand ( " edictcount " , ED_Count ) ;
Cmd_AddCommand ( " profile " , PR_Profile_f ) ;
Cvar_RegisterVariable ( & nomonsters ) ;
Cvar_RegisterVariable ( & gamecfg ) ;
Cvar_RegisterVariable ( & scratch1 ) ;
Cvar_RegisterVariable ( & scratch2 ) ;
Cvar_RegisterVariable ( & scratch3 ) ;
Cvar_RegisterVariable ( & scratch4 ) ;
Cvar_RegisterVariable ( & savedgamecfg ) ;
Cvar_RegisterVariable ( & saved1 ) ;
Cvar_RegisterVariable ( & saved2 ) ;
Cvar_RegisterVariable ( & saved3 ) ;
Cvar_RegisterVariable ( & saved4 ) ;
2019-11-24 20:45:15 -08:00
}
2019-11-25 16:49:58 -08:00
edict_t * EDICT_NUM ( int32_t n )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( n < 0 | | n > = sv . max_edicts )
Host_Error ( " EDICT_NUM: bad number % " PRIi32 " " , n ) ;
return ( edict_t * ) ( ( byte * ) sv . edicts + ( n ) * pr_edict_size ) ;
2019-11-24 20:45:15 -08:00
}
2019-11-25 16:49:58 -08:00
int32_t NUM_FOR_EDICT ( edict_t * e )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t b ;
2019-11-24 20:45:15 -08:00
b = ( byte * ) e - ( byte * ) sv . edicts ;
b = b / pr_edict_size ;
2019-11-25 17:40:18 -08:00
if ( b < 0 | | b > = sv . num_edicts )
Host_Error ( " NUM_FOR_EDICT: bad pointer " ) ;
2019-11-24 20:45:15 -08:00
return b ;
}
//===========================================================================
2019-11-25 17:40:18 -08:00
# define PR_STRING_ALLOCSLOTS 256
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
static void PR_AllocStringSlots ( void )
2019-11-24 20:45:15 -08:00
{
pr_maxknownstrings + = PR_STRING_ALLOCSLOTS ;
2019-11-25 16:56:15 -08:00
Con_DPrintf2 ( " PR_AllocStringSlots: realloc'ing for % " PRIi32 " slots \n " , pr_maxknownstrings ) ;
2019-11-25 17:40:18 -08:00
pr_knownstrings = ( const char * * ) Z_Realloc ( ( void * ) pr_knownstrings , pr_maxknownstrings * sizeof ( char * ) ) ;
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
const char * PR_GetString ( int32_t num )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( num > = 0 & & num < pr_stringssize )
2019-11-24 20:45:15 -08:00
return pr_strings + num ;
2019-11-25 17:40:18 -08:00
else if ( num < 0 & & num > = - pr_numknownstrings )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( ! pr_knownstrings [ - 1 - num ] )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Host_Error ( " PR_GetString: attempt to get a non-existant string % " PRIi32 " \n " , num ) ;
2019-11-24 20:45:15 -08:00
return " " ;
}
return pr_knownstrings [ - 1 - num ] ;
}
else
{
2019-11-25 16:56:15 -08:00
Host_Error ( " PR_GetString: invalid string offset % " PRIi32 " \n " , num ) ;
2019-11-24 20:45:15 -08:00
return " " ;
}
}
2019-11-25 17:40:18 -08:00
int32_t PR_SetEngineString ( const char * s )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( ! s )
2019-11-24 20:45:15 -08:00
return 0 ;
2019-11-25 17:40:18 -08:00
#if 0 /* can't: sv.model_precache & sv.sound_precache points to pr_strings */
if ( s > = pr_strings & & s < = pr_strings + pr_stringssize )
2019-11-24 20:45:15 -08:00
Host_Error ( " PR_SetEngineString: \" %s \" in pr_strings area \n " , s ) ;
# else
2019-11-25 17:40:18 -08:00
if ( s > = pr_strings & & s < = pr_strings + pr_stringssize - 2 )
2019-11-25 16:49:58 -08:00
return ( int32_t ) ( s - pr_strings ) ;
2019-11-24 20:45:15 -08:00
# endif
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < pr_numknownstrings ; i + + )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( pr_knownstrings [ i ] = = s )
2019-11-24 20:45:15 -08:00
return - 1 - i ;
}
// new unknown engine string
//Con_DPrintf ("PR_SetEngineString: new engine string %p\n", s);
#if 0
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < pr_numknownstrings ; i + + )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( ! pr_knownstrings [ i ] )
2019-11-24 20:45:15 -08:00
break ;
}
# endif
// if (i >= pr_numknownstrings)
// {
2019-11-25 17:40:18 -08:00
if ( i > = pr_maxknownstrings )
PR_AllocStringSlots ( ) ;
pr_numknownstrings + + ;
2019-11-24 20:45:15 -08:00
// }
pr_knownstrings [ i ] = s ;
return - 1 - i ;
}
2019-11-25 17:40:18 -08:00
int32_t PR_AllocString ( int32_t size , char * * ptr )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i ;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if ( ! size )
2019-11-24 20:45:15 -08:00
return 0 ;
2019-11-25 17:40:18 -08:00
for ( i = 0 ; i < pr_numknownstrings ; i + + )
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if ( ! pr_knownstrings [ i ] )
2019-11-24 20:45:15 -08:00
break ;
}
// if (i >= pr_numknownstrings)
// {
2019-11-25 17:40:18 -08:00
if ( i > = pr_maxknownstrings )
PR_AllocStringSlots ( ) ;
pr_numknownstrings + + ;
2019-11-24 20:45:15 -08:00
// }
pr_knownstrings [ i ] = ( char * ) Hunk_AllocName ( size , " string " ) ;
2019-11-25 17:40:18 -08:00
if ( ptr )
2019-11-24 20:45:15 -08:00
* ptr = ( char * ) pr_knownstrings [ i ] ;
return - 1 - i ;
}