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