]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_edict.c
memset arrays before writing skeletal vertices into them (as the code did long ago...
[divverent/darkplaces.git] / prvm_edict.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // AK new vm
21
22 #include "quakedef.h"
23 #include "progsvm.h"
24
25 prvm_prog_t *prog;
26
27 static prvm_prog_t prog_list[PRVM_MAXPROGS];
28
29 int             prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
30
31 ddef_t *PRVM_ED_FieldAtOfs(int ofs);
32 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s);
33
34 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
35 cvar_t prvm_boundscheck = {0, "prvm_boundscheck", "1", "enables detection of out of bounds memory access in the QuakeC code being run (in other words, prevents really exceedingly bad QuakeC code from doing nasty things to your computer)"};
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
41 //============================================================================
42 // mempool handling
43
44 /*
45 ===============
46 PRVM_MEM_Alloc
47 ===============
48 */
49 void PRVM_MEM_Alloc(void)
50 {
51         int i;
52
53         // reserve space for the null entity aka world
54         // check bound of max_edicts
55         prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
56         prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
57
58         // edictprivate_size has to be min as big prvm_edict_private_t
59         prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
60
61         // alloc edicts
62         prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
63
64         // alloc edict private space
65         prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
66
67         // alloc edict fields
68         prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
69
70         // set edict pointers
71         for(i = 0; i < prog->max_edicts; i++)
72         {
73                 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
74                 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
75         }
76 }
77
78 /*
79 ===============
80 PRVM_MEM_IncreaseEdicts
81 ===============
82 */
83 void PRVM_MEM_IncreaseEdicts(void)
84 {
85         int             i;
86         int             oldmaxedicts = prog->max_edicts;
87         void    *oldedictsfields = prog->edictsfields;
88         void    *oldedictprivate = prog->edictprivate;
89
90         if(prog->max_edicts >= prog->limit_edicts)
91                 return;
92
93         PRVM_GCALL(begin_increase_edicts)();
94
95         // increase edicts
96         prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
97
98         prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
99         prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
100
101         memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
102         memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
103
104         //set e and v pointers
105         for(i = 0; i < prog->max_edicts; i++)
106         {
107                 prog->edicts[i].priv.required  = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
108                 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
109         }
110
111         PRVM_GCALL(end_increase_edicts)();
112
113         Mem_Free(oldedictsfields);
114         Mem_Free(oldedictprivate);
115 }
116
117 //============================================================================
118 // normal prvm
119
120 int PRVM_ED_FindFieldOffset(const char *field)
121 {
122         ddef_t *d;
123         d = PRVM_ED_FindField(field);
124         if (!d)
125                 return -1;
126         return d->ofs;
127 }
128
129 int PRVM_ED_FindGlobalOffset(const char *global)
130 {
131         ddef_t *d;
132         d = PRVM_ED_FindGlobal(global);
133         if (!d)
134                 return -1;
135         return d->ofs;
136 }
137
138 func_t PRVM_ED_FindFunctionOffset(const char *function)
139 {
140         mfunction_t *f;
141         f = PRVM_ED_FindFunction(function);
142         if (!f)
143                 return 0;
144         return (func_t)(f - prog->functions);
145 }
146
147 qboolean PRVM_ProgLoaded(int prognr)
148 {
149         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
150                 return FALSE;
151
152         return (prog_list[prognr].loaded ? TRUE : FALSE);
153 }
154
155 /*
156 =================
157 PRVM_SetProgFromString
158 =================
159 */
160 // perhaps add a return value when the str doesnt exist
161 qboolean PRVM_SetProgFromString(const char *str)
162 {
163         int i = 0;
164         for(; i < PRVM_MAXPROGS ; i++)
165                 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
166                 {
167                         if(prog_list[i].loaded)
168                         {
169                                 prog = &prog_list[i];
170                                 return TRUE;
171                         }
172                         else
173                         {
174                                 Con_Printf("%s not loaded !\n",PRVM_NAME);
175                                 return FALSE;
176                         }
177                 }
178
179         Con_Printf("Invalid program name %s !\n", str);
180         return FALSE;
181 }
182
183 /*
184 =================
185 PRVM_SetProg
186 =================
187 */
188 void PRVM_SetProg(int prognr)
189 {
190         if(0 <= prognr && prognr < PRVM_MAXPROGS)
191         {
192                 if(prog_list[prognr].loaded)
193                         prog = &prog_list[prognr];
194                 else
195                         PRVM_ERROR("%i not loaded !", prognr);
196                 return;
197         }
198         PRVM_ERROR("Invalid program number %i", prognr);
199 }
200
201 /*
202 =================
203 PRVM_ED_ClearEdict
204
205 Sets everything to NULL
206 =================
207 */
208 void PRVM_ED_ClearEdict (prvm_edict_t *e)
209 {
210         memset (e->fields.vp, 0, prog->progs->entityfields * 4);
211         e->priv.required->free = false;
212
213         // AK: Let the init_edict function determine if something needs to be initialized
214         PRVM_GCALL(init_edict)(e);
215 }
216
217 /*
218 =================
219 PRVM_ED_Alloc
220
221 Either finds a free edict, or allocates a new one.
222 Try to avoid reusing an entity that was recently freed, because it
223 can cause the client to think the entity morphed into something else
224 instead of being removed and recreated, which can cause interpolated
225 angles and bad trails.
226 =================
227 */
228 prvm_edict_t *PRVM_ED_Alloc (void)
229 {
230         int                     i;
231         prvm_edict_t            *e;
232
233         // the client qc dont need maxclients
234         // thus it doesnt need to use svs.maxclients
235         // AK:  changed i=svs.maxclients+1
236         // AK:  changed so the edict 0 wont spawn -> used as reserved/world entity
237         //              although the menu/client has no world
238         for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
239         {
240                 e = PRVM_EDICT_NUM(i);
241                 // the first couple seconds of server time can involve a lot of
242                 // freeing and allocating, so relax the replacement policy
243                 if (e->priv.required->free && ( e->priv.required->freetime < 2 || prog->globaloffsets.time < 0 || (PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float - e->priv.required->freetime) > 0.5 ) )
244                 {
245                         PRVM_ED_ClearEdict (e);
246                         return e;
247                 }
248         }
249
250         if (i == prog->limit_edicts)
251                 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
252
253         prog->num_edicts++;
254         if (prog->num_edicts >= prog->max_edicts)
255                 PRVM_MEM_IncreaseEdicts();
256
257         e = PRVM_EDICT_NUM(i);
258         PRVM_ED_ClearEdict (e);
259
260         return e;
261 }
262
263 /*
264 =================
265 PRVM_ED_Free
266
267 Marks the edict as free
268 FIXME: walk all entities and NULL out references to this entity
269 =================
270 */
271 void PRVM_ED_Free (prvm_edict_t *ed)
272 {
273         // dont delete the null entity (world) or reserved edicts
274         if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
275                 return;
276
277         PRVM_GCALL(free_edict)(ed);
278
279         ed->priv.required->free = true;
280         ed->priv.required->freetime = prog->globaloffsets.time >= 0 ? PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float : 0;
281 }
282
283 //===========================================================================
284
285 /*
286 ============
287 PRVM_ED_GlobalAtOfs
288 ============
289 */
290 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
291 {
292         ddef_t          *def;
293         int                     i;
294
295         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
296         {
297                 def = &prog->globaldefs[i];
298                 if (def->ofs == ofs)
299                         return def;
300         }
301         return NULL;
302 }
303
304 /*
305 ============
306 PRVM_ED_FieldAtOfs
307 ============
308 */
309 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
310 {
311         ddef_t          *def;
312         int                     i;
313
314         for (i=0 ; i<prog->progs->numfielddefs ; i++)
315         {
316                 def = &prog->fielddefs[i];
317                 if (def->ofs == ofs)
318                         return def;
319         }
320         return NULL;
321 }
322
323 /*
324 ============
325 PRVM_ED_FindField
326 ============
327 */
328 ddef_t *PRVM_ED_FindField (const char *name)
329 {
330         ddef_t *def;
331         int i;
332
333         for (i=0 ; i<prog->progs->numfielddefs ; i++)
334         {
335                 def = &prog->fielddefs[i];
336                 if (!strcmp(PRVM_GetString(def->s_name), name))
337                         return def;
338         }
339         return NULL;
340 }
341
342 /*
343 ============
344 PRVM_ED_FindGlobal
345 ============
346 */
347 ddef_t *PRVM_ED_FindGlobal (const char *name)
348 {
349         ddef_t *def;
350         int i;
351
352         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
353         {
354                 def = &prog->globaldefs[i];
355                 if (!strcmp(PRVM_GetString(def->s_name), name))
356                         return def;
357         }
358         return NULL;
359 }
360
361
362 /*
363 ============
364 PRVM_ED_FindFunction
365 ============
366 */
367 mfunction_t *PRVM_ED_FindFunction (const char *name)
368 {
369         mfunction_t             *func;
370         int                             i;
371
372         for (i=0 ; i<prog->progs->numfunctions ; i++)
373         {
374                 func = &prog->functions[i];
375                 if (!strcmp(PRVM_GetString(func->s_name), name))
376                         return func;
377         }
378         return NULL;
379 }
380
381
382 /*
383 ============
384 PRVM_ValueString
385
386 Returns a string describing *data in a type specific manner
387 =============
388 */
389 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
390 {
391         static char line[MAX_INPUTLINE];
392         ddef_t *def;
393         mfunction_t *f;
394         int n;
395
396         type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
397
398         switch (type)
399         {
400         case ev_string:
401                 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
402                 break;
403         case ev_entity:
404                 n = val->edict;
405                 if (n < 0 || n >= prog->limit_edicts)
406                         sprintf (line, "entity %i (invalid!)", n);
407                 else
408                         sprintf (line, "entity %i", n);
409                 break;
410         case ev_function:
411                 f = prog->functions + val->function;
412                 sprintf (line, "%s()", PRVM_GetString(f->s_name));
413                 break;
414         case ev_field:
415                 def = PRVM_ED_FieldAtOfs ( val->_int );
416                 sprintf (line, ".%s", PRVM_GetString(def->s_name));
417                 break;
418         case ev_void:
419                 sprintf (line, "void");
420                 break;
421         case ev_float:
422                 // LordHavoc: changed from %5.1f to %10.4f
423                 sprintf (line, "%10.4f", val->_float);
424                 break;
425         case ev_vector:
426                 // LordHavoc: changed from %5.1f to %10.4f
427                 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
428                 break;
429         case ev_pointer:
430                 sprintf (line, "pointer");
431                 break;
432         default:
433                 sprintf (line, "bad type %i", (int) type);
434                 break;
435         }
436
437         return line;
438 }
439
440 /*
441 ============
442 PRVM_UglyValueString
443
444 Returns a string describing *data in a type specific manner
445 Easier to parse than PR_ValueString
446 =============
447 */
448 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
449 {
450         static char line[MAX_INPUTLINE];
451         int i;
452         const char *s;
453         ddef_t *def;
454         mfunction_t *f;
455
456         type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
457
458         switch (type)
459         {
460         case ev_string:
461                 // Parse the string a bit to turn special characters
462                 // (like newline, specifically) into escape codes,
463                 // this fixes saving games from various mods
464                 s = PRVM_GetString (val->string);
465                 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
466                 {
467                         if (*s == '\n')
468                         {
469                                 line[i++] = '\\';
470                                 line[i++] = 'n';
471                         }
472                         else if (*s == '\r')
473                         {
474                                 line[i++] = '\\';
475                                 line[i++] = 'r';
476                         }
477                         else
478                                 line[i++] = *s;
479                         s++;
480                 }
481                 line[i] = '\0';
482                 break;
483         case ev_entity:
484                 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
485                 break;
486         case ev_function:
487                 f = prog->functions + val->function;
488                 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
489                 break;
490         case ev_field:
491                 def = PRVM_ED_FieldAtOfs ( val->_int );
492                 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
493                 break;
494         case ev_void:
495                 dpsnprintf (line, sizeof (line), "void");
496                 break;
497         case ev_float:
498                 dpsnprintf (line, sizeof (line), "%f", val->_float);
499                 break;
500         case ev_vector:
501                 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
502                 break;
503         default:
504                 dpsnprintf (line, sizeof (line), "bad type %i", type);
505                 break;
506         }
507
508         return line;
509 }
510
511 /*
512 ============
513 PRVM_GlobalString
514
515 Returns a string with a description and the contents of a global,
516 padded to 20 field width
517 ============
518 */
519 char *PRVM_GlobalString (int ofs)
520 {
521         char    *s;
522         //size_t        i;
523         ddef_t  *def;
524         void    *val;
525         static char     line[128];
526
527         val = (void *)&prog->globals.generic[ofs];
528         def = PRVM_ED_GlobalAtOfs(ofs);
529         if (!def)
530                 sprintf (line,"GLOBAL%i", ofs);
531         else
532         {
533                 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
534                 sprintf (line,"%s (=%s)", PRVM_GetString(def->s_name), s);
535         }
536
537         //i = strlen(line);
538         //for ( ; i<20 ; i++)
539         //      strcat (line," ");
540         //strcat (line," ");
541
542         return line;
543 }
544
545 char *PRVM_GlobalStringNoContents (int ofs)
546 {
547         //size_t        i;
548         ddef_t  *def;
549         static char     line[128];
550
551         def = PRVM_ED_GlobalAtOfs(ofs);
552         if (!def)
553                 sprintf (line,"GLOBAL%i", ofs);
554         else
555                 sprintf (line,"%s", PRVM_GetString(def->s_name));
556
557         //i = strlen(line);
558         //for ( ; i<20 ; i++)
559         //      strcat (line," ");
560         //strcat (line," ");
561
562         return line;
563 }
564
565
566 /*
567 =============
568 PRVM_ED_Print
569
570 For debugging
571 =============
572 */
573 // LordHavoc: optimized this to print out much more quickly (tempstring)
574 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
575 void PRVM_ED_Print(prvm_edict_t *ed)
576 {
577         size_t  l;
578         ddef_t  *d;
579         int             *v;
580         int             i, j;
581         const char      *name;
582         int             type;
583         char    tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
584
585         if (ed->priv.required->free)
586         {
587                 Con_Printf("%s: FREE\n",PRVM_NAME);
588                 return;
589         }
590
591         tempstring[0] = 0;
592         sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
593         for (i=1 ; i<prog->progs->numfielddefs ; i++)
594         {
595                 d = &prog->fielddefs[i];
596                 name = PRVM_GetString(d->s_name);
597                 if (name[strlen(name)-2] == '_')
598                         continue;       // skip _x, _y, _z vars
599
600                 v = (int *)((char *)ed->fields.vp + d->ofs*4);
601
602         // if the value is still all 0, skip the field
603                 type = d->type & ~DEF_SAVEGLOBAL;
604
605                 for (j=0 ; j<prvm_type_size[type] ; j++)
606                         if (v[j])
607                                 break;
608                 if (j == prvm_type_size[type])
609                         continue;
610
611                 if (strlen(name) > sizeof(tempstring2)-4)
612                 {
613                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
614                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
615                         tempstring2[sizeof(tempstring2)-1] = 0;
616                         name = tempstring2;
617                 }
618                 strlcat(tempstring, name, sizeof(tempstring));
619                 for (l = strlen(name);l < 14;l++)
620                         strlcat(tempstring, " ", sizeof(tempstring));
621                 strlcat(tempstring, " ", sizeof(tempstring));
622
623                 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
624                 if (strlen(name) > sizeof(tempstring2)-4)
625                 {
626                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
627                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
628                         tempstring2[sizeof(tempstring2)-1] = 0;
629                         name = tempstring2;
630                 }
631                 strlcat(tempstring, name, sizeof(tempstring));
632                 strlcat(tempstring, "\n", sizeof(tempstring));
633                 if (strlen(tempstring) >= sizeof(tempstring)/2)
634                 {
635                         Con_Print(tempstring);
636                         tempstring[0] = 0;
637                 }
638         }
639         if (tempstring[0])
640                 Con_Print(tempstring);
641 }
642
643 /*
644 =============
645 PRVM_ED_Write
646
647 For savegames
648 =============
649 */
650 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
651 {
652         ddef_t  *d;
653         int             *v;
654         int             i, j;
655         const char      *name;
656         int             type;
657
658         FS_Print(f, "{\n");
659
660         if (ed->priv.required->free)
661         {
662                 FS_Print(f, "}\n");
663                 return;
664         }
665
666         for (i=1 ; i<prog->progs->numfielddefs ; i++)
667         {
668                 d = &prog->fielddefs[i];
669                 name = PRVM_GetString(d->s_name);
670                 if (name[strlen(name)-2] == '_')
671                         continue;       // skip _x, _y, _z vars
672
673                 v = (int *)((char *)ed->fields.vp + d->ofs*4);
674
675         // if the value is still all 0, skip the field
676                 type = d->type & ~DEF_SAVEGLOBAL;
677                 for (j=0 ; j<prvm_type_size[type] ; j++)
678                         if (v[j])
679                                 break;
680                 if (j == prvm_type_size[type])
681                         continue;
682
683                 FS_Printf(f,"\"%s\" ",name);
684                 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
685         }
686
687         FS_Print(f, "}\n");
688 }
689
690 void PRVM_ED_PrintNum (int ent)
691 {
692         PRVM_ED_Print(PRVM_EDICT_NUM(ent));
693 }
694
695 /*
696 =============
697 PRVM_ED_PrintEdicts_f
698
699 For debugging, prints all the entities in the current server
700 =============
701 */
702 void PRVM_ED_PrintEdicts_f (void)
703 {
704         int             i;
705
706         if(Cmd_Argc() != 2)
707         {
708                 Con_Print("prvm_edicts <program name>\n");
709                 return;
710         }
711
712         PRVM_Begin;
713         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
714                 return;
715
716         Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
717         for (i=0 ; i<prog->num_edicts ; i++)
718                 PRVM_ED_PrintNum (i);
719
720         PRVM_End;
721 }
722
723 /*
724 =============
725 PRVM_ED_PrintEdict_f
726
727 For debugging, prints a single edict
728 =============
729 */
730 void PRVM_ED_PrintEdict_f (void)
731 {
732         int             i;
733
734         if(Cmd_Argc() != 3)
735         {
736                 Con_Print("prvm_edict <program name> <edict number>\n");
737                 return;
738         }
739
740         PRVM_Begin;
741         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
742                 return;
743
744         i = atoi (Cmd_Argv(2));
745         if (i >= prog->num_edicts)
746         {
747                 Con_Print("Bad edict number\n");
748                 PRVM_End;
749                 return;
750         }
751         PRVM_ED_PrintNum (i);
752
753         PRVM_End;
754 }
755
756 /*
757 =============
758 PRVM_ED_Count
759
760 For debugging
761 =============
762 */
763 // 2 possibilities : 1. just displaying the active edict count
764 //                                       2. making a function pointer [x]
765 void PRVM_ED_Count_f (void)
766 {
767         int             i;
768         prvm_edict_t    *ent;
769         int             active;
770
771         if(Cmd_Argc() != 2)
772         {
773                 Con_Print("prvm_count <program name>\n");
774                 return;
775         }
776
777         PRVM_Begin;
778         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
779                 return;
780
781         if(prog->count_edicts)
782                 prog->count_edicts();
783         else
784         {
785                 active = 0;
786                 for (i=0 ; i<prog->num_edicts ; i++)
787                 {
788                         ent = PRVM_EDICT_NUM(i);
789                         if (ent->priv.required->free)
790                                 continue;
791                         active++;
792                 }
793
794                 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
795                 Con_Printf("active    :%3i\n", active);
796         }
797
798         PRVM_End;
799 }
800
801 /*
802 ==============================================================================
803
804                                         ARCHIVING GLOBALS
805
806 FIXME: need to tag constants, doesn't really work
807 ==============================================================================
808 */
809
810 /*
811 =============
812 PRVM_ED_WriteGlobals
813 =============
814 */
815 void PRVM_ED_WriteGlobals (qfile_t *f)
816 {
817         ddef_t          *def;
818         int                     i;
819         const char              *name;
820         int                     type;
821
822         FS_Print(f,"{\n");
823         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
824         {
825                 def = &prog->globaldefs[i];
826                 type = def->type;
827                 if ( !(def->type & DEF_SAVEGLOBAL) )
828                         continue;
829                 type &= ~DEF_SAVEGLOBAL;
830
831                 if (type != ev_string && type != ev_float && type != ev_entity)
832                         continue;
833
834                 name = PRVM_GetString(def->s_name);
835                 FS_Printf(f,"\"%s\" ", name);
836                 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
837         }
838         FS_Print(f,"}\n");
839 }
840
841 /*
842 =============
843 PRVM_ED_ParseGlobals
844 =============
845 */
846 void PRVM_ED_ParseGlobals (const char *data)
847 {
848         char keyname[MAX_INPUTLINE];
849         ddef_t *key;
850
851         while (1)
852         {
853                 // parse key
854                 if (!COM_ParseTokenConsole(&data))
855                         PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
856                 if (com_token[0] == '}')
857                         break;
858
859                 strlcpy (keyname, com_token, sizeof(keyname));
860
861                 // parse value
862                 if (!COM_ParseTokenConsole(&data))
863                         PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
864
865                 if (com_token[0] == '}')
866                         PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
867
868                 key = PRVM_ED_FindGlobal (keyname);
869                 if (!key)
870                 {
871                         Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
872                         continue;
873                 }
874
875                 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
876                         PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
877         }
878 }
879
880 //============================================================================
881
882
883 /*
884 =============
885 PRVM_ED_ParseEval
886
887 Can parse either fields or globals
888 returns false if error
889 =============
890 */
891 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
892 {
893         int i, l;
894         char *new_p;
895         ddef_t *def;
896         prvm_eval_t *val;
897         mfunction_t *func;
898
899         if (ent)
900                 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
901         else
902                 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
903         switch (key->type & ~DEF_SAVEGLOBAL)
904         {
905         case ev_string:
906                 l = (int)strlen(s) + 1;
907                 val->string = PRVM_AllocString(l, &new_p);
908                 for (i = 0;i < l;i++)
909                 {
910                         if (s[i] == '\\' && i < l-1)
911                         {
912                                 i++;
913                                 if (s[i] == 'n')
914                                         *new_p++ = '\n';
915                                 else if (s[i] == 'r')
916                                         *new_p++ = '\r';
917                                 else
918                                         *new_p++ = s[i];
919                         }
920                         else
921                                 *new_p++ = s[i];
922                 }
923                 break;
924
925         case ev_float:
926                 while (*s && *s <= ' ')
927                         s++;
928                 val->_float = atof(s);
929                 break;
930
931         case ev_vector:
932                 for (i = 0;i < 3;i++)
933                 {
934                         while (*s && *s <= ' ')
935                                 s++;
936                         if (!*s)
937                                 break;
938                         val->vector[i] = atof(s);
939                         while (*s > ' ')
940                                 s++;
941                         if (!*s)
942                                 break;
943                 }
944                 break;
945
946         case ev_entity:
947                 while (*s && *s <= ' ')
948                         s++;
949                 i = atoi(s);
950                 if (i >= prog->limit_edicts)
951                         Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %u >= MAX_EDICTS %u) on %s\n", (unsigned int)i, (unsigned int)MAX_EDICTS, PRVM_NAME);
952                 while (i >= prog->max_edicts)
953                         PRVM_MEM_IncreaseEdicts();
954                         //SV_IncreaseEdicts();
955                 // if SV_IncreaseEdicts was called the base pointer needs to be updated
956                 if (ent)
957                         val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
958                 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
959                 break;
960
961         case ev_field:
962                 def = PRVM_ED_FindField(s);
963                 if (!def)
964                 {
965                         Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
966                         return false;
967                 }
968                 val->_int = def->ofs;
969                 break;
970
971         case ev_function:
972                 func = PRVM_ED_FindFunction(s);
973                 if (!func)
974                 {
975                         Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
976                         return false;
977                 }
978                 val->function = func - prog->functions;
979                 break;
980
981         default:
982                 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
983                 return false;
984         }
985         return true;
986 }
987
988 /*
989 =============
990 PRVM_ED_EdictSet_f
991
992 Console command to set a field of a specified edict
993 =============
994 */
995 void PRVM_ED_EdictSet_f(void)
996 {
997         prvm_edict_t *ed;
998         ddef_t *key;
999
1000         if(Cmd_Argc() != 5)
1001         {
1002                 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1003                 return;
1004         }
1005
1006         PRVM_Begin;
1007         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1008         {
1009                 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1010                 return;
1011         }
1012
1013         ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1014
1015         if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1016                 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1017         else
1018                 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
1019
1020         PRVM_End;
1021 }
1022
1023 /*
1024 ====================
1025 PRVM_ED_ParseEdict
1026
1027 Parses an edict out of the given string, returning the new position
1028 ed should be a properly initialized empty edict.
1029 Used for initial level load and for savegames.
1030 ====================
1031 */
1032 extern cvar_t developer_entityparsing;
1033 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1034 {
1035         ddef_t *key;
1036         qboolean anglehack;
1037         qboolean init;
1038         char keyname[256];
1039         size_t n;
1040
1041         init = false;
1042
1043 // go through all the dictionary pairs
1044         while (1)
1045         {
1046         // parse key
1047                 if (!COM_ParseTokenConsole(&data))
1048                         PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1049                 if (developer_entityparsing.integer)
1050                         Con_Printf("Key: \"%s\"", com_token);
1051                 if (com_token[0] == '}')
1052                         break;
1053
1054                 // anglehack is to allow QuakeEd to write single scalar angles
1055                 // and allow them to be turned into vectors. (FIXME...)
1056                 if (!strcmp(com_token, "angle"))
1057                 {
1058                         strlcpy (com_token, "angles", sizeof(com_token));
1059                         anglehack = true;
1060                 }
1061                 else
1062                         anglehack = false;
1063
1064                 // FIXME: change light to _light to get rid of this hack
1065                 if (!strcmp(com_token, "light"))
1066                         strlcpy (com_token, "light_lev", sizeof(com_token));    // hack for single light def
1067
1068                 strlcpy (keyname, com_token, sizeof(keyname));
1069
1070                 // another hack to fix keynames with trailing spaces
1071                 n = strlen(keyname);
1072                 while (n && keyname[n-1] == ' ')
1073                 {
1074                         keyname[n-1] = 0;
1075                         n--;
1076                 }
1077
1078         // parse value
1079                 if (!COM_ParseTokenConsole(&data))
1080                         PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1081                 if (developer_entityparsing.integer)
1082                         Con_Printf(" \"%s\"\n", com_token);
1083
1084                 if (com_token[0] == '}')
1085                         PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1086
1087                 init = true;
1088
1089                 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1090                 if (!keyname[0])
1091                         continue;
1092
1093 // keynames with a leading underscore are used for utility comments,
1094 // and are immediately discarded by quake
1095                 if (keyname[0] == '_')
1096                         continue;
1097
1098                 key = PRVM_ED_FindField (keyname);
1099                 if (!key)
1100                 {
1101                         Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1102                         continue;
1103                 }
1104
1105                 if (anglehack)
1106                 {
1107                         char    temp[32];
1108                         strlcpy (temp, com_token, sizeof(temp));
1109                         sprintf (com_token, "0 %s 0", temp);
1110                 }
1111
1112                 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1113                         PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1114         }
1115
1116         if (!init)
1117                 ent->priv.required->free = true;
1118
1119         return data;
1120 }
1121
1122
1123 /*
1124 ================
1125 PRVM_ED_LoadFromFile
1126
1127 The entities are directly placed in the array, rather than allocated with
1128 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1129 number references out of order.
1130
1131 Creates a server's entity / program execution context by
1132 parsing textual entity definitions out of an ent file.
1133
1134 Used for both fresh maps and savegame loads.  A fresh map would also need
1135 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1136 ================
1137 */
1138 void PRVM_ED_LoadFromFile (const char *data)
1139 {
1140         prvm_edict_t *ent;
1141         int parsed, inhibited, spawned, died;
1142         mfunction_t *func;
1143
1144         parsed = 0;
1145         inhibited = 0;
1146         spawned = 0;
1147         died = 0;
1148
1149
1150 // parse ents
1151         while (1)
1152         {
1153 // parse the opening brace
1154                 if (!COM_ParseTokenConsole(&data))
1155                         break;
1156                 if (com_token[0] != '{')
1157                         PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1158
1159                 // CHANGED: this is not conform to PR_LoadFromFile
1160                 if(prog->loadintoworld)
1161                 {
1162                         prog->loadintoworld = false;
1163                         ent = PRVM_EDICT_NUM(0);
1164                 }
1165                 else
1166                         ent = PRVM_ED_Alloc();
1167
1168                 // clear it
1169                 if (ent != prog->edicts)        // hack
1170                         memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1171
1172                 data = PRVM_ED_ParseEdict (data, ent);
1173                 parsed++;
1174
1175                 // remove the entity ?
1176                 if(prog->load_edict && !prog->load_edict(ent))
1177                 {
1178                         PRVM_ED_Free(ent);
1179                         inhibited++;
1180                         continue;
1181                 }
1182
1183 //
1184 // immediately call spawn function, but only if there is a self global and a classname
1185 //
1186                 if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0)
1187                 {
1188                         string_t handle =  PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
1189                         if (!handle)
1190                         {
1191                                 Con_Print("No classname for:\n");
1192                                 PRVM_ED_Print(ent);
1193                                 PRVM_ED_Free (ent);
1194                                 continue;
1195                         }
1196
1197                         // look for the spawn function
1198                         func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1199
1200                         if (!func)
1201                         {
1202                                 if (developer.integer) // don't confuse non-developers with errors
1203                                 {
1204                                         Con_Print("No spawn function for:\n");
1205                                         PRVM_ED_Print(ent);
1206                                 }
1207                                 PRVM_ED_Free (ent);
1208                                 continue;
1209                         }
1210
1211                         // self = ent
1212                         PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1213                         PRVM_ExecuteProgram (func - prog->functions, "");
1214                 }
1215
1216                 spawned++;
1217                 if (ent->priv.required->free)
1218                         died++;
1219         }
1220
1221         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);
1222 }
1223
1224 void PRVM_FindOffsets(void)
1225 {
1226         // field and global searches use -1 for NULL
1227         memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
1228         memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
1229         // functions use 0 for NULL
1230         memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
1231
1232         // server and client qc use a lot of similar fields, so this is combined
1233         prog->fieldoffsets.SendEntity                     = PRVM_ED_FindFieldOffset("SendEntity");
1234         prog->fieldoffsets.Version                        = PRVM_ED_FindFieldOffset("Version");
1235         prog->fieldoffsets.alpha                          = PRVM_ED_FindFieldOffset("alpha");
1236         prog->fieldoffsets.ammo_cells1                    = PRVM_ED_FindFieldOffset("ammo_cells1");
1237         prog->fieldoffsets.ammo_lava_nails                = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1238         prog->fieldoffsets.ammo_multi_rockets             = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1239         prog->fieldoffsets.ammo_nails1                    = PRVM_ED_FindFieldOffset("ammo_nails1");
1240         prog->fieldoffsets.ammo_plasma                    = PRVM_ED_FindFieldOffset("ammo_plasma");
1241         prog->fieldoffsets.ammo_rockets1                  = PRVM_ED_FindFieldOffset("ammo_rockets1");
1242         prog->fieldoffsets.ammo_shells1                   = PRVM_ED_FindFieldOffset("ammo_shells1");
1243         prog->fieldoffsets.angles                         = PRVM_ED_FindFieldOffset("angles");
1244         prog->fieldoffsets.button3                        = PRVM_ED_FindFieldOffset("button3");
1245         prog->fieldoffsets.button4                        = PRVM_ED_FindFieldOffset("button4");
1246         prog->fieldoffsets.button5                        = PRVM_ED_FindFieldOffset("button5");
1247         prog->fieldoffsets.button6                        = PRVM_ED_FindFieldOffset("button6");
1248         prog->fieldoffsets.button7                        = PRVM_ED_FindFieldOffset("button7");
1249         prog->fieldoffsets.button8                        = PRVM_ED_FindFieldOffset("button8");
1250         prog->fieldoffsets.button9                        = PRVM_ED_FindFieldOffset("button9");
1251         prog->fieldoffsets.button10                       = PRVM_ED_FindFieldOffset("button10");
1252         prog->fieldoffsets.button11                       = PRVM_ED_FindFieldOffset("button11");
1253         prog->fieldoffsets.button12                       = PRVM_ED_FindFieldOffset("button12");
1254         prog->fieldoffsets.button13                       = PRVM_ED_FindFieldOffset("button13");
1255         prog->fieldoffsets.button14                       = PRVM_ED_FindFieldOffset("button14");
1256         prog->fieldoffsets.button15                       = PRVM_ED_FindFieldOffset("button15");
1257         prog->fieldoffsets.button16                       = PRVM_ED_FindFieldOffset("button16");
1258         prog->fieldoffsets.buttonchat                     = PRVM_ED_FindFieldOffset("buttonchat");
1259         prog->fieldoffsets.buttonuse                      = PRVM_ED_FindFieldOffset("buttonuse");
1260         prog->fieldoffsets.chain                          = PRVM_ED_FindFieldOffset("chain");
1261         prog->fieldoffsets.classname                      = PRVM_ED_FindFieldOffset("classname");
1262         prog->fieldoffsets.clientcolors                   = PRVM_ED_FindFieldOffset("clientcolors");
1263         prog->fieldoffsets.color                          = PRVM_ED_FindFieldOffset("color");
1264         prog->fieldoffsets.colormod                       = PRVM_ED_FindFieldOffset("colormod");
1265         prog->fieldoffsets.contentstransition             = PRVM_ED_FindFieldOffset("contentstransition");
1266         prog->fieldoffsets.cursor_active                  = PRVM_ED_FindFieldOffset("cursor_active");
1267         prog->fieldoffsets.cursor_screen                  = PRVM_ED_FindFieldOffset("cursor_screen");
1268         prog->fieldoffsets.cursor_trace_endpos            = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1269         prog->fieldoffsets.cursor_trace_ent               = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1270         prog->fieldoffsets.cursor_trace_start             = PRVM_ED_FindFieldOffset("cursor_trace_start");
1271         prog->fieldoffsets.customizeentityforclient       = PRVM_ED_FindFieldOffset("customizeentityforclient");
1272         prog->fieldoffsets.dimension_hit                  = PRVM_ED_FindFieldOffset("dimension_hit");
1273         prog->fieldoffsets.dimension_solid                = PRVM_ED_FindFieldOffset("dimension_solid");
1274         prog->fieldoffsets.dphitcontentsmask              = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1275         prog->fieldoffsets.drawonlytoclient               = PRVM_ED_FindFieldOffset("drawonlytoclient");
1276         prog->fieldoffsets.exteriormodeltoclient          = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1277         prog->fieldoffsets.fatness                        = PRVM_ED_FindFieldOffset("fatness");
1278         prog->fieldoffsets.forceshader                    = PRVM_ED_FindFieldOffset("forceshader");
1279         prog->fieldoffsets.frame                          = PRVM_ED_FindFieldOffset("frame");
1280         prog->fieldoffsets.frame1time                     = PRVM_ED_FindFieldOffset("frame1time");
1281         prog->fieldoffsets.frame2                         = PRVM_ED_FindFieldOffset("frame2");
1282         prog->fieldoffsets.frame2time                     = PRVM_ED_FindFieldOffset("frame2time");
1283         prog->fieldoffsets.fullbright                     = PRVM_ED_FindFieldOffset("fullbright");
1284         prog->fieldoffsets.glow_color                     = PRVM_ED_FindFieldOffset("glow_color");
1285         prog->fieldoffsets.glow_size                      = PRVM_ED_FindFieldOffset("glow_size");
1286         prog->fieldoffsets.glow_trail                     = PRVM_ED_FindFieldOffset("glow_trail");
1287         prog->fieldoffsets.gravity                        = PRVM_ED_FindFieldOffset("gravity");
1288         prog->fieldoffsets.groundentity                   = PRVM_ED_FindFieldOffset("groundentity");
1289         prog->fieldoffsets.hull                           = PRVM_ED_FindFieldOffset("hull");
1290         prog->fieldoffsets.ideal_yaw                      = PRVM_ED_FindFieldOffset("ideal_yaw");
1291         prog->fieldoffsets.idealpitch                     = PRVM_ED_FindFieldOffset("idealpitch");
1292         prog->fieldoffsets.items2                         = PRVM_ED_FindFieldOffset("items2");
1293         prog->fieldoffsets.lerpfrac                       = PRVM_ED_FindFieldOffset("lerpfrac");
1294         prog->fieldoffsets.light_lev                      = PRVM_ED_FindFieldOffset("light_lev");
1295         prog->fieldoffsets.movement                       = PRVM_ED_FindFieldOffset("movement");
1296         prog->fieldoffsets.nextthink                      = PRVM_ED_FindFieldOffset("nextthink");
1297         prog->fieldoffsets.nodrawtoclient                 = PRVM_ED_FindFieldOffset("nodrawtoclient");
1298         prog->fieldoffsets.pflags                         = PRVM_ED_FindFieldOffset("pflags");
1299         prog->fieldoffsets.ping                           = PRVM_ED_FindFieldOffset("ping");
1300         prog->fieldoffsets.pitch_speed                    = PRVM_ED_FindFieldOffset("pitch_speed");
1301         prog->fieldoffsets.playermodel                    = PRVM_ED_FindFieldOffset("playermodel");
1302         prog->fieldoffsets.playerskin                     = PRVM_ED_FindFieldOffset("playerskin");
1303         prog->fieldoffsets.pmodel                         = PRVM_ED_FindFieldOffset("pmodel");
1304         prog->fieldoffsets.punchvector                    = PRVM_ED_FindFieldOffset("punchvector");
1305         prog->fieldoffsets.renderamt                      = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1306         prog->fieldoffsets.renderflags                    = PRVM_ED_FindFieldOffset("renderflags");
1307         prog->fieldoffsets.rendermode                     = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1308         prog->fieldoffsets.scale                          = PRVM_ED_FindFieldOffset("scale");
1309         prog->fieldoffsets.style                          = PRVM_ED_FindFieldOffset("style");
1310         prog->fieldoffsets.tag_entity                     = PRVM_ED_FindFieldOffset("tag_entity");
1311         prog->fieldoffsets.tag_index                      = PRVM_ED_FindFieldOffset("tag_index");
1312         prog->fieldoffsets.think                          = PRVM_ED_FindFieldOffset("think");
1313         prog->fieldoffsets.viewmodelforclient             = PRVM_ED_FindFieldOffset("viewmodelforclient");
1314         prog->fieldoffsets.viewzoom                       = PRVM_ED_FindFieldOffset("viewzoom");
1315         prog->fieldoffsets.yaw_speed                      = PRVM_ED_FindFieldOffset("yaw_speed");
1316         prog->funcoffsets.CSQC_ConsoleCommand             = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1317         prog->funcoffsets.CSQC_Ent_Remove                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1318         prog->funcoffsets.CSQC_Ent_Update                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1319         prog->funcoffsets.CSQC_Event                      = PRVM_ED_FindFunctionOffset("CSQC_Event");
1320         prog->funcoffsets.CSQC_Init                       = PRVM_ED_FindFunctionOffset("CSQC_Init");
1321         prog->funcoffsets.CSQC_InputEvent                 = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1322         prog->funcoffsets.CSQC_Parse_CenterPrint          = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1323         prog->funcoffsets.CSQC_Parse_Print                = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1324         prog->funcoffsets.CSQC_Parse_StuffCmd             = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1325         prog->funcoffsets.CSQC_Parse_TempEntity           = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1326         prog->funcoffsets.CSQC_Shutdown                   = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1327         prog->funcoffsets.CSQC_UpdateView                 = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1328         prog->funcoffsets.EndFrame                        = PRVM_ED_FindFunctionOffset("EndFrame");
1329         prog->funcoffsets.RestoreGame                     = PRVM_ED_FindFunctionOffset("RestoreGame");
1330         prog->funcoffsets.SV_ChangeTeam                   = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1331         prog->funcoffsets.SV_ParseClientCommand           = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1332         prog->funcoffsets.SV_PlayerPhysics                = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1333         prog->globaloffsets.SV_InitCmd                    = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1334         prog->globaloffsets.self                          = PRVM_ED_FindGlobalOffset("self");
1335         prog->globaloffsets.time                          = PRVM_ED_FindGlobalOffset("time");
1336         prog->globaloffsets.v_forward                     = PRVM_ED_FindGlobalOffset("v_forward");
1337         prog->globaloffsets.v_right                       = PRVM_ED_FindGlobalOffset("v_right");
1338         prog->globaloffsets.v_up                          = PRVM_ED_FindGlobalOffset("v_up");
1339         prog->globaloffsets.trace_allsolid                = PRVM_ED_FindGlobalOffset("trace_allsolid");
1340         prog->globaloffsets.trace_startsolid              = PRVM_ED_FindGlobalOffset("trace_startsolid");
1341         prog->globaloffsets.trace_fraction                = PRVM_ED_FindGlobalOffset("trace_fraction");
1342         prog->globaloffsets.trace_inwater                 = PRVM_ED_FindGlobalOffset("trace_inwater");
1343         prog->globaloffsets.trace_inopen                  = PRVM_ED_FindGlobalOffset("trace_inopen");
1344         prog->globaloffsets.trace_endpos                  = PRVM_ED_FindGlobalOffset("trace_endpos");
1345         prog->globaloffsets.trace_plane_normal            = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1346         prog->globaloffsets.trace_plane_dist              = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1347         prog->globaloffsets.trace_ent                     = PRVM_ED_FindGlobalOffset("trace_ent");
1348         prog->globaloffsets.trace_dphitcontents           = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1349         prog->globaloffsets.trace_dphitq3surfaceflags     = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1350         prog->globaloffsets.trace_dphittexturename        = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1351         prog->globaloffsets.trace_dpstartcontents         = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1352
1353         // menu qc only uses some functions, nothing else
1354         prog->funcoffsets.m_display                       = PRVM_ED_FindFunctionOffset("m_display");
1355         prog->funcoffsets.m_draw                          = PRVM_ED_FindFunctionOffset("m_draw");
1356         prog->funcoffsets.m_hide                          = PRVM_ED_FindFunctionOffset("m_hide");
1357         prog->funcoffsets.m_init                          = PRVM_ED_FindFunctionOffset("m_init");
1358         prog->funcoffsets.m_keydown                       = PRVM_ED_FindFunctionOffset("m_keydown");
1359         prog->funcoffsets.m_keyup                         = PRVM_ED_FindFunctionOffset("m_keyup");
1360         prog->funcoffsets.m_shutdown                      = PRVM_ED_FindFunctionOffset("m_shutdown");
1361         prog->funcoffsets.m_toggle                        = PRVM_ED_FindFunctionOffset("m_toggle");
1362 }
1363
1364 // not used
1365 /*
1366 typedef struct dpfield_s
1367 {
1368         int type;
1369         char *string;
1370 }
1371 dpfield_t;
1372
1373 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1374
1375 dpfield_t dpfields[] =
1376 {
1377 };
1378 */
1379
1380 /*
1381 ===============
1382 PRVM_ResetProg
1383 ===============
1384 */
1385
1386 void PRVM_ResetProg()
1387 {
1388         PRVM_GCALL(reset_cmd)();
1389         Mem_FreePool(&prog->progs_mempool);
1390         memset(prog,0,sizeof(prvm_prog_t));
1391 }
1392
1393 /*
1394 ===============
1395 PRVM_LoadLNO
1396 ===============
1397 */
1398 void PRVM_LoadLNO( const char *progname ) {
1399         fs_offset_t filesize;
1400         unsigned char *lno;
1401         unsigned int *header;
1402         char filename[512];
1403
1404         FS_StripExtension( progname, filename, sizeof( filename ) );
1405         strlcat( filename, ".lno", sizeof( filename ) );
1406
1407         lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1408         if( !lno ) {
1409                 return;
1410         }
1411
1412 /*
1413 <Spike>    SafeWrite (h, &lnotype, sizeof(int));
1414 <Spike>    SafeWrite (h, &version, sizeof(int));
1415 <Spike>    SafeWrite (h, &numglobaldefs, sizeof(int));
1416 <Spike>    SafeWrite (h, &numpr_globals, sizeof(int));
1417 <Spike>    SafeWrite (h, &numfielddefs, sizeof(int));
1418 <Spike>    SafeWrite (h, &numstatements, sizeof(int));
1419 <Spike>    SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1420 */
1421         if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1422                 Mem_Free(lno);
1423                 return;
1424         }
1425
1426         header = (unsigned int *) lno;
1427         if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1428                 LittleLong( header[ 1 ] ) == 1 &&
1429                 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1430                 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1431                 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1432                 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1433         {
1434                 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1435                 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1436         }
1437         Mem_Free( lno );
1438 }
1439
1440 /*
1441 ===============
1442 PRVM_LoadProgs
1443 ===============
1444 */
1445 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1446 {
1447         int i;
1448         dstatement_t *st;
1449         ddef_t *infielddefs;
1450         dfunction_t *dfunctions;
1451         fs_offset_t filesize;
1452
1453         if( prog->loaded ) {
1454                 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1455         }
1456
1457         prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1458         if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1459                 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1460
1461         Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1462
1463         prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1464
1465 // byte swap the header
1466         for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1467                 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1468
1469         if (prog->progs->version != PROG_VERSION)
1470                 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1471         if (prog->progs->crc != prog->headercrc)
1472                 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1473
1474         //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1475         dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1476
1477         prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1478         prog->stringssize = 0;
1479         for (i = 0;i < prog->progs->numstrings;i++)
1480         {
1481                 if (prog->progs->ofs_strings + prog->stringssize >= (int)filesize)
1482                         PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1483                 prog->stringssize += (int)strlen (prog->strings + prog->stringssize) + 1;
1484         }
1485         prog->numknownstrings = 0;
1486         prog->maxknownstrings = 0;
1487         prog->knownstrings = NULL;
1488         prog->knownstrings_freeable = NULL;
1489
1490         prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1491
1492         // we need to expand the fielddefs list to include all the engine fields,
1493         // so allocate a new place for it
1494         infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1495         //                                                                                              ( + DPFIELDS                       )
1496         prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1497
1498         prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1499
1500         prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1501
1502         // moved edict_size calculation down below field adding code
1503
1504         //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1505         prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1506
1507 // byte swap the lumps
1508         for (i=0 ; i<prog->progs->numstatements ; i++)
1509         {
1510                 prog->statements[i].op = LittleShort(prog->statements[i].op);
1511                 prog->statements[i].a = LittleShort(prog->statements[i].a);
1512                 prog->statements[i].b = LittleShort(prog->statements[i].b);
1513                 prog->statements[i].c = LittleShort(prog->statements[i].c);
1514         }
1515
1516         prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1517         for (i = 0;i < prog->progs->numfunctions;i++)
1518         {
1519                 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1520                 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1521                 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1522                 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1523                 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1524                 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1525                 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1526         }
1527
1528         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1529         {
1530                 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1531                 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1532                 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1533         }
1534
1535         // copy the progs fields to the new fields list
1536         for (i = 0;i < prog->progs->numfielddefs;i++)
1537         {
1538                 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1539                 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1540                         PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1541                 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1542                 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1543         }
1544
1545         // append the required fields
1546         for (i = 0;i < (int) numrequiredfields;i++)
1547         {
1548                 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1549                 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1550                 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1551                 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1552                         prog->progs->entityfields += 3;
1553                 else
1554                         prog->progs->entityfields++;
1555                 prog->progs->numfielddefs++;
1556         }
1557
1558         // check required functions
1559         for(i=0 ; i < numrequiredfunc ; i++)
1560                 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1561                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1562
1563         // check required globals
1564         for(i=0 ; i < numrequiredglobals ; i++)
1565                 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1566                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1567
1568         for (i=0 ; i<prog->progs->numglobals ; i++)
1569                 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1570
1571         // moved edict_size calculation down here, below field adding code
1572         // LordHavoc: this no longer includes the prvm_edict_t header
1573         prog->edict_size = prog->progs->entityfields * 4;
1574         prog->edictareasize = prog->edict_size * prog->limit_edicts;
1575
1576         // LordHavoc: bounds check anything static
1577         for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1578         {
1579                 switch (st->op)
1580                 {
1581                 case OP_IF:
1582                 case OP_IFNOT:
1583                         if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1584                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1585                         break;
1586                 case OP_GOTO:
1587                         if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1588                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1589                         break;
1590                 // global global global
1591                 case OP_ADD_F:
1592                 case OP_ADD_V:
1593                 case OP_SUB_F:
1594                 case OP_SUB_V:
1595                 case OP_MUL_F:
1596                 case OP_MUL_V:
1597                 case OP_MUL_FV:
1598                 case OP_MUL_VF:
1599                 case OP_DIV_F:
1600                 case OP_BITAND:
1601                 case OP_BITOR:
1602                 case OP_GE:
1603                 case OP_LE:
1604                 case OP_GT:
1605                 case OP_LT:
1606                 case OP_AND:
1607                 case OP_OR:
1608                 case OP_EQ_F:
1609                 case OP_EQ_V:
1610                 case OP_EQ_S:
1611                 case OP_EQ_E:
1612                 case OP_EQ_FNC:
1613                 case OP_NE_F:
1614                 case OP_NE_V:
1615                 case OP_NE_S:
1616                 case OP_NE_E:
1617                 case OP_NE_FNC:
1618                 case OP_ADDRESS:
1619                 case OP_LOAD_F:
1620                 case OP_LOAD_FLD:
1621                 case OP_LOAD_ENT:
1622                 case OP_LOAD_S:
1623                 case OP_LOAD_FNC:
1624                 case OP_LOAD_V:
1625                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1626                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1627                         break;
1628                 // global none global
1629                 case OP_NOT_F:
1630                 case OP_NOT_V:
1631                 case OP_NOT_S:
1632                 case OP_NOT_FNC:
1633                 case OP_NOT_ENT:
1634                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1635                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1636                         break;
1637                 // 2 globals
1638                 case OP_STOREP_F:
1639                 case OP_STOREP_ENT:
1640                 case OP_STOREP_FLD:
1641                 case OP_STOREP_S:
1642                 case OP_STOREP_FNC:
1643                 case OP_STORE_F:
1644                 case OP_STORE_ENT:
1645                 case OP_STORE_FLD:
1646                 case OP_STORE_S:
1647                 case OP_STORE_FNC:
1648                 case OP_STATE:
1649                 case OP_STOREP_V:
1650                 case OP_STORE_V:
1651                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1652                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1653                         break;
1654                 // 1 global
1655                 case OP_CALL0:
1656                 case OP_CALL1:
1657                 case OP_CALL2:
1658                 case OP_CALL3:
1659                 case OP_CALL4:
1660                 case OP_CALL5:
1661                 case OP_CALL6:
1662                 case OP_CALL7:
1663                 case OP_CALL8:
1664                 case OP_DONE:
1665                 case OP_RETURN:
1666                         if ((unsigned short) st->a >= prog->progs->numglobals)
1667                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1668                         break;
1669                 default:
1670                         Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1671                         break;
1672                 }
1673         }
1674
1675         PRVM_LoadLNO(filename);
1676
1677         PRVM_Init_Exec();
1678
1679         prog->loaded = TRUE;
1680
1681         // set flags & ddef_ts in prog
1682
1683         prog->flag = 0;
1684
1685         PRVM_FindOffsets();
1686
1687         PRVM_GCALL(init_cmd)();
1688
1689         // init mempools
1690         PRVM_MEM_Alloc();
1691 }
1692
1693
1694 void PRVM_Fields_f (void)
1695 {
1696         int i, j, ednum, used, usedamount;
1697         int *counts;
1698         char tempstring[MAX_INPUTLINE], tempstring2[260];
1699         const char *name;
1700         prvm_edict_t *ed;
1701         ddef_t *d;
1702         int *v;
1703
1704         // TODO
1705         /*
1706         if (!sv.active)
1707         {
1708                 Con_Print("no progs loaded\n");
1709                 return;
1710         }
1711         */
1712
1713         if(Cmd_Argc() != 2)
1714         {
1715                 Con_Print("prvm_fields <program name>\n");
1716                 return;
1717         }
1718
1719         PRVM_Begin;
1720         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1721                 return;
1722
1723         counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1724         for (ednum = 0;ednum < prog->max_edicts;ednum++)
1725         {
1726                 ed = PRVM_EDICT_NUM(ednum);
1727                 if (ed->priv.required->free)
1728                         continue;
1729                 for (i = 1;i < prog->progs->numfielddefs;i++)
1730                 {
1731                         d = &prog->fielddefs[i];
1732                         name = PRVM_GetString(d->s_name);
1733                         if (name[strlen(name)-2] == '_')
1734                                 continue;       // skip _x, _y, _z vars
1735                         v = (int *)((char *)ed->fields.vp + d->ofs*4);
1736                         // if the value is still all 0, skip the field
1737                         for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1738                         {
1739                                 if (v[j])
1740                                 {
1741                                         counts[i]++;
1742                                         break;
1743                                 }
1744                         }
1745                 }
1746         }
1747         used = 0;
1748         usedamount = 0;
1749         tempstring[0] = 0;
1750         for (i = 0;i < prog->progs->numfielddefs;i++)
1751         {
1752                 d = &prog->fielddefs[i];
1753                 name = PRVM_GetString(d->s_name);
1754                 if (name[strlen(name)-2] == '_')
1755                         continue;       // skip _x, _y, _z vars
1756                 switch(d->type & ~DEF_SAVEGLOBAL)
1757                 {
1758                 case ev_string:
1759                         strlcat(tempstring, "string   ", sizeof(tempstring));
1760                         break;
1761                 case ev_entity:
1762                         strlcat(tempstring, "entity   ", sizeof(tempstring));
1763                         break;
1764                 case ev_function:
1765                         strlcat(tempstring, "function ", sizeof(tempstring));
1766                         break;
1767                 case ev_field:
1768                         strlcat(tempstring, "field    ", sizeof(tempstring));
1769                         break;
1770                 case ev_void:
1771                         strlcat(tempstring, "void     ", sizeof(tempstring));
1772                         break;
1773                 case ev_float:
1774                         strlcat(tempstring, "float    ", sizeof(tempstring));
1775                         break;
1776                 case ev_vector:
1777                         strlcat(tempstring, "vector   ", sizeof(tempstring));
1778                         break;
1779                 case ev_pointer:
1780                         strlcat(tempstring, "pointer  ", sizeof(tempstring));
1781                         break;
1782                 default:
1783                         sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1784                         strlcat(tempstring, tempstring2, sizeof(tempstring));
1785                         break;
1786                 }
1787                 if (strlen(name) > sizeof(tempstring2)-4)
1788                 {
1789                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
1790                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1791                         tempstring2[sizeof(tempstring2)-1] = 0;
1792                         name = tempstring2;
1793                 }
1794                 strlcat(tempstring, name, sizeof(tempstring));
1795                 for (j = (int)strlen(name);j < 25;j++)
1796                         strlcat(tempstring, " ", sizeof(tempstring));
1797                 sprintf(tempstring2, "%5d", counts[i]);
1798                 strlcat(tempstring, tempstring2, sizeof(tempstring));
1799                 strlcat(tempstring, "\n", sizeof(tempstring));
1800                 if (strlen(tempstring) >= sizeof(tempstring)/2)
1801                 {
1802                         Con_Print(tempstring);
1803                         tempstring[0] = 0;
1804                 }
1805                 if (counts[i])
1806                 {
1807                         used++;
1808                         usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1809                 }
1810         }
1811         Mem_Free(counts);
1812         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);
1813
1814         PRVM_End;
1815 }
1816
1817 void PRVM_Globals_f (void)
1818 {
1819         int i;
1820         // TODO
1821         /*if (!sv.active)
1822         {
1823                 Con_Print("no progs loaded\n");
1824                 return;
1825         }*/
1826         if(Cmd_Argc () != 2)
1827         {
1828                 Con_Print("prvm_globals <program name>\n");
1829                 return;
1830         }
1831
1832         PRVM_Begin;
1833         if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1834                 return;
1835
1836         Con_Printf("%s :", PRVM_NAME);
1837
1838         for (i = 0;i < prog->progs->numglobaldefs;i++)
1839                 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1840         Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1841
1842         PRVM_End;
1843 }
1844
1845 /*
1846 ===============
1847 PRVM_Global
1848 ===============
1849 */
1850 void PRVM_Global_f(void)
1851 {
1852         ddef_t *global;
1853         if( Cmd_Argc() != 3 ) {
1854                 Con_Printf( "prvm_global <program name> <global name>\n" );
1855                 return;
1856         }
1857
1858         PRVM_Begin;
1859         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1860                 return;
1861
1862         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1863         if( !global )
1864                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1865         else
1866                 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
1867         PRVM_End;
1868 }
1869
1870 /*
1871 ===============
1872 PRVM_GlobalSet
1873 ===============
1874 */
1875 void PRVM_GlobalSet_f(void)
1876 {
1877         ddef_t *global;
1878         if( Cmd_Argc() != 4 ) {
1879                 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
1880                 return;
1881         }
1882
1883         PRVM_Begin;
1884         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1885                 return;
1886
1887         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1888         if( !global )
1889                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1890         else
1891                 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
1892         PRVM_End;
1893 }
1894
1895 /*
1896 ===============
1897 PRVM_Init
1898 ===============
1899 */
1900 void PRVM_Init (void)
1901 {
1902         Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
1903         Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "set a property on an entity number in the selected VM (server, client, menu)");
1904         Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
1905         Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
1906         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)");
1907         Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
1908         Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
1909         Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
1910         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)");
1911         Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
1912         // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1913         Cvar_RegisterVariable (&prvm_boundscheck);
1914         Cvar_RegisterVariable (&prvm_traceqc);
1915         Cvar_RegisterVariable (&prvm_statementprofiling);
1916
1917         //VM_Cmd_Init();
1918 }
1919
1920 /*
1921 ===============
1922 PRVM_InitProg
1923 ===============
1924 */
1925 void PRVM_InitProg(int prognr)
1926 {
1927         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1928                 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
1929
1930         prog = &prog_list[prognr];
1931
1932         if(prog->loaded)
1933                 PRVM_ResetProg();
1934
1935         memset(prog, 0, sizeof(prvm_prog_t));
1936
1937         prog->error_cmd = Host_Error;
1938 }
1939
1940 int PRVM_GetProgNr()
1941 {
1942         return prog - prog_list;
1943 }
1944
1945 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
1946 {
1947         return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
1948 }
1949
1950 void _PRVM_Free(void *buffer, const char *filename, int fileline)
1951 {
1952         _Mem_Free(buffer, filename, fileline);
1953 }
1954
1955 void _PRVM_FreeAll(const char *filename, int fileline)
1956 {
1957         prog->progs = NULL;
1958         prog->fielddefs = NULL;
1959         prog->functions = NULL;
1960         _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
1961 }
1962
1963 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1964 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1965 {
1966         PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1967         return NULL;
1968 }
1969
1970 /*
1971 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
1972 {
1973         PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
1974         return 0;
1975 }
1976
1977 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
1978 {
1979         int n;
1980         n = e - prog->edicts;
1981         if ((unsigned int)n >= prog->limit_edicts)
1982                 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
1983         return n;
1984 }
1985
1986 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
1987 //{
1988 //      return e - prog->edicts;
1989 //}
1990
1991 //#define       PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
1992 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
1993 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
1994 {
1995         int n;
1996         n = e - prog->edicts;
1997         if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1998                 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
1999         return n;// EXPERIMENTAL
2000         //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2001 }
2002 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2003 {
2004         if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2005                 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2006         return prog->edicts + n; // EXPERIMENTAL
2007         //return prog->edicts + ((n) / (progs->entityfields * 4));
2008 }
2009 */
2010
2011
2012 sizebuf_t vm_tempstringsbuf;
2013
2014 const char *PRVM_GetString(int num)
2015 {
2016         if (num >= 0)
2017         {
2018                 if (num < prog->stringssize)
2019                         return prog->strings + num;
2020                 else
2021 #if 1
2022                 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2023                 {
2024                         num -= prog->stringssize;
2025                         if (num < vm_tempstringsbuf.cursize)
2026                                 return (char *)vm_tempstringsbuf.data + num;
2027                         else
2028                         {
2029                                 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
2030                                 return "";
2031                         }
2032                 }
2033                 else
2034 #endif
2035                 {
2036                         VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)", num, prog->stringssize);
2037                         return "";
2038                 }
2039         }
2040         else
2041         {
2042                 num = -1 - num;
2043 #if 0
2044                 if (num >= (1<<30))
2045                 {
2046                         // special range reserved for tempstrings
2047                         num -= (1<<30);
2048                         if (num < vm_tempstringsbuf.cursize)
2049                                 return (char *)vm_tempstringsbuf.data + num;
2050                         else
2051                         {
2052                                 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
2053                                 return "";
2054                         }
2055                 }
2056                 else
2057 #endif
2058                 if (num < prog->numknownstrings)
2059                 {
2060                         if (!prog->knownstrings[num])
2061                                 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)", num);
2062                         return prog->knownstrings[num];
2063                 }
2064                 else
2065                 {
2066                         VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)", num, prog->numknownstrings);
2067                         return "";
2068                 }
2069         }
2070 }
2071
2072 int PRVM_SetEngineString(const char *s)
2073 {
2074         int i;
2075         if (!s)
2076                 return 0;
2077         if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2078                 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2079         // if it's in the tempstrings area, use a reserved range
2080         // (otherwise we'd get millions of useless string offsets cluttering the database)
2081         if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2082 #if 1
2083                 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2084 #else
2085                 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2086 #endif
2087         // see if it's a known string address
2088         for (i = 0;i < prog->numknownstrings;i++)
2089                 if (prog->knownstrings[i] == s)
2090                         return -1 - i;
2091         // new unknown engine string
2092         if (developer.integer >= 100)
2093                 Con_Printf("new engine string %p\n", s);
2094         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2095                 if (!prog->knownstrings[i])
2096                         break;
2097         if (i >= prog->numknownstrings)
2098         {
2099                 if (i >= prog->maxknownstrings)
2100                 {
2101                         const char **oldstrings = prog->knownstrings;
2102                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2103                         prog->maxknownstrings += 128;
2104                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2105                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2106                         if (prog->numknownstrings)
2107                         {
2108                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2109                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2110                         }
2111                 }
2112                 prog->numknownstrings++;
2113         }
2114         prog->firstfreeknownstring = i + 1;
2115         prog->knownstrings[i] = s;
2116         return -1 - i;
2117 }
2118
2119 // temp string handling
2120
2121 // all tempstrings go into this buffer consecutively, and it is reset
2122 // whenever PRVM_ExecuteProgram returns to the engine
2123 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2124 //  restores it on return, so multiple recursive calls can share the same
2125 //  buffer)
2126 // the buffer size is automatically grown as needed
2127
2128 int PRVM_SetTempString(const char *s)
2129 {
2130         int size;
2131         char *t;
2132         if (!s)
2133                 return 0;
2134         size = (int)strlen(s) + 1;
2135         if (developer.integer >= 300)
2136                 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2137         if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2138         {
2139                 sizebuf_t old = vm_tempstringsbuf;
2140                 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2141                         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);
2142                 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2143                 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2144                         vm_tempstringsbuf.maxsize *= 2;
2145                 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2146                 {
2147                         if (developer.integer >= 100)
2148                                 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2149                         vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2150                         if (old.cursize)
2151                                 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2152                         if (old.data)
2153                                 Mem_Free(old.data);
2154                 }
2155         }
2156         t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2157         memcpy(t, s, size);
2158         vm_tempstringsbuf.cursize += size;
2159         return PRVM_SetEngineString(t);
2160 }
2161
2162 int PRVM_AllocString(size_t bufferlength, char **pointer)
2163 {
2164         int i;
2165         if (!bufferlength)
2166                 return 0;
2167         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2168                 if (!prog->knownstrings[i])
2169                         break;
2170         if (i >= prog->numknownstrings)
2171         {
2172                 if (i >= prog->maxknownstrings)
2173                 {
2174                         const char **oldstrings = prog->knownstrings;
2175                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2176                         prog->maxknownstrings += 128;
2177                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2178                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2179                         if (prog->numknownstrings)
2180                         {
2181                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2182                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2183                         }
2184                 }
2185                 prog->numknownstrings++;
2186         }
2187         prog->firstfreeknownstring = i + 1;
2188         prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2189         prog->knownstrings_freeable[i] = true;
2190         if (pointer)
2191                 *pointer = (char *)(prog->knownstrings[i]);
2192         return -1 - i;
2193 }
2194
2195 void PRVM_FreeString(int num)
2196 {
2197         if (num == 0)
2198                 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2199         else if (num >= 0 && num < prog->stringssize)
2200                 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2201         else if (num < 0 && num >= -prog->numknownstrings)
2202         {
2203                 num = -1 - num;
2204                 if (!prog->knownstrings[num])
2205                         PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2206                 if (!prog->knownstrings[num])
2207                         PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2208                 PRVM_Free((char *)prog->knownstrings[num]);
2209                 prog->knownstrings[num] = NULL;
2210                 prog->knownstrings_freeable[num] = false;
2211                 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2212         }
2213         else
2214                 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);
2215 }
2216