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 ddef_t *ED_FindField (const char *name);
79 mfunction_t *PRVM_ED_FindFunction (const char *name);
81 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
97 int eval_renderamt; // HalfLife support
98 int eval_rendermode; // HalfLife support
100 int eval_ammo_shells1;
101 int eval_ammo_nails1;
102 int eval_ammo_lava_nails;
103 int eval_ammo_rockets1;
104 int eval_ammo_multi_rockets;
105 int eval_ammo_cells1;
106 int eval_ammo_plasma;
108 int eval_pitch_speed;
109 int eval_viewmodelforclient;
110 int eval_nodrawtoclient;
111 int eval_exteriormodeltoclient;
112 int eval_drawonlytoclient;
116 int eval_punchvector;
118 int eval_clientcolors;
125 int eval_cursor_active;
126 int eval_cursor_screen;
127 int eval_cursor_trace_start;
128 int eval_cursor_trace_endpos;
129 int eval_cursor_trace_ent;
131 int eval_playermodel;
134 mfunction_t *SV_PlayerPhysicsQC;
135 mfunction_t *EndFrameQC;
136 //KrimZon - SERVER COMMANDS IN QUAKEC
137 mfunction_t *SV_ParseClientCommandQC;
139 int FindFieldOffset(const char *field)
142 d = ED_FindField(field);
148 void FindEdictFieldOffsets(void)
150 eval_gravity = FindFieldOffset("gravity");
151 eval_button3 = FindFieldOffset("button3");
152 eval_button4 = FindFieldOffset("button4");
153 eval_button5 = FindFieldOffset("button5");
154 eval_button6 = FindFieldOffset("button6");
155 eval_button7 = FindFieldOffset("button7");
156 eval_button8 = FindFieldOffset("button8");
157 eval_buttonuse = FindFieldOffset("buttonuse");
158 eval_buttonchat = FindFieldOffset("buttonchat");
159 eval_glow_size = FindFieldOffset("glow_size");
160 eval_glow_trail = FindFieldOffset("glow_trail");
161 eval_glow_color = FindFieldOffset("glow_color");
162 eval_items2 = FindFieldOffset("items2");
163 eval_scale = FindFieldOffset("scale");
164 eval_alpha = FindFieldOffset("alpha");
165 eval_renderamt = FindFieldOffset("renderamt"); // HalfLife support
166 eval_rendermode = FindFieldOffset("rendermode"); // HalfLife support
167 eval_fullbright = FindFieldOffset("fullbright");
168 eval_ammo_shells1 = FindFieldOffset("ammo_shells1");
169 eval_ammo_nails1 = FindFieldOffset("ammo_nails1");
170 eval_ammo_lava_nails = FindFieldOffset("ammo_lava_nails");
171 eval_ammo_rockets1 = FindFieldOffset("ammo_rockets1");
172 eval_ammo_multi_rockets = FindFieldOffset("ammo_multi_rockets");
173 eval_ammo_cells1 = FindFieldOffset("ammo_cells1");
174 eval_ammo_plasma = FindFieldOffset("ammo_plasma");
175 eval_idealpitch = FindFieldOffset("idealpitch");
176 eval_pitch_speed = FindFieldOffset("pitch_speed");
177 eval_viewmodelforclient = FindFieldOffset("viewmodelforclient");
178 eval_nodrawtoclient = FindFieldOffset("nodrawtoclient");
179 eval_exteriormodeltoclient = FindFieldOffset("exteriormodeltoclient");
180 eval_drawonlytoclient = FindFieldOffset("drawonlytoclient");
181 eval_ping = FindFieldOffset("ping");
182 eval_movement = FindFieldOffset("movement");
183 eval_pmodel = FindFieldOffset("pmodel");
184 eval_punchvector = FindFieldOffset("punchvector");
185 eval_viewzoom = FindFieldOffset("viewzoom");
186 eval_clientcolors = FindFieldOffset("clientcolors");
187 eval_tag_entity = FindFieldOffset("tag_entity");
188 eval_tag_index = FindFieldOffset("tag_index");
189 eval_light_lev = FindFieldOffset("light_lev");
190 eval_color = FindFieldOffset("color");
191 eval_style = FindFieldOffset("style");
192 eval_pflags = FindFieldOffset("pflags");
193 eval_cursor_active = FindFieldOffset("cursor_active");
194 eval_cursor_screen = FindFieldOffset("cursor_screen");
195 eval_cursor_trace_start = FindFieldOffset("cursor_trace_start");
196 eval_cursor_trace_endpos = FindFieldOffset("cursor_trace_endpos");
197 eval_cursor_trace_ent = FindFieldOffset("cursor_trace_ent");
198 eval_colormod = FindFieldOffset("colormod");
199 eval_playermodel = FindFieldOffset("playermodel");
200 eval_playerskin = FindFieldOffset("playerskin");
202 // LordHavoc: allowing QuakeC to override the player movement code
203 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
204 // LordHavoc: support for endframe
205 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
206 //KrimZon - SERVER COMMANDS IN QUAKEC
207 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
214 Sets everything to NULL
217 void ED_ClearEdict (prvm_edict_t *e)
220 memset (e->v, 0, progs->entityfields * 4);
221 e->priv.server->free = false;
222 // LordHavoc: for consistency set these here
223 num = PRVM_NUM_FOR_EDICT(e) - 1;
224 if (num >= 0 && num < svs.maxclients)
227 // set colormap and team on newly created player entity
228 e->fields.server->colormap = num + 1;
229 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
230 // set netname/clientcolors back to client values so that
231 // DP_SV_CLIENTNAME and DPV_SV_CLIENTCOLORS will not immediately
233 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
234 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
235 val->_float = svs.clients[num].colors;
236 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
237 if( eval_playermodel )
238 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
239 if( eval_playerskin )
240 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
248 Either finds a free edict, or allocates a new one.
249 Try to avoid reusing an entity that was recently freed, because it
250 can cause the client to think the entity morphed into something else
251 instead of being removed and recreated, which can cause interpolated
252 angles and bad trails.
255 prvm_edict_t *ED_Alloc (void)
260 for (i = svs.maxclients + 1;i < prog->num_edicts;i++)
262 e = PRVM_EDICT_NUM(i);
263 // the first couple seconds of server time can involve a lot of
264 // freeing and allocating, so relax the replacement policy
265 if (e->priv.server->free && ( e->priv.server->freetime < 2 || sv.time - e->priv.server->freetime > 0.5 ) )
273 Host_Error ("ED_Alloc: no free edicts");
276 if (prog->num_edicts >= prog->max_edicts)
278 e = PRVM_EDICT_NUM(i);
288 Marks the edict as free
289 FIXME: walk all entities and NULL out references to this entity
292 void ED_Free (prvm_edict_t *ed)
294 SV_UnlinkEdict (ed); // unlink from world bsp
296 ed->priv.server->free = true;
297 ed->fields.server->model = 0;
298 ed->fields.server->takedamage = 0;
299 ed->fields.server->modelindex = 0;
300 ed->fields.server->colormap = 0;
301 ed->fields.server->skin = 0;
302 ed->fields.server->frame = 0;
303 VectorClear(ed->fields.server->origin);
304 VectorClear(ed->fields.server->angles);
305 ed->fields.server->nextthink = -1;
306 ed->fields.server->solid = 0;
308 ed->priv.server->freetime = sv.time;
311 //===========================================================================
318 ddef_t *ED_GlobalAtOfs (int ofs)
323 for (i=0 ; i<progs->numglobaldefs ; i++)
325 def = &pr_globaldefs[i];
337 ddef_t *ED_FieldAtOfs (int ofs)
342 for (i=0 ; i<progs->numfielddefs ; i++)
344 def = &pr_fielddefs[i];
356 ddef_t *ED_FindField (const char *name)
361 for (i=0 ; i<progs->numfielddefs ; i++)
363 def = &pr_fielddefs[i];
364 if (!strcmp(PRVM_GetString(def->s_name), name))
375 ddef_t *ED_FindGlobal (const char *name)
380 for (i=0 ; i<progs->numglobaldefs ; i++)
382 def = &pr_globaldefs[i];
383 if (!strcmp(PRVM_GetString(def->s_name), name))
395 mfunction_t *PRVM_ED_FindFunction (const char *name)
400 for (i=0 ; i<progs->numfunctions ; i++)
402 func = &prog->functions[i];
403 if (!strcmp(PRVM_GetString(func->s_name), name))
414 Returns a string describing *data in a type specific manner
417 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e);
418 char *PR_ValueString (etype_t type, prvm_eval_t *val)
420 static char line[1024]; // LordHavoc: enlarged a bit (was 256)
425 type &= ~DEF_SAVEGLOBAL;
430 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
433 //n = NoCrash_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict));
435 if (n < 0 || n >= MAX_EDICTS)
436 dpsnprintf (line, sizeof (line), "entity %i (invalid!)", n);
438 dpsnprintf (line, sizeof (line), "entity %i", n);
441 f = prog->functions + val->function;
442 dpsnprintf (line, sizeof (line), "%s()", PRVM_GetString(f->s_name));
445 def = ED_FieldAtOfs ( val->_int );
446 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
449 dpsnprintf (line, sizeof (line), "void");
452 // LordHavoc: changed from %5.1f to %10.4f
453 dpsnprintf (line, sizeof (line), "%10.4f", val->_float);
456 // LordHavoc: changed from %5.1f to %10.4f
457 dpsnprintf (line, sizeof (line), "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
460 dpsnprintf (line, sizeof (line), "pointer");
463 dpsnprintf (line, sizeof (line), "bad type %i", type);
474 Returns a string describing *data in a type specific manner
475 Easier to parse than PR_ValueString
478 char *PR_UglyValueString (etype_t type, prvm_eval_t *val)
480 static char line[4096];
486 type &= ~DEF_SAVEGLOBAL;
491 // Parse the string a bit to turn special characters
492 // (like newline, specifically) into escape codes,
493 // this fixes saving games from various mods
494 s = PRVM_GetString (val->string);
495 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
514 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
517 f = prog->functions + val->function;
518 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
521 def = ED_FieldAtOfs ( val->_int );
522 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
525 dpsnprintf (line, sizeof (line), "void");
528 dpsnprintf (line, sizeof (line), "%f", val->_float);
531 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
534 dpsnprintf (line, sizeof (line), "bad type %i", type);
545 Returns a string with a description and the contents of a global,
546 padded to 20 field width
549 char *PR_GlobalString (int ofs)
555 static char line[128];
557 val = (void *)&pr_globals[ofs];
558 def = ED_GlobalAtOfs(ofs);
560 dpsnprintf (line, sizeof (line), "%i(?)", ofs);
563 s = PR_ValueString (def->type, val);
564 dpsnprintf (line, sizeof (line), "%i(%s)%s", ofs, PRVM_GetString(def->s_name), s);
569 strlcat (line, " ", sizeof (line));
570 strlcat (line, " ", sizeof (line));
575 char *PR_GlobalStringNoContents (int ofs)
579 static char line[128];
581 def = ED_GlobalAtOfs(ofs);
583 dpsnprintf (line, sizeof (line), "%i(?)", ofs);
585 dpsnprintf (line, sizeof (line), "%i(%s)", ofs, PRVM_GetString(def->s_name));
589 strlcat (line, " ", sizeof (line));
590 strlcat (line, " ", sizeof (line));
603 // LordHavoc: optimized this to print out much more quickly (tempstring)
604 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
605 void ED_Print(prvm_edict_t *ed)
613 char tempstring[8192], tempstring2[260]; // temporary string buffers
615 if (ed->priv.server->free)
622 dpsnprintf (tempstring, sizeof (tempstring), "\nEDICT %i:\n", PRVM_NUM_FOR_EDICT(ed));
623 for (i=1 ; i<progs->numfielddefs ; i++)
625 d = &pr_fielddefs[i];
626 name = PRVM_GetString(d->s_name);
627 if (name[strlen(name)-2] == '_')
628 continue; // skip _x, _y, _z vars
630 v = (int *)((char *)ed->v + d->ofs*4);
632 // if the value is still all 0, skip the field
633 type = d->type & ~DEF_SAVEGLOBAL;
635 for (j=0 ; j<type_size[type] ; j++)
638 if (j == type_size[type])
641 if (strlen(name) > 256)
643 memcpy (tempstring2, name, 256);
644 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
645 tempstring2[259] = 0;
648 strlcat (tempstring, name, sizeof (tempstring));
649 for (l = strlen(name);l < 14;l++)
650 strcat(tempstring, " ");
651 strcat(tempstring, " ");
653 name = PR_ValueString(d->type, (prvm_eval_t *)v);
654 if (strlen(name) > 256)
656 memcpy(tempstring2, name, 256);
657 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
658 tempstring2[259] = 0;
661 strlcat (tempstring, name, sizeof (tempstring));
662 strlcat (tempstring, "\n", sizeof (tempstring));
663 if (strlen(tempstring) >= 4096)
665 Con_Print(tempstring);
670 Con_Print(tempstring);
680 void ED_Write (qfile_t *f, prvm_edict_t *ed)
690 if (ed->priv.server->free)
696 for (i=1 ; i<progs->numfielddefs ; i++)
698 d = &pr_fielddefs[i];
699 name = PRVM_GetString(d->s_name);
700 if (name[strlen(name)-2] == '_')
701 continue; // skip _x, _y, _z vars
703 v = (int *)((char *)ed->v + d->ofs*4);
705 // if the value is still all 0, skip the field
706 type = d->type & ~DEF_SAVEGLOBAL;
707 for (j=0 ; j<type_size[type] ; j++)
710 if (j == type_size[type])
713 FS_Printf(f,"\"%s\" ",name);
714 FS_Printf(f,"\"%s\"\n", PR_UglyValueString(d->type, (prvm_eval_t *)v));
720 void ED_PrintNum (int ent)
722 ED_Print(PRVM_EDICT_NUM(ent));
729 For debugging, prints all the entities in the current server
732 void ED_PrintEdicts (void)
736 Con_Printf("%i entities\n", prog->num_edicts);
737 for (i=0 ; i<prog->num_edicts ; i++)
745 For debugging, prints a single edict
748 void ED_PrintEdict_f (void)
752 i = atoi (Cmd_Argv(1));
753 if (i < 0 || i >= prog->num_edicts)
755 Con_Print("Bad edict number\n");
772 int active, models, solid, step;
774 active = models = solid = step = 0;
775 for (i=0 ; i<prog->num_edicts ; i++)
777 ent = PRVM_EDICT_NUM(i);
778 if (ent->priv.server->free)
781 if (ent->fields.server->solid)
783 if (ent->fields.server->model)
785 if (ent->fields.server->movetype == MOVETYPE_STEP)
789 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
790 Con_Printf("active :%3i\n", active);
791 Con_Printf("view :%3i\n", models);
792 Con_Printf("touch :%3i\n", solid);
793 Con_Printf("step :%3i\n", step);
798 ==============================================================================
802 FIXME: need to tag constants, doesn't really work
803 ==============================================================================
811 void ED_WriteGlobals (qfile_t *f)
819 for (i=0 ; i<progs->numglobaldefs ; i++)
821 def = &pr_globaldefs[i];
823 if ( !(def->type & DEF_SAVEGLOBAL) )
825 type &= ~DEF_SAVEGLOBAL;
827 if (type != ev_string && type != ev_float && type != ev_entity)
830 name = PRVM_GetString(def->s_name);
831 FS_Printf(f,"\"%s\" ", name);
832 FS_Printf(f,"\"%s\"\n", PR_UglyValueString(type, (prvm_eval_t *)&pr_globals[def->ofs]));
841 Console command to set a field of a specified edict
844 void ED_EdictSet_f(void)
851 Con_Print("edictset <edict number> <field> <value>\n");
854 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(1)));
856 if((key = ED_FindField(Cmd_Argv(2))) == 0)
858 Con_Printf("Key %s not found !\n", Cmd_Argv(2));
862 ED_ParseEpair(ed, key, Cmd_Argv(3));
870 void ED_ParseGlobals (const char *data)
872 char keyname[1024]; // LordHavoc: good idea? bad idea? was 64
878 if (!COM_ParseToken(&data, false))
879 Host_Error ("ED_ParseEntity: EOF without closing brace");
880 if (com_token[0] == '}')
883 strcpy (keyname, com_token);
886 if (!COM_ParseToken(&data, false))
887 Host_Error ("ED_ParseEntity: EOF without closing brace");
889 if (com_token[0] == '}')
890 Host_Error ("ED_ParseEntity: closing brace without data");
892 key = ED_FindGlobal (keyname);
895 Con_DPrintf("'%s' is not a global\n", keyname);
899 if (!ED_ParseEpair(NULL, key, com_token))
900 Host_Error ("ED_ParseGlobals: parse error");
904 //============================================================================
911 Can parse either fields or globals
912 returns false if error
915 qboolean ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
924 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
926 val = (prvm_eval_t *)((int *)pr_globals + key->ofs);
927 switch (key->type & ~DEF_SAVEGLOBAL)
931 new_p = PR_AllocString(l);
932 val->string = PR_SetQCString(new_p);
933 for (i = 0;i < l;i++)
935 if (s[i] == '\\' && i < l-1)
940 else if (s[i] == 'r')
951 while (*s && *s <= ' ')
953 val->_float = atof(s);
957 for (i = 0;i < 3;i++)
959 while (*s && *s <= ' ')
962 val->vector[i] = atof(s);
971 while (*s && *s <= ' ')
974 if (i < 0 || i >= MAX_EDICTS)
975 Con_Printf("ED_ParseEpair: ev_entity reference too large (edict %i >= MAX_EDICTS %i)\n", i, MAX_EDICTS);
976 while (i >= prog->max_edicts)
978 // if SV_IncreaseEdicts was called the base pointer needs to be updated
980 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
981 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM(i));
985 def = ED_FindField(s);
988 Con_DPrintf("ED_ParseEpair: Can't find field %s\n", s);
991 //val->_int = PRVM_G_INT(def->ofs); // AK Please check this - seems to be an org. quake bug
992 val->_int = def->ofs;
996 func = PRVM_ED_FindFunction(s);
999 Con_Printf("ED_ParseEpair: Can't find function %s\n", s);
1002 val->function = func - prog->functions;
1006 Con_Printf("ED_ParseEpair: Unknown key->type %i for key \"%s\"\n", key->type, PRVM_GetString(key->s_name));
1013 ====================
1016 Parses an edict out of the given string, returning the new position
1017 ed should be a properly initialized empty edict.
1018 Used for initial level load and for savegames.
1019 ====================
1021 const char *ED_ParseEdict (const char *data, prvm_edict_t *ent)
1032 if (ent != prog->edicts) // hack
1033 memset (ent->v, 0, progs->entityfields * 4);
1035 // go through all the dictionary pairs
1039 if (!COM_ParseToken(&data, false))
1040 Host_Error ("ED_ParseEntity: EOF without closing brace");
1041 if (com_token[0] == '}')
1044 // anglehack is to allow QuakeEd to write single scalar angles
1045 // and allow them to be turned into vectors. (FIXME...)
1046 anglehack = !strcmp (com_token, "angle");
1048 strlcpy (com_token, "angles", sizeof (com_token));
1050 // FIXME: change light to _light to get rid of this hack
1051 if (!strcmp(com_token, "light"))
1052 strlcpy (com_token, "light_lev", sizeof (com_token)); // hack for single light def
1054 strlcpy (keyname, com_token, sizeof (keyname));
1056 // another hack to fix heynames with trailing spaces
1057 n = strlen(keyname);
1058 while (n && keyname[n-1] == ' ')
1065 if (!COM_ParseToken(&data, false))
1066 Host_Error ("ED_ParseEntity: EOF without closing brace");
1068 if (com_token[0] == '}')
1069 Host_Error ("ED_ParseEntity: closing brace without data");
1073 // keynames with a leading underscore are used for utility comments,
1074 // and are immediately discarded by quake
1075 if (keyname[0] == '_')
1078 key = ED_FindField (keyname);
1081 Con_DPrintf("'%s' is not a field\n", keyname);
1088 strlcpy (temp, com_token, sizeof (temp));
1089 dpsnprintf (com_token, sizeof (com_token), "0 %s 0", temp);
1092 if (!ED_ParseEpair(ent, key, com_token))
1093 Host_Error ("ED_ParseEdict: parse error");
1097 ent->priv.server->free = true;
1107 The entities are directly placed in the array, rather than allocated with
1108 ED_Alloc, because otherwise an error loading the map would have entity
1109 number references out of order.
1111 Creates a server's entity / program execution context by
1112 parsing textual entity definitions out of an ent file.
1114 Used for both fresh maps and savegame loads. A fresh map would also need
1115 to call ED_CallSpawnFunctions () to let the objects initialize themselves.
1118 void ED_LoadFromFile (const char *data)
1121 int parsed, inhibited, spawned, died;
1129 prog->globals.server->time = sv.time;
1134 // parse the opening brace
1135 if (!COM_ParseToken(&data, false))
1137 if (com_token[0] != '{')
1138 Host_Error ("ED_LoadFromFile: found %s when expecting {",com_token);
1141 ent = PRVM_EDICT_NUM(0);
1144 data = ED_ParseEdict (data, ent);
1147 // remove things from different skill levels or deathmatch
1148 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
1150 if (deathmatch.integer)
1152 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
1159 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
1160 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
1161 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
1169 // immediately call spawn function
1171 if (!ent->fields.server->classname)
1173 Con_Print("No classname for:\n");
1179 // look for the spawn function
1180 func = PRVM_ED_FindFunction (PRVM_GetString(ent->fields.server->classname));
1184 if (developer.integer) // don't confuse non-developers with errors
1186 Con_Print("No spawn function for:\n");
1193 prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
1194 PRVM_ExecuteProgram (func - prog->functions, "QC function spawn is missing");
1196 if (ent->priv.server->free)
1200 Con_DPrintf("%i entities parsed, %i inhibited, %i spawned (%i removed self, %i stayed)\n", parsed, inhibited, spawned, died, spawned - died);
1204 typedef struct dpfield_s
1211 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1213 dpfield_t dpfields[] =
1215 {ev_entity, "cursor_trace_ent"},
1216 {ev_entity, "drawonlytoclient"},
1217 {ev_entity, "exteriormodeltoclient"},
1218 {ev_entity, "nodrawtoclient"},
1219 {ev_entity, "tag_entity"},
1220 {ev_entity, "viewmodelforclient"},
1221 {ev_float, "alpha"},
1222 {ev_float, "ammo_cells1"},
1223 {ev_float, "ammo_lava_nails"},
1224 {ev_float, "ammo_multi_rockets"},
1225 {ev_float, "ammo_nails1"},
1226 {ev_float, "ammo_plasma"},
1227 {ev_float, "ammo_rockets1"},
1228 {ev_float, "ammo_shells1"},
1229 {ev_float, "button3"},
1230 {ev_float, "button4"},
1231 {ev_float, "button5"},
1232 {ev_float, "button6"},
1233 {ev_float, "button7"},
1234 {ev_float, "button8"},
1235 {ev_float, "buttonchat"},
1236 {ev_float, "buttonuse"},
1237 {ev_float, "clientcolors"},
1238 {ev_float, "cursor_active"},
1239 {ev_float, "fullbright"},
1240 {ev_float, "glow_color"},
1241 {ev_float, "glow_size"},
1242 {ev_float, "glow_trail"},
1243 {ev_float, "gravity"},
1244 {ev_float, "idealpitch"},
1245 {ev_float, "items2"},
1246 {ev_float, "light_lev"},
1247 {ev_float, "pflags"},
1249 {ev_float, "pitch_speed"},
1250 {ev_float, "pmodel"},
1251 {ev_float, "renderamt"}, // HalfLife support
1252 {ev_float, "rendermode"}, // HalfLife support
1253 {ev_float, "scale"},
1254 {ev_float, "style"},
1255 {ev_float, "tag_index"},
1256 {ev_float, "viewzoom"},
1257 {ev_vector, "color"},
1258 {ev_vector, "colormod"},
1259 {ev_vector, "cursor_screen"},
1260 {ev_vector, "cursor_trace_endpos"},
1261 {ev_vector, "cursor_trace_start"},
1262 {ev_vector, "movement"},
1263 {ev_vector, "punchvector"},
1264 {ev_string, "playermodel"},
1265 {ev_string, "playerskin"}
1273 extern void PR_Cmd_Reset (void);
1274 void PR_LoadProgs (const char *progsname)
1278 ddef_t *infielddefs;
1279 dfunction_t *dfunctions;
1281 if (!progsname || !*progsname)
1282 Host_Error("PR_LoadProgs: passed empty progsname");
1286 progs = (dprograms_t *)FS_LoadFile (progsname, serverprogs_mempool, false);
1288 Host_Error ("PR_LoadProgs: couldn't load %s", progsname);
1290 Con_DPrintf("Programs occupy %iK.\n", fs_filesize/1024);
1292 pr_crc = CRC_Block((qbyte *)progs, fs_filesize);
1294 // byte swap the header
1295 for (i = 0;i < (int) sizeof(*progs) / 4;i++)
1296 ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );
1298 if (progs->version != PROG_VERSION)
1299 Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
1300 if (progs->crc != PROGHEADER_CRC && progs->crc != 32401) // tenebrae crc also allowed
1301 Host_Error ("progs.dat system vars have been modified, progdefs.h is out of date");
1303 //prog->functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1304 dfunctions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1306 pr_strings = (char *)progs + progs->ofs_strings;
1308 for (i = 0;i < progs->numstrings;i++)
1310 if (progs->ofs_strings + pr_stringssize >= fs_filesize)
1311 Host_Error ("progs.dat strings go past end of file\n");
1312 pr_stringssize += strlen (pr_strings + pr_stringssize) + 1;
1314 pr_numknownstrings = 0;
1315 pr_maxknownstrings = 0;
1316 pr_knownstrings = NULL;
1318 pr_globaldefs = (ddef_t *)((qbyte *)progs + progs->ofs_globaldefs);
1320 // we need to expand the fielddefs list to include all the engine fields,
1321 // so allocate a new place for it
1322 infielddefs = (ddef_t *)((qbyte *)progs + progs->ofs_fielddefs);
1323 pr_fielddefs = PR_Alloc((progs->numfielddefs + DPFIELDS) * sizeof(ddef_t));
1324 prog->functions = PR_Alloc(sizeof(mfunction_t) * progs->numfunctions);
1326 pr_statements = (dstatement_t *)((qbyte *)progs + progs->ofs_statements);
1328 // moved edict_size calculation down below field adding code
1330 pr_global_struct = (globalvars_t *)((qbyte *)progs + progs->ofs_globals);
1331 pr_globals = (float *)pr_global_struct;
1333 // byte swap the lumps
1334 for (i=0 ; i<progs->numstatements ; i++)
1336 pr_statements[i].op = LittleShort(pr_statements[i].op);
1337 pr_statements[i].a = LittleShort(pr_statements[i].a);
1338 pr_statements[i].b = LittleShort(pr_statements[i].b);
1339 pr_statements[i].c = LittleShort(pr_statements[i].c);
1342 for (i = 0;i < progs->numfunctions;i++)
1344 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1345 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1346 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1347 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1348 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1349 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1350 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1353 for (i=0 ; i<progs->numglobaldefs ; i++)
1355 pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);
1356 pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);
1357 pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
1360 // copy the progs fields to the new fields list
1361 for (i = 0;i < progs->numfielddefs;i++)
1363 pr_fielddefs[i].type = LittleShort (infielddefs[i].type);
1364 if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)
1365 Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
1366 pr_fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1367 pr_fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1370 // append the darkplaces fields
1371 for (i = 0;i < (int) DPFIELDS;i++)
1373 pr_fielddefs[progs->numfielddefs].type = dpfields[i].type;
1374 pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields;
1375 pr_fielddefs[progs->numfielddefs].s_name = PRVM_SetEngineString(dpfields[i].string);
1376 if (pr_fielddefs[progs->numfielddefs].type == ev_vector)
1377 progs->entityfields += 3;
1379 progs->entityfields++;
1380 progs->numfielddefs++;
1383 for (i=0 ; i<progs->numglobals ; i++)
1384 ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
1386 // moved edict_size calculation down here, below field adding code
1387 // LordHavoc: this no longer includes the prvm_edict_t header
1388 prog->edict_size = progs->entityfields * 4;
1389 pr_edictareasize = prog->edict_size * MAX_EDICTS;
1391 // LordHavoc: bounds check anything static
1392 for (i = 0,st = pr_statements;i < progs->numstatements;i++,st++)
1398 if ((unsigned short) st->a >= progs->numglobals || st->b + i < 0 || st->b + i >= progs->numstatements)
1399 Host_Error("PR_LoadProgs: out of bounds IF/IFNOT (statement %d)\n", i);
1402 if (st->a + i < 0 || st->a + i >= progs->numstatements)
1403 Host_Error("PR_LoadProgs: out of bounds GOTO (statement %d)\n", i);
1405 // global global global
1440 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->b >= progs->numglobals || (unsigned short) st->c >= progs->numglobals)
1441 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1443 // global none global
1449 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->c >= progs->numglobals)
1450 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1466 if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->b >= progs->numglobals)
1467 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1481 if ((unsigned short) st->a >= progs->numglobals)
1482 Host_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
1485 Host_Error("PR_LoadProgs: unknown opcode %d at statement %d\n", st->op, i);
1490 FindEdictFieldOffsets(); // LordHavoc: update field offset list
1491 PR_Execute_ProgsLoaded();
1496 void PR_Fields_f (void)
1498 int i, j, ednum, used, usedamount;
1501 char tempstring[5000], tempstring2[260];
1507 Con_Print("no progs loaded\n");
1510 counts = Mem_Alloc(tempmempool, progs->numfielddefs * sizeof(int));
1511 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1513 ed = PRVM_EDICT_NUM(ednum);
1514 if (ed->priv.server->free)
1516 for (i = 1;i < progs->numfielddefs;i++)
1518 d = &pr_fielddefs[i];
1519 name = PRVM_GetString(d->s_name);
1520 if (name[strlen(name)-2] == '_')
1521 continue; // skip _x, _y, _z vars
1522 v = (int *)((char *)ed->v + d->ofs*4);
1523 // if the value is still all 0, skip the field
1524 for (j = 0;j < type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1537 for (i = 0;i < progs->numfielddefs;i++)
1539 d = &pr_fielddefs[i];
1540 name = PRVM_GetString(d->s_name);
1541 if (name[strlen(name)-2] == '_')
1542 continue; // skip _x, _y, _z vars
1543 switch(d->type & ~DEF_SAVEGLOBAL)
1546 strlcat (tempstring, "string ", sizeof (tempstring));
1549 strlcat (tempstring, "entity ", sizeof (tempstring));
1552 strlcat (tempstring, "function ", sizeof (tempstring));
1555 strlcat (tempstring, "field ", sizeof (tempstring));
1558 strlcat (tempstring, "void ", sizeof (tempstring));
1561 strlcat (tempstring, "float ", sizeof (tempstring));
1564 strlcat (tempstring, "vector ", sizeof (tempstring));
1567 strlcat (tempstring, "pointer ", sizeof (tempstring));
1570 dpsnprintf (tempstring2, sizeof (tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1571 strlcat (tempstring, tempstring2, sizeof (tempstring));
1574 if (strlen(name) > 256)
1576 memcpy(tempstring2, name, 256);
1577 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
1578 tempstring2[259] = 0;
1581 strcat (tempstring, name);
1582 for (j = strlen(name);j < 25;j++)
1583 strcat(tempstring, " ");
1584 dpsnprintf (tempstring2, sizeof (tempstring2), "%5d", counts[i]);
1585 strlcat (tempstring, tempstring2, sizeof (tempstring));
1586 strlcat (tempstring, "\n", sizeof (tempstring));
1587 if (strlen(tempstring) >= 4096)
1589 Con_Print(tempstring);
1595 usedamount += type_size[d->type & ~DEF_SAVEGLOBAL];
1599 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);
1602 void PR_Globals_f (void)
1607 Con_Print("no progs loaded\n");
1610 for (i = 0;i < progs->numglobaldefs;i++)
1611 Con_Printf("%s\n", PRVM_GetString(pr_globaldefs[i].s_name));
1612 Con_Printf("%i global variables, totalling %i bytes\n", progs->numglobals, progs->numglobals * 4);
1620 extern void PR_Cmd_Init(void);
1623 Cmd_AddCommand ("edict", ED_PrintEdict_f);
1624 Cmd_AddCommand ("edicts", ED_PrintEdicts);
1625 Cmd_AddCommand ("edictcount", ED_Count);
1626 Cmd_AddCommand ("edictset", ED_EdictSet_f);
1627 Cmd_AddCommand ("profile", PR_Profile_f);
1628 Cmd_AddCommand ("pr_fields", PR_Fields_f);
1629 Cmd_AddCommand ("pr_globals", PR_Globals_f);
1630 Cvar_RegisterVariable (&pr_checkextension);
1631 Cvar_RegisterVariable (&nomonsters);
1632 Cvar_RegisterVariable (&gamecfg);
1633 Cvar_RegisterVariable (&scratch1);
1634 Cvar_RegisterVariable (&scratch2);
1635 Cvar_RegisterVariable (&scratch3);
1636 Cvar_RegisterVariable (&scratch4);
1637 Cvar_RegisterVariable (&savedgamecfg);
1638 Cvar_RegisterVariable (&saved1);
1639 Cvar_RegisterVariable (&saved2);
1640 Cvar_RegisterVariable (&saved3);
1641 Cvar_RegisterVariable (&saved4);
1642 // LordHavoc: for DarkPlaces, this overrides the number of decors (shell casings, gibs, etc)
1643 Cvar_RegisterVariable (&decors);
1644 // LordHavoc: Nehahra uses these to pass data around cutscene demos
1645 if (gamemode == GAME_NEHAHRA)
1647 Cvar_RegisterVariable (&nehx00);Cvar_RegisterVariable (&nehx01);
1648 Cvar_RegisterVariable (&nehx02);Cvar_RegisterVariable (&nehx03);
1649 Cvar_RegisterVariable (&nehx04);Cvar_RegisterVariable (&nehx05);
1650 Cvar_RegisterVariable (&nehx06);Cvar_RegisterVariable (&nehx07);
1651 Cvar_RegisterVariable (&nehx08);Cvar_RegisterVariable (&nehx09);
1652 Cvar_RegisterVariable (&nehx10);Cvar_RegisterVariable (&nehx11);
1653 Cvar_RegisterVariable (&nehx12);Cvar_RegisterVariable (&nehx13);
1654 Cvar_RegisterVariable (&nehx14);Cvar_RegisterVariable (&nehx15);
1655 Cvar_RegisterVariable (&nehx16);Cvar_RegisterVariable (&nehx17);
1656 Cvar_RegisterVariable (&nehx18);Cvar_RegisterVariable (&nehx19);
1658 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
1659 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1660 Cvar_RegisterVariable (&pr_boundscheck);
1661 Cvar_RegisterVariable (&pr_traceqc);
1663 serverprogs_mempool = Mem_AllocPool("server progs", 0, NULL);
1673 extern void PR_Cmd_Shutdown(void);
1674 void PR_Shutdown (void)
1678 Mem_FreePool(&serverprogs_mempool);
1681 void *_PR_Alloc(size_t buffersize, const char *filename, int fileline)
1683 return _Mem_Alloc(serverprogs_mempool, buffersize, filename, fileline);
1686 void _PR_Free(void *buffer, const char *filename, int fileline)
1688 _Mem_Free(buffer, filename, fileline);
1691 void _PR_FreeAll(const char *filename, int fileline)
1694 pr_fielddefs = NULL;
1695 prog->functions = NULL;
1696 _Mem_EmptyPool(serverprogs_mempool, filename, fileline);
1699 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1700 prvm_edict_t *EDICT_NUM_ERROR(int n, char *filename, int fileline)
1702 Host_Error ("PRVM_EDICT_NUM: bad number %i (called at %s:%i)", n, filename, fileline);
1707 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
1709 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
1713 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
1716 n = e - prog->edicts;
1717 if ((unsigned int)n >= MAX_EDICTS)
1718 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
1722 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
1724 // return e - prog->edicts;
1727 //#define PRVM_EDICT_TO_PROG(e) ((qbyte *)(((prvm_edict_t *)e)->v) - (qbyte *)(prog->edictsfields))
1728 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
1729 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
1732 n = e - prog->edicts;
1733 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1734 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)\n", e, n, prog->edicts);
1735 return n;// EXPERIMENTAL
1736 //return (qbyte *)e->v - (qbyte *)prog->edictsfields;
1738 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
1740 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1741 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i\n", n);
1742 return prog->edicts + n; // EXPERIMENTAL
1743 //return prog->edicts + ((n) / (progs->entityfields * 4));
1747 const char *PRVM_GetString(int num)
1749 if (num >= 0 && num < pr_stringssize)
1750 return pr_strings + num;
1751 else if (num < 0 && num >= -pr_numknownstrings)
1754 if (!pr_knownstrings[num])
1755 Host_Error("PRVM_GetString: attempt to get string that is already freed\n");
1756 return pr_knownstrings[num];
1760 Host_Error("PRVM_GetString: invalid string offset %i\n", num);
1765 int PR_SetQCString(const char *s)
1770 if (s >= pr_strings && s <= pr_strings + pr_stringssize)
1771 return s - pr_strings;
1772 for (i = 0;i < pr_numknownstrings;i++)
1773 if (pr_knownstrings[i] == s)
1775 Host_Error("PR_SetQCString: unknown string\n");
1779 int PRVM_SetEngineString(const char *s)
1784 if (s >= pr_strings && s <= pr_strings + pr_stringssize)
1785 Host_Error("PRVM_SetEngineString: s in pr_strings area\n");
1786 for (i = 0;i < pr_numknownstrings;i++)
1787 if (pr_knownstrings[i] == s)
1789 // new unknown engine string
1790 if (developer.integer >= 3)
1791 Con_Printf("new engine string %p\n", s);
1792 for (i = 0;i < pr_numknownstrings;i++)
1793 if (!pr_knownstrings[i])
1795 if (i >= pr_numknownstrings)
1797 if (i >= pr_maxknownstrings)
1799 const char **oldstrings = pr_knownstrings;
1800 pr_maxknownstrings += 128;
1801 pr_knownstrings = PR_Alloc(pr_maxknownstrings * sizeof(char *));
1802 if (pr_numknownstrings)
1803 memcpy((char **)pr_knownstrings, oldstrings, pr_numknownstrings * sizeof(char *));
1805 pr_numknownstrings++;
1807 pr_knownstrings[i] = s;
1811 char *PR_AllocString(int bufferlength)
1816 for (i = 0;i < pr_numknownstrings;i++)
1817 if (!pr_knownstrings[i])
1819 if (i >= pr_numknownstrings)
1821 if (i >= pr_maxknownstrings)
1823 const char **oldstrings = pr_knownstrings;
1824 pr_maxknownstrings += 128;
1825 pr_knownstrings = PR_Alloc(pr_maxknownstrings * sizeof(char *));
1826 if (pr_numknownstrings)
1827 memcpy((char **)pr_knownstrings, oldstrings, pr_numknownstrings * sizeof(char *));
1829 pr_numknownstrings++;
1831 return (char *)(pr_knownstrings[i] = PR_Alloc(bufferlength));
1834 void PR_FreeString(char *s)
1838 Host_Error("PR_FreeString: attempt to free a NULL string\n");
1839 if (s >= pr_strings && s <= pr_strings + pr_stringssize)
1840 Host_Error("PR_FreeString: attempt to free a constant string\n");
1841 for (i = 0;i < pr_numknownstrings;i++)
1842 if (pr_knownstrings[i] == s)
1844 if (i == pr_numknownstrings)
1845 Host_Error("PR_FreeString: attempt to free a non-existent or already freed string\n");
1846 PR_Free((char *)pr_knownstrings[i]);
1847 pr_knownstrings[i] = NULL;