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