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); // LordHavoc: escaping the ?s so it is not a trigraph
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); // LordHavoc: escaping the ?s so it is not a trigraph
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);
1122 typedef struct dpfield_s
1129 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1131 dpfield_t dpfields[] =
1133 {ev_float, "gravity"},
1134 {ev_float, "button3"},
1135 {ev_float, "button4"},
1136 {ev_float, "button5"},
1137 {ev_float, "button6"},
1138 {ev_float, "button7"},
1139 {ev_float, "button8"},
1140 {ev_float, "glow_size"},
1141 {ev_float, "glow_trail"},
1142 {ev_float, "glow_color"},
1143 {ev_float, "items2"},
1144 {ev_float, "scale"},
1145 {ev_float, "alpha"},
1146 {ev_float, "renderamt"},
1147 {ev_float, "rendermode"},
1148 {ev_float, "fullbright"},
1149 {ev_float, "ammo_shells1"},
1150 {ev_float, "ammo_nails1"},
1151 {ev_float, "ammo_lava_nails"},
1152 {ev_float, "ammo_rockets1"},
1153 {ev_float, "ammo_multi_rockets"},
1154 {ev_float, "ammo_cells1"},
1155 {ev_float, "ammo_plasma"},
1156 {ev_float, "idealpitch"},
1157 {ev_float, "pitch_speed"},
1158 {ev_entity, "viewmodelforclient"},
1159 {ev_entity, "nodrawtoclient"},
1160 {ev_entity, "exteriormodeltoclient"},
1161 {ev_entity, "drawonlytoclient"},
1162 {ev_vector, "colormod"},
1164 {ev_vector, "movement"},
1165 {ev_float, "pmodel"},
1166 {ev_vector, "punchvector"}
1174 void PR_LoadProgs (void)
1178 ddef_t *infielddefs;
1180 // flush the non-C variable lookup cache
1181 for (i=0 ; i<GEFV_CACHESIZE ; i++)
1182 gefvCache[i].field[0] = 0;
1184 progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat", false);
1186 Host_Error ("PR_LoadProgs: couldn't load progs.dat");
1187 Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024);
1189 pr_crc = CRC_Block((byte *)progs, com_filesize);
1191 // byte swap the header
1192 for (i=0 ; i<sizeof(*progs)/4 ; i++)
1193 ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );
1195 if (progs->version != PROG_VERSION)
1196 Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
1197 if (progs->crc != PROGHEADER_CRC)
1198 Host_Error ("progs.dat system vars have been modified, progdefs.h is out of date");
1200 pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);
1201 pr_strings = (char *)progs + progs->ofs_strings;
1202 pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);
1204 // we need to expand the fielddefs list to include all the engine fields,
1205 // so allocate a new place for it
1206 infielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
1207 pr_fielddefs = Hunk_AllocName((progs->numfielddefs + DPFIELDS) * sizeof(ddef_t), "progs fields\n");
1209 pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);
1211 // moved edict_size calculation down below field adding code
1213 pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);
1214 pr_globals = (float *)pr_global_struct;
1216 // byte swap the lumps
1217 for (i=0 ; i<progs->numstatements ; i++)
1219 pr_statements[i].op = LittleShort(pr_statements[i].op);
1220 pr_statements[i].a = LittleShort(pr_statements[i].a);
1221 pr_statements[i].b = LittleShort(pr_statements[i].b);
1222 pr_statements[i].c = LittleShort(pr_statements[i].c);
1225 for (i=0 ; i<progs->numfunctions; i++)
1227 pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement);
1228 pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start);
1229 pr_functions[i].s_name = LittleLong (pr_functions[i].s_name);
1230 pr_functions[i].s_file = LittleLong (pr_functions[i].s_file);
1231 pr_functions[i].numparms = LittleLong (pr_functions[i].numparms);
1232 pr_functions[i].locals = LittleLong (pr_functions[i].locals);
1235 for (i=0 ; i<progs->numglobaldefs ; i++)
1237 pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);
1238 pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);
1239 pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
1242 // copy the progs fields to the new fields list
1243 for (i = 0;i < progs->numfielddefs;i++)
1245 pr_fielddefs[i].type = LittleShort (infielddefs[i].type);
1246 if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)
1247 Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
1248 pr_fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1249 pr_fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1252 // append the darkplaces fields
1253 for (i = 0;i < DPFIELDS;i++)
1255 pr_fielddefs[progs->numfielddefs].type = dpfields[i].type;
1256 pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields;
1257 pr_fielddefs[progs->numfielddefs].s_name = dpfields[i].string - pr_strings;
1258 if (pr_fielddefs[progs->numfielddefs].type == ev_vector)
1259 progs->entityfields += 3;
1261 progs->entityfields++;
1262 progs->numfielddefs++;
1265 for (i=0 ; i<progs->numglobals ; i++)
1266 ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
1268 // moved edict_size calculation down here, below field adding code
1269 pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t);
1271 pr_edictareasize = pr_edict_size * MAX_EDICTS;
1273 // LordHavoc: bounds check anything static
1274 for (i = 0,st = pr_statements;i < progs->numstatements;i++,st++)
1280 if ((unsigned short) st->a >= progs->numglobals || st->b + i < 0 || st->b + i >= progs->numstatements)
1281 Host_Error("PR_LoadProgs: out of bounds IF/IFNOT (statement %d)\n", i);
1284 if (st->a + i < 0 || st->a + i >= progs->numstatements)
1285 Host_Error("PR_LoadProgs: out of bounds GOTO (statement %d)\n", i);
1287 // global global global
1322 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->b >= progs->numglobals || (unsigned short) st->c >= progs->numglobals)
1323 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1325 // global none global
1331 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->c >= progs->numglobals)
1332 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1348 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->b >= progs->numglobals)
1349 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1363 if ((unsigned short) st->a >= progs->numglobals)
1364 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1367 Host_Error("PR_LoadProgs: unknown opcode %d at statement %d\n", st->op, i);
1372 FindEdictFieldOffsets(); // LordHavoc: update field offset list
1376 void PR_Fields_f (void)
1381 Con_Printf("no progs loaded\n");
1384 for (i = 0;i < progs->numfielddefs;i++)
1385 Con_Printf("%s\n", (pr_strings + pr_fielddefs[i].s_name));
1386 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);
1389 void PR_Globals_f (void)
1394 Con_Printf("no progs loaded\n");
1397 for (i = 0;i < progs->numglobaldefs;i++)
1398 Con_Printf("%s\n", (pr_strings + pr_globaldefs[i].s_name));
1399 Con_Printf("%i global variables, totalling %i bytes\n", progs->numglobals, progs->numglobals * 4);
1409 Cmd_AddCommand ("edict", ED_PrintEdict_f);
1410 Cmd_AddCommand ("edicts", ED_PrintEdicts);
1411 Cmd_AddCommand ("edictcount", ED_Count);
1412 Cmd_AddCommand ("profile", PR_Profile_f);
1413 Cmd_AddCommand ("pr_fields", PR_Fields_f);
1414 Cmd_AddCommand ("pr_globals", PR_Globals_f);
1415 Cvar_RegisterVariable (&pr_checkextension);
1416 Cvar_RegisterVariable (&nomonsters);
1417 Cvar_RegisterVariable (&gamecfg);
1418 Cvar_RegisterVariable (&scratch1);
1419 Cvar_RegisterVariable (&scratch2);
1420 Cvar_RegisterVariable (&scratch3);
1421 Cvar_RegisterVariable (&scratch4);
1422 Cvar_RegisterVariable (&savedgamecfg);
1423 Cvar_RegisterVariable (&saved1);
1424 Cvar_RegisterVariable (&saved2);
1425 Cvar_RegisterVariable (&saved3);
1426 Cvar_RegisterVariable (&saved4);
1427 // LordHavoc: for DarkPlaces, this overrides the number of decors (shell casings, gibs, etc)
1428 Cvar_RegisterVariable (&decors);
1429 // LordHavoc: Nehahra uses these to pass data around cutscene demos
1430 if (gamemode == GAME_NEHAHRA)
1432 Cvar_RegisterVariable (&nehx00);Cvar_RegisterVariable (&nehx01);
1433 Cvar_RegisterVariable (&nehx02);Cvar_RegisterVariable (&nehx03);
1434 Cvar_RegisterVariable (&nehx04);Cvar_RegisterVariable (&nehx05);
1435 Cvar_RegisterVariable (&nehx06);Cvar_RegisterVariable (&nehx07);
1436 Cvar_RegisterVariable (&nehx08);Cvar_RegisterVariable (&nehx09);
1437 Cvar_RegisterVariable (&nehx10);Cvar_RegisterVariable (&nehx11);
1438 Cvar_RegisterVariable (&nehx12);Cvar_RegisterVariable (&nehx13);
1439 Cvar_RegisterVariable (&nehx14);Cvar_RegisterVariable (&nehx15);
1440 Cvar_RegisterVariable (&nehx16);Cvar_RegisterVariable (&nehx17);
1441 Cvar_RegisterVariable (&nehx18);Cvar_RegisterVariable (&nehx19);
1443 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
1444 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1445 Cvar_RegisterVariable (&pr_boundscheck);
1448 // LordHavoc: turned EDICT_NUM into a #define for speed reasons
1449 edict_t *EDICT_NUM_ERROR(int n)
1451 Host_Error ("EDICT_NUM: bad number %i", n);
1455 edict_t *EDICT_NUM(int n)
1457 if (n < 0 || n >= sv.max_edicts)
1458 Sys_Error ("EDICT_NUM: bad number %i", n);
1459 return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size);
1463 int NUM_FOR_EDICT(edict_t *e)
1467 b = (byte *)e - (byte *)sv.edicts;
1468 b = b / pr_edict_size;
1470 if (b < 0 || b >= sv.num_edicts)
1471 Host_Error ("NUM_FOR_EDICT: bad pointer");