From a8f828a066773a59fdf646299359d35ae0e845af Mon Sep 17 00:00:00 2001 From: wyatt8740 Date: Mon, 6 Jan 2014 12:02:16 -0500 Subject: Removed accidental upload of copyrighted map files --- WinQuake/pr_edict.c | 2212 +++++++++++++++++++++++++-------------------------- 1 file changed, 1106 insertions(+), 1106 deletions(-) (limited to 'WinQuake/pr_edict.c') diff --git a/WinQuake/pr_edict.c b/WinQuake/pr_edict.c index 544e01a..a884b60 100644 --- a/WinQuake/pr_edict.c +++ b/WinQuake/pr_edict.c @@ -1,1106 +1,1106 @@ -/* -Copyright (C) 1996-1997 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_edict.c -- entity dictionary - -#include "quakedef.h" - -dprograms_t *progs; -dfunction_t *pr_functions; -char *pr_strings; -ddef_t *pr_fielddefs; -ddef_t *pr_globaldefs; -dstatement_t *pr_statements; -globalvars_t *pr_global_struct; -float *pr_globals; // same as pr_global_struct -int pr_edict_size; // in bytes - -unsigned short pr_crc; - -int type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4}; - -ddef_t *ED_FieldAtOfs (int ofs); -qboolean ED_ParseEpair (void *base, ddef_t *key, char *s); - -cvar_t nomonsters = {"nomonsters", "0"}; -cvar_t gamecfg = {"gamecfg", "0"}; -cvar_t scratch1 = {"scratch1", "0"}; -cvar_t scratch2 = {"scratch2", "0"}; -cvar_t scratch3 = {"scratch3", "0"}; -cvar_t scratch4 = {"scratch4", "0"}; -cvar_t savedgamecfg = {"savedgamecfg", "0", true}; -cvar_t saved1 = {"saved1", "0", true}; -cvar_t saved2 = {"saved2", "0", true}; -cvar_t saved3 = {"saved3", "0", true}; -cvar_t saved4 = {"saved4", "0", true}; - -#define MAX_FIELD_LEN 64 -#define GEFV_CACHESIZE 2 - -typedef struct { - ddef_t *pcache; - char field[MAX_FIELD_LEN]; -} gefv_cache; - -static gefv_cache gefvCache[GEFV_CACHESIZE] = {{NULL, ""}, {NULL, ""}}; - -/* -================= -ED_ClearEdict - -Sets everything to NULL -================= -*/ -void ED_ClearEdict (edict_t *e) -{ - memset (&e->v, 0, progs->entityfields * 4); - 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. -================= -*/ -edict_t *ED_Alloc (void) -{ - int i; - edict_t *e; - - for ( i=svs.maxclients+1 ; ifree && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) ) - { - ED_ClearEdict (e); - return e; - } - } - - if (i == MAX_EDICTS) - Sys_Error ("ED_Alloc: no free edicts"); - - sv.num_edicts++; - e = EDICT_NUM(i); - ED_ClearEdict (e); - - return e; -} - -/* -================= -ED_Free - -Marks the edict as free -FIXME: walk all entities and NULL out references to this entity -================= -*/ -void ED_Free (edict_t *ed) -{ - SV_UnlinkEdict (ed); // unlink from world bsp - - 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; - VectorCopy (vec3_origin, ed->v.origin); - VectorCopy (vec3_origin, ed->v.angles); - ed->v.nextthink = -1; - ed->v.solid = 0; - - ed->freetime = sv.time; -} - -//=========================================================================== - -/* -============ -ED_GlobalAtOfs -============ -*/ -ddef_t *ED_GlobalAtOfs (int ofs) -{ - ddef_t *def; - int i; - - for (i=0 ; inumglobaldefs ; i++) - { - def = &pr_globaldefs[i]; - if (def->ofs == ofs) - return def; - } - return NULL; -} - -/* -============ -ED_FieldAtOfs -============ -*/ -ddef_t *ED_FieldAtOfs (int ofs) -{ - ddef_t *def; - int i; - - for (i=0 ; inumfielddefs ; i++) - { - def = &pr_fielddefs[i]; - if (def->ofs == ofs) - return def; - } - return NULL; -} - -/* -============ -ED_FindField -============ -*/ -ddef_t *ED_FindField (char *name) -{ - ddef_t *def; - int i; - - for (i=0 ; inumfielddefs ; i++) - { - def = &pr_fielddefs[i]; - if (!strcmp(pr_strings + def->s_name,name) ) - return def; - } - return NULL; -} - - -/* -============ -ED_FindGlobal -============ -*/ -ddef_t *ED_FindGlobal (char *name) -{ - ddef_t *def; - int i; - - for (i=0 ; inumglobaldefs ; i++) - { - def = &pr_globaldefs[i]; - if (!strcmp(pr_strings + def->s_name,name) ) - return def; - } - return NULL; -} - - -/* -============ -ED_FindFunction -============ -*/ -dfunction_t *ED_FindFunction (char *name) -{ - dfunction_t *func; - int i; - - for (i=0 ; inumfunctions ; i++) - { - func = &pr_functions[i]; - if (!strcmp(pr_strings + func->s_name,name) ) - return func; - } - return NULL; -} - - -eval_t *GetEdictFieldValue(edict_t *ed, char *field) -{ - ddef_t *def = NULL; - int i; - static int rep = 0; - - for (i=0 ; iv + def->ofs*4); -} - - -/* -============ -PR_ValueString - -Returns a string describing *data in a type specific manner -============= -*/ -char *PR_ValueString (etype_t type, eval_t *val) -{ - static char line[256]; - ddef_t *def; - dfunction_t *f; - - type &= ~DEF_SAVEGLOBAL; - - switch (type) - { - case ev_string: - sprintf (line, "%s", pr_strings + val->string); - break; - case ev_entity: - sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) ); - break; - case ev_function: - f = pr_functions + val->function; - sprintf (line, "%s()", pr_strings + f->s_name); - break; - case ev_field: - def = ED_FieldAtOfs ( val->_int ); - sprintf (line, ".%s", pr_strings + def->s_name); - break; - case ev_void: - sprintf (line, "void"); - break; - case ev_float: - sprintf (line, "%5.1f", val->_float); - break; - case ev_vector: - sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]); - break; - case ev_pointer: - sprintf (line, "pointer"); - break; - default: - sprintf (line, "bad type %i", type); - break; - } - - return line; -} - -/* -============ -PR_UglyValueString - -Returns a string describing *data in a type specific manner -Easier to parse than PR_ValueString -============= -*/ -char *PR_UglyValueString (etype_t type, eval_t *val) -{ - static char line[256]; - ddef_t *def; - dfunction_t *f; - - type &= ~DEF_SAVEGLOBAL; - - switch (type) - { - case ev_string: - sprintf (line, "%s", pr_strings + val->string); - break; - case ev_entity: - sprintf (line, "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict))); - break; - case ev_function: - f = pr_functions + val->function; - sprintf (line, "%s", pr_strings + f->s_name); - break; - case ev_field: - def = ED_FieldAtOfs ( val->_int ); - sprintf (line, "%s", pr_strings + def->s_name); - break; - case ev_void: - sprintf (line, "void"); - break; - case ev_float: - sprintf (line, "%f", val->_float); - break; - case ev_vector: - sprintf (line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]); - break; - default: - sprintf (line, "bad type %i", type); - break; - } - - return line; -} - -/* -============ -PR_GlobalString - -Returns a string with a description and the contents of a global, -padded to 20 field width -============ -*/ -char *PR_GlobalString (int ofs) -{ - char *s; - int i; - ddef_t *def; - void *val; - static char line[128]; - - val = (void *)&pr_globals[ofs]; - def = ED_GlobalAtOfs(ofs); - if (!def) - sprintf (line,"%i(???)", ofs); - else - { - s = PR_ValueString (def->type, val); - sprintf (line,"%i(%s)%s", ofs, pr_strings + def->s_name, s); - } - - i = strlen(line); - for ( ; i<20 ; i++) - strcat (line," "); - strcat (line," "); - - return line; -} - -char *PR_GlobalStringNoContents (int ofs) -{ - int i; - ddef_t *def; - static char line[128]; - - def = ED_GlobalAtOfs(ofs); - if (!def) - sprintf (line,"%i(???)", ofs); - else - sprintf (line,"%i(%s)", ofs, pr_strings + def->s_name); - - i = strlen(line); - for ( ; i<20 ; i++) - strcat (line," "); - strcat (line," "); - - return line; -} - - -/* -============= -ED_Print - -For debugging -============= -*/ -void ED_Print (edict_t *ed) -{ - int l; - ddef_t *d; - int *v; - int i, j; - char *name; - int type; - - if (ed->free) - { - Con_Printf ("FREE\n"); - return; - } - - Con_Printf("\nEDICT %i:\n", NUM_FOR_EDICT(ed)); - for (i=1 ; inumfielddefs ; i++) - { - d = &pr_fielddefs[i]; - name = pr_strings + d->s_name; - if (name[strlen(name)-2] == '_') - continue; // skip _x, _y, _z vars - - v = (int *)((char *)&ed->v + d->ofs*4); - - // if the value is still all 0, skip the field - type = d->type & ~DEF_SAVEGLOBAL; - - for (j=0 ; jtype, (eval_t *)v)); - } -} - -/* -============= -ED_Write - -For savegames -============= -*/ -void ED_Write (FILE *f, edict_t *ed) -{ - ddef_t *d; - int *v; - int i, j; - char *name; - int type; - - fprintf (f, "{\n"); - - if (ed->free) - { - fprintf (f, "}\n"); - return; - } - - for (i=1 ; inumfielddefs ; i++) - { - d = &pr_fielddefs[i]; - name = pr_strings + d->s_name; - if (name[strlen(name)-2] == '_') - continue; // skip _x, _y, _z vars - - v = (int *)((char *)&ed->v + d->ofs*4); - - // if the value is still all 0, skip the field - type = d->type & ~DEF_SAVEGLOBAL; - for (j=0 ; jtype, (eval_t *)v)); - } - - fprintf (f, "}\n"); -} - -void ED_PrintNum (int ent) -{ - ED_Print (EDICT_NUM(ent)); -} - -/* -============= -ED_PrintEdicts - -For debugging, prints all the entities in the current server -============= -*/ -void ED_PrintEdicts (void) -{ - int i; - - Con_Printf ("%i entities\n", sv.num_edicts); - for (i=0 ; i= sv.num_edicts) - { - Con_Printf("Bad edict number\n"); - return; - } - ED_PrintNum (i); -} - -/* -============= -ED_Count - -For debugging -============= -*/ -void ED_Count (void) -{ - int i; - edict_t *ent; - int active, models, solid, step; - - active = models = solid = step = 0; - for (i=0 ; ifree) - continue; - active++; - if (ent->v.solid) - solid++; - if (ent->v.model) - models++; - if (ent->v.movetype == MOVETYPE_STEP) - step++; - } - - Con_Printf ("num_edicts:%3i\n", sv.num_edicts); - Con_Printf ("active :%3i\n", active); - Con_Printf ("view :%3i\n", models); - Con_Printf ("touch :%3i\n", solid); - Con_Printf ("step :%3i\n", step); - -} - -/* -============================================================================== - - ARCHIVING GLOBALS - -FIXME: need to tag constants, doesn't really work -============================================================================== -*/ - -/* -============= -ED_WriteGlobals -============= -*/ -void ED_WriteGlobals (FILE *f) -{ - ddef_t *def; - int i; - char *name; - int type; - - fprintf (f,"{\n"); - for (i=0 ; inumglobaldefs ; i++) - { - def = &pr_globaldefs[i]; - type = def->type; - if ( !(def->type & DEF_SAVEGLOBAL) ) - continue; - type &= ~DEF_SAVEGLOBAL; - - if (type != ev_string - && type != ev_float - && type != ev_entity) - continue; - - name = pr_strings + def->s_name; - fprintf (f,"\"%s\" ", name); - fprintf (f,"\"%s\"\n", PR_UglyValueString(type, (eval_t *)&pr_globals[def->ofs])); - } - fprintf (f,"}\n"); -} - -/* -============= -ED_ParseGlobals -============= -*/ -void ED_ParseGlobals (char *data) -{ - char keyname[64]; - ddef_t *key; - - while (1) - { - // parse key - data = COM_Parse (data); - if (com_token[0] == '}') - break; - if (!data) - Sys_Error ("ED_ParseEntity: EOF without closing brace"); - - strcpy (keyname, com_token); - - // parse value - data = COM_Parse (data); - if (!data) - Sys_Error ("ED_ParseEntity: EOF without closing brace"); - - if (com_token[0] == '}') - Sys_Error ("ED_ParseEntity: closing brace without data"); - - key = ED_FindGlobal (keyname); - if (!key) - { - Con_Printf ("'%s' is not a global\n", keyname); - continue; - } - - if (!ED_ParseEpair ((void *)pr_globals, key, com_token)) - Host_Error ("ED_ParseGlobals: parse error"); - } -} - -//============================================================================ - - -/* -============= -ED_NewString -============= -*/ -char *ED_NewString (char *string) -{ - char *new, *new_p; - int i,l; - - l = strlen(string) + 1; - new = Hunk_Alloc (l); - new_p = new; - - for (i=0 ; i< l ; i++) - { - if (string[i] == '\\' && i < l-1) - { - i++; - if (string[i] == 'n') - *new_p++ = '\n'; - else - *new_p++ = '\\'; - } - else - *new_p++ = string[i]; - } - - return new; -} - - -/* -============= -ED_ParseEval - -Can parse either fields or globals -returns false if error -============= -*/ -qboolean ED_ParseEpair (void *base, ddef_t *key, char *s) -{ - int i; - char string[128]; - ddef_t *def; - char *v, *w; - void *d; - dfunction_t *func; - - d = (void *)((int *)base + key->ofs); - - switch (key->type & ~DEF_SAVEGLOBAL) - { - case ev_string: - *(string_t *)d = ED_NewString (s) - pr_strings; - break; - - case ev_float: - *(float *)d = atof (s); - break; - - case ev_vector: - strcpy (string, s); - v = string; - w = string; - for (i=0 ; i<3 ; i++) - { - while (*v && *v != ' ') - v++; - *v = 0; - ((float *)d)[i] = atof (w); - w = v = v+1; - } - break; - - case ev_entity: - *(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s))); - break; - - case ev_field: - def = ED_FindField (s); - if (!def) - { - Con_Printf ("Can't find field %s\n", s); - return false; - } - *(int *)d = G_INT(def->ofs); - break; - - case ev_function: - func = ED_FindFunction (s); - if (!func) - { - Con_Printf ("Can't find function %s\n", s); - 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. -==================== -*/ -char *ED_ParseEdict (char *data, edict_t *ent) -{ - ddef_t *key; - qboolean anglehack; - qboolean init; - char keyname[256]; - int n; - - init = false; - -// clear it - if (ent != sv.edicts) // hack - memset (&ent->v, 0, progs->entityfields * 4); - -// go through all the dictionary pairs - while (1) - { - // parse key - data = COM_Parse (data); - if (com_token[0] == '}') - break; - if (!data) - Sys_Error ("ED_ParseEntity: EOF without closing brace"); - -// anglehack is to allow QuakeEd to write single scalar angles -// and allow them to be turned into vectors. (FIXME...) -if (!strcmp(com_token, "angle")) -{ - strcpy (com_token, "angles"); - anglehack = true; -} -else - anglehack = false; - -// FIXME: change light to _light to get rid of this hack -if (!strcmp(com_token, "light")) - strcpy (com_token, "light_lev"); // hack for single light def - - strcpy (keyname, com_token); - - // another hack to fix heynames with trailing spaces - n = strlen(keyname); - while (n && keyname[n-1] == ' ') - { - keyname[n-1] = 0; - n--; - } - - // parse value - data = COM_Parse (data); - if (!data) - Sys_Error ("ED_ParseEntity: EOF without closing brace"); - - if (com_token[0] == '}') - Sys_Error ("ED_ParseEntity: closing brace without data"); - - init = true; - -// keynames with a leading underscore are used for utility comments, -// and are immediately discarded by quake - if (keyname[0] == '_') - continue; - - key = ED_FindField (keyname); - if (!key) - { - Con_Printf ("'%s' is not a field\n", keyname); - continue; - } - -if (anglehack) -{ -char temp[32]; -strcpy (temp, com_token); -sprintf (com_token, "0 %s 0", temp); -} - - if (!ED_ParseEpair ((void *)&ent->v, key, com_token)) - Host_Error ("ED_ParseEdict: parse error"); - } - - if (!init) - 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. -================ -*/ -void ED_LoadFromFile (char *data) -{ - edict_t *ent; - int inhibit; - dfunction_t *func; - - ent = NULL; - inhibit = 0; - pr_global_struct->time = sv.time; - -// parse ents - while (1) - { -// parse the opening brace - data = COM_Parse (data); - if (!data) - break; - if (com_token[0] != '{') - Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token); - - if (!ent) - ent = EDICT_NUM(0); - else - ent = ED_Alloc (); - data = ED_ParseEdict (data, ent); - -// remove things from different skill levels or deathmatch - if (deathmatch.value) - { - if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) - { - ED_Free (ent); - inhibit++; - continue; - } - } - else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY)) - || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM)) - || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) ) - { - ED_Free (ent); - inhibit++; - continue; - } - -// -// immediately call spawn function -// - if (!ent->v.classname) - { - Con_Printf ("No classname for:\n"); - ED_Print (ent); - ED_Free (ent); - continue; - } - - // look for the spawn function - func = ED_FindFunction ( pr_strings + ent->v.classname ); - - if (!func) - { - Con_Printf ("No spawn function for:\n"); - ED_Print (ent); - ED_Free (ent); - continue; - } - - pr_global_struct->self = EDICT_TO_PROG(ent); - PR_ExecuteProgram (func - pr_functions); - } - - Con_DPrintf ("%i entities inhibited\n", inhibit); -} - - -/* -=============== -PR_LoadProgs -=============== -*/ -void PR_LoadProgs (void) -{ - int i; - -// flush the non-C variable lookup cache - for (i=0 ; iversion != PROG_VERSION) - Sys_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); - if (progs->crc != PROGHEADER_CRC) - Sys_Error ("progs.dat system vars have been modified, progdefs.h is out of date"); - - pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); - pr_strings = (char *)progs + progs->ofs_strings; - 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; - - pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t); - -// byte swap the lumps - for (i=0 ; inumstatements ; i++) - { - 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); - } - - for (i=0 ; inumfunctions; i++) - { - 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); - } - - for (i=0 ; inumglobaldefs ; i++) - { - 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); - } - - for (i=0 ; inumfielddefs ; i++) - { - pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); - if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) - Sys_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); - } - - for (i=0 ; inumglobals ; i++) - ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); -} - - -/* -=============== -PR_Init -=============== -*/ -void PR_Init (void) -{ - 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); -} - - - -edict_t *EDICT_NUM(int n) -{ - if (n < 0 || n >= sv.max_edicts) - Sys_Error ("EDICT_NUM: bad number %i", n); - return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size); -} - -int NUM_FOR_EDICT(edict_t *e) -{ - int b; - - b = (byte *)e - (byte *)sv.edicts; - b = b / pr_edict_size; - - if (b < 0 || b >= sv.num_edicts) - Sys_Error ("NUM_FOR_EDICT: bad pointer"); - return b; -} +/* +Copyright (C) 1996-1997 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_edict.c -- entity dictionary + +#include "quakedef.h" + +dprograms_t *progs; +dfunction_t *pr_functions; +char *pr_strings; +ddef_t *pr_fielddefs; +ddef_t *pr_globaldefs; +dstatement_t *pr_statements; +globalvars_t *pr_global_struct; +float *pr_globals; // same as pr_global_struct +int pr_edict_size; // in bytes + +unsigned short pr_crc; + +int type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4}; + +ddef_t *ED_FieldAtOfs (int ofs); +qboolean ED_ParseEpair (void *base, ddef_t *key, char *s); + +cvar_t nomonsters = {"nomonsters", "0"}; +cvar_t gamecfg = {"gamecfg", "0"}; +cvar_t scratch1 = {"scratch1", "0"}; +cvar_t scratch2 = {"scratch2", "0"}; +cvar_t scratch3 = {"scratch3", "0"}; +cvar_t scratch4 = {"scratch4", "0"}; +cvar_t savedgamecfg = {"savedgamecfg", "0", true}; +cvar_t saved1 = {"saved1", "0", true}; +cvar_t saved2 = {"saved2", "0", true}; +cvar_t saved3 = {"saved3", "0", true}; +cvar_t saved4 = {"saved4", "0", true}; + +#define MAX_FIELD_LEN 64 +#define GEFV_CACHESIZE 2 + +typedef struct { + ddef_t *pcache; + char field[MAX_FIELD_LEN]; +} gefv_cache; + +static gefv_cache gefvCache[GEFV_CACHESIZE] = {{NULL, ""}, {NULL, ""}}; + +/* +================= +ED_ClearEdict + +Sets everything to NULL +================= +*/ +void ED_ClearEdict (edict_t *e) +{ + memset (&e->v, 0, progs->entityfields * 4); + 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. +================= +*/ +edict_t *ED_Alloc (void) +{ + int i; + edict_t *e; + + for ( i=svs.maxclients+1 ; ifree && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) ) + { + ED_ClearEdict (e); + return e; + } + } + + if (i == MAX_EDICTS) + Sys_Error ("ED_Alloc: no free edicts"); + + sv.num_edicts++; + e = EDICT_NUM(i); + ED_ClearEdict (e); + + return e; +} + +/* +================= +ED_Free + +Marks the edict as free +FIXME: walk all entities and NULL out references to this entity +================= +*/ +void ED_Free (edict_t *ed) +{ + SV_UnlinkEdict (ed); // unlink from world bsp + + 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; + VectorCopy (vec3_origin, ed->v.origin); + VectorCopy (vec3_origin, ed->v.angles); + ed->v.nextthink = -1; + ed->v.solid = 0; + + ed->freetime = sv.time; +} + +//=========================================================================== + +/* +============ +ED_GlobalAtOfs +============ +*/ +ddef_t *ED_GlobalAtOfs (int ofs) +{ + ddef_t *def; + int i; + + for (i=0 ; inumglobaldefs ; i++) + { + def = &pr_globaldefs[i]; + if (def->ofs == ofs) + return def; + } + return NULL; +} + +/* +============ +ED_FieldAtOfs +============ +*/ +ddef_t *ED_FieldAtOfs (int ofs) +{ + ddef_t *def; + int i; + + for (i=0 ; inumfielddefs ; i++) + { + def = &pr_fielddefs[i]; + if (def->ofs == ofs) + return def; + } + return NULL; +} + +/* +============ +ED_FindField +============ +*/ +ddef_t *ED_FindField (char *name) +{ + ddef_t *def; + int i; + + for (i=0 ; inumfielddefs ; i++) + { + def = &pr_fielddefs[i]; + if (!strcmp(pr_strings + def->s_name,name) ) + return def; + } + return NULL; +} + + +/* +============ +ED_FindGlobal +============ +*/ +ddef_t *ED_FindGlobal (char *name) +{ + ddef_t *def; + int i; + + for (i=0 ; inumglobaldefs ; i++) + { + def = &pr_globaldefs[i]; + if (!strcmp(pr_strings + def->s_name,name) ) + return def; + } + return NULL; +} + + +/* +============ +ED_FindFunction +============ +*/ +dfunction_t *ED_FindFunction (char *name) +{ + dfunction_t *func; + int i; + + for (i=0 ; inumfunctions ; i++) + { + func = &pr_functions[i]; + if (!strcmp(pr_strings + func->s_name,name) ) + return func; + } + return NULL; +} + + +eval_t *GetEdictFieldValue(edict_t *ed, char *field) +{ + ddef_t *def = NULL; + int i; + static int rep = 0; + + for (i=0 ; iv + def->ofs*4); +} + + +/* +============ +PR_ValueString + +Returns a string describing *data in a type specific manner +============= +*/ +char *PR_ValueString (etype_t type, eval_t *val) +{ + static char line[256]; + ddef_t *def; + dfunction_t *f; + + type &= ~DEF_SAVEGLOBAL; + + switch (type) + { + case ev_string: + sprintf (line, "%s", pr_strings + val->string); + break; + case ev_entity: + sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) ); + break; + case ev_function: + f = pr_functions + val->function; + sprintf (line, "%s()", pr_strings + f->s_name); + break; + case ev_field: + def = ED_FieldAtOfs ( val->_int ); + sprintf (line, ".%s", pr_strings + def->s_name); + break; + case ev_void: + sprintf (line, "void"); + break; + case ev_float: + sprintf (line, "%5.1f", val->_float); + break; + case ev_vector: + sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]); + break; + case ev_pointer: + sprintf (line, "pointer"); + break; + default: + sprintf (line, "bad type %i", type); + break; + } + + return line; +} + +/* +============ +PR_UglyValueString + +Returns a string describing *data in a type specific manner +Easier to parse than PR_ValueString +============= +*/ +char *PR_UglyValueString (etype_t type, eval_t *val) +{ + static char line[256]; + ddef_t *def; + dfunction_t *f; + + type &= ~DEF_SAVEGLOBAL; + + switch (type) + { + case ev_string: + sprintf (line, "%s", pr_strings + val->string); + break; + case ev_entity: + sprintf (line, "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict))); + break; + case ev_function: + f = pr_functions + val->function; + sprintf (line, "%s", pr_strings + f->s_name); + break; + case ev_field: + def = ED_FieldAtOfs ( val->_int ); + sprintf (line, "%s", pr_strings + def->s_name); + break; + case ev_void: + sprintf (line, "void"); + break; + case ev_float: + sprintf (line, "%f", val->_float); + break; + case ev_vector: + sprintf (line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]); + break; + default: + sprintf (line, "bad type %i", type); + break; + } + + return line; +} + +/* +============ +PR_GlobalString + +Returns a string with a description and the contents of a global, +padded to 20 field width +============ +*/ +char *PR_GlobalString (int ofs) +{ + char *s; + int i; + ddef_t *def; + void *val; + static char line[128]; + + val = (void *)&pr_globals[ofs]; + def = ED_GlobalAtOfs(ofs); + if (!def) + sprintf (line,"%i(???)", ofs); + else + { + s = PR_ValueString (def->type, val); + sprintf (line,"%i(%s)%s", ofs, pr_strings + def->s_name, s); + } + + i = strlen(line); + for ( ; i<20 ; i++) + strcat (line," "); + strcat (line," "); + + return line; +} + +char *PR_GlobalStringNoContents (int ofs) +{ + int i; + ddef_t *def; + static char line[128]; + + def = ED_GlobalAtOfs(ofs); + if (!def) + sprintf (line,"%i(???)", ofs); + else + sprintf (line,"%i(%s)", ofs, pr_strings + def->s_name); + + i = strlen(line); + for ( ; i<20 ; i++) + strcat (line," "); + strcat (line," "); + + return line; +} + + +/* +============= +ED_Print + +For debugging +============= +*/ +void ED_Print (edict_t *ed) +{ + int l; + ddef_t *d; + int *v; + int i, j; + char *name; + int type; + + if (ed->free) + { + Con_Printf ("FREE\n"); + return; + } + + Con_Printf("\nEDICT %i:\n", NUM_FOR_EDICT(ed)); + for (i=1 ; inumfielddefs ; i++) + { + d = &pr_fielddefs[i]; + name = pr_strings + d->s_name; + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + + v = (int *)((char *)&ed->v + d->ofs*4); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + + for (j=0 ; jtype, (eval_t *)v)); + } +} + +/* +============= +ED_Write + +For savegames +============= +*/ +void ED_Write (FILE *f, edict_t *ed) +{ + ddef_t *d; + int *v; + int i, j; + char *name; + int type; + + fprintf (f, "{\n"); + + if (ed->free) + { + fprintf (f, "}\n"); + return; + } + + for (i=1 ; inumfielddefs ; i++) + { + d = &pr_fielddefs[i]; + name = pr_strings + d->s_name; + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + + v = (int *)((char *)&ed->v + d->ofs*4); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + for (j=0 ; jtype, (eval_t *)v)); + } + + fprintf (f, "}\n"); +} + +void ED_PrintNum (int ent) +{ + ED_Print (EDICT_NUM(ent)); +} + +/* +============= +ED_PrintEdicts + +For debugging, prints all the entities in the current server +============= +*/ +void ED_PrintEdicts (void) +{ + int i; + + Con_Printf ("%i entities\n", sv.num_edicts); + for (i=0 ; i= sv.num_edicts) + { + Con_Printf("Bad edict number\n"); + return; + } + ED_PrintNum (i); +} + +/* +============= +ED_Count + +For debugging +============= +*/ +void ED_Count (void) +{ + int i; + edict_t *ent; + int active, models, solid, step; + + active = models = solid = step = 0; + for (i=0 ; ifree) + continue; + active++; + if (ent->v.solid) + solid++; + if (ent->v.model) + models++; + if (ent->v.movetype == MOVETYPE_STEP) + step++; + } + + Con_Printf ("num_edicts:%3i\n", sv.num_edicts); + Con_Printf ("active :%3i\n", active); + Con_Printf ("view :%3i\n", models); + Con_Printf ("touch :%3i\n", solid); + Con_Printf ("step :%3i\n", step); + +} + +/* +============================================================================== + + ARCHIVING GLOBALS + +FIXME: need to tag constants, doesn't really work +============================================================================== +*/ + +/* +============= +ED_WriteGlobals +============= +*/ +void ED_WriteGlobals (FILE *f) +{ + ddef_t *def; + int i; + char *name; + int type; + + fprintf (f,"{\n"); + for (i=0 ; inumglobaldefs ; i++) + { + def = &pr_globaldefs[i]; + type = def->type; + if ( !(def->type & DEF_SAVEGLOBAL) ) + continue; + type &= ~DEF_SAVEGLOBAL; + + if (type != ev_string + && type != ev_float + && type != ev_entity) + continue; + + name = pr_strings + def->s_name; + fprintf (f,"\"%s\" ", name); + fprintf (f,"\"%s\"\n", PR_UglyValueString(type, (eval_t *)&pr_globals[def->ofs])); + } + fprintf (f,"}\n"); +} + +/* +============= +ED_ParseGlobals +============= +*/ +void ED_ParseGlobals (char *data) +{ + char keyname[64]; + ddef_t *key; + + while (1) + { + // parse key + data = COM_Parse (data); + if (com_token[0] == '}') + break; + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + strcpy (keyname, com_token); + + // parse value + data = COM_Parse (data); + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + if (com_token[0] == '}') + Sys_Error ("ED_ParseEntity: closing brace without data"); + + key = ED_FindGlobal (keyname); + if (!key) + { + Con_Printf ("'%s' is not a global\n", keyname); + continue; + } + + if (!ED_ParseEpair ((void *)pr_globals, key, com_token)) + Host_Error ("ED_ParseGlobals: parse error"); + } +} + +//============================================================================ + + +/* +============= +ED_NewString +============= +*/ +char *ED_NewString (char *string) +{ + char *new, *new_p; + int i,l; + + l = strlen(string) + 1; + new = Hunk_Alloc (l); + new_p = new; + + for (i=0 ; i< l ; i++) + { + if (string[i] == '\\' && i < l-1) + { + i++; + if (string[i] == 'n') + *new_p++ = '\n'; + else + *new_p++ = '\\'; + } + else + *new_p++ = string[i]; + } + + return new; +} + + +/* +============= +ED_ParseEval + +Can parse either fields or globals +returns false if error +============= +*/ +qboolean ED_ParseEpair (void *base, ddef_t *key, char *s) +{ + int i; + char string[128]; + ddef_t *def; + char *v, *w; + void *d; + dfunction_t *func; + + d = (void *)((int *)base + key->ofs); + + switch (key->type & ~DEF_SAVEGLOBAL) + { + case ev_string: + *(string_t *)d = ED_NewString (s) - pr_strings; + break; + + case ev_float: + *(float *)d = atof (s); + break; + + case ev_vector: + strcpy (string, s); + v = string; + w = string; + for (i=0 ; i<3 ; i++) + { + while (*v && *v != ' ') + v++; + *v = 0; + ((float *)d)[i] = atof (w); + w = v = v+1; + } + break; + + case ev_entity: + *(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s))); + break; + + case ev_field: + def = ED_FindField (s); + if (!def) + { + Con_Printf ("Can't find field %s\n", s); + return false; + } + *(int *)d = G_INT(def->ofs); + break; + + case ev_function: + func = ED_FindFunction (s); + if (!func) + { + Con_Printf ("Can't find function %s\n", s); + 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. +==================== +*/ +char *ED_ParseEdict (char *data, edict_t *ent) +{ + ddef_t *key; + qboolean anglehack; + qboolean init; + char keyname[256]; + int n; + + init = false; + +// clear it + if (ent != sv.edicts) // hack + memset (&ent->v, 0, progs->entityfields * 4); + +// go through all the dictionary pairs + while (1) + { + // parse key + data = COM_Parse (data); + if (com_token[0] == '}') + break; + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + +// anglehack is to allow QuakeEd to write single scalar angles +// and allow them to be turned into vectors. (FIXME...) +if (!strcmp(com_token, "angle")) +{ + strcpy (com_token, "angles"); + anglehack = true; +} +else + anglehack = false; + +// FIXME: change light to _light to get rid of this hack +if (!strcmp(com_token, "light")) + strcpy (com_token, "light_lev"); // hack for single light def + + strcpy (keyname, com_token); + + // another hack to fix heynames with trailing spaces + n = strlen(keyname); + while (n && keyname[n-1] == ' ') + { + keyname[n-1] = 0; + n--; + } + + // parse value + data = COM_Parse (data); + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + if (com_token[0] == '}') + Sys_Error ("ED_ParseEntity: closing brace without data"); + + init = true; + +// keynames with a leading underscore are used for utility comments, +// and are immediately discarded by quake + if (keyname[0] == '_') + continue; + + key = ED_FindField (keyname); + if (!key) + { + Con_Printf ("'%s' is not a field\n", keyname); + continue; + } + +if (anglehack) +{ +char temp[32]; +strcpy (temp, com_token); +sprintf (com_token, "0 %s 0", temp); +} + + if (!ED_ParseEpair ((void *)&ent->v, key, com_token)) + Host_Error ("ED_ParseEdict: parse error"); + } + + if (!init) + 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. +================ +*/ +void ED_LoadFromFile (char *data) +{ + edict_t *ent; + int inhibit; + dfunction_t *func; + + ent = NULL; + inhibit = 0; + pr_global_struct->time = sv.time; + +// parse ents + while (1) + { +// parse the opening brace + data = COM_Parse (data); + if (!data) + break; + if (com_token[0] != '{') + Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token); + + if (!ent) + ent = EDICT_NUM(0); + else + ent = ED_Alloc (); + data = ED_ParseEdict (data, ent); + +// remove things from different skill levels or deathmatch + if (deathmatch.value) + { + if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) + { + ED_Free (ent); + inhibit++; + continue; + } + } + else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY)) + || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM)) + || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) ) + { + ED_Free (ent); + inhibit++; + continue; + } + +// +// immediately call spawn function +// + if (!ent->v.classname) + { + Con_Printf ("No classname for:\n"); + ED_Print (ent); + ED_Free (ent); + continue; + } + + // look for the spawn function + func = ED_FindFunction ( pr_strings + ent->v.classname ); + + if (!func) + { + Con_Printf ("No spawn function for:\n"); + ED_Print (ent); + ED_Free (ent); + continue; + } + + pr_global_struct->self = EDICT_TO_PROG(ent); + PR_ExecuteProgram (func - pr_functions); + } + + Con_DPrintf ("%i entities inhibited\n", inhibit); +} + + +/* +=============== +PR_LoadProgs +=============== +*/ +void PR_LoadProgs (void) +{ + int i; + +// flush the non-C variable lookup cache + for (i=0 ; iversion != PROG_VERSION) + Sys_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); + if (progs->crc != PROGHEADER_CRC) + Sys_Error ("progs.dat system vars have been modified, progdefs.h is out of date"); + + pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); + pr_strings = (char *)progs + progs->ofs_strings; + 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; + + pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t); + +// byte swap the lumps + for (i=0 ; inumstatements ; i++) + { + 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); + } + + for (i=0 ; inumfunctions; i++) + { + 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); + } + + for (i=0 ; inumglobaldefs ; i++) + { + 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); + } + + for (i=0 ; inumfielddefs ; i++) + { + pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); + if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) + Sys_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); + } + + for (i=0 ; inumglobals ; i++) + ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); +} + + +/* +=============== +PR_Init +=============== +*/ +void PR_Init (void) +{ + 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); +} + + + +edict_t *EDICT_NUM(int n) +{ + if (n < 0 || n >= sv.max_edicts) + Sys_Error ("EDICT_NUM: bad number %i", n); + return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size); +} + +int NUM_FOR_EDICT(edict_t *e) +{ + int b; + + b = (byte *)e - (byte *)sv.edicts; + b = b / pr_edict_size; + + if (b < 0 || b >= sv.num_edicts) + Sys_Error ("NUM_FOR_EDICT: bad pointer"); + return b; +} -- cgit v1.2.3