]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - prvm_edict.c
c62ea463719b14c85008a7393813db874d7b40d8
[xonotic/darkplaces.git] / prvm_edict.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // AK new vm
21
22 #include "quakedef.h"
23 #include "progsvm.h"
24
25 prvm_prog_t *prog;
26
27 static prvm_prog_t prog_list[PRVM_MAXPROGS];
28
29 int             prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
30
31 ddef_t *PRVM_ED_FieldAtOfs(int ofs);
32 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash);
33
34 cvar_t prvm_language = {CVAR_SAVE, "prvm_language", "", "when set, loads progs.dat.LANGUAGENAME.po for string translations; when set to dump, progs.dat.pot is written from the strings in the progs"};
35 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
36 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
37 // LordHavoc: counts usage of each QuakeC statement
38 cvar_t prvm_statementprofiling = {0, "prvm_statementprofiling", "0", "counts how many times each QuakeC statement has been executed, these counts are displayed in prvm_printfunction output (if enabled)"};
39 cvar_t prvm_timeprofiling = {0, "prvm_timeprofiling", "0", "counts how long each function has been executed, these counts are displayed in prvm_profile output (if enabled)"};
40 cvar_t prvm_backtraceforwarnings = {0, "prvm_backtraceforwarnings", "0", "print a backtrace for warnings too"};
41 cvar_t prvm_leaktest = {0, "prvm_leaktest", "0", "try to detect memory leaks in strings or entities"};
42 cvar_t prvm_leaktest_ignore_classnames = {0, "prvm_leaktest_ignore_classnames", "", "classnames of entities to NOT leak check because they are found by find(world, classname, ...) but are actually spawned by QC code (NOT map entities)"};
43 cvar_t prvm_errordump = {0, "prvm_errordump", "0", "write a savegame on crash to crash-server.dmp"};
44 cvar_t prvm_reuseedicts_startuptime = {0, "prvm_reuseedicts_startuptime", "2", "allows immediate re-use of freed entity slots during start of new level (value in seconds)"};
45 cvar_t prvm_reuseedicts_neverinsameframe = {0, "prvm_reuseedicts_neverinsameframe", "1", "never allows re-use of freed entity slots during same frame"};
46
47 static double prvm_reuseedicts_always_allow = 0;
48 qboolean prvm_runawaycheck = true;
49
50 extern sizebuf_t vm_tempstringsbuf;
51
52 //============================================================================
53 // mempool handling
54
55 /*
56 ===============
57 PRVM_MEM_Alloc
58 ===============
59 */
60 void PRVM_MEM_Alloc(void)
61 {
62         int i;
63
64         // reserve space for the null entity aka world
65         // check bound of max_edicts
66         prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
67         prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
68
69         // edictprivate_size has to be min as big prvm_edict_private_t
70         prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
71
72         // alloc edicts
73         prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
74
75         // alloc edict private space
76         prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
77
78         // alloc edict fields
79         prog->entityfieldsarea = prog->entityfields * prog->max_edicts;
80         prog->edictsfields = (vec_t *)Mem_Alloc(prog->progs_mempool, prog->entityfieldsarea * sizeof(vec_t));
81
82         // set edict pointers
83         for(i = 0; i < prog->max_edicts; i++)
84         {
85                 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
86                 prog->edicts[i].fields.vp = prog->edictsfields + i * prog->entityfields;
87         }
88 }
89
90 /*
91 ===============
92 PRVM_MEM_IncreaseEdicts
93 ===============
94 */
95 void PRVM_MEM_IncreaseEdicts(void)
96 {
97         int             i;
98
99         if(prog->max_edicts >= prog->limit_edicts)
100                 return;
101
102         PRVM_GCALL(begin_increase_edicts)();
103
104         // increase edicts
105         prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
106
107         prog->entityfieldsarea = prog->entityfields * prog->max_edicts;
108         prog->edictsfields = (vec_t*)Mem_Realloc(prog->progs_mempool, (void *)prog->edictsfields, prog->entityfieldsarea * sizeof(vec_t));
109         prog->edictprivate = (void *)Mem_Realloc(prog->progs_mempool, (void *)prog->edictprivate, prog->max_edicts * prog->edictprivate_size);
110
111         //set e and v pointers
112         for(i = 0; i < prog->max_edicts; i++)
113         {
114                 prog->edicts[i].priv.required  = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
115                 prog->edicts[i].fields.vp = prog->edictsfields + i * prog->entityfields;
116         }
117
118         PRVM_GCALL(end_increase_edicts)();
119 }
120
121 //============================================================================
122 // normal prvm
123
124 int PRVM_ED_FindFieldOffset(const char *field)
125 {
126         ddef_t *d;
127         d = PRVM_ED_FindField(field);
128         if (!d)
129                 return -1;
130         return d->ofs;
131 }
132
133 int PRVM_ED_FindGlobalOffset(const char *global)
134 {
135         ddef_t *d;
136         d = PRVM_ED_FindGlobal(global);
137         if (!d)
138                 return -1;
139         return d->ofs;
140 }
141
142 func_t PRVM_ED_FindFunctionOffset(const char *function)
143 {
144         mfunction_t *f;
145         f = PRVM_ED_FindFunction(function);
146         if (!f)
147                 return 0;
148         return (func_t)(f - prog->functions);
149 }
150
151 qboolean PRVM_ProgLoaded(int prognr)
152 {
153         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
154                 return FALSE;
155
156         return (prog_list[prognr].loaded ? TRUE : FALSE);
157 }
158
159 /*
160 =================
161 PRVM_SetProgFromString
162 =================
163 */
164 // perhaps add a return value when the str doesnt exist
165 qboolean PRVM_SetProgFromString(const char *str)
166 {
167         int i = 0;
168         for(; i < PRVM_MAXPROGS ; i++)
169                 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
170                 {
171                         if(prog_list[i].loaded)
172                         {
173                                 prog = &prog_list[i];
174                                 return TRUE;
175                         }
176                         else
177                         {
178                                 Con_Printf("%s not loaded !\n",PRVM_NAME);
179                                 return FALSE;
180                         }
181                 }
182
183         Con_Printf("Invalid program name %s !\n", str);
184         return FALSE;
185 }
186
187 /*
188 =================
189 PRVM_SetProg
190 =================
191 */
192 void PRVM_SetProg(int prognr)
193 {
194         if(0 <= prognr && prognr < PRVM_MAXPROGS)
195         {
196                 if(prog_list[prognr].loaded)
197                         prog = &prog_list[prognr];
198                 else
199                         PRVM_ERROR("%i not loaded !", prognr);
200                 return;
201         }
202         PRVM_ERROR("Invalid program number %i", prognr);
203 }
204
205 /*
206 =================
207 PRVM_ED_ClearEdict
208
209 Sets everything to NULL
210 =================
211 */
212 void PRVM_ED_ClearEdict (prvm_edict_t *e)
213 {
214         memset (e->fields.vp, 0, prog->progs->entityfields * 4);
215         e->priv.required->free = false;
216
217         // AK: Let the init_edict function determine if something needs to be initialized
218         PRVM_GCALL(init_edict)(e);
219 }
220
221 const char *PRVM_AllocationOrigin(void)
222 {
223         char *buf = NULL;
224         if(prog->leaktest_active)
225         if(prog->depth > 0) // actually in QC code and not just parsing the entities block of a map/savegame
226         {
227                 buf = (char *)PRVM_Alloc(128);
228                 PRVM_ShortStackTrace(buf, 128);
229         }
230         return buf;
231 }
232
233 /*
234 =================
235 PRVM_ED_CanAlloc
236
237 Returns if this particular edict could get allocated by PRVM_ED_Alloc
238 =================
239 */
240 qboolean PRVM_ED_CanAlloc(prvm_edict_t *e)
241 {
242         if(!e->priv.required->free)
243                 return false;
244         if(prvm_reuseedicts_always_allow == realtime)
245                 return true;
246         if(realtime <= e->priv.required->freetime && prvm_reuseedicts_neverinsameframe.integer)
247                 return false; // never allow reuse in same frame (causes networking trouble)
248         if(e->priv.required->freetime < prog->starttime + prvm_reuseedicts_startuptime.value)
249                 return true;
250         if(realtime > e->priv.required->freetime + 1)
251                 return true;
252         return false; // entity slot still blocked because the entity was freed less than one second ago
253 }
254
255 /*
256 =================
257 PRVM_ED_Alloc
258
259 Either finds a free edict, or allocates a new one.
260 Try to avoid reusing an entity that was recently freed, because it
261 can cause the client to think the entity morphed into something else
262 instead of being removed and recreated, which can cause interpolated
263 angles and bad trails.
264 =================
265 */
266 prvm_edict_t *PRVM_ED_Alloc (void)
267 {
268         int                     i;
269         prvm_edict_t            *e;
270
271         // the client qc dont need maxclients
272         // thus it doesnt need to use svs.maxclients
273         // AK:  changed i=svs.maxclients+1
274         // AK:  changed so the edict 0 wont spawn -> used as reserved/world entity
275         //              although the menu/client has no world
276         for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
277         {
278                 e = PRVM_EDICT_NUM(i);
279                 if(PRVM_ED_CanAlloc(e))
280                 {
281                         PRVM_ED_ClearEdict (e);
282                         e->priv.required->allocation_origin = PRVM_AllocationOrigin();
283                         return e;
284                 }
285         }
286
287         if (i == prog->limit_edicts)
288                 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
289
290         prog->num_edicts++;
291         if (prog->num_edicts >= prog->max_edicts)
292                 PRVM_MEM_IncreaseEdicts();
293
294         e = PRVM_EDICT_NUM(i);
295         PRVM_ED_ClearEdict (e);
296
297         e->priv.required->allocation_origin = PRVM_AllocationOrigin();
298
299         return e;
300 }
301
302 /*
303 =================
304 PRVM_ED_Free
305
306 Marks the edict as free
307 FIXME: walk all entities and NULL out references to this entity
308 =================
309 */
310 void PRVM_ED_Free (prvm_edict_t *ed)
311 {
312         // dont delete the null entity (world) or reserved edicts
313         if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
314                 return;
315
316         PRVM_GCALL(free_edict)(ed);
317
318         ed->priv.required->free = true;
319         ed->priv.required->freetime = realtime;
320         if(ed->priv.required->allocation_origin)
321         {
322                 PRVM_Free((char *)ed->priv.required->allocation_origin);
323                 ed->priv.required->allocation_origin = NULL;
324         }
325 }
326
327 //===========================================================================
328
329 /*
330 ============
331 PRVM_ED_GlobalAtOfs
332 ============
333 */
334 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
335 {
336         ddef_t          *def;
337         int                     i;
338
339         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
340         {
341                 def = &prog->globaldefs[i];
342                 if (def->ofs == ofs)
343                         return def;
344         }
345         return NULL;
346 }
347
348 /*
349 ============
350 PRVM_ED_FieldAtOfs
351 ============
352 */
353 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
354 {
355         ddef_t          *def;
356         int                     i;
357
358         for (i=0 ; i<prog->progs->numfielddefs ; i++)
359         {
360                 def = &prog->fielddefs[i];
361                 if (def->ofs == ofs)
362                         return def;
363         }
364         return NULL;
365 }
366
367 /*
368 ============
369 PRVM_ED_FindField
370 ============
371 */
372 ddef_t *PRVM_ED_FindField (const char *name)
373 {
374         ddef_t *def;
375         int i;
376
377         for (i=0 ; i<prog->progs->numfielddefs ; i++)
378         {
379                 def = &prog->fielddefs[i];
380                 if (!strcmp(PRVM_GetString(def->s_name), name))
381                         return def;
382         }
383         return NULL;
384 }
385
386 /*
387 ============
388 PRVM_ED_FindGlobal
389 ============
390 */
391 ddef_t *PRVM_ED_FindGlobal (const char *name)
392 {
393         ddef_t *def;
394         int i;
395
396         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
397         {
398                 def = &prog->globaldefs[i];
399                 if (!strcmp(PRVM_GetString(def->s_name), name))
400                         return def;
401         }
402         return NULL;
403 }
404
405
406 /*
407 ============
408 PRVM_ED_FindFunction
409 ============
410 */
411 mfunction_t *PRVM_ED_FindFunction (const char *name)
412 {
413         mfunction_t             *func;
414         int                             i;
415
416         for (i=0 ; i<prog->progs->numfunctions ; i++)
417         {
418                 func = &prog->functions[i];
419                 if (!strcmp(PRVM_GetString(func->s_name), name))
420                         return func;
421         }
422         return NULL;
423 }
424
425
426 /*
427 ============
428 PRVM_ValueString
429
430 Returns a string describing *data in a type specific manner
431 =============
432 */
433 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
434 {
435         static char line[MAX_INPUTLINE];
436         ddef_t *def;
437         mfunction_t *f;
438         int n;
439
440         type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
441
442         switch (type)
443         {
444         case ev_string:
445                 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
446                 break;
447         case ev_entity:
448                 n = val->edict;
449                 if (n < 0 || n >= prog->max_edicts)
450                         dpsnprintf (line, sizeof(line), "entity %i (invalid!)", n);
451                 else
452                         dpsnprintf (line, sizeof(line), "entity %i", n);
453                 break;
454         case ev_function:
455                 f = prog->functions + val->function;
456                 dpsnprintf (line, sizeof(line), "%s()", PRVM_GetString(f->s_name));
457                 break;
458         case ev_field:
459                 def = PRVM_ED_FieldAtOfs ( val->_int );
460                 dpsnprintf (line, sizeof(line), ".%s", PRVM_GetString(def->s_name));
461                 break;
462         case ev_void:
463                 dpsnprintf (line, sizeof(line), "void");
464                 break;
465         case ev_float:
466                 // LordHavoc: changed from %5.1f to %10.4f
467                 dpsnprintf (line, sizeof(line), "%10.4f", val->_float);
468                 break;
469         case ev_vector:
470                 // LordHavoc: changed from %5.1f to %10.4f
471                 dpsnprintf (line, sizeof(line), "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
472                 break;
473         case ev_pointer:
474                 dpsnprintf (line, sizeof(line), "pointer");
475                 break;
476         default:
477                 dpsnprintf (line, sizeof(line), "bad type %i", (int) type);
478                 break;
479         }
480
481         return line;
482 }
483
484 /*
485 ============
486 PRVM_UglyValueString
487
488 Returns a string describing *data in a type specific manner
489 Easier to parse than PR_ValueString
490 =============
491 */
492 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
493 {
494         static char line[MAX_INPUTLINE];
495         int i;
496         const char *s;
497         ddef_t *def;
498         mfunction_t *f;
499
500         type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
501
502         switch (type)
503         {
504         case ev_string:
505                 // Parse the string a bit to turn special characters
506                 // (like newline, specifically) into escape codes,
507                 // this fixes saving games from various mods
508                 s = PRVM_GetString (val->string);
509                 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
510                 {
511                         if (*s == '\n')
512                         {
513                                 line[i++] = '\\';
514                                 line[i++] = 'n';
515                         }
516                         else if (*s == '\r')
517                         {
518                                 line[i++] = '\\';
519                                 line[i++] = 'r';
520                         }
521                         else if (*s == '\\')
522                         {
523                                 line[i++] = '\\';
524                                 line[i++] = '\\';
525                         }
526                         else if (*s == '"')
527                         {
528                                 line[i++] = '\\';
529                                 line[i++] = '"';
530                         }
531                         else
532                                 line[i++] = *s;
533                         s++;
534                 }
535                 line[i] = '\0';
536                 break;
537         case ev_entity:
538                 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
539                 break;
540         case ev_function:
541                 f = prog->functions + val->function;
542                 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
543                 break;
544         case ev_field:
545                 def = PRVM_ED_FieldAtOfs ( val->_int );
546                 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
547                 break;
548         case ev_void:
549                 dpsnprintf (line, sizeof (line), "void");
550                 break;
551         case ev_float:
552                 dpsnprintf (line, sizeof (line), "%.9g", val->_float);
553                 break;
554         case ev_vector:
555                 dpsnprintf (line, sizeof (line), "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]);
556                 break;
557         default:
558                 dpsnprintf (line, sizeof (line), "bad type %i", type);
559                 break;
560         }
561
562         return line;
563 }
564
565 /*
566 ============
567 PRVM_GlobalString
568
569 Returns a string with a description and the contents of a global,
570 padded to 20 field width
571 ============
572 */
573 char *PRVM_GlobalString (int ofs)
574 {
575         char    *s;
576         //size_t        i;
577         ddef_t  *def;
578         void    *val;
579         static char     line[128];
580
581         val = (void *)&prog->globals.generic[ofs];
582         def = PRVM_ED_GlobalAtOfs(ofs);
583         if (!def)
584                 dpsnprintf (line, sizeof(line), "GLOBAL%i", ofs);
585         else
586         {
587                 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
588                 dpsnprintf (line, sizeof(line), "%s (=%s)", PRVM_GetString(def->s_name), s);
589         }
590
591         //i = strlen(line);
592         //for ( ; i<20 ; i++)
593         //      strcat (line," ");
594         //strcat (line," ");
595
596         return line;
597 }
598
599 char *PRVM_GlobalStringNoContents (int ofs)
600 {
601         //size_t        i;
602         ddef_t  *def;
603         static char     line[128];
604
605         def = PRVM_ED_GlobalAtOfs(ofs);
606         if (!def)
607                 dpsnprintf (line, sizeof(line), "GLOBAL%i", ofs);
608         else
609                 dpsnprintf (line, sizeof(line), "%s", PRVM_GetString(def->s_name));
610
611         //i = strlen(line);
612         //for ( ; i<20 ; i++)
613         //      strcat (line," ");
614         //strcat (line," ");
615
616         return line;
617 }
618
619
620 /*
621 =============
622 PRVM_ED_Print
623
624 For debugging
625 =============
626 */
627 // LordHavoc: optimized this to print out much more quickly (tempstring)
628 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
629 void PRVM_ED_Print(prvm_edict_t *ed, const char *wildcard_fieldname)
630 {
631         size_t  l;
632         ddef_t  *d;
633         int             *v;
634         int             i, j;
635         const char      *name;
636         int             type;
637         char    tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
638
639         if (ed->priv.required->free)
640         {
641                 Con_Printf("%s: FREE\n",PRVM_NAME);
642                 return;
643         }
644
645         tempstring[0] = 0;
646         dpsnprintf(tempstring, sizeof(tempstring), "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
647         for (i=1 ; i<prog->progs->numfielddefs ; i++)
648         {
649                 d = &prog->fielddefs[i];
650                 name = PRVM_GetString(d->s_name);
651                 if(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
652                         continue;       // skip _x, _y, _z vars
653
654                 // Check Field Name Wildcard
655                 if(wildcard_fieldname)
656                         if( !matchpattern(name, wildcard_fieldname, 1) )
657                                 // Didn't match; skip
658                                 continue;
659
660                 v = (int *)(ed->fields.vp + d->ofs);
661
662         // if the value is still all 0, skip the field
663                 type = d->type & ~DEF_SAVEGLOBAL;
664
665                 for (j=0 ; j<prvm_type_size[type] ; j++)
666                         if (v[j])
667                                 break;
668                 if (j == prvm_type_size[type])
669                         continue;
670
671                 if (strlen(name) > sizeof(tempstring2)-4)
672                 {
673                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
674                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
675                         tempstring2[sizeof(tempstring2)-1] = 0;
676                         name = tempstring2;
677                 }
678                 strlcat(tempstring, name, sizeof(tempstring));
679                 for (l = strlen(name);l < 14;l++)
680                         strlcat(tempstring, " ", sizeof(tempstring));
681                 strlcat(tempstring, " ", sizeof(tempstring));
682
683                 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
684                 if (strlen(name) > sizeof(tempstring2)-4)
685                 {
686                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
687                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
688                         tempstring2[sizeof(tempstring2)-1] = 0;
689                         name = tempstring2;
690                 }
691                 strlcat(tempstring, name, sizeof(tempstring));
692                 strlcat(tempstring, "\n", sizeof(tempstring));
693                 if (strlen(tempstring) >= sizeof(tempstring)/2)
694                 {
695                         Con_Print(tempstring);
696                         tempstring[0] = 0;
697                 }
698         }
699         if (tempstring[0])
700                 Con_Print(tempstring);
701 }
702
703 /*
704 =============
705 PRVM_ED_Write
706
707 For savegames
708 =============
709 */
710 extern cvar_t developer_entityparsing;
711 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
712 {
713         ddef_t  *d;
714         int             *v;
715         int             i, j;
716         const char      *name;
717         int             type;
718
719         FS_Print(f, "{\n");
720
721         if (ed->priv.required->free)
722         {
723                 FS_Print(f, "}\n");
724                 return;
725         }
726
727         for (i=1 ; i<prog->progs->numfielddefs ; i++)
728         {
729                 d = &prog->fielddefs[i];
730                 name = PRVM_GetString(d->s_name);
731
732                 if(developer_entityparsing.integer)
733                         Con_Printf("PRVM_ED_Write: at entity %d field %s\n", PRVM_NUM_FOR_EDICT(ed), name);
734
735                 //if(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
736                 if(strlen(name) > 1 && name[strlen(name)-2] == '_')
737                         continue;       // skip _x, _y, _z vars, and ALSO other _? vars as some mods expect them to be never saved (TODO: a gameplayfix for using the "more precise" condition above?)
738
739                 v = (int *)(ed->fields.vp + d->ofs);
740
741         // if the value is still all 0, skip the field
742                 type = d->type & ~DEF_SAVEGLOBAL;
743                 for (j=0 ; j<prvm_type_size[type] ; j++)
744                         if (v[j])
745                                 break;
746                 if (j == prvm_type_size[type])
747                         continue;
748
749                 FS_Printf(f,"\"%s\" ",name);
750                 prog->statestring = va("PRVM_ED_Write, ent=%d, name=%s", i, name);
751                 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
752                 prog->statestring = NULL;
753         }
754
755         FS_Print(f, "}\n");
756 }
757
758 void PRVM_ED_PrintNum (int ent, const char *wildcard_fieldname)
759 {
760         PRVM_ED_Print(PRVM_EDICT_NUM(ent), wildcard_fieldname);
761 }
762
763 /*
764 =============
765 PRVM_ED_PrintEdicts_f
766
767 For debugging, prints all the entities in the current server
768 =============
769 */
770 void PRVM_ED_PrintEdicts_f (void)
771 {
772         int             i;
773         const char *wildcard_fieldname;
774
775         if(Cmd_Argc() < 2 || Cmd_Argc() > 3)
776         {
777                 Con_Print("prvm_edicts <program name> <optional field name wildcard>\n");
778                 return;
779         }
780
781         PRVM_Begin;
782         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
783                 return;
784
785         if( Cmd_Argc() == 3)
786                 wildcard_fieldname = Cmd_Argv(2);
787         else
788                 wildcard_fieldname = NULL;
789
790         Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
791         for (i=0 ; i<prog->num_edicts ; i++)
792                 PRVM_ED_PrintNum (i, wildcard_fieldname);
793
794         PRVM_End;
795 }
796
797 /*
798 =============
799 PRVM_ED_PrintEdict_f
800
801 For debugging, prints a single edict
802 =============
803 */
804 void PRVM_ED_PrintEdict_f (void)
805 {
806         int             i;
807         const char      *wildcard_fieldname;
808
809         if(Cmd_Argc() < 3 || Cmd_Argc() > 4)
810         {
811                 Con_Print("prvm_edict <program name> <edict number> <optional field name wildcard>\n");
812                 return;
813         }
814
815         PRVM_Begin;
816         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
817                 return;
818
819         i = atoi (Cmd_Argv(2));
820         if (i >= prog->num_edicts)
821         {
822                 Con_Print("Bad edict number\n");
823                 PRVM_End;
824                 return;
825         }
826         if( Cmd_Argc() == 4)
827                 // Optional Wildcard Provided
828                 wildcard_fieldname = Cmd_Argv(3);
829         else
830                 // Use All
831                 wildcard_fieldname = NULL;
832         PRVM_ED_PrintNum (i, wildcard_fieldname);
833
834         PRVM_End;
835 }
836
837 /*
838 =============
839 PRVM_ED_Count
840
841 For debugging
842 =============
843 */
844 // 2 possibilities : 1. just displaying the active edict count
845 //                                       2. making a function pointer [x]
846 void PRVM_ED_Count_f (void)
847 {
848         int             i;
849         prvm_edict_t    *ent;
850         int             active;
851
852         if(Cmd_Argc() != 2)
853         {
854                 Con_Print("prvm_count <program name>\n");
855                 return;
856         }
857
858         PRVM_Begin;
859         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
860                 return;
861
862         if(prog->count_edicts)
863                 prog->count_edicts();
864         else
865         {
866                 active = 0;
867                 for (i=0 ; i<prog->num_edicts ; i++)
868                 {
869                         ent = PRVM_EDICT_NUM(i);
870                         if (ent->priv.required->free)
871                                 continue;
872                         active++;
873                 }
874
875                 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
876                 Con_Printf("active    :%3i\n", active);
877         }
878
879         PRVM_End;
880 }
881
882 /*
883 ==============================================================================
884
885                                         ARCHIVING GLOBALS
886
887 FIXME: need to tag constants, doesn't really work
888 ==============================================================================
889 */
890
891 /*
892 =============
893 PRVM_ED_WriteGlobals
894 =============
895 */
896 void PRVM_ED_WriteGlobals (qfile_t *f)
897 {
898         ddef_t          *def;
899         int                     i;
900         const char              *name;
901         int                     type;
902
903         FS_Print(f,"{\n");
904         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
905         {
906                 def = &prog->globaldefs[i];
907                 type = def->type;
908                 if ( !(def->type & DEF_SAVEGLOBAL) )
909                         continue;
910                 type &= ~DEF_SAVEGLOBAL;
911
912                 if (type != ev_string && type != ev_float && type != ev_entity)
913                         continue;
914
915                 name = PRVM_GetString(def->s_name);
916
917                 if(developer_entityparsing.integer)
918                         Con_Printf("PRVM_ED_WriteGlobals: at global %s\n", name);
919
920                 prog->statestring = va("PRVM_ED_WriteGlobals, name=%s", name);
921                 FS_Printf(f,"\"%s\" ", name);
922                 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
923                 prog->statestring = NULL;
924         }
925         FS_Print(f,"}\n");
926 }
927
928 /*
929 =============
930 PRVM_ED_ParseGlobals
931 =============
932 */
933 void PRVM_ED_ParseGlobals (const char *data)
934 {
935         char keyname[MAX_INPUTLINE];
936         ddef_t *key;
937
938         while (1)
939         {
940                 // parse key
941                 if (!COM_ParseToken_Simple(&data, false, false))
942                         PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
943                 if (com_token[0] == '}')
944                         break;
945
946                 if (developer_entityparsing.integer)
947                         Con_Printf("Key: \"%s\"", com_token);
948
949                 strlcpy (keyname, com_token, sizeof(keyname));
950
951                 // parse value
952                 if (!COM_ParseToken_Simple(&data, false, true))
953                         PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
954
955                 if (developer_entityparsing.integer)
956                         Con_Printf(" \"%s\"\n", com_token);
957
958                 if (com_token[0] == '}')
959                         PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
960
961                 key = PRVM_ED_FindGlobal (keyname);
962                 if (!key)
963                 {
964                         Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
965                         continue;
966                 }
967
968                 if (!PRVM_ED_ParseEpair(NULL, key, com_token, true))
969                         PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
970         }
971 }
972
973 //============================================================================
974
975
976 /*
977 =============
978 PRVM_ED_ParseEval
979
980 Can parse either fields or globals
981 returns false if error
982 =============
983 */
984 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash)
985 {
986         int i, l;
987         char *new_p;
988         ddef_t *def;
989         prvm_eval_t *val;
990         mfunction_t *func;
991
992         if (ent)
993                 val = (prvm_eval_t *)(ent->fields.vp + key->ofs);
994         else
995                 val = (prvm_eval_t *)(prog->globals.generic + key->ofs);
996         switch (key->type & ~DEF_SAVEGLOBAL)
997         {
998         case ev_string:
999                 l = (int)strlen(s) + 1;
1000                 val->string = PRVM_AllocString(l, &new_p);
1001                 for (i = 0;i < l;i++)
1002                 {
1003                         if (s[i] == '\\' && s[i+1] && parsebackslash)
1004                         {
1005                                 i++;
1006                                 if (s[i] == 'n')
1007                                         *new_p++ = '\n';
1008                                 else if (s[i] == 'r')
1009                                         *new_p++ = '\r';
1010                                 else
1011                                         *new_p++ = s[i];
1012                         }
1013                         else
1014                                 *new_p++ = s[i];
1015                 }
1016                 break;
1017
1018         case ev_float:
1019                 while (*s && ISWHITESPACE(*s))
1020                         s++;
1021                 val->_float = atof(s);
1022                 break;
1023
1024         case ev_vector:
1025                 for (i = 0;i < 3;i++)
1026                 {
1027                         while (*s && ISWHITESPACE(*s))
1028                                 s++;
1029                         if (!*s)
1030                                 break;
1031                         val->vector[i] = atof(s);
1032                         while (!ISWHITESPACE(*s))
1033                                 s++;
1034                         if (!*s)
1035                                 break;
1036                 }
1037                 break;
1038
1039         case ev_entity:
1040                 while (*s && ISWHITESPACE(*s))
1041                         s++;
1042                 i = atoi(s);
1043                 if (i >= prog->limit_edicts)
1044                         Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %u >= MAX_EDICTS %u) on %s\n", (unsigned int)i, prog->limit_edicts, PRVM_NAME);
1045                 while (i >= prog->max_edicts)
1046                         PRVM_MEM_IncreaseEdicts();
1047                 // if IncreaseEdicts was called the base pointer needs to be updated
1048                 if (ent)
1049                         val = (prvm_eval_t *)(ent->fields.vp + key->ofs);
1050                 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
1051                 break;
1052
1053         case ev_field:
1054                 if (*s != '.')
1055                 {
1056                         Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, PRVM_NAME);
1057                         return false;
1058                 }
1059                 def = PRVM_ED_FindField(s + 1);
1060                 if (!def)
1061                 {
1062                         Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
1063                         return false;
1064                 }
1065                 val->_int = def->ofs;
1066                 break;
1067
1068         case ev_function:
1069                 func = PRVM_ED_FindFunction(s);
1070                 if (!func)
1071                 {
1072                         Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
1073                         return false;
1074                 }
1075                 val->function = func - prog->functions;
1076                 break;
1077
1078         default:
1079                 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
1080                 return false;
1081         }
1082         return true;
1083 }
1084
1085 /*
1086 =============
1087 PRVM_GameCommand_f
1088
1089 Console command to send a string to QC function GameCommand of the
1090 indicated progs
1091
1092 Usage:
1093   sv_cmd adminmsg 3 "do not teamkill"
1094   cl_cmd someclientcommand
1095   menu_cmd somemenucommand
1096
1097 All progs can support this extension; sg calls it in server QC, cg in client
1098 QC, mg in menu QC.
1099 =============
1100 */
1101 void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
1102 {
1103         if(Cmd_Argc() < 1)
1104         {
1105                 Con_Printf("%s text...\n", whichcmd);
1106                 return;
1107         }
1108
1109         PRVM_Begin;
1110         if(!PRVM_SetProgFromString(whichprogs))
1111         // note: this is not PRVM_SetProg because that one aborts "hard" using PRVM_Error
1112         // also, it makes printing error messages easier!
1113         {
1114                 Con_Printf("%s program not loaded.\n", whichprogs);
1115                 return;
1116         }
1117
1118         if(!prog->funcoffsets.GameCommand)
1119         {
1120                 Con_Printf("%s program do not support GameCommand!\n", whichprogs);
1121         }
1122         else
1123         {
1124                 int restorevm_tempstringsbuf_cursize;
1125                 const char *s;
1126
1127                 s = Cmd_Args();
1128
1129                 restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1130                 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s ? s : "");
1131                 PRVM_ExecuteProgram (prog->funcoffsets.GameCommand, "QC function GameCommand is missing");
1132                 vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1133         }
1134
1135         PRVM_End;
1136 }
1137 void PRVM_GameCommand_Server_f(void)
1138 {
1139         PRVM_GameCommand("server", "sv_cmd");
1140 }
1141 void PRVM_GameCommand_Client_f(void)
1142 {
1143         PRVM_GameCommand("client", "cl_cmd");
1144 }
1145 void PRVM_GameCommand_Menu_f(void)
1146 {
1147         PRVM_GameCommand("menu", "menu_cmd");
1148 }
1149
1150 /*
1151 =============
1152 PRVM_ED_EdictGet_f
1153
1154 Console command to load a field of a specified edict
1155 =============
1156 */
1157 void PRVM_ED_EdictGet_f(void)
1158 {
1159         prvm_edict_t *ed;
1160         ddef_t *key;
1161         const char *s;
1162         prvm_eval_t *v;
1163
1164         if(Cmd_Argc() != 4 && Cmd_Argc() != 5)
1165         {
1166                 Con_Print("prvm_edictget <program name> <edict number> <field> [<cvar>]\n");
1167                 return;
1168         }
1169
1170         PRVM_Begin;
1171         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1172         {
1173                 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1174                 return;
1175         }
1176
1177         ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1178
1179         if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1180         {
1181                 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1182                 goto fail;
1183         }
1184
1185         v = (prvm_eval_t *)(ed->fields.vp + key->ofs);
1186         s = PRVM_UglyValueString((etype_t)key->type, v);
1187         if(Cmd_Argc() == 5)
1188         {
1189                 cvar_t *cvar = Cvar_FindVar(Cmd_Argv(4));
1190                 if (cvar && cvar->flags & CVAR_READONLY)
1191                 {
1192                         Con_Printf("prvm_edictget: %s is read-only\n", cvar->name);
1193                         goto fail;
1194                 }
1195                 Cvar_Get(Cmd_Argv(4), s, 0, NULL);
1196         }
1197         else
1198                 Con_Printf("%s\n", s);
1199
1200 fail:
1201         PRVM_End;
1202 }
1203
1204 void PRVM_ED_GlobalGet_f(void)
1205 {
1206         ddef_t *key;
1207         const char *s;
1208         prvm_eval_t *v;
1209
1210         if(Cmd_Argc() != 3 && Cmd_Argc() != 4)
1211         {
1212                 Con_Print("prvm_globalget <program name> <global> [<cvar>]\n");
1213                 return;
1214         }
1215
1216         PRVM_Begin;
1217         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1218         {
1219                 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1220                 return;
1221         }
1222
1223         key = PRVM_ED_FindGlobal(Cmd_Argv(2));
1224         if(!key)
1225         {
1226                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1227                 goto fail;
1228         }
1229
1230         v = (prvm_eval_t *) &prog->globals.generic[key->ofs];
1231         s = PRVM_UglyValueString((etype_t)key->type, v);
1232         if(Cmd_Argc() == 4)
1233         {
1234                 cvar_t *cvar = Cvar_FindVar(Cmd_Argv(3));
1235                 if (cvar && cvar->flags & CVAR_READONLY)
1236                 {
1237                         Con_Printf("prvm_globalget: %s is read-only\n", cvar->name);
1238                         goto fail;
1239                 }
1240                 Cvar_Get(Cmd_Argv(3), s, 0, NULL);
1241         }
1242         else
1243                 Con_Printf("%s\n", s);
1244
1245 fail:
1246         PRVM_End;
1247 }
1248
1249 /*
1250 =============
1251 PRVM_ED_EdictSet_f
1252
1253 Console command to set a field of a specified edict
1254 =============
1255 */
1256 void PRVM_ED_EdictSet_f(void)
1257 {
1258         prvm_edict_t *ed;
1259         ddef_t *key;
1260
1261         if(Cmd_Argc() != 5)
1262         {
1263                 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1264                 return;
1265         }
1266
1267         PRVM_Begin;
1268         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1269         {
1270                 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1271                 return;
1272         }
1273
1274         ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1275
1276         if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1277                 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1278         else
1279                 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4), true);
1280
1281         PRVM_End;
1282 }
1283
1284 /*
1285 ====================
1286 PRVM_ED_ParseEdict
1287
1288 Parses an edict out of the given string, returning the new position
1289 ed should be a properly initialized empty edict.
1290 Used for initial level load and for savegames.
1291 ====================
1292 */
1293 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1294 {
1295         ddef_t *key;
1296         qboolean anglehack;
1297         qboolean init;
1298         char keyname[256];
1299         size_t n;
1300
1301         init = false;
1302
1303 // go through all the dictionary pairs
1304         while (1)
1305         {
1306         // parse key
1307                 if (!COM_ParseToken_Simple(&data, false, false))
1308                         PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1309                 if (developer_entityparsing.integer)
1310                         Con_Printf("Key: \"%s\"", com_token);
1311                 if (com_token[0] == '}')
1312                         break;
1313
1314                 // anglehack is to allow QuakeEd to write single scalar angles
1315                 // and allow them to be turned into vectors. (FIXME...)
1316                 if (!strcmp(com_token, "angle"))
1317                 {
1318                         strlcpy (com_token, "angles", sizeof(com_token));
1319                         anglehack = true;
1320                 }
1321                 else
1322                         anglehack = false;
1323
1324                 // FIXME: change light to _light to get rid of this hack
1325                 if (!strcmp(com_token, "light"))
1326                         strlcpy (com_token, "light_lev", sizeof(com_token));    // hack for single light def
1327
1328                 strlcpy (keyname, com_token, sizeof(keyname));
1329
1330                 // another hack to fix keynames with trailing spaces
1331                 n = strlen(keyname);
1332                 while (n && keyname[n-1] == ' ')
1333                 {
1334                         keyname[n-1] = 0;
1335                         n--;
1336                 }
1337
1338         // parse value
1339                 if (!COM_ParseToken_Simple(&data, false, false))
1340                         PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1341                 if (developer_entityparsing.integer)
1342                         Con_Printf(" \"%s\"\n", com_token);
1343
1344                 if (com_token[0] == '}')
1345                         PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1346
1347                 init = true;
1348
1349                 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1350                 if (!keyname[0])
1351                         continue;
1352
1353 // keynames with a leading underscore are used for utility comments,
1354 // and are immediately discarded by quake
1355                 if (keyname[0] == '_')
1356                         continue;
1357
1358                 key = PRVM_ED_FindField (keyname);
1359                 if (!key)
1360                 {
1361                         Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1362                         continue;
1363                 }
1364
1365                 if (anglehack)
1366                 {
1367                         char    temp[32];
1368                         strlcpy (temp, com_token, sizeof(temp));
1369                         dpsnprintf (com_token, sizeof(com_token), "0 %s 0", temp);
1370                 }
1371
1372                 if (!PRVM_ED_ParseEpair(ent, key, com_token, strcmp(keyname, "wad") != 0))
1373                         PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1374         }
1375
1376         if (!init)
1377                 ent->priv.required->free = true;
1378
1379         return data;
1380 }
1381
1382
1383 /*
1384 ================
1385 PRVM_ED_LoadFromFile
1386
1387 The entities are directly placed in the array, rather than allocated with
1388 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1389 number references out of order.
1390
1391 Creates a server's entity / program execution context by
1392 parsing textual entity definitions out of an ent file.
1393
1394 Used for both fresh maps and savegame loads.  A fresh map would also need
1395 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1396 ================
1397 */
1398 void PRVM_ED_LoadFromFile (const char *data)
1399 {
1400         prvm_edict_t *ent;
1401         int parsed, inhibited, spawned, died;
1402         const char *funcname;
1403         mfunction_t *func;
1404
1405         parsed = 0;
1406         inhibited = 0;
1407         spawned = 0;
1408         died = 0;
1409
1410         prvm_reuseedicts_always_allow = realtime;
1411
1412 // parse ents
1413         while (1)
1414         {
1415 // parse the opening brace
1416                 if (!COM_ParseToken_Simple(&data, false, false))
1417                         break;
1418                 if (com_token[0] != '{')
1419                         PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1420
1421                 // CHANGED: this is not conform to PR_LoadFromFile
1422                 if(prog->loadintoworld)
1423                 {
1424                         prog->loadintoworld = false;
1425                         ent = PRVM_EDICT_NUM(0);
1426                 }
1427                 else
1428                         ent = PRVM_ED_Alloc();
1429
1430                 // clear it
1431                 if (ent != prog->edicts)        // hack
1432                         memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1433
1434                 data = PRVM_ED_ParseEdict (data, ent);
1435                 parsed++;
1436
1437                 // remove the entity ?
1438                 if(prog->load_edict && !prog->load_edict(ent))
1439                 {
1440                         PRVM_ED_Free(ent);
1441                         inhibited++;
1442                         continue;
1443                 }
1444
1445                 if (prog->funcoffsets.SV_OnEntityPreSpawnFunction)
1446                 {
1447                         // self = ent
1448                         PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1449                         PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityPreSpawnFunction, "QC function SV_OnEntityPreSpawnFunction is missing");
1450                 }
1451
1452                 if(ent->priv.required->free)
1453                 {
1454                         inhibited++;
1455                         continue;
1456                 }
1457
1458 //
1459 // immediately call spawn function, but only if there is a self global and a classname
1460 //
1461                 if(!ent->priv.required->free)
1462                 if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0)
1463                 {
1464                         string_t handle =  PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
1465                         if (!handle)
1466                         {
1467                                 Con_Print("No classname for:\n");
1468                                 PRVM_ED_Print(ent, NULL);
1469                                 PRVM_ED_Free (ent);
1470                                 continue;
1471                         }
1472
1473                         // look for the spawn function
1474                         funcname = PRVM_GetString(handle);
1475                         func = PRVM_ED_FindFunction (va("spawnfunc_%s", funcname));
1476                         if(!func)
1477                                 if(prog->globaloffsets.require_spawnfunc_prefix < 0)
1478                                         func = PRVM_ED_FindFunction (funcname);
1479
1480                         if (!func)
1481                         {
1482                                 // check for OnEntityNoSpawnFunction
1483                                 if (prog->funcoffsets.SV_OnEntityNoSpawnFunction)
1484                                 {
1485                                         // self = ent
1486                                         PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1487                                         PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityNoSpawnFunction, "QC function SV_OnEntityNoSpawnFunction is missing");
1488                                 }
1489                                 else
1490                                 {
1491                                         if (developer.integer > 0) // don't confuse non-developers with errors
1492                                         {
1493                                                 Con_Print("No spawn function for:\n");
1494                                                 PRVM_ED_Print(ent, NULL);
1495                                         }
1496                                         PRVM_ED_Free (ent);
1497                                         continue; // not included in "inhibited" count
1498                                 }
1499                         }
1500                         else
1501                         {
1502                                 // self = ent
1503                                 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1504                                 PRVM_ExecuteProgram (func - prog->functions, "");
1505                         }
1506                 }
1507
1508                 if(!ent->priv.required->free)
1509                 if (prog->funcoffsets.SV_OnEntityPostSpawnFunction)
1510                 {
1511                         // self = ent
1512                         PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1513                         PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityPostSpawnFunction, "QC function SV_OnEntityPostSpawnFunction is missing");
1514                 }
1515
1516                 spawned++;
1517                 if (ent->priv.required->free)
1518                         died++;
1519         }
1520
1521         Con_DPrintf("%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, prog->num_edicts, spawned, died, spawned - died);
1522
1523         prvm_reuseedicts_always_allow = 0;
1524 }
1525
1526 void PRVM_FindOffsets(void)
1527 {
1528         // field and global searches use -1 for NULL
1529         memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
1530         memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
1531         // functions use 0 for NULL
1532         memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
1533
1534         // server and client qc use a lot of similar fields, so this is combined
1535         prog->fieldoffsets.SendEntity                     = PRVM_ED_FindFieldOffset("SendEntity");
1536         prog->fieldoffsets.SendFlags                      = PRVM_ED_FindFieldOffset("SendFlags");
1537         prog->fieldoffsets.Version                        = PRVM_ED_FindFieldOffset("Version");
1538         prog->fieldoffsets.alpha                          = PRVM_ED_FindFieldOffset("alpha");
1539         prog->fieldoffsets.ammo_cells1                    = PRVM_ED_FindFieldOffset("ammo_cells1");
1540         prog->fieldoffsets.ammo_lava_nails                = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1541         prog->fieldoffsets.ammo_multi_rockets             = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1542         prog->fieldoffsets.ammo_nails1                    = PRVM_ED_FindFieldOffset("ammo_nails1");
1543         prog->fieldoffsets.ammo_plasma                    = PRVM_ED_FindFieldOffset("ammo_plasma");
1544         prog->fieldoffsets.ammo_rockets1                  = PRVM_ED_FindFieldOffset("ammo_rockets1");
1545         prog->fieldoffsets.ammo_shells1                   = PRVM_ED_FindFieldOffset("ammo_shells1");
1546         prog->fieldoffsets.angles                         = PRVM_ED_FindFieldOffset("angles");
1547         prog->fieldoffsets.button3                        = PRVM_ED_FindFieldOffset("button3");
1548         prog->fieldoffsets.button4                        = PRVM_ED_FindFieldOffset("button4");
1549         prog->fieldoffsets.button5                        = PRVM_ED_FindFieldOffset("button5");
1550         prog->fieldoffsets.button6                        = PRVM_ED_FindFieldOffset("button6");
1551         prog->fieldoffsets.button7                        = PRVM_ED_FindFieldOffset("button7");
1552         prog->fieldoffsets.button8                        = PRVM_ED_FindFieldOffset("button8");
1553         prog->fieldoffsets.button9                        = PRVM_ED_FindFieldOffset("button9");
1554         prog->fieldoffsets.button10                       = PRVM_ED_FindFieldOffset("button10");
1555         prog->fieldoffsets.button11                       = PRVM_ED_FindFieldOffset("button11");
1556         prog->fieldoffsets.button12                       = PRVM_ED_FindFieldOffset("button12");
1557         prog->fieldoffsets.button13                       = PRVM_ED_FindFieldOffset("button13");
1558         prog->fieldoffsets.button14                       = PRVM_ED_FindFieldOffset("button14");
1559         prog->fieldoffsets.button15                       = PRVM_ED_FindFieldOffset("button15");
1560         prog->fieldoffsets.button16                       = PRVM_ED_FindFieldOffset("button16");
1561         prog->fieldoffsets.buttonchat                     = PRVM_ED_FindFieldOffset("buttonchat");
1562         prog->fieldoffsets.buttonuse                      = PRVM_ED_FindFieldOffset("buttonuse");
1563         prog->fieldoffsets.chain                          = PRVM_ED_FindFieldOffset("chain");
1564         prog->fieldoffsets.classname                      = PRVM_ED_FindFieldOffset("classname");
1565         prog->fieldoffsets.clientcamera                   = PRVM_ED_FindFieldOffset("clientcamera");
1566         prog->fieldoffsets.clientcolors                   = PRVM_ED_FindFieldOffset("clientcolors");
1567         prog->fieldoffsets.clientstatus                   = PRVM_ED_FindFieldOffset("clientstatus");
1568         prog->fieldoffsets.color                          = PRVM_ED_FindFieldOffset("color");
1569         prog->fieldoffsets.colormod                       = PRVM_ED_FindFieldOffset("colormod");
1570         prog->fieldoffsets.contentstransition             = PRVM_ED_FindFieldOffset("contentstransition");
1571         prog->fieldoffsets.cursor_active                  = PRVM_ED_FindFieldOffset("cursor_active");
1572         prog->fieldoffsets.cursor_screen                  = PRVM_ED_FindFieldOffset("cursor_screen");
1573         prog->fieldoffsets.cursor_trace_endpos            = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1574         prog->fieldoffsets.cursor_trace_ent               = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1575         prog->fieldoffsets.cursor_trace_start             = PRVM_ED_FindFieldOffset("cursor_trace_start");
1576         prog->fieldoffsets.customizeentityforclient       = PRVM_ED_FindFieldOffset("customizeentityforclient");
1577         prog->fieldoffsets.dimension_hit                  = PRVM_ED_FindFieldOffset("dimension_hit");
1578         prog->fieldoffsets.dimension_solid                = PRVM_ED_FindFieldOffset("dimension_solid");
1579         prog->fieldoffsets.disableclientprediction        = PRVM_ED_FindFieldOffset("disableclientprediction");
1580         prog->fieldoffsets.discardabledemo                = PRVM_ED_FindFieldOffset("discardabledemo");
1581         prog->fieldoffsets.dphitcontentsmask              = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1582         prog->fieldoffsets.drawonlytoclient               = PRVM_ED_FindFieldOffset("drawonlytoclient");
1583         prog->fieldoffsets.exteriormodeltoclient          = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1584         prog->fieldoffsets.fatness                        = PRVM_ED_FindFieldOffset("fatness");
1585         prog->fieldoffsets.forceshader                    = PRVM_ED_FindFieldOffset("forceshader");
1586         prog->fieldoffsets.frame                          = PRVM_ED_FindFieldOffset("frame");
1587         prog->fieldoffsets.frame1time                     = PRVM_ED_FindFieldOffset("frame1time");
1588         prog->fieldoffsets.frame2                         = PRVM_ED_FindFieldOffset("frame2");
1589         prog->fieldoffsets.frame2time                     = PRVM_ED_FindFieldOffset("frame2time");
1590         prog->fieldoffsets.frame3                         = PRVM_ED_FindFieldOffset("frame3");
1591         prog->fieldoffsets.frame3time                     = PRVM_ED_FindFieldOffset("frame3time");
1592         prog->fieldoffsets.frame4                         = PRVM_ED_FindFieldOffset("frame4");
1593         prog->fieldoffsets.frame4time                     = PRVM_ED_FindFieldOffset("frame4time");
1594         prog->fieldoffsets.fullbright                     = PRVM_ED_FindFieldOffset("fullbright");
1595         prog->fieldoffsets.glow_color                     = PRVM_ED_FindFieldOffset("glow_color");
1596         prog->fieldoffsets.glow_size                      = PRVM_ED_FindFieldOffset("glow_size");
1597         prog->fieldoffsets.glow_trail                     = PRVM_ED_FindFieldOffset("glow_trail");
1598         prog->fieldoffsets.glowmod                        = PRVM_ED_FindFieldOffset("glowmod");
1599         prog->fieldoffsets.gravity                        = PRVM_ED_FindFieldOffset("gravity");
1600         prog->fieldoffsets.groundentity                   = PRVM_ED_FindFieldOffset("groundentity");
1601         prog->fieldoffsets.hull                           = PRVM_ED_FindFieldOffset("hull");
1602         prog->fieldoffsets.ideal_yaw                      = PRVM_ED_FindFieldOffset("ideal_yaw");
1603         prog->fieldoffsets.idealpitch                     = PRVM_ED_FindFieldOffset("idealpitch");
1604         prog->fieldoffsets.items2                         = PRVM_ED_FindFieldOffset("items2");
1605         prog->fieldoffsets.lerpfrac                       = PRVM_ED_FindFieldOffset("lerpfrac");
1606         prog->fieldoffsets.lerpfrac3                      = PRVM_ED_FindFieldOffset("lerpfrac3");
1607         prog->fieldoffsets.lerpfrac4                      = PRVM_ED_FindFieldOffset("lerpfrac4");
1608         prog->fieldoffsets.light_lev                      = PRVM_ED_FindFieldOffset("light_lev");
1609         prog->fieldoffsets.message                        = PRVM_ED_FindFieldOffset("message");
1610         prog->fieldoffsets.modelflags                     = PRVM_ED_FindFieldOffset("modelflags");
1611         prog->fieldoffsets.movement                       = PRVM_ED_FindFieldOffset("movement");
1612         prog->fieldoffsets.movetypesteplandevent          = PRVM_ED_FindFieldOffset("movetypesteplandevent");
1613         prog->fieldoffsets.netaddress                     = PRVM_ED_FindFieldOffset("netaddress");
1614         prog->fieldoffsets.nextthink                      = PRVM_ED_FindFieldOffset("nextthink");
1615         prog->fieldoffsets.nodrawtoclient                 = PRVM_ED_FindFieldOffset("nodrawtoclient");
1616         prog->fieldoffsets.pflags                         = PRVM_ED_FindFieldOffset("pflags");
1617         prog->fieldoffsets.ping                           = PRVM_ED_FindFieldOffset("ping");
1618         prog->fieldoffsets.packetloss                     = PRVM_ED_FindFieldOffset("ping_packetloss");
1619         prog->fieldoffsets.movementloss                   = PRVM_ED_FindFieldOffset("ping_movementloss");
1620         prog->fieldoffsets.pitch_speed                    = PRVM_ED_FindFieldOffset("pitch_speed");
1621         prog->fieldoffsets.playermodel                    = PRVM_ED_FindFieldOffset("playermodel");
1622         prog->fieldoffsets.playerskin                     = PRVM_ED_FindFieldOffset("playerskin");
1623         prog->fieldoffsets.pmodel                         = PRVM_ED_FindFieldOffset("pmodel");
1624         prog->fieldoffsets.punchvector                    = PRVM_ED_FindFieldOffset("punchvector");
1625         prog->fieldoffsets.renderamt                      = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1626         prog->fieldoffsets.renderflags                    = PRVM_ED_FindFieldOffset("renderflags");
1627         prog->fieldoffsets.rendermode                     = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1628         prog->fieldoffsets.scale                          = PRVM_ED_FindFieldOffset("scale");
1629         prog->fieldoffsets.shadertime                     = PRVM_ED_FindFieldOffset("shadertime");
1630         prog->fieldoffsets.skeletonindex                  = PRVM_ED_FindFieldOffset("skeletonindex");
1631         prog->fieldoffsets.style                          = PRVM_ED_FindFieldOffset("style");
1632         prog->fieldoffsets.tag_entity                     = PRVM_ED_FindFieldOffset("tag_entity");
1633         prog->fieldoffsets.tag_index                      = PRVM_ED_FindFieldOffset("tag_index");
1634         prog->fieldoffsets.think                          = PRVM_ED_FindFieldOffset("think");
1635         prog->fieldoffsets.viewmodelforclient             = PRVM_ED_FindFieldOffset("viewmodelforclient");
1636         prog->fieldoffsets.viewzoom                       = PRVM_ED_FindFieldOffset("viewzoom");
1637         prog->fieldoffsets.yaw_speed                      = PRVM_ED_FindFieldOffset("yaw_speed");
1638         prog->fieldoffsets.bouncefactor                   = PRVM_ED_FindFieldOffset("bouncefactor");
1639         prog->fieldoffsets.bouncestop                     = PRVM_ED_FindFieldOffset("bouncestop");
1640
1641         prog->fieldoffsets.solid                          = PRVM_ED_FindFieldOffset("solid");
1642         prog->fieldoffsets.movetype                       = PRVM_ED_FindFieldOffset("movetype");
1643         prog->fieldoffsets.modelindex                     = PRVM_ED_FindFieldOffset("modelindex");
1644         prog->fieldoffsets.mins                           = PRVM_ED_FindFieldOffset("mins");
1645         prog->fieldoffsets.maxs                           = PRVM_ED_FindFieldOffset("maxs");
1646         prog->fieldoffsets.mass                           = PRVM_ED_FindFieldOffset("mass");
1647         prog->fieldoffsets.origin                         = PRVM_ED_FindFieldOffset("origin");
1648         prog->fieldoffsets.velocity                       = PRVM_ED_FindFieldOffset("velocity");
1649         //prog->fieldoffsets.axis_forward                   = PRVM_ED_FindFieldOffset("axis_forward");
1650         //prog->fieldoffsets.axis_left                      = PRVM_ED_FindFieldOffset("axis_left");
1651         //prog->fieldoffsets.axis_up                        = PRVM_ED_FindFieldOffset("axis_up");
1652         //prog->fieldoffsets.spinvelocity                   = PRVM_ED_FindFieldOffset("spinvelocity");
1653         prog->fieldoffsets.angles                         = PRVM_ED_FindFieldOffset("angles");
1654         prog->fieldoffsets.avelocity                      = PRVM_ED_FindFieldOffset("avelocity");
1655         prog->fieldoffsets.aiment                         = PRVM_ED_FindFieldOffset("aiment");
1656         prog->fieldoffsets.enemy                          = PRVM_ED_FindFieldOffset("enemy");
1657         prog->fieldoffsets.jointtype                      = PRVM_ED_FindFieldOffset("jointtype");
1658         prog->fieldoffsets.movedir                        = PRVM_ED_FindFieldOffset("movedir");
1659
1660         prog->fieldoffsets.camera_transform               = PRVM_ED_FindFieldOffset("camera_transform");
1661         prog->fieldoffsets.userwavefunc_param0            = PRVM_ED_FindFieldOffset("userwavefunc_param0");
1662         prog->fieldoffsets.userwavefunc_param1            = PRVM_ED_FindFieldOffset("userwavefunc_param1");
1663         prog->fieldoffsets.userwavefunc_param2            = PRVM_ED_FindFieldOffset("userwavefunc_param2");
1664         prog->fieldoffsets.userwavefunc_param3            = PRVM_ED_FindFieldOffset("userwavefunc_param3");
1665
1666         prog->fieldoffsets.crypto_keyfp                   = PRVM_ED_FindFieldOffset("crypto_keyfp");
1667         prog->fieldoffsets.crypto_mykeyfp                 = PRVM_ED_FindFieldOffset("crypto_mykeyfp");
1668         prog->fieldoffsets.crypto_idfp                    = PRVM_ED_FindFieldOffset("crypto_idfp");
1669         prog->fieldoffsets.crypto_encryptmethod           = PRVM_ED_FindFieldOffset("crypto_encryptmethod");
1670         prog->fieldoffsets.crypto_signmethod              = PRVM_ED_FindFieldOffset("crypto_signmethod");
1671
1672         prog->funcoffsets.CSQC_ConsoleCommand             = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1673         prog->funcoffsets.CSQC_Ent_Remove                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1674         prog->funcoffsets.CSQC_Ent_Spawn                  = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn");
1675         prog->funcoffsets.CSQC_Ent_Update                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1676         prog->funcoffsets.CSQC_Event                      = PRVM_ED_FindFunctionOffset("CSQC_Event");
1677         prog->funcoffsets.CSQC_Event_Sound                = PRVM_ED_FindFunctionOffset("CSQC_Event_Sound");
1678         prog->funcoffsets.CSQC_Init                       = PRVM_ED_FindFunctionOffset("CSQC_Init");
1679         prog->funcoffsets.CSQC_InputEvent                 = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1680         prog->funcoffsets.CSQC_Parse_CenterPrint          = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1681         prog->funcoffsets.CSQC_Parse_Print                = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1682         prog->funcoffsets.CSQC_Parse_StuffCmd             = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1683         prog->funcoffsets.CSQC_Parse_TempEntity           = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1684         prog->funcoffsets.CSQC_Shutdown                   = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1685         prog->funcoffsets.CSQC_UpdateView                 = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1686         prog->funcoffsets.EndFrame                        = PRVM_ED_FindFunctionOffset("EndFrame");
1687         prog->funcoffsets.GameCommand                     = PRVM_ED_FindFunctionOffset("GameCommand");
1688         prog->funcoffsets.Gecko_Query                     = PRVM_ED_FindFunctionOffset("Gecko_Query");
1689         prog->funcoffsets.RestoreGame                     = PRVM_ED_FindFunctionOffset("RestoreGame");
1690         prog->funcoffsets.SV_ChangeTeam                   = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1691         prog->funcoffsets.SV_OnEntityNoSpawnFunction      = PRVM_ED_FindFunctionOffset("SV_OnEntityNoSpawnFunction");
1692         prog->funcoffsets.SV_OnEntityPostSpawnFunction    = PRVM_ED_FindFunctionOffset("SV_OnEntityPostSpawnFunction");
1693         prog->funcoffsets.SV_OnEntityPreSpawnFunction     = PRVM_ED_FindFunctionOffset("SV_OnEntityPreSpawnFunction");
1694         prog->funcoffsets.SV_ParseClientCommand           = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1695         prog->funcoffsets.SV_PausedTic                    = PRVM_ED_FindFunctionOffset("SV_PausedTic");
1696         prog->funcoffsets.SV_PlayerPhysics                = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1697         prog->funcoffsets.SV_Shutdown                     = PRVM_ED_FindFunctionOffset("SV_Shutdown");
1698         prog->funcoffsets.URI_Get_Callback                = PRVM_ED_FindFunctionOffset("URI_Get_Callback");
1699         prog->globaloffsets.SV_InitCmd                    = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1700         prog->globaloffsets.coop                          = PRVM_ED_FindGlobalOffset("coop");
1701         prog->globaloffsets.deathmatch                    = PRVM_ED_FindGlobalOffset("deathmatch");
1702         prog->globaloffsets.dmg_origin                    = PRVM_ED_FindGlobalOffset("dmg_origin");
1703         prog->globaloffsets.dmg_save                      = PRVM_ED_FindGlobalOffset("dmg_save");
1704         prog->globaloffsets.dmg_take                      = PRVM_ED_FindGlobalOffset("dmg_take");
1705         prog->globaloffsets.drawfont                      = PRVM_ED_FindGlobalOffset("drawfont");
1706         prog->globaloffsets.drawfontscale                 = PRVM_ED_FindGlobalOffset("drawfontscale");
1707         prog->globaloffsets.gettaginfo_forward            = PRVM_ED_FindGlobalOffset("gettaginfo_forward");
1708         prog->globaloffsets.gettaginfo_name               = PRVM_ED_FindGlobalOffset("gettaginfo_name");
1709         prog->globaloffsets.gettaginfo_offset             = PRVM_ED_FindGlobalOffset("gettaginfo_offset");
1710         prog->globaloffsets.gettaginfo_parent             = PRVM_ED_FindGlobalOffset("gettaginfo_parent");
1711         prog->globaloffsets.gettaginfo_right              = PRVM_ED_FindGlobalOffset("gettaginfo_right");
1712         prog->globaloffsets.gettaginfo_up                 = PRVM_ED_FindGlobalOffset("gettaginfo_up");
1713         prog->globaloffsets.transparent_offset            = PRVM_ED_FindGlobalOffset("transparent_offset");
1714         prog->globaloffsets.intermission                  = PRVM_ED_FindGlobalOffset("intermission");
1715         prog->globaloffsets.require_spawnfunc_prefix      = PRVM_ED_FindGlobalOffset("require_spawnfunc_prefix");
1716         prog->globaloffsets.sb_showscores                 = PRVM_ED_FindGlobalOffset("sb_showscores");
1717         prog->globaloffsets.self                          = PRVM_ED_FindGlobalOffset("self");
1718         prog->globaloffsets.serverdeltatime               = PRVM_ED_FindGlobalOffset("serverdeltatime");
1719         prog->globaloffsets.serverprevtime                = PRVM_ED_FindGlobalOffset("serverprevtime");
1720         prog->globaloffsets.servertime                    = PRVM_ED_FindGlobalOffset("servertime");
1721         prog->globaloffsets.time                          = PRVM_ED_FindGlobalOffset("time");
1722         prog->globaloffsets.trace_allsolid                = PRVM_ED_FindGlobalOffset("trace_allsolid");
1723         prog->globaloffsets.trace_dphitcontents           = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1724         prog->globaloffsets.trace_dphitq3surfaceflags     = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1725         prog->globaloffsets.trace_dphittexturename        = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1726         prog->globaloffsets.trace_dpstartcontents         = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1727         prog->globaloffsets.trace_endpos                  = PRVM_ED_FindGlobalOffset("trace_endpos");
1728         prog->globaloffsets.trace_ent                     = PRVM_ED_FindGlobalOffset("trace_ent");
1729         prog->globaloffsets.trace_fraction                = PRVM_ED_FindGlobalOffset("trace_fraction");
1730         prog->globaloffsets.trace_inopen                  = PRVM_ED_FindGlobalOffset("trace_inopen");
1731         prog->globaloffsets.trace_inwater                 = PRVM_ED_FindGlobalOffset("trace_inwater");
1732         prog->globaloffsets.trace_networkentity           = PRVM_ED_FindGlobalOffset("trace_networkentity");
1733         prog->globaloffsets.trace_plane_dist              = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1734         prog->globaloffsets.trace_plane_normal            = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1735         prog->globaloffsets.trace_startsolid              = PRVM_ED_FindGlobalOffset("trace_startsolid");
1736         prog->globaloffsets.v_forward                     = PRVM_ED_FindGlobalOffset("v_forward");
1737         prog->globaloffsets.v_right                       = PRVM_ED_FindGlobalOffset("v_right");
1738         prog->globaloffsets.v_up                          = PRVM_ED_FindGlobalOffset("v_up");
1739         prog->globaloffsets.view_angles                   = PRVM_ED_FindGlobalOffset("view_angles");
1740         prog->globaloffsets.view_punchangle               = PRVM_ED_FindGlobalOffset("view_punchangle");
1741         prog->globaloffsets.view_punchvector              = PRVM_ED_FindGlobalOffset("view_punchvector");
1742         prog->globaloffsets.worldstatus                   = PRVM_ED_FindGlobalOffset("worldstatus");
1743         prog->globaloffsets.particles_alphamin            = PRVM_ED_FindGlobalOffset("particles_alphamin");
1744         prog->globaloffsets.particles_alphamax            = PRVM_ED_FindGlobalOffset("particles_alphamax");
1745         prog->globaloffsets.particles_colormin            = PRVM_ED_FindGlobalOffset("particles_colormin");
1746         prog->globaloffsets.particles_colormax            = PRVM_ED_FindGlobalOffset("particles_colormax");
1747
1748         // menu qc only uses some functions, nothing else
1749         prog->funcoffsets.m_draw                          = PRVM_ED_FindFunctionOffset("m_draw");
1750         prog->funcoffsets.m_init                          = PRVM_ED_FindFunctionOffset("m_init");
1751         prog->funcoffsets.m_keydown                       = PRVM_ED_FindFunctionOffset("m_keydown");
1752         prog->funcoffsets.m_keyup                         = PRVM_ED_FindFunctionOffset("m_keyup");
1753         prog->funcoffsets.m_shutdown                      = PRVM_ED_FindFunctionOffset("m_shutdown");
1754         prog->funcoffsets.m_toggle                        = PRVM_ED_FindFunctionOffset("m_toggle");
1755         prog->funcoffsets.m_newmap                        = PRVM_ED_FindFunctionOffset("m_newmap");
1756 }
1757
1758 // not used
1759 /*
1760 typedef struct dpfield_s
1761 {
1762         int type;
1763         char *string;
1764 }
1765 dpfield_t;
1766
1767 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1768
1769 dpfield_t dpfields[] =
1770 {
1771 };
1772 */
1773
1774 /*
1775 ===============
1776 PRVM_ResetProg
1777 ===============
1778 */
1779
1780 #define PO_HASHSIZE 16384
1781 typedef struct po_string_s
1782 {
1783         char *key, *value;
1784         struct po_string_s *nextonhashchain;
1785 }
1786 po_string_t;
1787 typedef struct po_s
1788 {
1789         po_string_t *hashtable[PO_HASHSIZE];
1790 }
1791 po_t;
1792 void PRVM_PO_UnparseString(char *out, const char *in, size_t outsize)
1793 {
1794         for(;;)
1795         {
1796                 switch(*in)
1797                 {
1798                         case 0:
1799                                 *out++ = 0;
1800                                 return;
1801                         case '\a': if(outsize >= 2) { *out++ = '\\'; *out++ = 'a'; outsize -= 2; } break;
1802                         case '\b': if(outsize >= 2) { *out++ = '\\'; *out++ = 'b'; outsize -= 2; } break;
1803                         case '\t': if(outsize >= 2) { *out++ = '\\'; *out++ = 't'; outsize -= 2; } break;
1804                         case '\r': if(outsize >= 2) { *out++ = '\\'; *out++ = 'r'; outsize -= 2; } break;
1805                         case '\n': if(outsize >= 2) { *out++ = '\\'; *out++ = 'n'; outsize -= 2; } break;
1806                         case '\\': if(outsize >= 2) { *out++ = '\\'; *out++ = '\\'; outsize -= 2; } break;
1807                         case '"': if(outsize >= 2) { *out++ = '\\'; *out++ = '"'; outsize -= 2; } break;
1808                         default:
1809                                 if(*in >= 0 && *in <= 0x1F)
1810                                 {
1811                                         if(outsize >= 4)
1812                                         {
1813                                                 *out++ = '\\';
1814                                                 *out++ = '0' + ((*in & 0700) >> 6);
1815                                                 *out++ = '0' + ((*in & 0070) >> 3);
1816                                                 *out++ = '0' + ((*in & 0007));
1817                                                 outsize -= 4;
1818                                         }
1819                                 }
1820                                 else
1821                                 {
1822                                         if(outsize >= 1)
1823                                         {
1824                                                 *out++ = *in;
1825                                                 outsize -= 1;
1826                                         }
1827                                 }
1828                                 break;
1829                 }
1830                 ++in;
1831         }
1832 }
1833 void PRVM_PO_ParseString(char *out, const char *in, size_t outsize)
1834 {
1835         for(;;)
1836         {
1837                 switch(*in)
1838                 {
1839                         case 0:
1840                                 *out++ = 0;
1841                                 return;
1842                         case '\\':
1843                                 ++in;
1844                                 switch(*in)
1845                                 {
1846                                         case 'a': if(outsize > 0) { *out++ = '\a'; --outsize; } break;
1847                                         case 'b': if(outsize > 0) { *out++ = '\b'; --outsize; } break;
1848                                         case 't': if(outsize > 0) { *out++ = '\t'; --outsize; } break;
1849                                         case 'r': if(outsize > 0) { *out++ = '\r'; --outsize; } break;
1850                                         case 'n': if(outsize > 0) { *out++ = '\n'; --outsize; } break;
1851                                         case '\\': if(outsize > 0) { *out++ = '\\'; --outsize; } break;
1852                                         case '"': if(outsize > 0) { *out++ = '"'; --outsize; } break;
1853                                         case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
1854                                                 if(outsize > 0) 
1855                                                         *out = *in - '0';
1856                                                 ++in;
1857                                                 if(*in >= '0' && *in <= '7')
1858                                                 {
1859                                                         if(outsize > 0)
1860                                                                 *out = (*out << 3) | (*in - '0');
1861                                                         ++in;
1862                                                 }
1863                                                 if(*in >= '0' && *in <= '7')
1864                                                 {
1865                                                         if(outsize > 0)
1866                                                                 *out = (*out << 3) | (*in - '0');
1867                                                         ++in;
1868                                                 }
1869                                                 --in;
1870                                                 if(outsize > 0)
1871                                                 {
1872                                                         ++out;
1873                                                         --outsize;
1874                                                 }
1875                                                 break;
1876                                         default:
1877                                                 if(outsize > 0) { *out++ = *in; --outsize; }
1878                                                 break;
1879                                 }
1880                                 break;
1881                         default:
1882                                 if(outsize > 0)
1883                                 {
1884                                         *out++ = *in;
1885                                         --outsize;
1886                                 }
1887                                 break;
1888                 }
1889                 ++in;
1890         }
1891 }
1892 po_t *PRVM_PO_Load(const char *filename, mempool_t *pool)
1893 {
1894         po_t *po;
1895         const char *p, *q;
1896         int mode;
1897         char inbuf[MAX_INPUTLINE];
1898         char decodedbuf[MAX_INPUTLINE];
1899         size_t decodedpos;
1900         int hashindex;
1901         po_string_t thisstr;
1902         const char *buf = (const char *) FS_LoadFile(filename, pool, true, NULL);
1903
1904         if(!buf)
1905                 return NULL;
1906
1907         memset(&thisstr, 0, sizeof(thisstr)); // hush compiler warning
1908
1909         po = (po_t *)Mem_Alloc(pool, sizeof(*po));
1910         memset(po, 0, sizeof(*po));
1911
1912         p = buf;
1913         while(*p)
1914         {
1915                 if(*p == '#')
1916                 {
1917                         // skip to newline
1918                         p = strchr(p, '\n');
1919                         if(!p)
1920                                 break;
1921                         ++p;
1922                         continue;
1923                 }
1924                 if(*p == '\r' || *p == '\n')
1925                 {
1926                         ++p;
1927                         continue;
1928                 }
1929                 if(!strncmp(p, "msgid \"", 7))
1930                 {
1931                         mode = 0;
1932                         p += 6;
1933                 }
1934                 else if(!strncmp(p, "msgstr \"", 8))
1935                 {
1936                         mode = 1;
1937                         p += 7;
1938                 }
1939                 else
1940                 {
1941                         p = strchr(p, '\n');
1942                         if(!p)
1943                                 break;
1944                         ++p;
1945                         continue;
1946                 }
1947                 decodedpos = 0;
1948                 while(*p == '"')
1949                 {
1950                         ++p;
1951                         q = strchr(p, '\n');
1952                         if(!q)
1953                                 break;
1954                         if(*(q-1) == '\r')
1955                                 --q;
1956                         if(*(q-1) != '"')
1957                                 break;
1958                         if((size_t)(q - p) >= (size_t) sizeof(inbuf))
1959                                 break;
1960                         strlcpy(inbuf, p, q - p); // not - 1, because this adds a NUL
1961                         PRVM_PO_ParseString(decodedbuf + decodedpos, inbuf, sizeof(decodedbuf) - decodedpos);
1962                         decodedpos += strlen(decodedbuf + decodedpos);
1963                         if(*q == '\r')
1964                                 ++q;
1965                         if(*q == '\n')
1966                                 ++q;
1967                         p = q;
1968                 }
1969                 if(mode == 0)
1970                 {
1971                         if(thisstr.key)
1972                                 Mem_Free(thisstr.key);
1973                         thisstr.key = (char *)Mem_Alloc(pool, decodedpos + 1);
1974                         memcpy(thisstr.key, decodedbuf, decodedpos + 1);
1975                 }
1976                 else if(decodedpos > 0 && thisstr.key) // skip empty translation results
1977                 {
1978                         thisstr.value = (char *)Mem_Alloc(pool, decodedpos + 1);
1979                         memcpy(thisstr.value, decodedbuf, decodedpos + 1);
1980                         hashindex = CRC_Block((const unsigned char *) thisstr.key, strlen(thisstr.key)) % PO_HASHSIZE;
1981                         thisstr.nextonhashchain = po->hashtable[hashindex];
1982                         po->hashtable[hashindex] = (po_string_t *)Mem_Alloc(pool, sizeof(thisstr));
1983                         memcpy(po->hashtable[hashindex], &thisstr, sizeof(thisstr));
1984                         memset(&thisstr, 0, sizeof(thisstr));
1985                 }
1986         }
1987         
1988         Mem_Free((char *) buf);
1989         return po;
1990 }
1991 const char *PRVM_PO_Lookup(po_t *po, const char *str)
1992 {
1993         int hashindex = CRC_Block((const unsigned char *) str, strlen(str)) % PO_HASHSIZE;
1994         po_string_t *p = po->hashtable[hashindex];
1995         while(p)
1996         {
1997                 if(!strcmp(str, p->key))
1998                         return p->value;
1999                 p = p->nextonhashchain;
2000         }
2001         return NULL;
2002 }
2003 void PRVM_PO_Destroy(po_t *po)
2004 {
2005         int i;
2006         for(i = 0; i < PO_HASHSIZE; ++i)
2007         {
2008                 po_string_t *p = po->hashtable[i];
2009                 while(p)
2010                 {
2011                         po_string_t *q = p;
2012                         p = p->nextonhashchain;
2013                         Mem_Free(q->key);
2014                         Mem_Free(q->value);
2015                         Mem_Free(q);
2016                 }
2017         }
2018         Mem_Free(po);
2019 }
2020
2021 void PRVM_LeakTest(void);
2022 void PRVM_ResetProg(void)
2023 {
2024         PRVM_LeakTest();
2025         PRVM_GCALL(reset_cmd)();
2026         Mem_FreePool(&prog->progs_mempool);
2027         if(prog->po)
2028                 PRVM_PO_Destroy((po_t *) prog->po);
2029         memset(prog,0,sizeof(prvm_prog_t));
2030         prog->starttime = Sys_DoubleTime();
2031 }
2032
2033 /*
2034 ===============
2035 PRVM_LoadLNO
2036 ===============
2037 */
2038 void PRVM_LoadLNO( const char *progname ) {
2039         fs_offset_t filesize;
2040         unsigned char *lno;
2041         unsigned int *header;
2042         char filename[512];
2043
2044         FS_StripExtension( progname, filename, sizeof( filename ) );
2045         strlcat( filename, ".lno", sizeof( filename ) );
2046
2047         lno = FS_LoadFile( filename, tempmempool, false, &filesize );
2048         if( !lno ) {
2049                 return;
2050         }
2051
2052 /*
2053 <Spike>    SafeWrite (h, &lnotype, sizeof(int));
2054 <Spike>    SafeWrite (h, &version, sizeof(int));
2055 <Spike>    SafeWrite (h, &numglobaldefs, sizeof(int));
2056 <Spike>    SafeWrite (h, &numpr_globals, sizeof(int));
2057 <Spike>    SafeWrite (h, &numfielddefs, sizeof(int));
2058 <Spike>    SafeWrite (h, &numstatements, sizeof(int));
2059 <Spike>    SafeWrite (h, statement_linenums, numstatements*sizeof(int));
2060 */
2061         if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
2062                 Mem_Free(lno);
2063                 return;
2064         }
2065
2066         header = (unsigned int *) lno;
2067         if( header[ 0 ] == *(unsigned int *) "LNOF" &&
2068                 LittleLong( header[ 1 ] ) == 1 &&
2069                 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
2070                 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
2071                 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
2072                 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
2073         {
2074                 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
2075                 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
2076         }
2077         Mem_Free( lno );
2078 }
2079
2080 /*
2081 ===============
2082 PRVM_LoadProgs
2083 ===============
2084 */
2085 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
2086 {
2087         int i;
2088         dstatement_t *st;
2089         ddef_t *infielddefs;
2090         dfunction_t *dfunctions;
2091         fs_offset_t filesize;
2092
2093         if( prog->loaded ) {
2094                 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
2095         }
2096
2097         prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
2098         if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
2099                 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
2100         // TODO bounds check header fields (e.g. numstatements), they must never go behind end of file
2101
2102         Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
2103
2104         prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
2105
2106 // byte swap the header
2107         for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
2108                 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
2109
2110         if (prog->progs->version != PROG_VERSION)
2111                 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
2112         if (prog->progs->crc != prog->headercrc && prog->progs->crc != prog->headercrc2)
2113                 PRVM_ERROR ("%s: %s system vars have been modified (CRC of progs.dat systemvars %i != engine %i), progdefs.h is out of date", PRVM_NAME, filename, prog->progs->crc, prog->headercrc);
2114
2115         //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
2116         dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
2117
2118         if (prog->progs->ofs_strings + prog->progs->numstrings >= (int)filesize)
2119                 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
2120         prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
2121         prog->stringssize = prog->progs->numstrings;
2122
2123         prog->numknownstrings = 0;
2124         prog->maxknownstrings = 0;
2125         prog->knownstrings = NULL;
2126         prog->knownstrings_freeable = NULL;
2127
2128         Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
2129
2130         prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
2131
2132         // we need to expand the fielddefs list to include all the engine fields,
2133         // so allocate a new place for it
2134         infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
2135         //                                                                                              ( + DPFIELDS                       )
2136         prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
2137
2138         prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
2139
2140         prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
2141
2142         //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
2143         prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
2144
2145 // byte swap the lumps
2146         for (i=0 ; i<prog->progs->numstatements ; i++)
2147         {
2148                 prog->statements[i].op = LittleShort(prog->statements[i].op);
2149                 prog->statements[i].a = LittleShort(prog->statements[i].a);
2150                 prog->statements[i].b = LittleShort(prog->statements[i].b);
2151                 prog->statements[i].c = LittleShort(prog->statements[i].c);
2152         }
2153
2154         prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
2155         for (i = 0;i < prog->progs->numfunctions;i++)
2156         {
2157                 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
2158                 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
2159                 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
2160                 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
2161                 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
2162                 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
2163                 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
2164                 if(prog->functions[i].first_statement >= prog->progs->numstatements)
2165                         PRVM_ERROR("PRVM_LoadProgs: out of bounds function statement (function %d) in %s", i, PRVM_NAME);
2166                 // TODO bounds check parm_start, s_name, s_file, numparms, locals, parm_size
2167         }
2168
2169         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
2170         {
2171                 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
2172                 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
2173                 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
2174                 // TODO bounds check ofs, s_name
2175         }
2176
2177         // copy the progs fields to the new fields list
2178         for (i = 0;i < prog->progs->numfielddefs;i++)
2179         {
2180                 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
2181                 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
2182                         PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
2183                 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
2184                 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
2185                 // TODO bounds check ofs, s_name
2186         }
2187
2188         // append the required fields
2189         for (i = 0;i < (int) numrequiredfields;i++)
2190         {
2191                 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
2192                 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
2193                 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
2194                 // TODO bounds check ofs, s_name
2195                 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
2196                         prog->progs->entityfields += 3;
2197                 else
2198                         prog->progs->entityfields++;
2199                 prog->progs->numfielddefs++;
2200         }
2201         prog->entityfields = prog->progs->entityfields;
2202
2203         // check required functions
2204         for(i=0 ; i < numrequiredfunc ; i++)
2205                 if(PRVM_ED_FindFunction(required_func[i]) == 0)
2206                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
2207
2208         // check required globals
2209         for(i=0 ; i < numrequiredglobals ; i++)
2210                 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
2211                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
2212
2213         for (i=0 ; i<prog->progs->numglobals ; i++)
2214                 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
2215
2216         // LordHavoc: bounds check anything static
2217         for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
2218         {
2219                 switch (st->op)
2220                 {
2221                 case OP_IF:
2222                 case OP_IFNOT:
2223                         if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
2224                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
2225                         break;
2226                 case OP_GOTO:
2227                         if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
2228                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
2229                         break;
2230                 // global global global
2231                 case OP_ADD_F:
2232                 case OP_ADD_V:
2233                 case OP_SUB_F:
2234                 case OP_SUB_V:
2235                 case OP_MUL_F:
2236                 case OP_MUL_V:
2237                 case OP_MUL_FV:
2238                 case OP_MUL_VF:
2239                 case OP_DIV_F:
2240                 case OP_BITAND:
2241                 case OP_BITOR:
2242                 case OP_GE:
2243                 case OP_LE:
2244                 case OP_GT:
2245                 case OP_LT:
2246                 case OP_AND:
2247                 case OP_OR:
2248                 case OP_EQ_F:
2249                 case OP_EQ_V:
2250                 case OP_EQ_S:
2251                 case OP_EQ_E:
2252                 case OP_EQ_FNC:
2253                 case OP_NE_F:
2254                 case OP_NE_V:
2255                 case OP_NE_S:
2256                 case OP_NE_E:
2257                 case OP_NE_FNC:
2258                 case OP_ADDRESS:
2259                 case OP_LOAD_F:
2260                 case OP_LOAD_FLD:
2261                 case OP_LOAD_ENT:
2262                 case OP_LOAD_S:
2263                 case OP_LOAD_FNC:
2264                 case OP_LOAD_V:
2265                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
2266                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
2267                         break;
2268                 // global none global
2269                 case OP_NOT_F:
2270                 case OP_NOT_V:
2271                 case OP_NOT_S:
2272                 case OP_NOT_FNC:
2273                 case OP_NOT_ENT:
2274                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
2275                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
2276                         break;
2277                 // 2 globals
2278                 case OP_STOREP_F:
2279                 case OP_STOREP_ENT:
2280                 case OP_STOREP_FLD:
2281                 case OP_STOREP_S:
2282                 case OP_STOREP_FNC:
2283                 case OP_STORE_F:
2284                 case OP_STORE_ENT:
2285                 case OP_STORE_FLD:
2286                 case OP_STORE_S:
2287                 case OP_STORE_FNC:
2288                 case OP_STATE:
2289                 case OP_STOREP_V:
2290                 case OP_STORE_V:
2291                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
2292                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
2293                         break;
2294                 // 1 global
2295                 case OP_CALL0:
2296                 case OP_CALL1:
2297                 case OP_CALL2:
2298                 case OP_CALL3:
2299                 case OP_CALL4:
2300                 case OP_CALL5:
2301                 case OP_CALL6:
2302                 case OP_CALL7:
2303                 case OP_CALL8:
2304                 case OP_DONE:
2305                 case OP_RETURN:
2306                         if ((unsigned short) st->a >= prog->progs->numglobals)
2307                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
2308                         break;
2309                 default:
2310                         Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
2311                         break;
2312                 }
2313         }
2314         if(prog->progs->numstatements < 1)
2315         {
2316                 PRVM_ERROR("PRVM_LoadProgs: empty program in %s", PRVM_NAME);
2317         }
2318         else switch(prog->statements[prog->progs->numstatements - 1].op)
2319         {
2320                 case OP_RETURN:
2321                 case OP_GOTO:
2322                 case OP_DONE:
2323                         break;
2324                 default:
2325                         PRVM_ERROR("PRVM_LoadProgs: program may fall off the edge (does not end with RETURN, GOTO or DONE) in %s", PRVM_NAME);
2326                         break;
2327         }
2328
2329         PRVM_LoadLNO(filename);
2330
2331         PRVM_Init_Exec();
2332
2333         if(*prvm_language.string)
2334         // in CSQC we really shouldn't be able to change how stuff works... sorry for now
2335         // later idea: include a list of authorized .po file checksums with the csprogs
2336         {
2337                 qboolean deftrans = !!strcmp(PRVM_NAME, "client");
2338                 const char *realfilename = (strcmp(PRVM_NAME, "client") ? filename : sv.csqc_progname);
2339                 if(deftrans) // once we have dotranslate_ strings, ALWAYS use the opt-in method!
2340                 {
2341                         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
2342                         {
2343                                 const char *name;
2344                                 name = PRVM_GetString(prog->globaldefs[i].s_name);
2345                                 if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2346                                 if(name && !strncmp(name, "dotranslate_", 12))
2347                                 {
2348                                         deftrans = false;
2349                                         break;
2350                                 }
2351                         }
2352                 }
2353                 if(!strcmp(prvm_language.string, "dump"))
2354                 {
2355                         qfile_t *f = FS_OpenRealFile(va("%s.pot", realfilename), "w", false);
2356                         Con_Printf("Dumping to %s.pot\n", realfilename);
2357                         if(f)
2358                         {
2359                                 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
2360                                 {
2361                                         const char *name;
2362                                         name = PRVM_GetString(prog->globaldefs[i].s_name);
2363                                         if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12)))
2364                                         if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2365                                         {
2366                                                 prvm_eval_t *val = (prvm_eval_t *)(prog->globals.generic + prog->globaldefs[i].ofs);
2367                                                 const char *value = PRVM_GetString(val->string);
2368                                                 if(*value)
2369                                                 {
2370                                                         char buf[MAX_INPUTLINE];
2371                                                         PRVM_PO_UnparseString(buf, value, sizeof(buf));
2372                                                         FS_Printf(f, "msgid \"%s\"\nmsgstr \"\"\n\n", buf);
2373                                                 }
2374                                         }
2375                                 }
2376                                 FS_Close(f);
2377                         }
2378                 }
2379                 else
2380                 {
2381                         po_t *po = PRVM_PO_Load(va("%s.%s.po", realfilename, prvm_language.string), prog->progs_mempool);
2382                         if(po)
2383                         {
2384                                 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
2385                                 {
2386                                         const char *name;
2387                                         name = PRVM_GetString(prog->globaldefs[i].s_name);
2388                                         if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12)))
2389                                         if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2390                                         {
2391                                                 prvm_eval_t *val = (prvm_eval_t *)(prog->globals.generic + prog->globaldefs[i].ofs);
2392                                                 const char *value = PRVM_GetString(val->string);
2393                                                 if(*value)
2394                                                 {
2395                                                         value = PRVM_PO_Lookup(po, value);
2396                                                         if(value)
2397                                                                 val->string = PRVM_SetEngineString(value);
2398                                                 }
2399                                         }
2400                                 }
2401                         }
2402                 }
2403         }
2404
2405         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
2406         {
2407                 const char *name;
2408                 name = PRVM_GetString(prog->globaldefs[i].s_name);
2409                 //Con_Printf("found var %s\n", name);
2410                 if(name
2411                         && !strncmp(name, "autocvar_", 9)
2412                         && !(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
2413                 )
2414                 {
2415                         prvm_eval_t *val = (prvm_eval_t *)(prog->globals.generic + prog->globaldefs[i].ofs);
2416                         cvar_t *cvar = Cvar_FindVar(name + 9);
2417                         //Con_Printf("PRVM_LoadProgs: autocvar global %s in %s, processing...\n", name, PRVM_NAME);
2418                         if(!cvar)
2419                         {
2420                                 const char *value;
2421                                 char buf[64];
2422                                 Con_DPrintf("PRVM_LoadProgs: no cvar for autocvar global %s in %s, creating...\n", name, PRVM_NAME);
2423                                 switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL)
2424                                 {
2425                                         case ev_float:
2426                                                 if((float)((int)(val->_float)) == val->_float)
2427                                                         dpsnprintf(buf, sizeof(buf), "%i", (int)(val->_float));
2428                                                 else
2429                                                         dpsnprintf(buf, sizeof(buf), "%.9g", val->_float);
2430                                                 value = buf;
2431                                                 break;
2432                                         case ev_vector:
2433                                                 dpsnprintf(buf, sizeof(buf), "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]); value = buf;
2434                                                 break;
2435                                         case ev_string:
2436                                                 value = PRVM_GetString(val->string);
2437                                                 break;
2438                                         default:
2439                                                 Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, PRVM_NAME);
2440                                                 goto fail;
2441                                 }
2442                                 cvar = Cvar_Get(name + 9, value, 0, NULL);
2443                                 if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2444                                 {
2445                                         val->string = PRVM_SetEngineString(cvar->string);
2446                                         cvar->globaldefindex_stringno[prog - prog_list] = val->string;
2447                                 }
2448                                 if(!cvar)
2449                                         PRVM_ERROR("PRVM_LoadProgs: could not create cvar for autocvar global %s in %s", name, PRVM_NAME);
2450                                 cvar->globaldefindex_progid[prog - prog_list] = prog->id;
2451                                 cvar->globaldefindex[prog - prog_list] = i;
2452                         }
2453                         else if((cvar->flags & CVAR_PRIVATE) == 0)
2454                         {
2455                                 // MUST BE SYNCED WITH cvar.c Cvar_Set
2456                                 int j;
2457                                 const char *s;
2458                                 switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL)
2459                                 {
2460                                         case ev_float:
2461                                                 val->_float = cvar->value;
2462                                                 break;
2463                                         case ev_vector:
2464                                                 s = cvar->string;
2465                                                 VectorClear(val->vector);
2466                                                 for (j = 0;j < 3;j++)
2467                                                 {
2468                                                         while (*s && ISWHITESPACE(*s))
2469                                                                 s++;
2470                                                         if (!*s)
2471                                                                 break;
2472                                                         val->vector[j] = atof(s);
2473                                                         while (!ISWHITESPACE(*s))
2474                                                                 s++;
2475                                                         if (!*s)
2476                                                                 break;
2477                                                 }
2478                                                 break;
2479                                         case ev_string:
2480                                                 val->string = PRVM_SetEngineString(cvar->string);
2481                                                 cvar->globaldefindex_stringno[prog - prog_list] = val->string;
2482                                                 break;
2483                                         default:
2484                                                 Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, PRVM_NAME);
2485                                                 goto fail;
2486                                 }
2487                                 cvar->globaldefindex_progid[prog - prog_list] = prog->id;
2488                                 cvar->globaldefindex[prog - prog_list] = i;
2489                         }
2490                         else
2491                                 Con_Printf("PRVM_LoadProgs: private cvar for autocvar global %s in %s\n", name, PRVM_NAME);
2492                 }
2493 fail:
2494                 ;
2495         }
2496
2497         prog->loaded = TRUE;
2498
2499         // set flags & ddef_ts in prog
2500
2501         prog->flag = 0;
2502
2503         PRVM_FindOffsets();
2504
2505         PRVM_GCALL(init_cmd)();
2506
2507         // init mempools
2508         PRVM_MEM_Alloc();
2509 }
2510
2511
2512 void PRVM_Fields_f (void)
2513 {
2514         int i, j, ednum, used, usedamount;
2515         int *counts;
2516         char tempstring[MAX_INPUTLINE], tempstring2[260];
2517         const char *name;
2518         prvm_edict_t *ed;
2519         ddef_t *d;
2520         int *v;
2521
2522         // TODO
2523         /*
2524         if (!sv.active)
2525         {
2526                 Con_Print("no progs loaded\n");
2527                 return;
2528         }
2529         */
2530
2531         if(Cmd_Argc() != 2)
2532         {
2533                 Con_Print("prvm_fields <program name>\n");
2534                 return;
2535         }
2536
2537         PRVM_Begin;
2538         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
2539                 return;
2540
2541         counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
2542         for (ednum = 0;ednum < prog->max_edicts;ednum++)
2543         {
2544                 ed = PRVM_EDICT_NUM(ednum);
2545                 if (ed->priv.required->free)
2546                         continue;
2547                 for (i = 1;i < prog->progs->numfielddefs;i++)
2548                 {
2549                         d = &prog->fielddefs[i];
2550                         name = PRVM_GetString(d->s_name);
2551                         if (name[strlen(name)-2] == '_')
2552                                 continue;       // skip _x, _y, _z vars
2553                         v = (int *)(ed->fields.vp + d->ofs);
2554                         // if the value is still all 0, skip the field
2555                         for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
2556                         {
2557                                 if (v[j])
2558                                 {
2559                                         counts[i]++;
2560                                         break;
2561                                 }
2562                         }
2563                 }
2564         }
2565         used = 0;
2566         usedamount = 0;
2567         tempstring[0] = 0;
2568         for (i = 0;i < prog->progs->numfielddefs;i++)
2569         {
2570                 d = &prog->fielddefs[i];
2571                 name = PRVM_GetString(d->s_name);
2572                 if (name[strlen(name)-2] == '_')
2573                         continue;       // skip _x, _y, _z vars
2574                 switch(d->type & ~DEF_SAVEGLOBAL)
2575                 {
2576                 case ev_string:
2577                         strlcat(tempstring, "string   ", sizeof(tempstring));
2578                         break;
2579                 case ev_entity:
2580                         strlcat(tempstring, "entity   ", sizeof(tempstring));
2581                         break;
2582                 case ev_function:
2583                         strlcat(tempstring, "function ", sizeof(tempstring));
2584                         break;
2585                 case ev_field:
2586                         strlcat(tempstring, "field    ", sizeof(tempstring));
2587                         break;
2588                 case ev_void:
2589                         strlcat(tempstring, "void     ", sizeof(tempstring));
2590                         break;
2591                 case ev_float:
2592                         strlcat(tempstring, "float    ", sizeof(tempstring));
2593                         break;
2594                 case ev_vector:
2595                         strlcat(tempstring, "vector   ", sizeof(tempstring));
2596                         break;
2597                 case ev_pointer:
2598                         strlcat(tempstring, "pointer  ", sizeof(tempstring));
2599                         break;
2600                 default:
2601                         dpsnprintf (tempstring2, sizeof(tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
2602                         strlcat(tempstring, tempstring2, sizeof(tempstring));
2603                         break;
2604                 }
2605                 if (strlen(name) > sizeof(tempstring2)-4)
2606                 {
2607                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
2608                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
2609                         tempstring2[sizeof(tempstring2)-1] = 0;
2610                         name = tempstring2;
2611                 }
2612                 strlcat(tempstring, name, sizeof(tempstring));
2613                 for (j = (int)strlen(name);j < 25;j++)
2614                         strlcat(tempstring, " ", sizeof(tempstring));
2615                 dpsnprintf(tempstring2, sizeof(tempstring2), "%5d", counts[i]);
2616                 strlcat(tempstring, tempstring2, sizeof(tempstring));
2617                 strlcat(tempstring, "\n", sizeof(tempstring));
2618                 if (strlen(tempstring) >= sizeof(tempstring)/2)
2619                 {
2620                         Con_Print(tempstring);
2621                         tempstring[0] = 0;
2622                 }
2623                 if (counts[i])
2624                 {
2625                         used++;
2626                         usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
2627                 }
2628         }
2629         Mem_Free(counts);
2630         Con_Printf("%s: %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", PRVM_NAME, prog->progs->entityfields, used, prog->progs->entityfields * 4, usedamount * 4, prog->max_edicts, prog->progs->entityfields * 4 * prog->max_edicts, usedamount * 4 * prog->max_edicts);
2631
2632         PRVM_End;
2633 }
2634
2635 void PRVM_Globals_f (void)
2636 {
2637         int i;
2638         const char *wildcard;
2639         int numculled;
2640                 numculled = 0;
2641         // TODO
2642         /*if (!sv.active)
2643         {
2644                 Con_Print("no progs loaded\n");
2645                 return;
2646         }*/
2647         if(Cmd_Argc () < 2 || Cmd_Argc() > 3)
2648         {
2649                 Con_Print("prvm_globals <program name> <optional name wildcard>\n");
2650                 return;
2651         }
2652
2653         PRVM_Begin;
2654         if(!PRVM_SetProgFromString (Cmd_Argv (1)))
2655                 return;
2656
2657         if( Cmd_Argc() == 3)
2658                 wildcard = Cmd_Argv(2);
2659         else
2660                 wildcard = NULL;
2661
2662         Con_Printf("%s :", PRVM_NAME);
2663
2664         for (i = 0;i < prog->progs->numglobaldefs;i++)
2665         {
2666                 if(wildcard)
2667                         if( !matchpattern( PRVM_GetString(prog->globaldefs[i].s_name), wildcard, 1) )
2668                         {
2669                                 numculled++;
2670                                 continue;
2671                         }
2672                 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
2673         }
2674         Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->progs->numglobals, numculled, prog->progs->numglobals * 4);
2675
2676         PRVM_End;
2677 }
2678
2679 /*
2680 ===============
2681 PRVM_Global
2682 ===============
2683 */
2684 void PRVM_Global_f(void)
2685 {
2686         ddef_t *global;
2687         if( Cmd_Argc() != 3 ) {
2688                 Con_Printf( "prvm_global <program name> <global name>\n" );
2689                 return;
2690         }
2691
2692         PRVM_Begin;
2693         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2694                 return;
2695
2696         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2697         if( !global )
2698                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2699         else
2700                 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
2701         PRVM_End;
2702 }
2703
2704 /*
2705 ===============
2706 PRVM_GlobalSet
2707 ===============
2708 */
2709 void PRVM_GlobalSet_f(void)
2710 {
2711         ddef_t *global;
2712         if( Cmd_Argc() != 4 ) {
2713                 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
2714                 return;
2715         }
2716
2717         PRVM_Begin;
2718         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2719                 return;
2720
2721         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2722         if( !global )
2723                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2724         else
2725                 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3), true );
2726         PRVM_End;
2727 }
2728
2729 /*
2730 ===============
2731 PRVM_Init
2732 ===============
2733 */
2734 void PRVM_Init (void)
2735 {
2736         Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
2737         Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
2738         Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
2739         Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
2740         Cmd_AddCommand ("prvm_childprofile", PRVM_ChildProfile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu), sorted by time taken in function with child calls");
2741         Cmd_AddCommand ("prvm_callprofile", PRVM_CallProfile_f, "prints execution statistics about the most time consuming QuakeC calls from the engine in the selected VM (server, client, menu)");
2742         Cmd_AddCommand ("prvm_fields", PRVM_Fields_f, "prints usage statistics on properties (how many entities have non-zero values) in the selected VM (server, client, menu)");
2743         Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
2744         Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
2745         Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
2746         Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f, "changes value of a specified property of a specified entity in the selected VM (server, client, menu)");
2747         Cmd_AddCommand ("prvm_edictget", PRVM_ED_EdictGet_f, "retrieves the value of a specified property of a specified entity in the selected VM (server, client menu) into a cvar or to the console");
2748         Cmd_AddCommand ("prvm_globalget", PRVM_ED_GlobalGet_f, "retrieves the value of a specified global variable in the selected VM (server, client menu) into a cvar or to the console");
2749         Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
2750         Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
2751         Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
2752         Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
2753
2754         Cvar_RegisterVariable (&prvm_language);
2755         Cvar_RegisterVariable (&prvm_traceqc);
2756         Cvar_RegisterVariable (&prvm_statementprofiling);
2757         Cvar_RegisterVariable (&prvm_timeprofiling);
2758         Cvar_RegisterVariable (&prvm_backtraceforwarnings);
2759         Cvar_RegisterVariable (&prvm_leaktest);
2760         Cvar_RegisterVariable (&prvm_leaktest_ignore_classnames);
2761         Cvar_RegisterVariable (&prvm_errordump);
2762         Cvar_RegisterVariable (&prvm_reuseedicts_startuptime);
2763         Cvar_RegisterVariable (&prvm_reuseedicts_neverinsameframe);
2764
2765         // COMMANDLINEOPTION: PRVM: -norunaway disables the runaway loop check (it might be impossible to exit DarkPlaces if used!)
2766         prvm_runawaycheck = !COM_CheckParm("-norunaway");
2767
2768         //VM_Cmd_Init();
2769 }
2770
2771 /*
2772 ===============
2773 PRVM_InitProg
2774 ===============
2775 */
2776 void PRVM_InitProg(int prognr)
2777 {
2778         static unsigned int progid = 0;
2779
2780         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
2781                 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
2782
2783         prog = &prog_list[prognr];
2784
2785         if(prog->loaded)
2786                 PRVM_ResetProg();
2787
2788         memset(prog, 0, sizeof(prvm_prog_t));
2789         prog->starttime = Sys_DoubleTime();
2790         prog->id = ++progid;
2791
2792         prog->error_cmd = Host_Error;
2793         prog->leaktest_active = prvm_leaktest.integer != 0;
2794 }
2795
2796 int PRVM_GetProgNr(void)
2797 {
2798         return prog - prog_list;
2799 }
2800
2801 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
2802 {
2803         return _Mem_Alloc(prog->progs_mempool, NULL, buffersize, 16, filename, fileline);
2804 }
2805
2806 void _PRVM_Free(void *buffer, const char *filename, int fileline)
2807 {
2808         _Mem_Free(buffer, filename, fileline);
2809 }
2810
2811 void _PRVM_FreeAll(const char *filename, int fileline)
2812 {
2813         prog->progs = NULL;
2814         prog->fielddefs = NULL;
2815         prog->functions = NULL;
2816         _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
2817 }
2818
2819 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
2820 unsigned int PRVM_EDICT_NUM_ERROR(unsigned int n, const char *filename, int fileline)
2821 {
2822         PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
2823         return 0;
2824 }
2825
2826 sizebuf_t vm_tempstringsbuf;
2827 #define PRVM_KNOWNSTRINGBASE 0x40000000
2828
2829 const char *PRVM_GetString(int num)
2830 {
2831         if (num < 0)
2832         {
2833                 // invalid
2834                 VM_Warning("PRVM_GetString: Invalid string offset (%i < 0)\n", num);
2835                 return "";
2836         }
2837         else if (num < prog->stringssize)
2838         {
2839                 // constant string from progs.dat
2840                 return prog->strings + num;
2841         }
2842         else if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2843         {
2844                 // tempstring returned by engine to QC (becomes invalid after returning to engine)
2845                 num -= prog->stringssize;
2846                 if (num < vm_tempstringsbuf.cursize)
2847                         return (char *)vm_tempstringsbuf.data + num;
2848                 else
2849                 {
2850                         VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2851                         return "";
2852                 }
2853         }
2854         else if (num & PRVM_KNOWNSTRINGBASE)
2855         {
2856                 // allocated string
2857                 num = num - PRVM_KNOWNSTRINGBASE;
2858                 if (num >= 0 && num < prog->numknownstrings)
2859                 {
2860                         if (!prog->knownstrings[num])
2861                         {
2862                                 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
2863                                 return "";
2864                         }
2865                         return prog->knownstrings[num];
2866                 }
2867                 else
2868                 {
2869                         VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
2870                         return "";
2871                 }
2872         }
2873         else
2874         {
2875                 // invalid string offset
2876                 VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
2877                 return "";
2878         }
2879 }
2880
2881 const char *PRVM_ChangeEngineString(int i, const char *s)
2882 {
2883         const char *old;
2884         i = i - PRVM_KNOWNSTRINGBASE;
2885         if(i < 0 || i >= prog->numknownstrings)
2886                 PRVM_ERROR("PRVM_ChangeEngineString: s is not an engine string");
2887         old = prog->knownstrings[i];
2888         prog->knownstrings[i] = s;
2889         return old;
2890 }
2891
2892 int PRVM_SetEngineString(const char *s)
2893 {
2894         int i;
2895         if (!s)
2896                 return 0;
2897         if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2898                 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2899         // if it's in the tempstrings area, use a reserved range
2900         // (otherwise we'd get millions of useless string offsets cluttering the database)
2901         if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2902 #if 1
2903                 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2904 #endif
2905         // see if it's a known string address
2906         for (i = 0;i < prog->numknownstrings;i++)
2907                 if (prog->knownstrings[i] == s)
2908                         return PRVM_KNOWNSTRINGBASE + i;
2909         // new unknown engine string
2910         if (developer_insane.integer)
2911                 Con_DPrintf("new engine string %p = \"%s\"\n", s, s);
2912         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2913                 if (!prog->knownstrings[i])
2914                         break;
2915         if (i >= prog->numknownstrings)
2916         {
2917                 if (i >= prog->maxknownstrings)
2918                 {
2919                         const char **oldstrings = prog->knownstrings;
2920                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2921                         const char **oldstrings_origin = prog->knownstrings_origin;
2922                         prog->maxknownstrings += 128;
2923                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2924                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2925                         if(prog->leaktest_active)
2926                                 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2927                         if (prog->numknownstrings)
2928                         {
2929                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2930                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2931                                 if(prog->leaktest_active)
2932                                         memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
2933                         }
2934                 }
2935                 prog->numknownstrings++;
2936         }
2937         prog->firstfreeknownstring = i + 1;
2938         prog->knownstrings[i] = s;
2939         prog->knownstrings_freeable[i] = false;
2940         if(prog->leaktest_active)
2941                 prog->knownstrings_origin[i] = NULL;
2942         return PRVM_KNOWNSTRINGBASE + i;
2943 }
2944
2945 // temp string handling
2946
2947 // all tempstrings go into this buffer consecutively, and it is reset
2948 // whenever PRVM_ExecuteProgram returns to the engine
2949 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2950 //  restores it on return, so multiple recursive calls can share the same
2951 //  buffer)
2952 // the buffer size is automatically grown as needed
2953
2954 int PRVM_SetTempString(const char *s)
2955 {
2956         int size;
2957         char *t;
2958         if (!s)
2959                 return 0;
2960         size = (int)strlen(s) + 1;
2961         if (developer_insane.integer)
2962                 Con_DPrintf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2963         if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2964         {
2965                 sizebuf_t old = vm_tempstringsbuf;
2966                 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2967                         PRVM_ERROR("PRVM_SetTempString: ran out of tempstring memory!  (refusing to grow tempstring buffer over 256MB, cursize %i, size %i)\n", vm_tempstringsbuf.cursize, size);
2968                 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2969                 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2970                         vm_tempstringsbuf.maxsize *= 2;
2971                 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2972                 {
2973                         Con_DPrintf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2974                         vm_tempstringsbuf.data = (unsigned char *) Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2975                         if (old.cursize)
2976                                 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2977                         if (old.data)
2978                                 Mem_Free(old.data);
2979                 }
2980         }
2981         t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2982         memcpy(t, s, size);
2983         vm_tempstringsbuf.cursize += size;
2984         return PRVM_SetEngineString(t);
2985 }
2986
2987 int PRVM_AllocString(size_t bufferlength, char **pointer)
2988 {
2989         int i;
2990         if (!bufferlength)
2991                 return 0;
2992         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2993                 if (!prog->knownstrings[i])
2994                         break;
2995         if (i >= prog->numknownstrings)
2996         {
2997                 if (i >= prog->maxknownstrings)
2998                 {
2999                         const char **oldstrings = prog->knownstrings;
3000                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
3001                         const char **oldstrings_origin = prog->knownstrings_origin;
3002                         prog->maxknownstrings += 128;
3003                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
3004                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
3005                         if(prog->leaktest_active)
3006                                 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
3007                         if (prog->numknownstrings)
3008                         {
3009                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
3010                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
3011                                 if(prog->leaktest_active)
3012                                         memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
3013                         }
3014                         if (oldstrings)
3015                                 Mem_Free((char **)oldstrings);
3016                         if (oldstrings_freeable)
3017                                 Mem_Free((unsigned char *)oldstrings_freeable);
3018                         if (oldstrings_origin)
3019                                 Mem_Free((char **)oldstrings_origin);
3020                 }
3021                 prog->numknownstrings++;
3022         }
3023         prog->firstfreeknownstring = i + 1;
3024         prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
3025         prog->knownstrings_freeable[i] = true;
3026         if(prog->leaktest_active)
3027                 prog->knownstrings_origin[i] = PRVM_AllocationOrigin();
3028         if (pointer)
3029                 *pointer = (char *)(prog->knownstrings[i]);
3030         return PRVM_KNOWNSTRINGBASE + i;
3031 }
3032
3033 void PRVM_FreeString(int num)
3034 {
3035         if (num == 0)
3036                 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
3037         else if (num >= 0 && num < prog->stringssize)
3038                 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
3039         else if (num >= PRVM_KNOWNSTRINGBASE && num < PRVM_KNOWNSTRINGBASE + prog->numknownstrings)
3040         {
3041                 num = num - PRVM_KNOWNSTRINGBASE;
3042                 if (!prog->knownstrings[num])
3043                         PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
3044                 if (!prog->knownstrings_freeable[num])
3045                         PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
3046                 PRVM_Free((char *)prog->knownstrings[num]);
3047                 if(prog->leaktest_active)
3048                         if(prog->knownstrings_origin[num])
3049                                 PRVM_Free((char *)prog->knownstrings_origin[num]);
3050                 prog->knownstrings[num] = NULL;
3051                 prog->knownstrings_freeable[num] = false;
3052                 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
3053         }
3054         else
3055                 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);
3056 }
3057
3058 static qboolean PRVM_IsStringReferenced(string_t string)
3059 {
3060         int i, j;
3061
3062         for (i = 0;i < prog->progs->numglobaldefs;i++)
3063         {
3064                 ddef_t *d = &prog->globaldefs[i];
3065                 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
3066                         continue;
3067                 if(string == ((prvm_eval_t *) &prog->globals.generic[d->ofs])->string)
3068                         return true;
3069         }
3070
3071         for(j = 0; j < prog->num_edicts; ++j)
3072         {
3073                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3074                 if (ed->priv.required->free)
3075                         continue;
3076                 for (i=0; i<prog->progs->numfielddefs; ++i)
3077                 {
3078                         ddef_t *d = &prog->fielddefs[i];
3079                         if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
3080                                 continue;
3081                         if(string == ((prvm_eval_t *) &ed->fields.vp[d->ofs])->string)
3082                                 return true;
3083                 }
3084         }
3085
3086         return false;
3087 }
3088
3089 static qboolean PRVM_IsEdictRelevant(prvm_edict_t *edict)
3090 {
3091         if(PRVM_NUM_FOR_EDICT(edict) <= prog->reserved_edicts)
3092                 return true; // world or clients
3093         switch(prog - prog_list)
3094         {
3095                 case PRVM_SERVERPROG:
3096                         {
3097                                 entvars_t *ev = edict->fields.server;
3098                                 if(ev->solid) // can block other stuff, or is a trigger?
3099                                         return true;
3100                                 if(ev->modelindex) // visible ent?
3101                                         return true;
3102                                 if(ev->effects) // particle effect?
3103                                         return true;
3104                                 if(ev->think) // has a think function?
3105                                         if(ev->nextthink > 0) // that actually will eventually run?
3106                                                 return true;
3107                                 if(ev->takedamage)
3108                                         return true;
3109                                 if(*prvm_leaktest_ignore_classnames.string)
3110                                 {
3111                                         if(strstr(va(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(ev->classname))))
3112                                                 return true;
3113                                 }
3114                         }
3115                         break;
3116                 case PRVM_CLIENTPROG:
3117                         {
3118                                 // TODO someone add more stuff here
3119                                 cl_entvars_t *ev = edict->fields.client;
3120                                 if(ev->entnum) // csqc networked
3121                                         return true;
3122                                 if(ev->modelindex) // visible ent?
3123                                         return true;
3124                                 if(ev->effects) // particle effect?
3125                                         return true;
3126                                 if(ev->think) // has a think function?
3127                                         if(ev->nextthink > 0) // that actually will eventually run?
3128                                                 return true;
3129                                 if(*prvm_leaktest_ignore_classnames.string)
3130                                 {
3131                                         if(strstr(va(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(ev->classname))))
3132                                                 return true;
3133                                 }
3134                         }
3135                         break;
3136                 case PRVM_MENUPROG:
3137                         // menu prog does not have classnames
3138                         break;
3139         }
3140         return false;
3141 }
3142
3143 static qboolean PRVM_IsEdictReferenced(prvm_edict_t *edict, int mark)
3144 {
3145         int i, j;
3146         int edictnum = PRVM_NUM_FOR_EDICT(edict);
3147         const char *targetname = NULL;
3148
3149         switch(prog - prog_list)
3150         {
3151                 case PRVM_SERVERPROG:
3152                         targetname = PRVM_GetString(edict->fields.server->targetname);
3153                         break;
3154         }
3155
3156         if(targetname)
3157                 if(!*targetname) // ""
3158                         targetname = NULL;
3159
3160         for (i = 0;i < prog->progs->numglobaldefs;i++)
3161         {
3162                 ddef_t *d = &prog->globaldefs[i];
3163                 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
3164                         continue;
3165                 if(edictnum == ((prvm_eval_t *) &prog->globals.generic[d->ofs])->edict)
3166                         return true;
3167         }
3168
3169         for(j = 0; j < prog->num_edicts; ++j)
3170         {
3171                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3172                 if (ed->priv.required->mark < mark)
3173                         continue;
3174                 if(ed == edict)
3175                         continue;
3176                 if(targetname)
3177                 {
3178                         const char *target = PRVM_GetString(ed->fields.server->target);
3179                         if(target)
3180                                 if(!strcmp(target, targetname))
3181                                         return true;
3182                 }
3183                 for (i=0; i<prog->progs->numfielddefs; ++i)
3184                 {
3185                         ddef_t *d = &prog->fielddefs[i];
3186                         if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
3187                                 continue;
3188                         if(edictnum == ((prvm_eval_t *) &ed->fields.vp[d->ofs])->edict)
3189                                 return true;
3190                 }
3191         }
3192
3193         return false;
3194 }
3195
3196 static void PRVM_MarkReferencedEdicts(void)
3197 {
3198         int j;
3199         qboolean found_new;
3200         int stage;
3201
3202         for(j = 0; j < prog->num_edicts; ++j)
3203         {
3204                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3205                 if(ed->priv.required->free)
3206                         continue;
3207                 ed->priv.required->mark = PRVM_IsEdictRelevant(ed) ? 1 : 0;
3208         }
3209
3210         stage = 1;
3211         do
3212         {
3213                 found_new = false;
3214                 for(j = 0; j < prog->num_edicts; ++j)
3215                 {
3216                         prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3217                         if(ed->priv.required->free)
3218                                 continue;
3219                         if(ed->priv.required->mark)
3220                                 continue;
3221                         if(PRVM_IsEdictReferenced(ed, stage))
3222                         {
3223                                 ed->priv.required->mark = stage + 1;
3224                                 found_new = true;
3225                         }
3226                 }
3227                 ++stage;
3228         }
3229         while(found_new);
3230         Con_DPrintf("leak check used %d stages to find all references\n", stage);
3231 }
3232
3233 void PRVM_LeakTest(void)
3234 {
3235         int i, j;
3236         qboolean leaked = false;
3237
3238         if(!prog->leaktest_active)
3239                 return;
3240
3241         // 1. Strings
3242         for (i = 0; i < prog->numknownstrings; ++i)
3243         {
3244                 if(prog->knownstrings[i])
3245                 if(prog->knownstrings_freeable[i])
3246                 if(prog->knownstrings_origin[i])
3247                 if(!PRVM_IsStringReferenced(PRVM_KNOWNSTRINGBASE + i))
3248                 {
3249                         Con_Printf("Unreferenced string found!\n  Value: %s\n  Origin: %s\n", prog->knownstrings[i], prog->knownstrings_origin[i]);
3250                         leaked = true;
3251                 }
3252         }
3253
3254         // 2. Edicts
3255         PRVM_MarkReferencedEdicts();
3256         for(j = 0; j < prog->num_edicts; ++j)
3257         {
3258                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3259                 if(ed->priv.required->free)
3260                         continue;
3261                 if(!ed->priv.required->mark)
3262                 if(ed->priv.required->allocation_origin)
3263                 {
3264                         Con_Printf("Unreferenced edict found!\n  Allocated at: %s\n", ed->priv.required->allocation_origin);
3265                         PRVM_ED_Print(ed, NULL);
3266                         Con_Print("\n");
3267                         leaked = true;
3268                 }
3269         }
3270
3271         for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); ++i)
3272         {
3273                 prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
3274                 if(stringbuffer)
3275                 if(stringbuffer->origin)
3276                 {
3277                         Con_Printf("Open string buffer handle found!\n  Allocated at: %s\n", stringbuffer->origin);
3278                         leaked = true;
3279                 }
3280         }
3281
3282         for(i = 0; i < PRVM_MAX_OPENFILES; ++i)
3283         {
3284                 if(prog->openfiles[i])
3285                 if(prog->openfiles_origin[i])
3286                 {
3287                         Con_Printf("Open file handle found!\n  Allocated at: %s\n", prog->openfiles_origin[i]);
3288                         leaked = true;
3289                 }
3290         }
3291
3292         for(i = 0; i < PRVM_MAX_OPENSEARCHES; ++i)
3293         {
3294                 if(prog->opensearches[i])
3295                 if(prog->opensearches_origin[i])
3296                 {
3297                         Con_Printf("Open search handle found!\n  Allocated at: %s\n", prog->opensearches_origin[i]);
3298                         leaked = true;
3299                 }
3300         }
3301
3302         if(!leaked)
3303                 Con_Printf("Congratulations. No leaks found.\n");
3304 }