2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // sv_edict.c -- entity dictionary
25 dfunction_t *pr_functions;
28 ddef_t *pr_globaldefs;
29 dstatement_t *pr_statements;
30 globalvars_t *pr_global_struct;
31 float *pr_globals; // same as pr_global_struct
32 int pr_edict_size; // in bytes
33 int pr_edictareasize; // LordHavoc: in bytes
35 unsigned short pr_crc;
37 int type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
39 ddef_t *ED_FieldAtOfs (int ofs);
40 qboolean ED_ParseEpair (void *base, ddef_t *key, char *s);
42 cvar_t pr_checkextension = {0, "pr_checkextension", "1"};
43 cvar_t nomonsters = {0, "nomonsters", "0"};
44 cvar_t gamecfg = {0, "gamecfg", "0"};
45 cvar_t scratch1 = {0, "scratch1", "0"};
46 cvar_t scratch2 = {0,"scratch2", "0"};
47 cvar_t scratch3 = {0, "scratch3", "0"};
48 cvar_t scratch4 = {0, "scratch4", "0"};
49 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0"};
50 cvar_t saved1 = {CVAR_SAVE, "saved1", "0"};
51 cvar_t saved2 = {CVAR_SAVE, "saved2", "0"};
52 cvar_t saved3 = {CVAR_SAVE, "saved3", "0"};
53 cvar_t saved4 = {CVAR_SAVE, "saved4", "0"};
54 cvar_t decors = {0, "decors", "0"};
55 cvar_t nehx00 = {0, "nehx00", "0"};cvar_t nehx01 = {0, "nehx01", "0"};
56 cvar_t nehx02 = {0, "nehx02", "0"};cvar_t nehx03 = {0, "nehx03", "0"};
57 cvar_t nehx04 = {0, "nehx04", "0"};cvar_t nehx05 = {0, "nehx05", "0"};
58 cvar_t nehx06 = {0, "nehx06", "0"};cvar_t nehx07 = {0, "nehx07", "0"};
59 cvar_t nehx08 = {0, "nehx08", "0"};cvar_t nehx09 = {0, "nehx09", "0"};
60 cvar_t nehx10 = {0, "nehx10", "0"};cvar_t nehx11 = {0, "nehx11", "0"};
61 cvar_t nehx12 = {0, "nehx12", "0"};cvar_t nehx13 = {0, "nehx13", "0"};
62 cvar_t nehx14 = {0, "nehx14", "0"};cvar_t nehx15 = {0, "nehx15", "0"};
63 cvar_t nehx16 = {0, "nehx16", "0"};cvar_t nehx17 = {0, "nehx17", "0"};
64 cvar_t nehx18 = {0, "nehx18", "0"};cvar_t nehx19 = {0, "nehx19", "0"};
65 cvar_t cutscene = {0, "cutscene", "1"};
66 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
67 cvar_t pr_boundscheck = {0, "pr_boundscheck", "1"};
69 #define MAX_FIELD_LEN 64
70 #define GEFV_CACHESIZE 2
74 char field[MAX_FIELD_LEN];
77 static gefv_cache gefvCache[GEFV_CACHESIZE] = {{NULL, ""}, {NULL, ""}};
79 ddef_t *ED_FindField (char *name);
80 dfunction_t *ED_FindFunction (char *name);
82 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
96 int eval_renderamt; // HalfLife support
97 int eval_rendermode; // HalfLife support
99 int eval_ammo_shells1;
100 int eval_ammo_nails1;
101 int eval_ammo_lava_nails;
102 int eval_ammo_rockets1;
103 int eval_ammo_multi_rockets;
104 int eval_ammo_cells1;
105 int eval_ammo_plasma;
107 int eval_pitch_speed;
108 int eval_viewmodelforclient;
109 int eval_nodrawtoclient;
110 int eval_exteriormodeltoclient;
111 int eval_drawonlytoclient;
116 int eval_punchvector;
118 dfunction_t *SV_PlayerPhysicsQC;
119 dfunction_t *EndFrameQC;
121 int FindFieldOffset(char *field)
124 d = ED_FindField(field);
130 void FindEdictFieldOffsets(void)
132 eval_gravity = FindFieldOffset("gravity");
133 eval_button3 = FindFieldOffset("button3");
134 eval_button4 = FindFieldOffset("button4");
135 eval_button5 = FindFieldOffset("button5");
136 eval_button6 = FindFieldOffset("button6");
137 eval_button7 = FindFieldOffset("button7");
138 eval_button8 = FindFieldOffset("button8");
139 eval_glow_size = FindFieldOffset("glow_size");
140 eval_glow_trail = FindFieldOffset("glow_trail");
141 eval_glow_color = FindFieldOffset("glow_color");
142 eval_items2 = FindFieldOffset("items2");
143 eval_scale = FindFieldOffset("scale");
144 eval_alpha = FindFieldOffset("alpha");
145 eval_renderamt = FindFieldOffset("renderamt"); // HalfLife support
146 eval_rendermode = FindFieldOffset("rendermode"); // HalfLife support
147 eval_fullbright = FindFieldOffset("fullbright");
148 eval_ammo_shells1 = FindFieldOffset("ammo_shells1");
149 eval_ammo_nails1 = FindFieldOffset("ammo_nails1");
150 eval_ammo_lava_nails = FindFieldOffset("ammo_lava_nails");
151 eval_ammo_rockets1 = FindFieldOffset("ammo_rockets1");
152 eval_ammo_multi_rockets = FindFieldOffset("ammo_multi_rockets");
153 eval_ammo_cells1 = FindFieldOffset("ammo_cells1");
154 eval_ammo_plasma = FindFieldOffset("ammo_plasma");
155 eval_idealpitch = FindFieldOffset("idealpitch");
156 eval_pitch_speed = FindFieldOffset("pitch_speed");
157 eval_viewmodelforclient = FindFieldOffset("viewmodelforclient");
158 eval_nodrawtoclient = FindFieldOffset("nodrawtoclient");
159 eval_exteriormodeltoclient = FindFieldOffset("exteriormodeltoclient");
160 eval_drawonlytoclient = FindFieldOffset("drawonlytoclient");
161 eval_colormod = FindFieldOffset("colormod");
162 eval_ping = FindFieldOffset("ping");
163 eval_movement = FindFieldOffset("movement");
164 eval_pmodel = FindFieldOffset("pmodel");
165 eval_punchvector = FindFieldOffset("punchvector");
167 // LordHavoc: allowing QuakeC to override the player movement code
168 SV_PlayerPhysicsQC = ED_FindFunction ("SV_PlayerPhysics");
169 // LordHavoc: support for endframe
170 EndFrameQC = ED_FindFunction ("EndFrame");
177 Sets everything to NULL
180 void ED_ClearEdict (edict_t *e)
182 memset (&e->v, 0, progs->entityfields * 4);
190 Either finds a free edict, or allocates a new one.
191 Try to avoid reusing an entity that was recently freed, because it
192 can cause the client to think the entity morphed into something else
193 instead of being removed and recreated, which can cause interpolated
194 angles and bad trails.
197 edict_t *ED_Alloc (void)
202 for ( i=svs.maxclients+1 ; i<sv.num_edicts ; i++)
205 // the first couple seconds of server time can involve a lot of
206 // freeing and allocating, so relax the replacement policy
207 if (e->free && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )
215 Host_Error ("ED_Alloc: no free edicts");
228 Marks the edict as free
229 FIXME: walk all entities and NULL out references to this entity
232 void ED_Free (edict_t *ed)
234 SV_UnlinkEdict (ed); // unlink from world bsp
238 ed->v.takedamage = 0;
239 ed->v.modelindex = 0;
243 VectorClear(ed->v.origin);
244 VectorClear(ed->v.angles);
245 ed->v.nextthink = -1;
248 ed->freetime = sv.time;
251 //===========================================================================
258 ddef_t *ED_GlobalAtOfs (int ofs)
263 for (i=0 ; i<progs->numglobaldefs ; i++)
265 def = &pr_globaldefs[i];
277 ddef_t *ED_FieldAtOfs (int ofs)
282 for (i=0 ; i<progs->numfielddefs ; i++)
284 def = &pr_fielddefs[i];
296 ddef_t *ED_FindField (char *name)
301 for (i=0 ; i<progs->numfielddefs ; i++)
303 def = &pr_fielddefs[i];
304 if (!strcmp(pr_strings + def->s_name,name) )
315 ddef_t *ED_FindGlobal (char *name)
320 for (i=0 ; i<progs->numglobaldefs ; i++)
322 def = &pr_globaldefs[i];
323 if (!strcmp(pr_strings + def->s_name,name) )
335 dfunction_t *ED_FindFunction (char *name)
340 for (i=0 ; i<progs->numfunctions ; i++)
342 func = &pr_functions[i];
343 if (!strcmp(pr_strings + func->s_name,name) )
351 eval_t *GetEdictFieldValue(edict_t *ed, char *field)
357 for (i=0 ; i<GEFV_CACHESIZE ; i++)
359 if (!strcmp(field, gefvCache[i].field))
361 def = gefvCache[i].pcache;
366 def = ED_FindField (field);
368 if (strlen(field) < MAX_FIELD_LEN)
370 gefvCache[rep].pcache = def;
371 strcpy (gefvCache[rep].field, field);
379 return (eval_t *)((char *)&ed->v + def->ofs*4);
387 Returns a string describing *data in a type specific manner
390 char *PR_ValueString (etype_t type, eval_t *val)
392 static char line[1024]; // LordHavoc: enlarged a bit (was 256)
396 type &= ~DEF_SAVEGLOBAL;
401 sprintf (line, "%s", pr_strings + val->string);
404 sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) );
407 f = pr_functions + val->function;
408 sprintf (line, "%s()", pr_strings + f->s_name);
411 def = ED_FieldAtOfs ( val->_int );
412 sprintf (line, ".%s", pr_strings + def->s_name);
415 sprintf (line, "void");
418 // LordHavoc: changed from %5.1f to %10.4f
419 sprintf (line, "%10.4f", val->_float);
422 // LordHavoc: changed from %5.1f to %10.4f
423 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
426 sprintf (line, "pointer");
429 sprintf (line, "bad type %i", type);
440 Returns a string describing *data in a type specific manner
441 Easier to parse than PR_ValueString
444 char *PR_UglyValueString (etype_t type, eval_t *val)
446 static char line[256];
450 type &= ~DEF_SAVEGLOBAL;
455 sprintf (line, "%s", pr_strings + val->string);
458 sprintf (line, "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)));
461 f = pr_functions + val->function;
462 sprintf (line, "%s", pr_strings + f->s_name);
465 def = ED_FieldAtOfs ( val->_int );
466 sprintf (line, "%s", pr_strings + def->s_name);
469 sprintf (line, "void");
472 sprintf (line, "%f", val->_float);
475 sprintf (line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
478 sprintf (line, "bad type %i", type);
489 Returns a string with a description and the contents of a global,
490 padded to 20 field width
493 char *PR_GlobalString (int ofs)
499 static char line[128];
501 val = (void *)&pr_globals[ofs];
502 def = ED_GlobalAtOfs(ofs);
504 sprintf (line,"%i(???)", ofs);
507 s = PR_ValueString (def->type, val);
508 sprintf (line,"%i(%s)%s", ofs, pr_strings + def->s_name, s);
519 char *PR_GlobalStringNoContents (int ofs)
523 static char line[128];
525 def = ED_GlobalAtOfs(ofs);
527 sprintf (line,"%i(???)", ofs);
529 sprintf (line,"%i(%s)", ofs, pr_strings + def->s_name);
547 // LordHavoc: optimized this to print out much more quickly (tempstring)
548 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
549 void ED_Print (edict_t *ed)
557 char tempstring[8192], tempstring2[260]; // temporary string buffers
561 Con_Printf ("FREE\n");
566 sprintf(tempstring, "\nEDICT %i:\n", NUM_FOR_EDICT(ed));
567 for (i=1 ; i<progs->numfielddefs ; i++)
569 d = &pr_fielddefs[i];
570 name = pr_strings + d->s_name;
571 if (name[strlen(name)-2] == '_')
572 continue; // skip _x, _y, _z vars
574 v = (int *)((char *)&ed->v + d->ofs*4);
576 // if the value is still all 0, skip the field
577 type = d->type & ~DEF_SAVEGLOBAL;
579 for (j=0 ; j<type_size[type] ; j++)
582 if (j == type_size[type])
585 if (strlen(name) > 256)
587 strncpy(tempstring2, name, 256);
588 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
589 tempstring2[259] = 0;
592 strcat(tempstring, name);
593 for (l = strlen(name);l < 14;l++)
594 strcat(tempstring, " ");
595 strcat(tempstring, " ");
597 name = PR_ValueString(d->type, (eval_t *)v);
598 if (strlen(name) > 256)
600 strncpy(tempstring2, name, 256);
601 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
602 tempstring2[259] = 0;
605 strcat(tempstring, name);
606 strcat(tempstring, "\n");
607 if (strlen(tempstring) >= 4096)
609 Con_Printf("%s", tempstring);
614 Con_Printf("%s", tempstring);
624 void ED_Write (QFile *f, edict_t *ed)
640 for (i=1 ; i<progs->numfielddefs ; i++)
642 d = &pr_fielddefs[i];
643 name = pr_strings + d->s_name;
644 if (name[strlen(name)-2] == '_')
645 continue; // skip _x, _y, _z vars
647 v = (int *)((char *)&ed->v + d->ofs*4);
649 // if the value is still all 0, skip the field
650 type = d->type & ~DEF_SAVEGLOBAL;
651 for (j=0 ; j<type_size[type] ; j++)
654 if (j == type_size[type])
657 Qprintf (f,"\"%s\" ",name);
658 Qprintf (f,"\"%s\"\n", PR_UglyValueString(d->type, (eval_t *)v));
664 void ED_PrintNum (int ent)
666 ED_Print (EDICT_NUM(ent));
673 For debugging, prints all the entities in the current server
676 void ED_PrintEdicts (void)
680 Con_Printf ("%i entities\n", sv.num_edicts);
681 for (i=0 ; i<sv.num_edicts ; i++)
689 For debugging, prints a single edicy
692 void ED_PrintEdict_f (void)
696 i = atoi (Cmd_Argv(1));
697 if (i >= sv.num_edicts)
699 Con_Printf("Bad edict number\n");
716 int active, models, solid, step;
718 active = models = solid = step = 0;
719 for (i=0 ; i<sv.num_edicts ; i++)
729 if (ent->v.movetype == MOVETYPE_STEP)
733 Con_Printf ("num_edicts:%3i\n", sv.num_edicts);
734 Con_Printf ("active :%3i\n", active);
735 Con_Printf ("view :%3i\n", models);
736 Con_Printf ("touch :%3i\n", solid);
737 Con_Printf ("step :%3i\n", step);
742 ==============================================================================
746 FIXME: need to tag constants, doesn't really work
747 ==============================================================================
755 void ED_WriteGlobals (QFile *f)
763 for (i=0 ; i<progs->numglobaldefs ; i++)
765 def = &pr_globaldefs[i];
767 if ( !(def->type & DEF_SAVEGLOBAL) )
769 type &= ~DEF_SAVEGLOBAL;
771 if (type != ev_string && type != ev_float && type != ev_entity)
774 name = pr_strings + def->s_name;
775 Qprintf (f,"\"%s\" ", name);
776 Qprintf (f,"\"%s\"\n", PR_UglyValueString(type, (eval_t *)&pr_globals[def->ofs]));
786 void ED_ParseGlobals (char *data)
788 char keyname[1024]; // LordHavoc: good idea? bad idea? was 64
794 data = COM_Parse (data);
795 if (com_token[0] == '}')
798 Host_Error ("ED_ParseEntity: EOF without closing brace");
800 strcpy (keyname, com_token);
803 data = COM_Parse (data);
805 Host_Error ("ED_ParseEntity: EOF without closing brace");
807 if (com_token[0] == '}')
808 Host_Error ("ED_ParseEntity: closing brace without data");
810 key = ED_FindGlobal (keyname);
813 Con_DPrintf ("'%s' is not a global\n", keyname);
817 if (!ED_ParseEpair ((void *)pr_globals, key, com_token))
818 Host_Error ("ED_ParseGlobals: parse error");
822 //============================================================================
830 char *ED_NewString (char *string)
835 l = strlen(string) + 1;
836 new = Hunk_AllocName (l, "edict string");
839 for (i=0 ; i< l ; i++)
841 if (string[i] == '\\' && i < l-1)
844 if (string[i] == 'n')
850 *new_p++ = string[i];
861 Can parse either fields or globals
862 returns false if error
865 qboolean ED_ParseEpair (void *base, ddef_t *key, char *s)
874 d = (void *)((int *)base + key->ofs);
876 switch (key->type & ~DEF_SAVEGLOBAL)
879 *(string_t *)d = ED_NewString (s) - pr_strings;
883 *(float *)d = atof (s);
890 for (i=0 ; i<3 ; i++)
892 while (*v && *v != ' ')
895 ((float *)d)[i] = atof (w);
901 *(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s)));
905 def = ED_FindField (s);
908 // LordHavoc: don't warn about worldspawn sky/fog fields because they don't require mod support
909 if (strcmp(s, "sky") && strcmp(s, "fog") && strncmp(s, "fog_", 4) && strcmp(s, "farclip"))
910 Con_DPrintf ("Can't find field %s\n", s);
913 *(int *)d = G_INT(def->ofs);
917 func = ED_FindFunction (s);
920 Con_DPrintf ("Can't find function %s\n", s);
923 *(func_t *)d = func - pr_functions;
936 Parses an edict out of the given string, returning the new position
937 ed should be a properly initialized empty edict.
938 Used for initial level load and for savegames.
941 char *ED_ParseEdict (char *data, edict_t *ent)
952 if (ent != sv.edicts) // hack
953 memset (&ent->v, 0, progs->entityfields * 4);
955 // go through all the dictionary pairs
959 data = COM_Parse (data);
960 if (com_token[0] == '}')
963 Host_Error ("ED_ParseEntity: EOF without closing brace");
965 // anglehack is to allow QuakeEd to write single scalar angles
966 // and allow them to be turned into vectors. (FIXME...)
967 if (!strcmp(com_token, "angle"))
969 strcpy (com_token, "angles");
975 // FIXME: change light to _light to get rid of this hack
976 if (!strcmp(com_token, "light"))
977 strcpy (com_token, "light_lev"); // hack for single light def
979 strcpy (keyname, com_token);
981 // another hack to fix heynames with trailing spaces
983 while (n && keyname[n-1] == ' ')
990 data = COM_Parse (data);
992 Host_Error ("ED_ParseEntity: EOF without closing brace");
994 if (com_token[0] == '}')
995 Host_Error ("ED_ParseEntity: closing brace without data");
999 // keynames with a leading underscore are used for utility comments,
1000 // and are immediately discarded by quake
1001 if (keyname[0] == '_')
1004 key = ED_FindField (keyname);
1007 Con_DPrintf ("'%s' is not a field\n", keyname);
1014 strcpy (temp, com_token);
1015 sprintf (com_token, "0 %s 0", temp);
1018 if (!ED_ParseEpair ((void *)&ent->v, key, com_token))
1019 Host_Error ("ED_ParseEdict: parse error");
1033 The entities are directly placed in the array, rather than allocated with
1034 ED_Alloc, because otherwise an error loading the map would have entity
1035 number references out of order.
1037 Creates a server's entity / program execution context by
1038 parsing textual entity definitions out of an ent file.
1040 Used for both fresh maps and savegame loads. A fresh map would also need
1041 to call ED_CallSpawnFunctions () to let the objects initialize themselves.
1044 void ED_LoadFromFile (char *data)
1052 pr_global_struct->time = sv.time;
1057 // parse the opening brace
1058 data = COM_Parse (data);
1061 if (com_token[0] != '{')
1062 Host_Error ("ED_LoadFromFile: found %s when expecting {",com_token);
1068 data = ED_ParseEdict (data, ent);
1070 // remove things from different skill levels or deathmatch
1071 if (deathmatch.value)
1073 if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
1080 else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY ))
1081 || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM))
1082 || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD )))
1090 // immediately call spawn function
1092 if (!ent->v.classname)
1094 Con_Printf ("No classname for:\n");
1100 // look for the spawn function
1101 func = ED_FindFunction ( pr_strings + ent->v.classname );
1105 if (developer.value) // don't confuse non-developers with errors
1107 Con_Printf ("No spawn function for:\n");
1114 pr_global_struct->self = EDICT_TO_PROG(ent);
1115 PR_ExecuteProgram (func - pr_functions, "");
1118 Con_DPrintf ("%i entities inhibited\n", inhibit);
1127 void PR_LoadProgs (void)
1132 // flush the non-C variable lookup cache
1133 for (i=0 ; i<GEFV_CACHESIZE ; i++)
1134 gefvCache[i].field[0] = 0;
1136 progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat", false);
1138 Host_Error ("PR_LoadProgs: couldn't load progs.dat");
1139 Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024);
1141 pr_crc = CRC_Block((byte *)progs, com_filesize);
1143 // byte swap the header
1144 for (i=0 ; i<sizeof(*progs)/4 ; i++)
1145 ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );
1147 if (progs->version != PROG_VERSION)
1148 Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
1149 if (progs->crc != PROGHEADER_CRC)
1150 Host_Error ("progs.dat system vars have been modified, progdefs.h is out of date");
1152 pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);
1153 pr_strings = (char *)progs + progs->ofs_strings;
1154 pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);
1155 pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
1156 pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);
1158 pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);
1159 pr_globals = (float *)pr_global_struct;
1161 pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t);
1163 pr_edictareasize = pr_edict_size * MAX_EDICTS;
1165 // byte swap the lumps
1166 for (i=0 ; i<progs->numstatements ; i++)
1168 pr_statements[i].op = LittleShort(pr_statements[i].op);
1169 pr_statements[i].a = LittleShort(pr_statements[i].a);
1170 pr_statements[i].b = LittleShort(pr_statements[i].b);
1171 pr_statements[i].c = LittleShort(pr_statements[i].c);
1174 for (i=0 ; i<progs->numfunctions; i++)
1176 pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement);
1177 pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start);
1178 pr_functions[i].s_name = LittleLong (pr_functions[i].s_name);
1179 pr_functions[i].s_file = LittleLong (pr_functions[i].s_file);
1180 pr_functions[i].numparms = LittleLong (pr_functions[i].numparms);
1181 pr_functions[i].locals = LittleLong (pr_functions[i].locals);
1184 for (i=0 ; i<progs->numglobaldefs ; i++)
1186 pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);
1187 pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);
1188 pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
1191 for (i=0 ; i<progs->numfielddefs ; i++)
1193 pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type);
1194 if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)
1195 Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
1196 pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);
1197 pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);
1200 for (i=0 ; i<progs->numglobals ; i++)
1201 ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
1203 // LordHavoc: bounds check anything static
1204 for (i = 0,st = pr_statements;i < progs->numstatements;i++,st++)
1210 if ((unsigned short) st->a >= progs->numglobals || st->b + i < 0 || st->b + i >= progs->numstatements)
1211 Host_Error("PR_LoadProgs: out of bounds IF/IFNOT (statement %d)\n", i);
1214 if (st->a + i < 0 || st->a + i >= progs->numstatements)
1215 Host_Error("PR_LoadProgs: out of bounds GOTO (statement %d)\n", i);
1217 // global global global
1252 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->b >= progs->numglobals || (unsigned short) st->c >= progs->numglobals)
1253 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1255 // global none global
1261 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->c >= progs->numglobals)
1262 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1278 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->b >= progs->numglobals)
1279 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1293 if ((unsigned short) st->a >= progs->numglobals)
1294 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1297 Host_Error("PR_LoadProgs: unknown opcode %d at statement %d\n", st->op, i);
1302 FindEdictFieldOffsets(); // LordHavoc: update field offset list
1306 void PR_Fields_f (void)
1311 Con_Printf("no progs loaded\n");
1314 for (i = 0;i < progs->numfielddefs;i++)
1315 Con_Printf("%s\n", (pr_strings + pr_fielddefs[i].s_name));
1316 Con_Printf("%i entity fields, totalling %i bytes per edict, %i edicts, %i bytes total spent on edict fields\n", progs->entityfields, progs->entityfields * 4, MAX_EDICTS, progs->entityfields * 4 * MAX_EDICTS);
1319 void PR_Globals_f (void)
1324 Con_Printf("no progs loaded\n");
1327 for (i = 0;i < progs->numglobaldefs;i++)
1328 Con_Printf("%s\n", (pr_strings + pr_globaldefs[i].s_name));
1329 Con_Printf("%i global variables, totalling %i bytes\n", progs->numglobals, progs->numglobals * 4);
1339 Cmd_AddCommand ("edict", ED_PrintEdict_f);
1340 Cmd_AddCommand ("edicts", ED_PrintEdicts);
1341 Cmd_AddCommand ("edictcount", ED_Count);
1342 Cmd_AddCommand ("profile", PR_Profile_f);
1343 Cmd_AddCommand ("pr_fields", PR_Fields_f);
1344 Cmd_AddCommand ("pr_globals", PR_Globals_f);
1345 Cvar_RegisterVariable (&pr_checkextension);
1346 Cvar_RegisterVariable (&nomonsters);
1347 Cvar_RegisterVariable (&gamecfg);
1348 Cvar_RegisterVariable (&scratch1);
1349 Cvar_RegisterVariable (&scratch2);
1350 Cvar_RegisterVariable (&scratch3);
1351 Cvar_RegisterVariable (&scratch4);
1352 Cvar_RegisterVariable (&savedgamecfg);
1353 Cvar_RegisterVariable (&saved1);
1354 Cvar_RegisterVariable (&saved2);
1355 Cvar_RegisterVariable (&saved3);
1356 Cvar_RegisterVariable (&saved4);
1357 // LordHavoc: for DarkPlaces, this overrides the number of decors (shell casings, gibs, etc)
1358 Cvar_RegisterVariable (&decors);
1359 // LordHavoc: Nehahra uses these to pass data around cutscene demos
1362 Cvar_RegisterVariable (&nehx00);Cvar_RegisterVariable (&nehx01);
1363 Cvar_RegisterVariable (&nehx02);Cvar_RegisterVariable (&nehx03);
1364 Cvar_RegisterVariable (&nehx04);Cvar_RegisterVariable (&nehx05);
1365 Cvar_RegisterVariable (&nehx06);Cvar_RegisterVariable (&nehx07);
1366 Cvar_RegisterVariable (&nehx08);Cvar_RegisterVariable (&nehx09);
1367 Cvar_RegisterVariable (&nehx10);Cvar_RegisterVariable (&nehx11);
1368 Cvar_RegisterVariable (&nehx12);Cvar_RegisterVariable (&nehx13);
1369 Cvar_RegisterVariable (&nehx14);Cvar_RegisterVariable (&nehx15);
1370 Cvar_RegisterVariable (&nehx16);Cvar_RegisterVariable (&nehx17);
1371 Cvar_RegisterVariable (&nehx18);Cvar_RegisterVariable (&nehx19);
1373 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
1374 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1375 Cvar_RegisterVariable (&pr_boundscheck);
1378 // LordHavoc: turned EDICT_NUM into a #define for speed reasons
1379 edict_t *EDICT_NUM_ERROR(int n)
1381 Host_Error ("EDICT_NUM: bad number %i", n);
1385 edict_t *EDICT_NUM(int n)
1387 if (n < 0 || n >= sv.max_edicts)
1388 Sys_Error ("EDICT_NUM: bad number %i", n);
1389 return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size);
1393 int NUM_FOR_EDICT(edict_t *e)
1397 b = (byte *)e - (byte *)sv.edicts;
1398 b = b / pr_edict_size;
1400 if (b < 0 || b >= sv.num_edicts)
1401 Host_Error ("NUM_FOR_EDICT: bad pointer");