summaryrefslogtreecommitdiff
path: root/samples/quake/jni/pr_edict.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'samples/quake/jni/pr_edict.cpp')
-rw-r--r--samples/quake/jni/pr_edict.cpp1106
1 files changed, 1106 insertions, 0 deletions
diff --git a/samples/quake/jni/pr_edict.cpp b/samples/quake/jni/pr_edict.cpp
new file mode 100644
index 0000000..dbfb8ed
--- /dev/null
+++ b/samples/quake/jni/pr_edict.cpp
@@ -0,0 +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 = CVAR2("nomonsters", "0");
+cvar_t gamecfg = CVAR2("gamecfg", "0");
+cvar_t scratch1 = CVAR2("scratch1", "0");
+cvar_t scratch2 = CVAR2("scratch2", "0");
+cvar_t scratch3 = CVAR2("scratch3", "0");
+cvar_t scratch4 = CVAR2("scratch4", "0");
+cvar_t savedgamecfg = CVAR3("savedgamecfg", "0", true);
+cvar_t saved1 = CVAR3("saved1", "0", true);
+cvar_t saved2 = CVAR3("saved2", "0", true);
+cvar_t saved3 = CVAR3("saved3", "0", true);
+cvar_t saved4 = CVAR3("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->u.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 ; i<sv.num_edicts ; i++)
+ {
+ e = EDICT_NUM(i);
+ // the first couple seconds of server time can involve a lot of
+ // freeing and allocating, so relax the replacement policy
+ if (e->free && ( 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->u.v.model = 0;
+ ed->u.v.takedamage = 0;
+ ed->u.v.modelindex = 0;
+ ed->u.v.colormap = 0;
+ ed->u.v.skin = 0;
+ ed->u.v.frame = 0;
+ VectorCopy (vec3_origin, ed->u.v.origin);
+ VectorCopy (vec3_origin, ed->u.v.angles);
+ ed->u.v.nextthink = -1;
+ ed->u.v.solid = 0;
+
+ ed->freetime = sv.time;
+}
+
+//===========================================================================
+
+/*
+============
+ED_GlobalAtOfs
+============
+*/
+ddef_t *ED_GlobalAtOfs (int ofs)
+{
+ ddef_t *def;
+ int i;
+
+ for (i=0 ; i<progs->numglobaldefs ; 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 ; i<progs->numfielddefs ; i++)
+ {
+ def = &pr_fielddefs[i];
+ if (def->ofs == ofs)
+ return def;
+ }
+ return NULL;
+}
+
+/*
+============
+ED_FindField
+============
+*/
+ddef_t *ED_FindField (const char *name)
+{
+ ddef_t *def;
+ int i;
+
+ for (i=0 ; i<progs->numfielddefs ; i++)
+ {
+ def = &pr_fielddefs[i];
+ if (!strcmp(pr_strings + def->s_name,name) )
+ return def;
+ }
+ return NULL;
+}
+
+
+/*
+============
+ED_FindGlobal
+============
+*/
+ddef_t *ED_FindGlobal (const char *name)
+{
+ ddef_t *def;
+ int i;
+
+ for (i=0 ; i<progs->numglobaldefs ; i++)
+ {
+ def = &pr_globaldefs[i];
+ if (!strcmp(pr_strings + def->s_name,name) )
+ return def;
+ }
+ return NULL;
+}
+
+
+/*
+============
+ED_FindFunction
+============
+*/
+dfunction_t *ED_FindFunction (const char *name)
+{
+ dfunction_t *func;
+ int i;
+
+ for (i=0 ; i<progs->numfunctions ; i++)
+ {
+ func = &pr_functions[i];
+ if (!strcmp(pr_strings + func->s_name,name) )
+ return func;
+ }
+ return NULL;
+}
+
+
+eval_t *GetEdictFieldValue(edict_t *ed, const char *field)
+{
+ ddef_t *def = NULL;
+ int i;
+ static int rep = 0;
+
+ for (i=0 ; i<GEFV_CACHESIZE ; i++)
+ {
+ if (!strcmp(field, gefvCache[i].field))
+ {
+ def = gefvCache[i].pcache;
+ goto Done;
+ }
+ }
+
+ def = ED_FindField (field);
+
+ if (strlen(field) < MAX_FIELD_LEN)
+ {
+ gefvCache[rep].pcache = def;
+ strcpy (gefvCache[rep].field, field);
+ rep ^= 1;
+ }
+
+Done:
+ if (!def)
+ return NULL;
+
+ return (eval_t *)((char *)&ed->u.v + 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 = (etype_t) (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 = (etype_t) (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 ((etype_t) def->type, (eval_t*) 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 ; i<progs->numfielddefs ; 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->u.v + d->ofs*4);
+
+ // if the value is still all 0, skip the field
+ type = d->type & ~DEF_SAVEGLOBAL;
+
+ for (j=0 ; j<type_size[type] ; j++)
+ if (v[j])
+ break;
+ if (j == type_size[type])
+ continue;
+
+ Con_Printf ("%s",name);
+ l = strlen (name);
+ while (l++ < 15)
+ Con_Printf (" ");
+
+ Con_Printf ("%s\n", PR_ValueString((etype_t) d->type, (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 ; i<progs->numfielddefs ; 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->u.v + d->ofs*4);
+
+ // if the value is still all 0, skip the field
+ type = d->type & ~DEF_SAVEGLOBAL;
+ for (j=0 ; j<type_size[type] ; j++)
+ if (v[j])
+ break;
+ if (j == type_size[type])
+ continue;
+
+ fprintf (f,"\"%s\" ",name);
+ fprintf (f,"\"%s\"\n", PR_UglyValueString((etype_t) d->type, (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 ; i++)
+ ED_PrintNum (i);
+}
+
+/*
+=============
+ED_PrintEdict_f
+
+For debugging, prints a single edicy
+=============
+*/
+void ED_PrintEdict_f (void)
+{
+ int i;
+
+ i = Q_atoi (Cmd_Argv(1));
+ if (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 ; i<sv.num_edicts ; i++)
+ {
+ ent = EDICT_NUM(i);
+ if (ent->free)
+ continue;
+ active++;
+ if (ent->u.v.solid)
+ solid++;
+ if (ent->u.v.model)
+ models++;
+ if (ent->u.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 ; i<progs->numglobaldefs ; 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((etype_t) 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_ = (char*) 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->u.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->u.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->u.v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
+ {
+ ED_Free (ent);
+ inhibit++;
+ continue;
+ }
+ }
+ else if ((current_skill == 0 && ((int)ent->u.v.spawnflags & SPAWNFLAG_NOT_EASY))
+ || (current_skill == 1 && ((int)ent->u.v.spawnflags & SPAWNFLAG_NOT_MEDIUM))
+ || (current_skill >= 2 && ((int)ent->u.v.spawnflags & SPAWNFLAG_NOT_HARD)) )
+ {
+ ED_Free (ent);
+ inhibit++;
+ continue;
+ }
+
+//
+// immediately call spawn function
+//
+ if (!ent->u.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->u.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 ; i<GEFV_CACHESIZE ; i++)
+ gefvCache[i].field[0] = 0;
+
+ CRC_Init (&pr_crc);
+
+ progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat");
+ if (!progs)
+ Sys_Error ("PR_LoadProgs: couldn't load progs.dat");
+ Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024);
+
+ for (i=0 ; i<com_filesize ; i++)
+ CRC_ProcessByte (&pr_crc, ((byte *)progs)[i]);
+
+// byte swap the header
+ for (i=0 ; i< (int) (sizeof(*progs)/4) ; i++)
+ ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );
+
+ if (progs->version != 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 ; i<progs->numstatements ; 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 ; i<progs->numfunctions; 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 ; i<progs->numglobaldefs ; 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 ; i<progs->numfielddefs ; 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 ; i<progs->numglobals ; 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;
+}