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
2019-12-02 07:07:37 -08:00
# include "q_defs.h"
2019-11-24 20:45:15 -08:00
2019-12-05 19:09:23 -08:00
dprograms_t progs ;
dfunction_t * pr_functions ;
dstatement_t * pr_statements ;
byte * pr_global_data ;
2019-11-25 17:40:18 -08:00
2019-12-05 19:09:23 -08:00
ddef_t * pr_fielddefs ;
int32_t pr_edict_size ; // in bytes
2019-11-25 17:40:18 -08:00
2019-12-02 23:02:24 -08:00
bool pr_alpha_supported ; //johnfitz
2019-11-25 17:40:18 -08:00
2019-12-02 23:02:24 -08:00
uint16_t pr_crc ;
2019-11-25 17:40:18 -08:00
2019-12-02 23:02:24 -08:00
static int32_t type_size [ ] =
2019-11-25 17:40:18 -08:00
{
2019-12-02 23:02:24 -08:00
[ ev_void ] = 1 ,
[ ev_string ] = 1 ,
[ ev_float ] = 1 ,
[ ev_vector ] = 3 ,
[ ev_entity ] = 1 ,
[ ev_field ] = 1 ,
[ ev_function ] = 1 ,
[ ev_pointer ] = 1 ,
2019-11-24 20:45:15 -08:00
} ;
2019-12-02 23:02:24 -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
} ;
/*
= = = = = = = = = = = = = = = = =
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-12-06 07:53:56 -08:00
memset ( e - > fields , 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
{
2019-12-08 12:35:56 -08:00
e = EdictNum ( i ) ;
2019-11-24 20:45:15 -08:00
// 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 + + ;
2019-12-08 12:35:56 -08:00
e = EdictNum ( i ) ;
2019-11-24 20:45:15 -08:00
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 ;
2019-12-08 12:35:56 -08:00
ED_RString ( ed , ED_model ) = 0 ;
ED_Float ( ed , ED_takedamage ) = 0 ;
ED_Float ( ed , ED_modelindex ) = 0 ;
ED_Float ( ed , ED_colormap ) = 0 ;
ED_Float ( ed , ED_skin ) = 0 ;
ED_Float ( ed , ED_frame ) = 0 ;
VectorCopy ( vec3_origin , ED_Vector ( ed , ED_origin ) ) ;
VectorCopy ( vec3_origin , ED_Vector ( ed , ED_angles ) ) ;
ED_Float ( ed , ED_nextthink ) = - 1 ;
ED_Float ( ed , ED_solid ) = 0 ;
2019-11-24 20:45:15 -08:00
ed - > alpha = ENTALPHA_DEFAULT ; //johnfitz -- reset alpha for next entity
ed - > freetime = sv . time ;
}
//===========================================================================
/*
= = = = = = = = = = = =
ED_GlobalAtOfs
= = = = = = = = = = = =
*/
2019-12-03 05:59:16 -08:00
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-12-02 23:31:56 -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-12-03 05:59:16 -08:00
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-12-02 23:31:56 -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-12-02 23:31:56 -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-12-02 23:31:56 -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-12-02 23:31:56 -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 ;
2019-12-07 08:26:29 -08:00
goto done ;
2019-11-24 20:45:15 -08:00
}
}
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 ;
}
2019-12-07 08:26:29 -08:00
done :
2019-11-25 17:40:18 -08:00
if ( ! def )
2019-11-24 20:45:15 -08:00
return NULL ;
2019-12-08 12:35:56 -08:00
return ED_Eval ( ed , def - > ofs ) ;
2019-11-24 20:45:15 -08:00
}
/*
= = = = = = = = = = = = =
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-12-08 12:35:56 -08:00
Con_SafePrintf ( " \n EDICT % " PRIi32 " : \n " , NumForEdict ( ed ) ) ; //johnfitz -- was Con_Printf
2019-12-02 23:31:56 -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-12-08 12:35:56 -08:00
v = & ED_Int ( ed , d - > ofs ) ;
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-12-02 23:31:56 -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-12-08 12:35:56 -08:00
v = & ED_Int ( ed , d - > ofs ) ;
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
}
2019-12-02 23:31:56 -08:00
//johnfitz -- save entity alpha manually when program 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-12-08 12:35:56 -08:00
ED_Print ( EdictNum ( 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-12-07 09:27:26 -08:00
i = atoi ( Cmd_Argv ( 1 ) ) ;
2019-11-25 17:40:18 -08:00
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
{
2019-12-08 12:35:56 -08:00
ent = EdictNum ( i ) ;
2019-11-25 17:40:18 -08:00
if ( ent - > free )
2019-11-24 20:45:15 -08:00
continue ;
active + + ;
2019-12-08 12:35:56 -08:00
if ( ED_Float ( ent , ED_solid ) )
2019-11-24 20:45:15 -08:00
solid + + ;
2019-12-08 12:35:56 -08:00
if ( ED_RString ( ent , ED_model ) )
2019-11-24 20:45:15 -08:00
models + + ;
2019-12-08 12:35:56 -08:00
if ( ED_Float ( ent , ED_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 " ) ;
2019-12-02 23:31:56 -08:00
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 ) ;
2019-12-08 12:35:56 -08:00
fprintf ( f , " \" %s \" \n " , PR_UglyValueString ( type , G_Eval ( 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-12-05 19:09:23 -08:00
if ( ! ED_ParseEpair ( pr_global_data , key , com_token ) )
2019-11-25 17:40:18 -08:00
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
= = = = = = = = = = = = =
*/
2019-12-03 05:59:16 -08:00
bool ED_ParseEpair ( void * base , ddef_t * key , const char * s )
2019-11-24 20:45:15 -08:00
{
2019-11-28 16:24:30 -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-12-03 05:23:56 -08:00
d = ( 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-12-08 12:35:56 -08:00
* ( int32_t * ) d = EdictProg ( EdictNum ( 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
{
2019-12-06 09:07:30 -08:00
//johnfitz -- HACK -- suppress error becuase fog/sky 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-12-08 12:35:56 -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
2019-12-06 07:53:56 -08:00
memset ( ent - > fields , 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 ;
2019-12-02 23:31:56 -08:00
//johnfitz -- hack to support .alpha even when program 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
{
2019-12-06 09:07:30 -08:00
//johnfitz -- HACK -- suppress error becuase fog/sky/alpha 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-12-06 07:53:56 -08:00
if ( ! ED_ParseEpair ( ent - > fields , key , com_token ) )
2019-11-25 17:40:18 -08:00
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
2019-12-08 12:35:56 -08:00
G_Float ( GBL_time ) = sv . time ;
2019-11-24 20:45:15 -08:00
// 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-12-08 12:35:56 -08:00
ent = EdictNum ( 0 ) ;
2019-11-24 20:45:15 -08:00
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-12-08 12:35:56 -08:00
if ( ( ( int32_t ) ED_Float ( ent , ED_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-12-08 12:35:56 -08:00
else if ( ( current_skill = = 0 & & ( ( int32_t ) ED_Float ( ent , ED_spawnflags ) & SPAWNFLAG_NOT_EASY ) )
| | ( current_skill = = 1 & & ( ( int32_t ) ED_Float ( ent , ED_spawnflags ) & SPAWNFLAG_NOT_MEDIUM ) )
| | ( current_skill > = 2 & & ( ( int32_t ) ED_Float ( ent , ED_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-12-08 12:35:56 -08:00
if ( ! ED_RString ( ent , ED_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
2019-12-08 12:35:56 -08:00
func = ED_FindFunction ( ED_String ( ent , ED_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 ;
}
2019-12-08 12:35:56 -08:00
G_PEdict ( GBL_self ) = EdictProg ( 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
}
2019-12-03 05:59:16 -08:00
void ED_Load ( void )
2019-11-24 20:45:15 -08:00
{
2019-12-03 05:23:56 -08:00
int32_t i ;
// flush the non-C variable lookup cache
for ( i = 0 ; i < GEFV_CACHESIZE ; i + + )
gefvCache [ i ] . field [ 0 ] = 0 ;
2019-11-24 20:45:15 -08:00
}
2019-12-03 05:59:16 -08:00
void ED_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 ) ;
2019-11-24 20:45:15 -08:00
}
2019-12-08 12:35:56 -08:00
edict_t * EdictNum ( 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 )
2019-12-08 12:35:56 -08:00
Host_Error ( " EdictNum: bad number % " PRIi32 , n ) ;
return ProgEdict ( n * pr_edict_size ) ;
2019-11-24 20:45:15 -08:00
}
2019-12-08 12:35:56 -08:00
int32_t NumForEdict ( edict_t * e )
2019-11-24 20:45:15 -08:00
{
2019-12-06 17:01:10 -08:00
int32_t b ;
2019-11-24 20:45:15 -08:00
2019-12-08 12:35:56 -08:00
b = EdictProg ( e ) ;
2019-11-24 20:45:15 -08:00
b = b / pr_edict_size ;
2019-11-25 17:40:18 -08:00
if ( b < 0 | | b > = sv . num_edicts )
2019-12-08 12:35:56 -08:00
Host_Error ( " NumForEdict: bad pointer " ) ;
2019-11-24 20:45:15 -08:00
return b ;
}
2019-12-06 17:01:10 -08:00
2019-12-08 12:35:56 -08:00
pedict_t EdictProg ( void * e )
2019-12-06 17:01:10 -08:00
{
return ( byte * ) e - ( byte * ) sv . edicts ;
}
2019-12-08 12:35:56 -08:00
void * ProgEdict ( pedict_t e )
2019-12-06 17:01:10 -08:00
{
return ( byte * ) sv . edicts + e ;
}