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 mfunction_t *prog->functions;
29 ddef_t *pr_globaldefs;
30 dstatement_t *pr_statements;
31 globalvars_t *pr_global_struct;
32 float *pr_globals; // same as pr_global_struct
33 int prog->edict_size; // in bytes
34 int pr_edictareasize; // LordHavoc: in bytes
36 int pr_maxknownstrings;
37 int pr_numknownstrings;
38 const char **pr_knownstrings;
40 unsigned short pr_crc;
42 mempool_t *serverprogs_mempool;
44 int type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
46 ddef_t *ED_FieldAtOfs(int ofs);
47 qboolean ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s);
49 cvar_t pr_checkextension = {CVAR_READONLY, "pr_checkextension", "1"};
50 cvar_t nomonsters = {0, "nomonsters", "0"};
51 cvar_t gamecfg = {0, "gamecfg", "0"};
52 cvar_t scratch1 = {0, "scratch1", "0"};
53 cvar_t scratch2 = {0,"scratch2", "0"};
54 cvar_t scratch3 = {0, "scratch3", "0"};
55 cvar_t scratch4 = {0, "scratch4", "0"};
56 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0"};
57 cvar_t saved1 = {CVAR_SAVE, "saved1", "0"};
58 cvar_t saved2 = {CVAR_SAVE, "saved2", "0"};
59 cvar_t saved3 = {CVAR_SAVE, "saved3", "0"};
60 cvar_t saved4 = {CVAR_SAVE, "saved4", "0"};
61 cvar_t decors = {0, "decors", "0"};
62 cvar_t nehx00 = {0, "nehx00", "0"};cvar_t nehx01 = {0, "nehx01", "0"};
63 cvar_t nehx02 = {0, "nehx02", "0"};cvar_t nehx03 = {0, "nehx03", "0"};
64 cvar_t nehx04 = {0, "nehx04", "0"};cvar_t nehx05 = {0, "nehx05", "0"};
65 cvar_t nehx06 = {0, "nehx06", "0"};cvar_t nehx07 = {0, "nehx07", "0"};
66 cvar_t nehx08 = {0, "nehx08", "0"};cvar_t nehx09 = {0, "nehx09", "0"};
67 cvar_t nehx10 = {0, "nehx10", "0"};cvar_t nehx11 = {0, "nehx11", "0"};
68 cvar_t nehx12 = {0, "nehx12", "0"};cvar_t nehx13 = {0, "nehx13", "0"};
69 cvar_t nehx14 = {0, "nehx14", "0"};cvar_t nehx15 = {0, "nehx15", "0"};
70 cvar_t nehx16 = {0, "nehx16", "0"};cvar_t nehx17 = {0, "nehx17", "0"};
71 cvar_t nehx18 = {0, "nehx18", "0"};cvar_t nehx19 = {0, "nehx19", "0"};
72 cvar_t cutscene = {0, "cutscene", "1"};
73 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
74 cvar_t pr_boundscheck = {0, "pr_boundscheck", "1"};
75 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
76 cvar_t pr_traceqc = {0, "pr_traceqc", "0"};
78 #define MAX_FIELD_LEN 64
79 #define GEFV_CACHESIZE 2
83 char field[MAX_FIELD_LEN];
86 static gefv_cache gefvCache[GEFV_CACHESIZE] = {{NULL, ""}, {NULL, ""}};
88 ddef_t *ED_FindField (const char *name);
89 mfunction_t *PRVM_ED_FindFunction (const char *name);
91 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
107 int eval_renderamt; // HalfLife support
108 int eval_rendermode; // HalfLife support
110 int eval_ammo_shells1;
111 int eval_ammo_nails1;
112 int eval_ammo_lava_nails;
113 int eval_ammo_rockets1;
114 int eval_ammo_multi_rockets;
115 int eval_ammo_cells1;
116 int eval_ammo_plasma;
118 int eval_pitch_speed;
119 int eval_viewmodelforclient;
120 int eval_nodrawtoclient;
121 int eval_exteriormodeltoclient;
122 int eval_drawonlytoclient;
126 int eval_punchvector;
128 int eval_clientcolors;
135 int eval_cursor_active;
136 int eval_cursor_screen;
137 int eval_cursor_trace_start;
138 int eval_cursor_trace_endpos;
139 int eval_cursor_trace_ent;
141 int eval_playermodel;
144 mfunction_t *SV_PlayerPhysicsQC;
145 mfunction_t *EndFrameQC;
146 //KrimZon - SERVER COMMANDS IN QUAKEC
147 mfunction_t *SV_ParseClientCommandQC;
149 int FindFieldOffset(const char *field)
152 d = ED_FindField(field);
158 void FindEdictFieldOffsets(void)
160 eval_gravity = FindFieldOffset("gravity");
161 eval_button3 = FindFieldOffset("button3");
162 eval_button4 = FindFieldOffset("button4");
163 eval_button5 = FindFieldOffset("button5");
164 eval_button6 = FindFieldOffset("button6");
165 eval_button7 = FindFieldOffset("button7");
166 eval_button8 = FindFieldOffset("button8");
167 eval_buttonuse = FindFieldOffset("buttonuse");
168 eval_buttonchat = FindFieldOffset("buttonchat");
169 eval_glow_size = FindFieldOffset("glow_size");
170 eval_glow_trail = FindFieldOffset("glow_trail");
171 eval_glow_color = FindFieldOffset("glow_color");
172 eval_items2 = FindFieldOffset("items2");
173 eval_scale = FindFieldOffset("scale");
174 eval_alpha = FindFieldOffset("alpha");
175 eval_renderamt = FindFieldOffset("renderamt"); // HalfLife support
176 eval_rendermode = FindFieldOffset("rendermode"); // HalfLife support
177 eval_fullbright = FindFieldOffset("fullbright");
178 eval_ammo_shells1 = FindFieldOffset("ammo_shells1");
179 eval_ammo_nails1 = FindFieldOffset("ammo_nails1");
180 eval_ammo_lava_nails = FindFieldOffset("ammo_lava_nails");
181 eval_ammo_rockets1 = FindFieldOffset("ammo_rockets1");
182 eval_ammo_multi_rockets = FindFieldOffset("ammo_multi_rockets");
183 eval_ammo_cells1 = FindFieldOffset("ammo_cells1");
184 eval_ammo_plasma = FindFieldOffset("ammo_plasma");
185 eval_idealpitch = FindFieldOffset("idealpitch");
186 eval_pitch_speed = FindFieldOffset("pitch_speed");
187 eval_viewmodelforclient = FindFieldOffset("viewmodelforclient");
188 eval_nodrawtoclient = FindFieldOffset("nodrawtoclient");
189 eval_exteriormodeltoclient = FindFieldOffset("exteriormodeltoclient");
190 eval_drawonlytoclient = FindFieldOffset("drawonlytoclient");
191 eval_ping = FindFieldOffset("ping");
192 eval_movement = FindFieldOffset("movement");
193 eval_pmodel = FindFieldOffset("pmodel");
194 eval_punchvector = FindFieldOffset("punchvector");
195 eval_viewzoom = FindFieldOffset("viewzoom");
196 eval_clientcolors = FindFieldOffset("clientcolors");
197 eval_tag_entity = FindFieldOffset("tag_entity");
198 eval_tag_index = FindFieldOffset("tag_index");
199 eval_light_lev = FindFieldOffset("light_lev");
200 eval_color = FindFieldOffset("color");
201 eval_style = FindFieldOffset("style");
202 eval_pflags = FindFieldOffset("pflags");
203 eval_cursor_active = FindFieldOffset("cursor_active");
204 eval_cursor_screen = FindFieldOffset("cursor_screen");
205 eval_cursor_trace_start = FindFieldOffset("cursor_trace_start");
206 eval_cursor_trace_endpos = FindFieldOffset("cursor_trace_endpos");
207 eval_cursor_trace_ent = FindFieldOffset("cursor_trace_ent");
208 eval_colormod = FindFieldOffset("colormod");
209 eval_playermodel = FindFieldOffset("playermodel");
210 eval_playerskin = FindFieldOffset("playerskin");
212 // LordHavoc: allowing QuakeC to override the player movement code
213 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
214 // LordHavoc: support for endframe
215 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
216 //KrimZon - SERVER COMMANDS IN QUAKEC
217 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
224 Sets everything to NULL
227 void ED_ClearEdict (prvm_edict_t *e)
230 memset (e->v, 0, progs->entityfields * 4);
231 e->priv.server->free = false;
232 // LordHavoc: for consistency set these here
233 num = PRVM_NUM_FOR_EDICT(e) - 1;
234 if (num >= 0 && num < svs.maxclients)
237 // set colormap and team on newly created player entity
238 e->fields.server->colormap = num + 1;
239 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
240 // set netname/clientcolors back to client values so that
241 // DP_SV_CLIENTNAME and DPV_SV_CLIENTCOLORS will not immediately
243 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
244 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
245 val->_float = svs.clients[num].colors;
246 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
247 if( eval_playermodel )
248 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
249 if( eval_playerskin )
250 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
258 Either finds a free edict, or allocates a new one.
259 Try to avoid reusing an entity that was recently freed, because it
260 can cause the client to think the entity morphed into something else
261 instead of being removed and recreated, which can cause interpolated
262 angles and bad trails.
265 prvm_edict_t *ED_Alloc (void)
270 for (i = svs.maxclients + 1;i < prog->num_edicts;i++)
272 e = PRVM_EDICT_NUM(i);
273 // the first couple seconds of server time can involve a lot of
274 // freeing and allocating, so relax the replacement policy
275 if (e->priv.server->free && ( e->priv.server->freetime < 2 || sv.time - e->priv.server->freetime > 0.5 ) )
283 Host_Error ("ED_Alloc: no free edicts");
286 if (prog->num_edicts >= prog->max_edicts)
288 e = PRVM_EDICT_NUM(i);
298 Marks the edict as free
299 FIXME: walk all entities and NULL out references to this entity
302 void ED_Free (prvm_edict_t *ed)
304 SV_UnlinkEdict (ed); // unlink from world bsp
306 ed->priv.server->free = true;
307 ed->fields.server->model = 0;
308 ed->fields.server->takedamage = 0;
309 ed->fields.server->modelindex = 0;
310 ed->fields.server->colormap = 0;
311 ed->fields.server->skin = 0;
312 ed->fields.server->frame = 0;
313 VectorClear(ed->fields.server->origin);
314 VectorClear(ed->fields.server->angles);
315 ed->fields.server->nextthink = -1;
316 ed->fields.server->solid = 0;
318 ed->priv.server->freetime = sv.time;
321 //===========================================================================
328 ddef_t *ED_GlobalAtOfs (int ofs)
333 for (i=0 ; i<progs->numglobaldefs ; i++)
335 def = &pr_globaldefs[i];
347 ddef_t *ED_FieldAtOfs (int ofs)
352 for (i=0 ; i<progs->numfielddefs ; i++)
354 def = &pr_fielddefs[i];
366 ddef_t *ED_FindField (const char *name)
371 for (i=0 ; i<progs->numfielddefs ; i++)
373 def = &pr_fielddefs[i];
374 if (!strcmp(PRVM_GetString(def->s_name), name))
385 ddef_t *ED_FindGlobal (const char *name)
390 for (i=0 ; i<progs->numglobaldefs ; i++)
392 def = &pr_globaldefs[i];
393 if (!strcmp(PRVM_GetString(def->s_name), name))
405 mfunction_t *PRVM_ED_FindFunction (const char *name)
410 for (i=0 ; i<progs->numfunctions ; i++)
412 func = &prog->functions[i];
413 if (!strcmp(PRVM_GetString(func->s_name), name))
424 Returns a string describing *data in a type specific manner
427 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e);
428 char *PR_ValueString (etype_t type, prvm_eval_t *val)
430 static char line[1024]; // LordHavoc: enlarged a bit (was 256)
435 type &= ~DEF_SAVEGLOBAL;
440 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
443 //n = NoCrash_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict));
445 if (n < 0 || n >= MAX_EDICTS)
446 dpsnprintf (line, sizeof (line), "entity %i (invalid!)", n);
448 dpsnprintf (line, sizeof (line), "entity %i", n);
451 f = prog->functions + val->function;
452 dpsnprintf (line, sizeof (line), "%s()", PRVM_GetString(f->s_name));
455 def = ED_FieldAtOfs ( val->_int );
456 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
459 dpsnprintf (line, sizeof (line), "void");
462 // LordHavoc: changed from %5.1f to %10.4f
463 dpsnprintf (line, sizeof (line), "%10.4f", val->_float);
466 // LordHavoc: changed from %5.1f to %10.4f
467 dpsnprintf (line, sizeof (line), "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
470 dpsnprintf (line, sizeof (line), "pointer");
473 dpsnprintf (line, sizeof (line), "bad type %i", type);
484 Returns a string describing *data in a type specific manner
485 Easier to parse than PR_ValueString
488 char *PR_UglyValueString (etype_t type, prvm_eval_t *val)
490 static char line[4096];
496 type &= ~DEF_SAVEGLOBAL;
501 // Parse the string a bit to turn special characters
502 // (like newline, specifically) into escape codes,
503 // this fixes saving games from various mods
504 s = PRVM_GetString (val->string);
505 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
524 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
527 f = prog->functions + val->function;
528 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
531 def = ED_FieldAtOfs ( val->_int );
532 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
535 dpsnprintf (line, sizeof (line), "void");
538 dpsnprintf (line, sizeof (line), "%f", val->_float);
541 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
544 dpsnprintf (line, sizeof (line), "bad type %i", type);
555 Returns a string with a description and the contents of a global,
556 padded to 20 field width
559 char *PR_GlobalString (int ofs)
565 static char line[128];
567 val = (void *)&pr_globals[ofs];
568 def = ED_GlobalAtOfs(ofs);
570 dpsnprintf (line, sizeof (line), "%i(?)", ofs);
573 s = PR_ValueString (def->type, val);
574 dpsnprintf (line, sizeof (line), "%i(%s)%s", ofs, PRVM_GetString(def->s_name), s);
579 strlcat (line, " ", sizeof (line));
580 strlcat (line, " ", sizeof (line));
585 char *PR_GlobalStringNoContents (int ofs)
589 static char line[128];
591 def = ED_GlobalAtOfs(ofs);
593 dpsnprintf (line, sizeof (line), "%i(?)", ofs);
595 dpsnprintf (line, sizeof (line), "%i(%s)", ofs, PRVM_GetString(def->s_name));
599 strlcat (line, " ", sizeof (line));
600 strlcat (line, " ", sizeof (line));
613 // LordHavoc: optimized this to print out much more quickly (tempstring)
614 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
615 void ED_Print(prvm_edict_t *ed)
623 char tempstring[8192], tempstring2[260]; // temporary string buffers
625 if (ed->priv.server->free)
632 dpsnprintf (tempstring, sizeof (tempstring), "\nEDICT %i:\n", PRVM_NUM_FOR_EDICT(ed));
633 for (i=1 ; i<progs->numfielddefs ; i++)
635 d = &pr_fielddefs[i];
636 name = PRVM_GetString(d->s_name);
637 if (name[strlen(name)-2] == '_')
638 continue; // skip _x, _y, _z vars
640 v = (int *)((char *)ed->v + d->ofs*4);
642 // if the value is still all 0, skip the field
643 type = d->type & ~DEF_SAVEGLOBAL;
645 for (j=0 ; j<type_size[type] ; j++)
648 if (j == type_size[type])
651 if (strlen(name) > 256)
653 memcpy (tempstring2, name, 256);
654 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
655 tempstring2[259] = 0;
658 strlcat (tempstring, name, sizeof (tempstring));
659 for (l = strlen(name);l < 14;l++)
660 strcat(tempstring, " ");
661 strcat(tempstring, " ");
663 name = PR_ValueString(d->type, (prvm_eval_t *)v);
664 if (strlen(name) > 256)
666 memcpy(tempstring2, name, 256);
667 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
668 tempstring2[259] = 0;
671 strlcat (tempstring, name, sizeof (tempstring));
672 strlcat (tempstring, "\n", sizeof (tempstring));
673 if (strlen(tempstring) >= 4096)
675 Con_Print(tempstring);
680 Con_Print(tempstring);
690 void ED_Write (qfile_t *f, prvm_edict_t *ed)
700 if (ed->priv.server->free)
706 for (i=1 ; i<progs->numfielddefs ; i++)
708 d = &pr_fielddefs[i];
709 name = PRVM_GetString(d->s_name);
710 if (name[strlen(name)-2] == '_')
711 continue; // skip _x, _y, _z vars
713 v = (int *)((char *)ed->v + d->ofs*4);
715 // if the value is still all 0, skip the field
716 type = d->type & ~DEF_SAVEGLOBAL;
717 for (j=0 ; j<type_size[type] ; j++)
720 if (j == type_size[type])
723 FS_Printf(f,"\"%s\" ",name);
724 FS_Printf(f,"\"%s\"\n", PR_UglyValueString(d->type, (prvm_eval_t *)v));
730 void ED_PrintNum (int ent)
732 ED_Print(PRVM_EDICT_NUM(ent));
739 For debugging, prints all the entities in the current server
742 void ED_PrintEdicts (void)
746 Con_Printf("%i entities\n", prog->num_edicts);
747 for (i=0 ; i<prog->num_edicts ; i++)
755 For debugging, prints a single edict
758 void ED_PrintEdict_f (void)
762 i = atoi (Cmd_Argv(1));
763 if (i < 0 || i >= prog->num_edicts)
765 Con_Print("Bad edict number\n");
782 int active, models, solid, step;
784 active = models = solid = step = 0;
785 for (i=0 ; i<prog->num_edicts ; i++)
787 ent = PRVM_EDICT_NUM(i);
788 if (ent->priv.server->free)
791 if (ent->fields.server->solid)
793 if (ent->fields.server->model)
795 if (ent->fields.server->movetype == MOVETYPE_STEP)
799 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
800 Con_Printf("active :%3i\n", active);
801 Con_Printf("view :%3i\n", models);
802 Con_Printf("touch :%3i\n", solid);
803 Con_Printf("step :%3i\n", step);
808 ==============================================================================
812 FIXME: need to tag constants, doesn't really work
813 ==============================================================================
821 void ED_WriteGlobals (qfile_t *f)
829 for (i=0 ; i<progs->numglobaldefs ; i++)
831 def = &pr_globaldefs[i];
833 if ( !(def->type & DEF_SAVEGLOBAL) )
835 type &= ~DEF_SAVEGLOBAL;
837 if (type != ev_string && type != ev_float && type != ev_entity)
840 name = PRVM_GetString(def->s_name);
841 FS_Printf(f,"\"%s\" ", name);
842 FS_Printf(f,"\"%s\"\n", PR_UglyValueString(type, (prvm_eval_t *)&pr_globals[def->ofs]));
851 Console command to set a field of a specified edict
854 void ED_EdictSet_f(void)
861 Con_Print("edictset <edict number> <field> <value>\n");
864 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(1)));
866 if((key = ED_FindField(Cmd_Argv(2))) == 0)
868 Con_Printf("Key %s not found !\n", Cmd_Argv(2));
872 ED_ParseEpair(ed, key, Cmd_Argv(3));
880 void ED_ParseGlobals (const char *data)
882 char keyname[1024]; // LordHavoc: good idea? bad idea? was 64
888 if (!COM_ParseToken(&data, false))
889 Host_Error ("ED_ParseEntity: EOF without closing brace");
890 if (com_token[0] == '}')
893 strcpy (keyname, com_token);
896 if (!COM_ParseToken(&data, false))
897 Host_Error ("ED_ParseEntity: EOF without closing brace");
899 if (com_token[0] == '}')
900 Host_Error ("ED_ParseEntity: closing brace without data");
902 key = ED_FindGlobal (keyname);
905 Con_DPrintf("'%s' is not a global\n", keyname);
909 if (!ED_ParseEpair(NULL, key, com_token))
910 Host_Error ("ED_ParseGlobals: parse error");
914 //============================================================================
921 Can parse either fields or globals
922 returns false if error
925 qboolean ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
934 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
936 val = (prvm_eval_t *)((int *)pr_globals + key->ofs);
937 switch (key->type & ~DEF_SAVEGLOBAL)
941 new_p = PR_AllocString(l);
942 val->string = PR_SetQCString(new_p);
943 for (i = 0;i < l;i++)
945 if (s[i] == '\\' && i < l-1)
950 else if (s[i] == 'r')
961 while (*s && *s <= ' ')
963 val->_float = atof(s);
967 for (i = 0;i < 3;i++)
969 while (*s && *s <= ' ')
972 val->vector[i] = atof(s);
981 while (*s && *s <= ' ')
984 if (i < 0 || i >= MAX_EDICTS)
985 Con_Printf("ED_ParseEpair: ev_entity reference too large (edict %i >= MAX_EDICTS %i)\n", i, MAX_EDICTS);
986 while (i >= prog->max_edicts)
988 // if SV_IncreaseEdicts was called the base pointer needs to be updated
990 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
991 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM(i));
995 def = ED_FindField(s);
998 Con_DPrintf("ED_ParseEpair: Can't find field %s\n", s);
1001 //val->_int = PRVM_G_INT(def->ofs); // AK Please check this - seems to be an org. quake bug
1002 val->_int = def->ofs;
1006 func = PRVM_ED_FindFunction(s);
1009 Con_Printf("ED_ParseEpair: Can't find function %s\n", s);
1012 val->function = func - prog->functions;
1016 Con_Printf("ED_ParseEpair: Unknown key->type %i for key \"%s\"\n", key->type, PRVM_GetString(key->s_name));
1023 ====================
1026 Parses an edict out of the given string, returning the new position
1027 ed should be a properly initialized empty edict.
1028 Used for initial level load and for savegames.
1029 ====================
1031 const char *ED_ParseEdict (const char *data, prvm_edict_t *ent)
1042 if (ent != prog->edicts) // hack
1043 memset (ent->v, 0, progs->entityfields * 4);
1045 // go through all the dictionary pairs
1049 if (!COM_ParseToken(&data, false))
1050 Host_Error ("ED_ParseEntity: EOF without closing brace");
1051 if (com_token[0] == '}')
1054 // anglehack is to allow QuakeEd to write single scalar angles
1055 // and allow them to be turned into vectors. (FIXME...)
1056 anglehack = !strcmp (com_token, "angle");
1058 strlcpy (com_token, "angles", sizeof (com_token));
1060 // FIXME: change light to _light to get rid of this hack
1061 if (!strcmp(com_token, "light"))
1062 strlcpy (com_token, "light_lev", sizeof (com_token)); // hack for single light def
1064 strlcpy (keyname, com_token, sizeof (keyname));
1066 // another hack to fix heynames with trailing spaces
1067 n = strlen(keyname);
1068 while (n && keyname[n-1] == ' ')
1075 if (!COM_ParseToken(&data, false))
1076 Host_Error ("ED_ParseEntity: EOF without closing brace");
1078 if (com_token[0] == '}')
1079 Host_Error ("ED_ParseEntity: closing brace without data");
1083 // keynames with a leading underscore are used for utility comments,
1084 // and are immediately discarded by quake
1085 if (keyname[0] == '_')
1088 key = ED_FindField (keyname);
1091 Con_DPrintf("'%s' is not a field\n", keyname);
1098 strlcpy (temp, com_token, sizeof (temp));
1099 dpsnprintf (com_token, sizeof (com_token), "0 %s 0", temp);
1102 if (!ED_ParseEpair(ent, key, com_token))
1103 Host_Error ("ED_ParseEdict: parse error");
1107 ent->priv.server->free = true;
1117 The entities are directly placed in the array, rather than allocated with
1118 ED_Alloc, because otherwise an error loading the map would have entity
1119 number references out of order.
1121 Creates a server's entity / program execution context by
1122 parsing textual entity definitions out of an ent file.
1124 Used for both fresh maps and savegame loads. A fresh map would also need
1125 to call ED_CallSpawnFunctions () to let the objects initialize themselves.
1128 void ED_LoadFromFile (const char *data)
1131 int parsed, inhibited, spawned, died;
1139 prog->globals.server->time = sv.time;
1144 // parse the opening brace
1145 if (!COM_ParseToken(&data, false))
1147 if (com_token[0] != '{')
1148 Host_Error ("ED_LoadFromFile: found %s when expecting {",com_token);
1151 ent = PRVM_EDICT_NUM(0);
1154 data = ED_ParseEdict (data, ent);
1157 // remove things from different skill levels or deathmatch
1158 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
1160 if (deathmatch.integer)
1162 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
1169 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
1170 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
1171 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
1179 // immediately call spawn function
1181 if (!ent->fields.server->classname)
1183 Con_Print("No classname for:\n");
1189 // look for the spawn function
1190 func = PRVM_ED_FindFunction (PRVM_GetString(ent->fields.server->classname));
1194 if (developer.integer) // don't confuse non-developers with errors
1196 Con_Print("No spawn function for:\n");
1203 prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
1204 PRVM_ExecuteProgram (func - prog->functions, "QC function spawn is missing");
1206 if (ent->priv.server->free)
1210 Con_DPrintf("%i entities parsed, %i inhibited, %i spawned (%i removed self, %i stayed)\n", parsed, inhibited, spawned, died, spawned - died);
1214 typedef struct dpfield_s
1221 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1223 dpfield_t dpfields[] =
1225 {ev_entity, "cursor_trace_ent"},
1226 {ev_entity, "drawonlytoclient"},
1227 {ev_entity, "exteriormodeltoclient"},
1228 {ev_entity, "nodrawtoclient"},
1229 {ev_entity, "tag_entity"},
1230 {ev_entity, "viewmodelforclient"},
1231 {ev_float, "alpha"},
1232 {ev_float, "ammo_cells1"},
1233 {ev_float, "ammo_lava_nails"},
1234 {ev_float, "ammo_multi_rockets"},
1235 {ev_float, "ammo_nails1"},
1236 {ev_float, "ammo_plasma"},
1237 {ev_float, "ammo_rockets1"},
1238 {ev_float, "ammo_shells1"},
1239 {ev_float, "button3"},
1240 {ev_float, "button4"},
1241 {ev_float, "button5"},
1242 {ev_float, "button6"},
1243 {ev_float, "button7"},
1244 {ev_float, "button8"},
1245 {ev_float, "buttonchat"},
1246 {ev_float, "buttonuse"},
1247 {ev_float, "clientcolors"},
1248 {ev_float, "cursor_active"},
1249 {ev_float, "fullbright"},
1250 {ev_float, "glow_color"},
1251 {ev_float, "glow_size"},
1252 {ev_float, "glow_trail"},
1253 {ev_float, "gravity"},
1254 {ev_float, "idealpitch"},
1255 {ev_float, "items2"},
1256 {ev_float, "light_lev"},
1257 {ev_float, "pflags"},
1259 {ev_float, "pitch_speed"},
1260 {ev_float, "pmodel"},
1261 {ev_float, "renderamt"}, // HalfLife support
1262 {ev_float, "rendermode"}, // HalfLife support
1263 {ev_float, "scale"},
1264 {ev_float, "style"},
1265 {ev_float, "tag_index"},
1266 {ev_float, "viewzoom"},
1267 {ev_vector, "color"},
1268 {ev_vector, "colormod"},
1269 {ev_vector, "cursor_screen"},
1270 {ev_vector, "cursor_trace_endpos"},
1271 {ev_vector, "cursor_trace_start"},
1272 {ev_vector, "movement"},
1273 {ev_vector, "punchvector"},
1274 {ev_string, "playermodel"},
1275 {ev_string, "playerskin"}
1283 extern void PR_Cmd_Reset (void);
1284 void PR_LoadProgs (const char *progsname)
1288 ddef_t *infielddefs;
1289 dfunction_t *dfunctions;
1291 if (!progsname || !*progsname)
1292 Host_Error("PR_LoadProgs: passed empty progsname");
1294 // flush the non-C variable lookup cache
1295 for (i=0 ; i<GEFV_CACHESIZE ; i++)
1296 gefvCache[i].field[0] = 0;
1300 progs = (dprograms_t *)FS_LoadFile (progsname, serverprogs_mempool, false);
1302 Host_Error ("PR_LoadProgs: couldn't load %s", progsname);
1304 Con_DPrintf("Programs occupy %iK.\n", fs_filesize/1024);
1306 pr_crc = CRC_Block((qbyte *)progs, fs_filesize);
1308 // byte swap the header
1309 for (i = 0;i < (int) sizeof(*progs) / 4;i++)
1310 ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );
1312 if (progs->version != PROG_VERSION)
1313 Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
1314 if (progs->crc != PROGHEADER_CRC && progs->crc != 32401) // tenebrae crc also allowed
1315 Host_Error ("progs.dat system vars have been modified, progdefs.h is out of date");
1317 //prog->functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1318 dfunctions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1320 pr_strings = (char *)progs + progs->ofs_strings;
1322 for (i = 0;i < progs->numstrings;i++)
1324 if (progs->ofs_strings + pr_stringssize >= fs_filesize)
1325 Host_Error ("progs.dat strings go past end of file\n");
1326 pr_stringssize += strlen (pr_strings + pr_stringssize) + 1;
1328 pr_numknownstrings = 0;
1329 pr_maxknownstrings = 0;
1330 pr_knownstrings = NULL;
1332 pr_globaldefs = (ddef_t *)((qbyte *)progs + progs->ofs_globaldefs);
1334 // we need to expand the fielddefs list to include all the engine fields,
1335 // so allocate a new place for it
1336 infielddefs = (ddef_t *)((qbyte *)progs + progs->ofs_fielddefs);
1337 pr_fielddefs = PR_Alloc((progs->numfielddefs + DPFIELDS) * sizeof(ddef_t));
1338 prog->functions = PR_Alloc(sizeof(mfunction_t) * progs->numfunctions);
1340 pr_statements = (dstatement_t *)((qbyte *)progs + progs->ofs_statements);
1342 // moved edict_size calculation down below field adding code
1344 pr_global_struct = (globalvars_t *)((qbyte *)progs + progs->ofs_globals);
1345 pr_globals = (float *)pr_global_struct;
1347 // byte swap the lumps
1348 for (i=0 ; i<progs->numstatements ; i++)
1350 pr_statements[i].op = LittleShort(pr_statements[i].op);
1351 pr_statements[i].a = LittleShort(pr_statements[i].a);
1352 pr_statements[i].b = LittleShort(pr_statements[i].b);
1353 pr_statements[i].c = LittleShort(pr_statements[i].c);
1356 for (i = 0;i < progs->numfunctions;i++)
1358 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1359 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1360 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1361 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1362 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1363 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1364 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1367 for (i=0 ; i<progs->numglobaldefs ; i++)
1369 pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);
1370 pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);
1371 pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
1374 // copy the progs fields to the new fields list
1375 for (i = 0;i < progs->numfielddefs;i++)
1377 pr_fielddefs[i].type = LittleShort (infielddefs[i].type);
1378 if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)
1379 Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
1380 pr_fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1381 pr_fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1384 // append the darkplaces fields
1385 for (i = 0;i < (int) DPFIELDS;i++)
1387 pr_fielddefs[progs->numfielddefs].type = dpfields[i].type;
1388 pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields;
1389 pr_fielddefs[progs->numfielddefs].s_name = PRVM_SetEngineString(dpfields[i].string);
1390 if (pr_fielddefs[progs->numfielddefs].type == ev_vector)
1391 progs->entityfields += 3;
1393 progs->entityfields++;
1394 progs->numfielddefs++;
1397 for (i=0 ; i<progs->numglobals ; i++)
1398 ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
1400 // moved edict_size calculation down here, below field adding code
1401 // LordHavoc: this no longer includes the prvm_edict_t header
1402 prog->edict_size = progs->entityfields * 4;
1403 pr_edictareasize = prog->edict_size * MAX_EDICTS;
1405 // LordHavoc: bounds check anything static
1406 for (i = 0,st = pr_statements;i < progs->numstatements;i++,st++)
1412 if ((unsigned short) st->a >= progs->numglobals || st->b + i < 0 || st->b + i >= progs->numstatements)
1413 Host_Error("PR_LoadProgs: out of bounds IF/IFNOT (statement %d)\n", i);
1416 if (st->a + i < 0 || st->a + i >= progs->numstatements)
1417 Host_Error("PR_LoadProgs: out of bounds GOTO (statement %d)\n", i);
1419 // global global global
1454 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->b >= progs->numglobals || (unsigned short) st->c >= progs->numglobals)
1455 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1457 // global none global
1463 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->c >= progs->numglobals)
1464 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1480 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->b >= progs->numglobals)
1481 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1495 if ((unsigned short) st->a >= progs->numglobals)
1496 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1499 Host_Error("PR_LoadProgs: unknown opcode %d at statement %d\n", st->op, i);
1504 FindEdictFieldOffsets(); // LordHavoc: update field offset list
1505 PR_Execute_ProgsLoaded();
1510 void PR_Fields_f (void)
1512 int i, j, ednum, used, usedamount;
1515 char tempstring[5000], tempstring2[260];
1521 Con_Print("no progs loaded\n");
1524 counts = Mem_Alloc(tempmempool, progs->numfielddefs * sizeof(int));
1525 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1527 ed = PRVM_EDICT_NUM(ednum);
1528 if (ed->priv.server->free)
1530 for (i = 1;i < progs->numfielddefs;i++)
1532 d = &pr_fielddefs[i];
1533 name = PRVM_GetString(d->s_name);
1534 if (name[strlen(name)-2] == '_')
1535 continue; // skip _x, _y, _z vars
1536 v = (int *)((char *)ed->v + d->ofs*4);
1537 // if the value is still all 0, skip the field
1538 for (j = 0;j < type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1551 for (i = 0;i < progs->numfielddefs;i++)
1553 d = &pr_fielddefs[i];
1554 name = PRVM_GetString(d->s_name);
1555 if (name[strlen(name)-2] == '_')
1556 continue; // skip _x, _y, _z vars
1557 switch(d->type & ~DEF_SAVEGLOBAL)
1560 strlcat (tempstring, "string ", sizeof (tempstring));
1563 strlcat (tempstring, "entity ", sizeof (tempstring));
1566 strlcat (tempstring, "function ", sizeof (tempstring));
1569 strlcat (tempstring, "field ", sizeof (tempstring));
1572 strlcat (tempstring, "void ", sizeof (tempstring));
1575 strlcat (tempstring, "float ", sizeof (tempstring));
1578 strlcat (tempstring, "vector ", sizeof (tempstring));
1581 strlcat (tempstring, "pointer ", sizeof (tempstring));
1584 dpsnprintf (tempstring2, sizeof (tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1585 strlcat (tempstring, tempstring2, sizeof (tempstring));
1588 if (strlen(name) > 256)
1590 memcpy(tempstring2, name, 256);
1591 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
1592 tempstring2[259] = 0;
1595 strcat (tempstring, name);
1596 for (j = strlen(name);j < 25;j++)
1597 strcat(tempstring, " ");
1598 dpsnprintf (tempstring2, sizeof (tempstring2), "%5d", counts[i]);
1599 strlcat (tempstring, tempstring2, sizeof (tempstring));
1600 strlcat (tempstring, "\n", sizeof (tempstring));
1601 if (strlen(tempstring) >= 4096)
1603 Con_Print(tempstring);
1609 usedamount += type_size[d->type & ~DEF_SAVEGLOBAL];
1613 Con_Printf("%i entity fields (%i in use), totalling %i bytes per edict (%i in use), %i edicts allocated, %i bytes total spent on edict fields (%i needed)\n", progs->entityfields, used, progs->entityfields * 4, usedamount * 4, prog->max_edicts, progs->entityfields * 4 * prog->max_edicts, usedamount * 4 * prog->max_edicts);
1616 void PR_Globals_f (void)
1621 Con_Print("no progs loaded\n");
1624 for (i = 0;i < progs->numglobaldefs;i++)
1625 Con_Printf("%s\n", PRVM_GetString(pr_globaldefs[i].s_name));
1626 Con_Printf("%i global variables, totalling %i bytes\n", progs->numglobals, progs->numglobals * 4);
1634 extern void PR_Cmd_Init(void);
1637 Cmd_AddCommand ("edict", ED_PrintEdict_f);
1638 Cmd_AddCommand ("edicts", ED_PrintEdicts);
1639 Cmd_AddCommand ("edictcount", ED_Count);
1640 Cmd_AddCommand ("edictset", ED_EdictSet_f);
1641 Cmd_AddCommand ("profile", PR_Profile_f);
1642 Cmd_AddCommand ("pr_fields", PR_Fields_f);
1643 Cmd_AddCommand ("pr_globals", PR_Globals_f);
1644 Cvar_RegisterVariable (&pr_checkextension);
1645 Cvar_RegisterVariable (&nomonsters);
1646 Cvar_RegisterVariable (&gamecfg);
1647 Cvar_RegisterVariable (&scratch1);
1648 Cvar_RegisterVariable (&scratch2);
1649 Cvar_RegisterVariable (&scratch3);
1650 Cvar_RegisterVariable (&scratch4);
1651 Cvar_RegisterVariable (&savedgamecfg);
1652 Cvar_RegisterVariable (&saved1);
1653 Cvar_RegisterVariable (&saved2);
1654 Cvar_RegisterVariable (&saved3);
1655 Cvar_RegisterVariable (&saved4);
1656 // LordHavoc: for DarkPlaces, this overrides the number of decors (shell casings, gibs, etc)
1657 Cvar_RegisterVariable (&decors);
1658 // LordHavoc: Nehahra uses these to pass data around cutscene demos
1659 if (gamemode == GAME_NEHAHRA)
1661 Cvar_RegisterVariable (&nehx00);Cvar_RegisterVariable (&nehx01);
1662 Cvar_RegisterVariable (&nehx02);Cvar_RegisterVariable (&nehx03);
1663 Cvar_RegisterVariable (&nehx04);Cvar_RegisterVariable (&nehx05);
1664 Cvar_RegisterVariable (&nehx06);Cvar_RegisterVariable (&nehx07);
1665 Cvar_RegisterVariable (&nehx08);Cvar_RegisterVariable (&nehx09);
1666 Cvar_RegisterVariable (&nehx10);Cvar_RegisterVariable (&nehx11);
1667 Cvar_RegisterVariable (&nehx12);Cvar_RegisterVariable (&nehx13);
1668 Cvar_RegisterVariable (&nehx14);Cvar_RegisterVariable (&nehx15);
1669 Cvar_RegisterVariable (&nehx16);Cvar_RegisterVariable (&nehx17);
1670 Cvar_RegisterVariable (&nehx18);Cvar_RegisterVariable (&nehx19);
1672 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
1673 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1674 Cvar_RegisterVariable (&pr_boundscheck);
1675 Cvar_RegisterVariable (&pr_traceqc);
1677 serverprogs_mempool = Mem_AllocPool("server progs", 0, NULL);
1687 extern void PR_Cmd_Shutdown(void);
1688 void PR_Shutdown (void)
1692 Mem_FreePool(&serverprogs_mempool);
1695 void *_PR_Alloc(size_t buffersize, const char *filename, int fileline)
1697 return _Mem_Alloc(serverprogs_mempool, buffersize, filename, fileline);
1700 void _PR_Free(void *buffer, const char *filename, int fileline)
1702 _Mem_Free(buffer, filename, fileline);
1705 void _PR_FreeAll(const char *filename, int fileline)
1708 pr_fielddefs = NULL;
1709 prog->functions = NULL;
1710 _Mem_EmptyPool(serverprogs_mempool, filename, fileline);
1713 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1714 prvm_edict_t *EDICT_NUM_ERROR(int n, char *filename, int fileline)
1716 Host_Error ("PRVM_EDICT_NUM: bad number %i (called at %s:%i)", n, filename, fileline);
1721 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
1723 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
1727 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
1730 n = e - prog->edicts;
1731 if ((unsigned int)n >= MAX_EDICTS)
1732 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
1736 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
1738 // return e - prog->edicts;
1741 //#define PRVM_EDICT_TO_PROG(e) ((qbyte *)(((prvm_edict_t *)e)->v) - (qbyte *)(prog->edictsfields))
1742 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
1743 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
1746 n = e - prog->edicts;
1747 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1748 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)\n", e, n, prog->edicts);
1749 return n;// EXPERIMENTAL
1750 //return (qbyte *)e->v - (qbyte *)prog->edictsfields;
1752 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
1754 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1755 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i\n", n);
1756 return prog->edicts + n; // EXPERIMENTAL
1757 //return prog->edicts + ((n) / (progs->entityfields * 4));
1761 const char *PRVM_GetString(int num)
1763 if (num >= 0 && num < pr_stringssize)
1764 return pr_strings + num;
1765 else if (num < 0 && num >= -pr_numknownstrings)
1768 if (!pr_knownstrings[num])
1769 Host_Error("PRVM_GetString: attempt to get string that is already freed\n");
1770 return pr_knownstrings[num];
1774 Host_Error("PRVM_GetString: invalid string offset %i\n", num);
1779 int PR_SetQCString(const char *s)
1784 if (s >= pr_strings && s <= pr_strings + pr_stringssize)
1785 return s - pr_strings;
1786 for (i = 0;i < pr_numknownstrings;i++)
1787 if (pr_knownstrings[i] == s)
1789 Host_Error("PR_SetQCString: unknown string\n");
1793 int PRVM_SetEngineString(const char *s)
1798 if (s >= pr_strings && s <= pr_strings + pr_stringssize)
1799 Host_Error("PRVM_SetEngineString: s in pr_strings area\n");
1800 for (i = 0;i < pr_numknownstrings;i++)
1801 if (pr_knownstrings[i] == s)
1803 // new unknown engine string
1804 if (developer.integer >= 3)
1805 Con_Printf("new engine string %p\n", s);
1806 for (i = 0;i < pr_numknownstrings;i++)
1807 if (!pr_knownstrings[i])
1809 if (i >= pr_numknownstrings)
1811 if (i >= pr_maxknownstrings)
1813 const char **oldstrings = pr_knownstrings;
1814 pr_maxknownstrings += 128;
1815 pr_knownstrings = PR_Alloc(pr_maxknownstrings * sizeof(char *));
1816 if (pr_numknownstrings)
1817 memcpy((char **)pr_knownstrings, oldstrings, pr_numknownstrings * sizeof(char *));
1819 pr_numknownstrings++;
1821 pr_knownstrings[i] = s;
1825 char *PR_AllocString(int bufferlength)
1830 for (i = 0;i < pr_numknownstrings;i++)
1831 if (!pr_knownstrings[i])
1833 if (i >= pr_numknownstrings)
1835 if (i >= pr_maxknownstrings)
1837 const char **oldstrings = pr_knownstrings;
1838 pr_maxknownstrings += 128;
1839 pr_knownstrings = PR_Alloc(pr_maxknownstrings * sizeof(char *));
1840 if (pr_numknownstrings)
1841 memcpy((char **)pr_knownstrings, oldstrings, pr_numknownstrings * sizeof(char *));
1843 pr_numknownstrings++;
1845 return (char *)(pr_knownstrings[i] = PR_Alloc(bufferlength));
1848 void PR_FreeString(char *s)
1852 Host_Error("PR_FreeString: attempt to free a NULL string\n");
1853 if (s >= pr_strings && s <= pr_strings + pr_stringssize)
1854 Host_Error("PR_FreeString: attempt to free a constant string\n");
1855 for (i = 0;i < pr_numknownstrings;i++)
1856 if (pr_knownstrings[i] == s)
1858 if (i == pr_numknownstrings)
1859 Host_Error("PR_FreeString: attempt to free a non-existent or already freed string\n");
1860 PR_Free((char *)pr_knownstrings[i]);
1861 pr_knownstrings[i] = NULL;