123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086 |
- /*
- 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 "qwsvdef.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
- int type_size[8] = {1,sizeof(void *)/4,1,3,1,1,sizeof(void *)/4,sizeof(void *)/4};
- ddef_t *ED_FieldAtOfs (int ofs);
- qboolean ED_ParseEpair (void *base, ddef_t *key, char *s);
- #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, ""}};
- func_t SpectatorConnect;
- func_t SpectatorThink;
- func_t SpectatorDisconnect;
- /*
- =================
- 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=MAX_CLIENTS+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)
- {
- Con_Printf ("WARNING: ED_Alloc: no free edicts\n");
- i--; // step on whatever is the last edict
- e = EDICT_NUM(i);
- SV_UnlinkEdict(e);
- }
- else
- 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 ; 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 (char *name)
- {
- ddef_t *def;
- int i;
-
- for (i=0 ; i<progs->numfielddefs ; i++)
- {
- def = &pr_fielddefs[i];
- if (!strcmp(PR_GetString(def->s_name),name) )
- return def;
- }
- return NULL;
- }
- /*
- ============
- ED_FindGlobal
- ============
- */
- ddef_t *ED_FindGlobal (char *name)
- {
- ddef_t *def;
- int i;
-
- for (i=0 ; i<progs->numglobaldefs ; i++)
- {
- def = &pr_globaldefs[i];
- if (!strcmp(PR_GetString(def->s_name),name) )
- return def;
- }
- return NULL;
- }
- /*
- ============
- ED_FindFunction
- ============
- */
- dfunction_t *ED_FindFunction (char *name)
- {
- dfunction_t *func;
- int i;
-
- for (i=0 ; i<progs->numfunctions ; i++)
- {
- func = &pr_functions[i];
- if (!strcmp(PR_GetString(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 ; 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->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 &= ~DEF_SAVEGLOBAL;
- switch (type)
- {
- case ev_string:
- sprintf (line, "%s", PR_GetString(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_GetString(f->s_name));
- break;
- case ev_field:
- def = ED_FieldAtOfs ( val->_int );
- sprintf (line, ".%s", PR_GetString(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_GetString(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_GetString(f->s_name));
- break;
- case ev_field:
- def = ED_FieldAtOfs ( val->_int );
- sprintf (line, "%s", PR_GetString(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_GetString(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_GetString(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;
- }
-
- for (i=1 ; i<progs->numfielddefs ; i++)
- {
- d = &pr_fielddefs[i];
- name = PR_GetString(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 ; 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(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_GetString(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 ; 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(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++)
- {
- Con_Printf ("\nEDICT %i:\n",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));
- Con_Printf ("\n EDICT %i:\n",i);
- 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->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 ; 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_GetString(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)
- SV_Error ("ED_ParseEntity: EOF without closing brace");
- strcpy (keyname, com_token);
- // parse value
- data = COM_Parse (data);
- if (!data)
- SV_Error ("ED_ParseEntity: EOF without closing brace");
- if (com_token[0] == '}')
- SV_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))
- SV_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 = PR_SetString(ED_NewString (s));
- 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];
- 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)
- SV_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);
-
- // parse value
- data = COM_Parse (data);
- if (!data)
- SV_Error ("ED_ParseEntity: EOF without closing brace");
- if (com_token[0] == '}')
- SV_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))
- SV_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] != '{')
- SV_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 (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
- {
- 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_GetString(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);
- SV_FlushSignon();
- }
- Con_DPrintf ("%i entities inhibited\n", inhibit);
- }
- /*
- ===============
- PR_LoadProgs
- ===============
- */
- void PR_LoadProgs (void)
- {
- int i;
- char num[32];
- dfunction_t *f;
- // flush the non-C variable lookup cache
- for (i=0 ; i<GEFV_CACHESIZE ; i++)
- gefvCache[i].field[0] = 0;
- progs = (dprograms_t *)COM_LoadHunkFile ("qwprogs.dat");
- if (!progs)
- progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat");
- if (!progs)
- SV_Error ("PR_LoadProgs: couldn't load progs.dat");
- Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024);
- // add prog crc to the serverinfo
- sprintf (num, "%i", CRC_Block ((byte *)progs, com_filesize));
- Info_SetValueForStarKey (svs.info, "*progs", num, MAX_SERVERINFO_STRING);
- // byte swap the header
- for (i=0 ; i<sizeof(*progs)/4 ; i++)
- ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );
- if (progs->version != PROG_VERSION)
- SV_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
- if (progs->crc != PROGHEADER_CRC)
- SV_Error ("You must have the progs.dat from QuakeWorld installed");
- 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);
- num_prstr = 0;
- 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)
- SV_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]);
- // Zoid, find the spectator functions
- SpectatorConnect = SpectatorThink = SpectatorDisconnect = 0;
- if ((f = ED_FindFunction ("SpectatorConnect")) != NULL)
- SpectatorConnect = (func_t)(f - pr_functions);
- if ((f = ED_FindFunction ("SpectatorThink")) != NULL)
- SpectatorThink = (func_t)(f - pr_functions);
- if ((f = ED_FindFunction ("SpectatorDisconnect")) != NULL)
- SpectatorDisconnect = (func_t)(f - pr_functions);
- }
- /*
- ===============
- 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);
- }
- edict_t *EDICT_NUM(int n)
- {
- if (n < 0 || n >= MAX_EDICTS)
- SV_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)
- SV_Error ("NUM_FOR_EDICT: bad pointer");
- return b;
- }
|