]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_edict.c
added r_shadow_help and r_editlights_help commands containing documentation
[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
24 prvm_prog_t *prog;
25
26 static prvm_prog_t prog_list[PRVM_MAXPROGS];
27
28 int             prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
29
30 ddef_t *PRVM_ED_FieldAtOfs(int ofs);
31 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s);
32
33 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
34 cvar_t  prvm_boundscheck = {0, "prvm_boundscheck", "1"};
35 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
36 cvar_t  prvm_traceqc = {0, "prvm_traceqc", "0"};
37
38 ddef_t *PRVM_ED_FindField (const char *name);
39 mfunction_t *PRVM_ED_FindFunction (const char *name);
40
41 //============================================================================
42 // mempool handling
43
44 /*
45 ===============
46 PRVM_MEM_Alloc
47 ===============
48 */
49 void PRVM_MEM_Alloc()
50 {
51         int i;
52
53         // check bound of max_edicts
54         prog->max_edicts = min(prog->max_edicts,prog->limit_edicts);
55
56         // edictprivate_size has to be min as big prvm_edict_private_t
57         prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t)); 
58
59         // alloc edicts
60         prog->edicts = Mem_Alloc(prog->edicts_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
61         
62         // alloc edict private space
63         prog->edictprivate = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edictprivate_size);
64         
65         // alloc edict fields
66         prog->edictsfields = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edict_size);
67
68         // set edict pointers
69         for(i = 0; i < prog->max_edicts; i++)
70         {
71                 prog->edicts[i].e = (prvm_edict_private_t *)((qbyte  *)prog->edictprivate + i * prog->edictprivate_size);
72                 prog->edicts[i].v = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
73         }
74 }
75
76 /*
77 ===============
78 PRVM_MEM_IncreaseEdicts
79 ===============
80 */
81 void PRVM_MEM_IncreaseEdicts()
82 {
83         int             i;
84         int             oldmaxedicts = prog->max_edicts; 
85         void    *oldedictsfields = prog->edictsfields;
86         void    *oldedictprivate = prog->edictprivate;
87         
88         if(prog->max_edicts >= prog->limit_edicts)
89                 return;
90         
91         PRVM_GCALL(begin_increase_edicts)();
92
93         // increase edicts
94         prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
95
96         prog->edictsfields = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edict_size);
97         prog->edictprivate = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edictprivate_size);
98
99         memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
100         memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
101
102         //set e and v pointers
103         for(i = 0; i < prog->max_edicts; i++)
104         {
105                 prog->edicts[i].e = (prvm_edict_private_t *)((qbyte  *)prog->edictprivate + i * prog->edictprivate_size);
106                 prog->edicts[i].v = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
107         }
108
109         PRVM_GCALL(end_increase_edicts)();
110
111         Mem_Free(oldedictsfields);
112         Mem_Free(oldedictprivate);
113 }
114
115 //============================================================================
116 // normal prvm
117
118 int PRVM_ED_FindFieldOffset(const char *field)
119 {
120         ddef_t *d;
121         d = PRVM_ED_FindField(field);
122         if (!d)
123                 return 0;
124         return d->ofs*4;
125 }
126
127 qboolean PRVM_ProgLoaded(int prognr)
128 {
129         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
130                 return FALSE;
131
132         return (prog_list[prognr].loaded ? TRUE : FALSE);
133 }
134
135 /*
136 =================
137 PRVM_SetProgFromString
138 =================
139 */
140 // perhaps add a return value when the str doesnt exist
141 qboolean PRVM_SetProgFromString(const char *str)
142 {
143         int i = 0;
144         for(; i < PRVM_MAXPROGS ; i++)
145                 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
146                 {
147                         if(prog_list[i].loaded)
148                         {
149                                 prog = &prog_list[i];
150                                 return TRUE;
151                         }
152                         else
153                         {
154                                 Con_Printf("%s not loaded !\n",PRVM_NAME);
155                                 return FALSE;
156                         }
157                 }
158
159         Con_Printf("Invalid program name %s !\n", str);
160         return FALSE;
161 }
162
163 /*
164 =================
165 PRVM_SetProg
166 =================
167 */
168 void PRVM_SetProg(int prognr)
169 {
170         if(prognr && prognr < PRVM_MAXPROGS)
171         {       
172                 if(prog_list[prognr].loaded)
173                         prog = &prog_list[prognr];
174                 else
175                         PRVM_ERROR("%i(%s) not loaded !\n", prognr, PRVM_NAME);
176                 return;
177         }
178         PRVM_ERROR("Invalid program number %i\n", prognr);
179 }
180
181 /*
182 =================
183 PRVM_ED_ClearEdict
184
185 Sets everything to NULL
186 =================
187 */
188 void PRVM_ED_ClearEdict (prvm_edict_t *e)
189 {
190         int num;
191         memset (e->v, 0, prog->progs->entityfields * 4);
192         e->e->free = false;
193         // LordHavoc: for consistency set these here
194         num = PRVM_NUM_FOR_EDICT(e) - 1;
195
196         // AK: Let the init_edict function determine if something needs to be initialized
197         PRVM_GCALL(init_edict)(num);    
198 }
199
200 /*
201 =================
202 PRVM_ED_Alloc
203
204 Either finds a free edict, or allocates a new one.
205 Try to avoid reusing an entity that was recently freed, because it
206 can cause the client to think the entity morphed into something else
207 instead of being removed and recreated, which can cause interpolated
208 angles and bad trails.
209 =================
210 */
211 prvm_edict_t *PRVM_ED_Alloc (void)
212 {
213         int                     i;
214         prvm_edict_t            *e;
215
216         // the client qc dont need maxclients
217         // thus it doesnt need to use svs.maxclients
218         // AK:  changed i=svs.maxclients+1
219         // AK:  changed so the edict 0 wont spawned -> used as reserved/world entity
220         //              although the menu/client has no world
221         for (i = 1;i < prog->num_edicts;i++)
222         {
223                 e = PRVM_EDICT_NUM(i);
224                 // the first couple seconds of server time can involve a lot of
225                 // freeing and allocating, so relax the replacement policy
226                 if (e->e->free && ( e->e->freetime < 2 || prog->time - e->e->freetime > 0.5 ) )
227                 {
228                         PRVM_ED_ClearEdict (e);
229                         return e;
230                 }
231         }
232
233         if (i == MAX_EDICTS)
234                 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
235
236         prog->num_edicts++;
237         if (prog->num_edicts >= prog->max_edicts)
238                 PRVM_MEM_IncreaseEdicts();
239
240         e = PRVM_EDICT_NUM(i);
241         PRVM_ED_ClearEdict (e);
242
243         return e;
244 }
245
246 /*
247 =================
248 PRVM_ED_Free
249
250 Marks the edict as free
251 FIXME: walk all entities and NULL out references to this entity
252 =================
253 */
254 void PRVM_ED_Free (prvm_edict_t *ed)
255 {
256         PRVM_GCALL(free_edict)(ed);
257
258         ed->e->free = true;
259         ed->e->freetime = prog->time;
260 }
261
262 //===========================================================================
263
264 /*
265 ============
266 PRVM_ED_GlobalAtOfs
267 ============
268 */
269 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
270 {
271         ddef_t          *def;
272         int                     i;
273
274         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
275         {
276                 def = &prog->globaldefs[i];
277                 if (def->ofs == ofs)
278                         return def;
279         }
280         return NULL;
281 }
282
283 /*
284 ============
285 PRVM_ED_FieldAtOfs
286 ============
287 */
288 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
289 {
290         ddef_t          *def;
291         int                     i;
292
293         for (i=0 ; i<prog->progs->numfielddefs ; i++)
294         {
295                 def = &prog->fielddefs[i];
296                 if (def->ofs == ofs)
297                         return def;
298         }
299         return NULL;
300 }
301
302 /*
303 ============
304 PRVM_ED_FindField
305 ============
306 */
307 ddef_t *PRVM_ED_FindField (const char *name)
308 {
309         ddef_t *def;
310         int i;
311
312         for (i=0 ; i<prog->progs->numfielddefs ; i++)
313         {
314                 def = &prog->fielddefs[i];
315                 if (!strcmp(PRVM_GetString(def->s_name), name))
316                         return def;
317         }
318         return NULL;
319 }
320
321 /*
322 ============
323 PRVM_ED_FindGlobal
324 ============
325 */
326 ddef_t *PRVM_ED_FindGlobal (const char *name)
327 {
328         ddef_t *def;
329         int i;
330
331         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
332         {
333                 def = &prog->globaldefs[i];
334                 if (!strcmp(PRVM_GetString(def->s_name), name))
335                         return def;
336         }
337         return NULL;
338 }
339
340
341 /*
342 ============
343 PRVM_ED_FindFunction
344 ============
345 */
346 mfunction_t *PRVM_ED_FindFunction (const char *name)
347 {
348         mfunction_t             *func;
349         int                             i;
350
351         for (i=0 ; i<prog->progs->numfunctions ; i++)
352         {
353                 func = &prog->functions[i];
354                 if (!strcmp(PRVM_GetString(func->s_name), name))
355                         return func;
356         }
357         return NULL;
358 }
359
360
361 /*
362 ============
363 PRVM_ValueString
364
365 Returns a string describing *data in a type specific manner
366 =============
367 */
368 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
369 {
370         static char line[1024]; // LordHavoc: enlarged a bit (was 256)
371         ddef_t *def;
372         mfunction_t *f;
373         int n;
374
375         type &= ~DEF_SAVEGLOBAL;
376
377         switch (type)
378         {
379         case ev_string:
380                 sprintf (line, "%s", PRVM_GetString(val->string));
381                 break;
382         case ev_entity:
383                 n = val->edict;
384                 if (n < 0 || n >= MAX_EDICTS)
385                         sprintf (line, "entity %i (invalid!)", n);
386                 else
387                         sprintf (line, "entity %i", n);
388                 break;
389         case ev_function:
390                 f = prog->functions + val->function;
391                 sprintf (line, "%s()", PRVM_GetString(f->s_name));
392                 break;
393         case ev_field:
394                 def = PRVM_ED_FieldAtOfs ( val->_int );
395                 sprintf (line, ".%s", PRVM_GetString(def->s_name));
396                 break;
397         case ev_void:
398                 sprintf (line, "void");
399                 break;
400         case ev_float:
401                 // LordHavoc: changed from %5.1f to %10.4f
402                 sprintf (line, "%10.4f", val->_float);
403                 break;
404         case ev_vector:
405                 // LordHavoc: changed from %5.1f to %10.4f
406                 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
407                 break;
408         case ev_pointer:
409                 sprintf (line, "pointer");
410                 break;
411         default:
412                 sprintf (line, "bad type %i", type);
413                 break;
414         }
415
416         return line;
417 }
418
419 /*
420 ============
421 PRVM_UglyValueString
422
423 Returns a string describing *data in a type specific manner
424 Easier to parse than PR_ValueString
425 =============
426 */
427 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
428 {
429         static char line[4096];
430         int i;
431         char *s;
432         ddef_t *def;
433         mfunction_t *f;
434         
435         type &= ~DEF_SAVEGLOBAL;
436         
437         switch (type)
438         {
439         case ev_string:
440                 // Parse the string a bit to turn special characters
441                 // (like newline, specifically) into escape codes,
442                 // this fixes saving games from various mods
443                 s = PRVM_GetString (val->string);
444                 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
445                 {
446                         if (*s == '\n')
447                         {
448                                 line[i++] = '\\';
449                                 line[i++] = 'n';
450                         }
451                         else if (*s == '\r')
452                         {
453                                 line[i++] = '\\';
454                                 line[i++] = 'r';
455                         }
456                         else
457                                 line[i++] = *s;
458                         s++;
459                 }
460                 line[i] = '\0';
461                 break;
462         case ev_entity:
463                 snprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
464                 break;
465         case ev_function:
466                 f = pr_functions + val->function;
467                 snprintf (line, sizeof (line), "%s", PRVM_GetString(f->s_name));
468                 break;
469         case ev_field:
470                 def = PRVM_ED_FieldAtOfs ( val->_int );
471                 snprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
472                 break;
473         case ev_void:
474                 snprintf (line, sizeof (line), "void");
475                 break;
476         case ev_float:
477                 snprintf (line, sizeof (line), "%f", val->_float);
478                 break;
479         case ev_vector:
480                 snprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
481                 break;
482         default:
483                 snprintf (line, sizeof (line), "bad type %i", type);
484                 break;
485         }
486         
487         return line;
488 }
489
490 /*
491 ============
492 PRVM_GlobalString
493
494 Returns a string with a description and the contents of a global,
495 padded to 20 field width
496 ============
497 */
498 char *PRVM_GlobalString (int ofs)
499 {
500         char    *s;
501         int             i;
502         ddef_t  *def;
503         void    *val;
504         static char     line[128];
505
506         val = (void *)&prog->globals[ofs];
507         def = PRVM_ED_GlobalAtOfs(ofs);
508         if (!def)
509                 sprintf (line,"%i(?)", ofs);
510         else
511         {
512                 s = PRVM_ValueString (def->type, val);
513                 sprintf (line,"%i(%s)%s", ofs, PRVM_GetString(def->s_name), s);
514         }
515
516         i = strlen(line);
517         for ( ; i<20 ; i++)
518                 strcat (line," ");
519         strcat (line," ");
520
521         return line;
522 }
523
524 char *PRVM_GlobalStringNoContents (int ofs)
525 {
526         int             i;
527         ddef_t  *def;
528         static char     line[128];
529
530         def = PRVM_ED_GlobalAtOfs(ofs);
531         if (!def)
532                 sprintf (line,"%i(?)", ofs);
533         else
534                 sprintf (line,"%i(%s)", ofs, PRVM_GetString(def->s_name));
535
536         i = strlen(line);
537         for ( ; i<20 ; i++)
538                 strcat (line," ");
539         strcat (line," ");
540
541         return line;
542 }
543
544
545 /*
546 =============
547 PRVM_ED_Print
548
549 For debugging
550 =============
551 */
552 // LordHavoc: optimized this to print out much more quickly (tempstring)
553 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
554 void PRVM_ED_Print (prvm_edict_t *ed)
555 {
556         int             l;
557         ddef_t  *d;
558         int             *v;
559         int             i, j;
560         char    *name;
561         int             type;
562         char    tempstring[8192], tempstring2[260]; // temporary string buffers
563
564         if (ed->e->free)
565         {
566                 Con_Printf ("%s: FREE\n",PRVM_NAME);
567                 return;
568         }
569
570         tempstring[0] = 0;
571         sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
572         for (i=1 ; i<prog->progs->numfielddefs ; i++)
573         {
574                 d = &prog->fielddefs[i];
575                 name = PRVM_GetString(d->s_name);
576                 if (name[strlen(name)-2] == '_')
577                         continue;       // skip _x, _y, _z vars
578
579                 v = (int *)((char *)ed->v + d->ofs*4);
580
581         // if the value is still all 0, skip the field
582                 type = d->type & ~DEF_SAVEGLOBAL;
583
584                 for (j=0 ; j<prvm_type_size[type] ; j++)
585                         if (v[j])
586                                 break;
587                 if (j == prvm_type_size[type])
588                         continue;
589
590                 if (strlen(name) > 256)
591                 {
592                         strncpy(tempstring2, name, 256);
593                         tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
594                         tempstring2[259] = 0;
595                         name = tempstring2;
596                 }
597                 strcat(tempstring, name);
598                 for (l = strlen(name);l < 14;l++)
599                         strcat(tempstring, " ");
600                 strcat(tempstring, " ");
601
602                 name = PRVM_ValueString(d->type, (prvm_eval_t *)v);
603                 if (strlen(name) > 256)
604                 {
605                         strncpy(tempstring2, name, 256);
606                         tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
607                         tempstring2[259] = 0;
608                         name = tempstring2;
609                 }
610                 strcat(tempstring, name);
611                 strcat(tempstring, "\n");
612                 if (strlen(tempstring) >= 4096)
613                 {
614                         Con_Printf("%s", tempstring);
615                         tempstring[0] = 0;
616                 }
617         }
618         if (tempstring[0])
619                 Con_Printf("%s", tempstring);
620 }
621
622 /*
623 =============
624 PRVM_ED_Write
625
626 For savegames
627 =============
628 */
629 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
630 {
631         ddef_t  *d;
632         int             *v;
633         int             i, j;
634         char    *name;
635         int             type;
636
637         FS_Printf (f, "{\n");
638
639         if (ed->e->free)
640         {
641                 FS_Printf (f, "}\n");
642                 return;
643         }
644
645         for (i=1 ; i<prog->progs->numfielddefs ; i++)
646         {
647                 d = &prog->fielddefs[i];
648                 name = PRVM_GetString(d->s_name);
649                 if (name[strlen(name)-2] == '_')
650                         continue;       // skip _x, _y, _z vars
651
652                 v = (int *)((char *)ed->v + d->ofs*4);
653
654         // if the value is still all 0, skip the field
655                 type = d->type & ~DEF_SAVEGLOBAL;
656                 for (j=0 ; j<prvm_type_size[type] ; j++)
657                         if (v[j])
658                                 break;
659                 if (j == prvm_type_size[type])
660                         continue;
661
662                 FS_Printf (f,"\"%s\" ",name);
663                 FS_Printf (f,"\"%s\"\n", PRVM_UglyValueString(d->type, (prvm_eval_t *)v));
664         }
665
666         FS_Printf (f, "}\n");
667 }
668
669 void PRVM_ED_PrintNum (int ent)
670 {
671         PRVM_ED_Print (PRVM_EDICT_NUM(ent));
672 }
673
674 /*
675 =============
676 PRVM_ED_PrintEdicts_f
677
678 For debugging, prints all the entities in the current server
679 =============
680 */
681 void PRVM_ED_PrintEdicts_f (void)
682 {
683         int             i;
684
685         if(Cmd_Argc() != 2)
686         {
687                 Con_Print("prvm_edicts <program name>\n");
688                 return;
689         }
690         
691         PRVM_Begin;
692         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
693                 return;
694
695         Con_Printf ("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
696         for (i=0 ; i<prog->num_edicts ; i++)
697                 PRVM_ED_PrintNum (i);
698
699         PRVM_End;
700 }
701
702 /*
703 =============
704 PRVM_ED_PrintEdict_f
705
706 For debugging, prints a single edict
707 =============
708 */
709 void PRVM_ED_PrintEdict_f (void)
710 {
711         int             i;
712
713         if(Cmd_Argc() != 3)
714         {
715                 Con_Print("prvm_edict <program name> <edict number>\n");
716                 return;
717         }
718
719         PRVM_Begin;
720         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
721                 return;
722
723         i = atoi (Cmd_Argv(2));
724         if (i >= prog->num_edicts)
725         {
726                 Con_Printf("Bad edict number\n");
727                 PRVM_End;
728                 return;
729         }
730         PRVM_ED_PrintNum (i);
731
732         PRVM_End;
733 }
734
735 /*
736 =============
737 PRVM_ED_Count
738
739 For debugging
740 =============
741 */
742 // 2 possibilities : 1. just displaying the active edict count
743 //                                       2. making a function pointer [x]
744 void PRVM_ED_Count_f (void)
745 {
746         int             i;
747         prvm_edict_t    *ent;
748         int             active;
749
750         if(Cmd_Argc() != 2)
751         {
752                 Con_Print("prvm_count <program name>\n");
753                 return;
754         }
755
756         PRVM_Begin;
757         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
758                 return;
759
760         if(prog->count_edicts)
761                 prog->count_edicts();
762         else
763         {
764                 active = 0;
765                 for (i=0 ; i<prog->num_edicts ; i++)
766                 {
767                         ent = PRVM_EDICT_NUM(i);
768                         if (ent->e->free)
769                                 continue;
770                         active++;
771                 }
772                 
773                 Con_Printf ("num_edicts:%3i\n", sv.num_edicts);
774                 Con_Printf ("active    :%3i\n", active);
775         }
776
777         PRVM_End;
778 }
779
780 /*
781 ==============================================================================
782
783                                         ARCHIVING GLOBALS
784
785 FIXME: need to tag constants, doesn't really work
786 ==============================================================================
787 */
788
789 /*
790 =============
791 PRVM_ED_WriteGlobals
792 =============
793 */
794 void PRVM_ED_WriteGlobals (qfile_t *f)
795 {
796         ddef_t          *def;
797         int                     i;
798         char            *name;
799         int                     type;
800
801         FS_Printf (f,"{\n");
802         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
803         {
804                 def = &prog->globaldefs[i];
805                 type = def->type;
806                 if ( !(def->type & DEF_SAVEGLOBAL) )
807                         continue;
808                 type &= ~DEF_SAVEGLOBAL;
809
810                 if (type != ev_string && type != ev_float && type != ev_entity)
811                         continue;
812
813                 name = PRVM_GetString(def->s_name);
814                 FS_Printf (f,"\"%s\" ", name);
815                 FS_Printf (f,"\"%s\"\n", PRVM_UglyValueString(type, (prvm_eval_t *)&prog->globals[def->ofs]));
816         }
817         FS_Printf (f,"}\n");
818 }
819
820 /*
821 =============
822 PRVM_ED_ParseGlobals
823 =============
824 */
825 void PRVM_ED_ParseGlobals (const char *data)
826 {
827         char keyname[1024]; // LordHavoc: good idea? bad idea?  was 64
828         ddef_t *key;
829
830         while (1)
831         {
832                 // parse key
833                 if (!COM_ParseToken(&data, false))
834                         PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
835                 if (com_token[0] == '}')
836                         break;
837
838                 strcpy (keyname, com_token);
839
840                 // parse value
841                 if (!COM_ParseToken(&data, false))
842                         PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
843
844                 if (com_token[0] == '}')
845                         PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
846
847                 key = PRVM_ED_FindGlobal (keyname);
848                 if (!key)
849                 {
850                         Con_DPrintf ("'%s' is not a global on %s\n", keyname, PRVM_NAME);
851                         continue;
852                 }
853
854                 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
855                         PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
856         }
857 }
858
859 //============================================================================
860
861
862 /*
863 =============
864 PRVM_ED_NewString
865 =============
866 */
867 char *PRVM_ED_NewString (const char *string)
868 {
869         char *new, *new_p;
870         int i,l;
871
872         l = strlen(string) + 1;
873         new = Mem_Alloc(prog->edictstring_mempool, l);
874         new_p = new;
875
876         for (i=0 ; i< l ; i++)
877         {
878                 if (string[i] == '\\' && i < l-1)
879                 {
880                         i++;
881                         if (string[i] == 'n')
882                                 *new_p++ = '\n';
883                         else
884                                 *new_p++ = '\\';
885                 }
886                 else
887                         *new_p++ = string[i];
888         }
889
890         return new;
891 }
892
893
894 /*
895 =============
896 PRVM_ED_ParseEval
897
898 Can parse either fields or globals
899 returns false if error
900 =============
901 */
902 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
903 {
904         int i;
905         ddef_t *def;
906         prvm_eval_t *val;
907         mfunction_t *func;
908
909         if (ent)
910                 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
911         else
912                 val = (prvm_eval_t *)((int *)pr_globals + key->ofs);
913         switch (key->type & ~DEF_SAVEGLOBAL)
914         {
915         case ev_string:
916                 val->string = PRVM_SetString(ED_NewString(s));
917                 break;
918
919         case ev_float:
920                 while (*s && *s <= ' ')
921                         s++;
922                 val->_float = atof(s);
923                 break;
924
925         case ev_vector:
926                 for (i = 0;i < 3;i++)
927                 {
928                         while (*s && *s <= ' ')
929                                 s++;
930                         if (!*s)
931                                 break;
932                         val->vector[i] = atof(s);
933                         while (*s > ' ')
934                                 s++;
935                         if (!*s)
936                                 break;
937                 }
938                 break;
939
940         case ev_entity:
941                 while (*s && *s <= ' ')
942                         s++;
943                 i = atoi(s);
944                 if (i < 0 || i >= MAX_EDICTS)
945                         Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %i >= MAX_EDICTS %i) on %s\n", i, MAX_EDICTS, PRVM_NAME);
946                 while (i >= prog->max_edicts)
947                         PRVM_MEM_IncreaseEdicts();
948                         //SV_IncreaseEdicts();
949                 // if SV_IncreaseEdicts was called the base pointer needs to be updated
950                 if (ent)
951                         val = (prvm_eval_t *)((int *)ent->v + key->ofs);
952                 val->edict = PRVM_EDICT_TO_PROG(EDICT_NUM(i));
953                 break;
954
955         case ev_field:
956                 def = PRVM_ED_FindField(s);
957                 if (!def)
958                 {
959                         Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s on %s\n", s, PRVM_NAME);
960                         return false;
961                 }
962                 val->_int = PRVM_G_INT(def->ofs);
963                 break;
964
965         case ev_function:
966                 func = PRVM_ED_FindFunction(s);
967                 if (!func)
968                 {
969                         Con_Printf ("PRVM_ED_ParseEpair: Can't find function %s on %s\n", s, PRVM_NAME);
970                         return false;
971                 }
972                 val->function = func - prog->functions;
973                 break;
974
975         default:
976                 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PR_GetString(key->s_name), PRVM_NAME);
977                 return false;
978         }
979         return true;
980 }
981
982 /*
983 ====================
984 PRVM_ED_ParseEdict
985
986 Parses an edict out of the given string, returning the new position
987 ed should be a properly initialized empty edict.
988 Used for initial level load and for savegames.
989 ====================
990 */
991 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
992 {
993         ddef_t *key;
994         qboolean anglehack;
995         qboolean init;
996         char keyname[256];
997         int n;
998
999         init = false;
1000
1001 // clear it
1002         if (ent != prog->edicts)        // hack
1003                 memset (ent->v, 0, prog->progs->entityfields * 4);
1004
1005 // go through all the dictionary pairs
1006         while (1)
1007         {
1008         // parse key
1009                 if (!COM_ParseToken(&data, false))
1010                         PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1011                 if (com_token[0] == '}')
1012                         break;
1013
1014                 // anglehack is to allow QuakeEd to write single scalar angles
1015                 // and allow them to be turned into vectors. (FIXME...)
1016                 if (!strcmp(com_token, "angle"))
1017                 {
1018                         strcpy (com_token, "angles");
1019                         anglehack = true;
1020                 }
1021                 else
1022                         anglehack = false;
1023
1024                 // FIXME: change light to _light to get rid of this hack
1025                 if (!strcmp(com_token, "light"))
1026                         strcpy (com_token, "light_lev");        // hack for single light def
1027
1028                 strcpy (keyname, com_token);
1029
1030                 // another hack to fix heynames with trailing spaces
1031                 n = strlen(keyname);
1032                 while (n && keyname[n-1] == ' ')
1033                 {
1034                         keyname[n-1] = 0;
1035                         n--;
1036                 }
1037
1038         // parse value
1039                 if (!COM_ParseToken(&data, false))
1040                         PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1041
1042                 if (com_token[0] == '}')
1043                         PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
1044
1045                 init = true;
1046
1047 // keynames with a leading underscore are used for utility comments,
1048 // and are immediately discarded by quake
1049                 if (keyname[0] == '_')
1050                         continue;
1051
1052                 key = PRVM_ED_FindField (keyname);
1053                 if (!key)
1054                 {
1055                         Con_DPrintf ("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1056                         continue;
1057                 }
1058
1059                 if (anglehack)
1060                 {
1061                         char    temp[32];
1062                         strcpy (temp, com_token);
1063                         sprintf (com_token, "0 %s 0", temp);
1064                 }
1065
1066                 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1067                         PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1068         }
1069
1070         if (!init)
1071                 ent->e->free = true;
1072
1073         return data;
1074 }
1075
1076
1077 /*
1078 ================
1079 PRVM_ED_LoadFromFile
1080
1081 The entities are directly placed in the array, rather than allocated with
1082 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1083 number references out of order.
1084
1085 Creates a server's entity / program execution context by
1086 parsing textual entity definitions out of an ent file.
1087
1088 Used for both fresh maps and savegame loads.  A fresh map would also need
1089 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1090 ================
1091 */
1092 void PRVM_ED_LoadFromFile (const char *data)
1093 {
1094         prvm_edict_t *ent;
1095         int parsed, inhibited, spawned, died;
1096         mfunction_t *func;
1097
1098         ent = NULL;
1099         parsed = 0;
1100         inhibited = 0;
1101         spawned = 0;
1102         died = 0;
1103
1104         // time defined ?
1105         if(prog->flag & PRVM_GE_TIME)
1106                 PRVM_G_FLOAT(PRVM_ED_FindFieldOffset("time")) = prog->time;
1107         
1108 // parse ents
1109         while (1)
1110         {
1111 // parse the opening brace
1112                 if (!COM_ParseToken(&data, false))
1113                         break;
1114                 if (com_token[0] != '{')
1115                         PRVM_ERROR ("PRVM_ED_LoadFromFile: found %s when expecting (%s) {",com_token, PRVM_NAME);
1116
1117                 if (!ent)
1118                         ent = PRVM_EDICT_NUM(0);
1119                 else
1120                         ent = PRVM_ED_Alloc ();
1121                 data = PRVM_ED_ParseEdict (data, ent);
1122                 parsed++;
1123
1124                 // remove the entity ?
1125                 if(prog->load_edict && !prog->load_edict(ent))
1126                 {
1127                         PRVM_ED_Free(ent);
1128                         inhibited++;
1129                         continue;
1130                 }
1131
1132 //
1133 // immediately call spawn function, but only if there is a self global
1134 //
1135                 if(prog->self && prog->flag & PRVM_FE_CLASSNAME)
1136                 {
1137                         string_t handle =  *(string_t*)&((float*)ent->v)[PRVM_ED_FindFieldOffset("classname")];
1138                         if (!handle)
1139                         {
1140                                 Con_Printf ("No classname for:\n");
1141                                 PRVM_ED_Print (ent);
1142                                 PRVM_ED_Free (ent);
1143                                 continue;
1144                         }
1145                         
1146                         // look for the spawn function
1147                         func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1148                         
1149                         if (!func)
1150                         {
1151                                 if (developer.integer) // don't confuse non-developers with errors
1152                                 {
1153                                         Con_Printf ("No spawn function for:\n");
1154                                         PRVM_ED_Print (ent);
1155                                 }
1156                                 PRVM_ED_Free (ent);
1157                                 continue;
1158                         }
1159                         
1160                         // self = ent
1161                         PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent);
1162                         PRVM_ExecuteProgram (func - prog->functions, "");
1163                 }
1164         
1165                 spawned++;
1166                 if (ent->e->free)
1167                         died++;
1168         }
1169
1170         Con_DPrintf ("%s: %i entities parsed, %i inhibited, %i spawned (%i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, spawned, died, spawned - died);
1171 }
1172
1173 // not used
1174 /*
1175 typedef struct dpfield_s
1176 {
1177         int type;
1178         char *string;
1179 }
1180 dpfield_t;
1181
1182 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1183
1184 dpfield_t dpfields[] =
1185 {
1186 };
1187 */
1188
1189 /*
1190 ===============
1191 PRVM_ResetProg
1192 ===============
1193 */
1194
1195 void PRVM_ResetProg()
1196 {
1197         mempool_t *t1, *t2, *t3;
1198
1199         t1 = prog->progs_mempool;
1200         t2 = prog->edictstring_mempool;
1201         t3 = prog->edicts_mempool;
1202         
1203         Mem_EmptyPool(prog->progs_mempool);
1204         Mem_EmptyPool(prog->edictstring_mempool);
1205         Mem_EmptyPool(prog->edicts_mempool);
1206         
1207         memset(prog,0,sizeof(prvm_prog_t));
1208         
1209         
1210         prog->progs_mempool = t1;
1211         prog->edictstring_mempool = t2;
1212         prog->edicts_mempool = t3;
1213
1214         PRVM_GCALL(reset_cmd)();
1215 }
1216
1217 /*
1218 ===============
1219 PRVM_LoadProgs
1220 ===============
1221 */
1222 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func)
1223 {
1224         int i;
1225         dstatement_t *st;
1226         ddef_t *infielddefs;
1227         void *temp;
1228         dfunction_t *dfunctions;
1229
1230         Mem_EmptyPool(prog->progs_mempool);
1231         Mem_EmptyPool(prog->edictstring_mempool);
1232
1233         temp = FS_LoadFile (filename, false);
1234         if (temp == 0)
1235                 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1236
1237         prog->progs = (dprograms_t *)Mem_Alloc(prog->progs_mempool, fs_filesize);
1238
1239         memcpy(prog->progs, temp, fs_filesize);
1240         Mem_Free(temp);
1241
1242         Con_DPrintf ("%s programs occupy %iK.\n", PRVM_NAME, fs_filesize/1024);
1243
1244         pr_crc = CRC_Block((qbyte *)prog->progs, fs_filesize);
1245
1246 // byte swap the header
1247         for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1248                 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1249
1250         if (prog->progs->version != PROG_VERSION)
1251                 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1252         if (prog->progs->crc != prog->crc)
1253                 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1254
1255         //pr_functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1256         dfunctions = (dfunction_t *)((qbyte *)prog->progs + prog->progs->ofs_functions);
1257         prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1258         prog->globaldefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_globaldefs);
1259
1260         // we need to expand the fielddefs list to include all the engine fields,
1261         // so allocate a new place for it
1262         infielddefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_fielddefs);
1263         //                                                                                              ( + DPFIELDS                       )
1264         prog->fielddefs = Mem_Alloc(prog->progs_mempool, prog->progs->numfielddefs * sizeof(ddef_t));
1265
1266         prog->statements = (dstatement_t *)((qbyte *)prog->progs + prog->progs->ofs_statements);
1267
1268         // moved edict_size calculation down below field adding code
1269
1270         //pr_global_struct = (globalvars_t *)((qbyte *)progs + progs->ofs_globals);
1271         prog->globals = (float *)((qbyte *)prog->progs + prog->progs->ofs_globals);
1272
1273 // byte swap the lumps
1274         for (i=0 ; i<prog->progs->numstatements ; i++)
1275         {
1276                 prog->statements[i].op = LittleShort(prog->statements[i].op);
1277                 prog->statements[i].a = LittleShort(prog->statements[i].a);
1278                 prog->statements[i].b = LittleShort(prog->statements[i].b);
1279                 prog->statements[i].c = LittleShort(prog->statements[i].c);
1280         }
1281
1282         prog->functions = Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1283         for (i = 0;i < prog->progs->numfunctions;i++)
1284         {
1285                 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1286                 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1287                 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1288                 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1289                 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1290                 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1291                 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1292         }
1293
1294         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1295         {
1296                 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1297                 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1298                 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1299         }
1300
1301         // copy the progs fields to the new fields list
1302         for (i = 0;i < prog->progs->numfielddefs;i++)
1303         {
1304                 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1305                 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1306                         PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1307                 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1308                 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1309         }
1310
1311 /*      // append the darkplaces fields
1312         for (i = 0;i < (int) DPFIELDS;i++)
1313         {
1314                 pr_fielddefs[progs->numfielddefs].type = dpfields[i].type;
1315                 pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields;
1316                 pr_fielddefs[progs->numfielddefs].s_name = PR_SetString(dpfields[i].string);
1317                 if (pr_fielddefs[progs->numfielddefs].type == ev_vector)
1318                         progs->entityfields += 3;
1319                 else
1320                         progs->entityfields++;
1321                 progs->numfielddefs++;
1322         }*/
1323
1324         // check required functions
1325         for(i=0 ; i < numrequiredfunc ; i++)
1326                 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1327                         PRVM_ERROR("%s: %s not found in %s\n",PRVM_NAME, required_func[i], filename);
1328
1329         for (i=0 ; i<prog->progs->numglobals ; i++)
1330                 ((int *)prog->globals)[i] = LittleLong (((int *)prog->globals)[i]);
1331
1332         // moved edict_size calculation down here, below field adding code
1333         // LordHavoc: this no longer includes the edict_t header
1334         prog->edict_size = prog->progs->entityfields * 4;
1335         prog->edictareasize = prog->edict_size * MAX_EDICTS;
1336
1337         // LordHavoc: bounds check anything static
1338         for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1339         {
1340                 switch (st->op)
1341                 {
1342                 case OP_IF:
1343                 case OP_IFNOT:
1344                         if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1345                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s\n", i, PRVM_NAME);
1346                         break;
1347                 case OP_GOTO:
1348                         if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1349                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s\n", i, PRVM_NAME);
1350                         break;
1351                 // global global global
1352                 case OP_ADD_F:
1353                 case OP_ADD_V:
1354                 case OP_SUB_F:
1355                 case OP_SUB_V:
1356                 case OP_MUL_F:
1357                 case OP_MUL_V:
1358                 case OP_MUL_FV:
1359                 case OP_MUL_VF:
1360                 case OP_DIV_F:
1361                 case OP_BITAND:
1362                 case OP_BITOR:
1363                 case OP_GE:
1364                 case OP_LE:
1365                 case OP_GT:
1366                 case OP_LT:
1367                 case OP_AND:
1368                 case OP_OR:
1369                 case OP_EQ_F:
1370                 case OP_EQ_V:
1371                 case OP_EQ_S:
1372                 case OP_EQ_E:
1373                 case OP_EQ_FNC:
1374                 case OP_NE_F:
1375                 case OP_NE_V:
1376                 case OP_NE_S:
1377                 case OP_NE_E:
1378                 case OP_NE_FNC:
1379                 case OP_ADDRESS:
1380                 case OP_LOAD_F:
1381                 case OP_LOAD_FLD:
1382                 case OP_LOAD_ENT:
1383                 case OP_LOAD_S:
1384                 case OP_LOAD_FNC:
1385                 case OP_LOAD_V:
1386                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1387                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n", i);
1388                         break;
1389                 // global none global
1390                 case OP_NOT_F:
1391                 case OP_NOT_V:
1392                 case OP_NOT_S:
1393                 case OP_NOT_FNC:
1394                 case OP_NOT_ENT:
1395                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1396                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1397                         break;
1398                 // 2 globals
1399                 case OP_STOREP_F:
1400                 case OP_STOREP_ENT:
1401                 case OP_STOREP_FLD:
1402                 case OP_STOREP_S:
1403                 case OP_STOREP_FNC:
1404                 case OP_STORE_F:
1405                 case OP_STORE_ENT:
1406                 case OP_STORE_FLD:
1407                 case OP_STORE_S:
1408                 case OP_STORE_FNC:
1409                 case OP_STATE:
1410                 case OP_STOREP_V:
1411                 case OP_STORE_V:
1412                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1413                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n in %s", i, PRVM_NAME);
1414                         break;
1415                 // 1 global
1416                 case OP_CALL0:
1417                 case OP_CALL1:
1418                 case OP_CALL2:
1419                 case OP_CALL3:
1420                 case OP_CALL4:
1421                 case OP_CALL5:
1422                 case OP_CALL6:
1423                 case OP_CALL7:
1424                 case OP_CALL8:
1425                 case OP_DONE:
1426                 case OP_RETURN:
1427                         if ((unsigned short) st->a >= prog->progs->numglobals)
1428                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1429                         break;
1430                 default:
1431                         PRVM_ERROR("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1432                         break;
1433                 }
1434         }
1435
1436         PRVM_Init_Exec();
1437
1438         prog->loaded = TRUE;
1439         
1440         // set flags & ddef_ts in prog
1441         
1442         prog->flag = 0;
1443         
1444         prog->self = PRVM_ED_FindGlobal("self");
1445
1446         if(PRVM_ED_FindGlobal("time"))
1447                 prog->flag |= PRVM_GE_TIME;
1448
1449         if(PRVM_ED_FindField ("chain"))
1450                 prog->flag |= PRVM_FE_CHAIN;
1451
1452         if(PRVM_ED_FindField ("classname"))
1453                 prog->flag |= PRVM_FE_CLASSNAME; 
1454
1455         if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think") 
1456                 && prog->flag &  PRVM_GE_TIME && prog->self) 
1457                 prog->flag |= PRVM_OP_STATE;
1458         
1459         PRVM_GCALL(reset_cmd)();
1460
1461         // init mempools
1462         PRVM_MEM_Alloc();
1463 }
1464
1465
1466 void PRVM_Fields_f (void)
1467 {
1468         int i, j, ednum, used, usedamount;
1469         int *counts;
1470         char tempstring[5000], tempstring2[260], *name;
1471         prvm_edict_t *ed;
1472         ddef_t *d;
1473         int *v;
1474
1475         // TODO
1476         /*
1477         if (!sv.active)
1478         {
1479                 Con_Printf("no progs loaded\n");
1480                 return;
1481         }
1482         */
1483
1484         if(Cmd_Argc() != 2)
1485         {
1486                 Con_Print("prvm_fields <program name>\n");
1487                 return;
1488         }
1489
1490         PRVM_Begin;
1491         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1492                 return;
1493
1494         counts = Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1495         for (ednum = 0;ednum < prog->max_edicts;ednum++)
1496         {
1497                 ed = PRVM_EDICT_NUM(ednum);
1498                 if (ed->e->free)
1499                         continue;
1500                 for (i = 1;i < prog->progs->numfielddefs;i++)
1501                 {
1502                         d = &prog->fielddefs[i];
1503                         name = PRVM_GetString(d->s_name);
1504                         if (name[strlen(name)-2] == '_')
1505                                 continue;       // skip _x, _y, _z vars
1506                         v = (int *)((char *)ed->v + d->ofs*4);
1507                         // if the value is still all 0, skip the field
1508                         for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1509                         {
1510                                 if (v[j])
1511                                 {
1512                                         counts[i]++;
1513                                         break;
1514                                 }
1515                         }
1516                 }
1517         }
1518         used = 0;
1519         usedamount = 0;
1520         tempstring[0] = 0;
1521         for (i = 0;i < prog->progs->numfielddefs;i++)
1522         {
1523                 d = &prog->fielddefs[i];
1524                 name = PRVM_GetString(d->s_name);
1525                 if (name[strlen(name)-2] == '_')
1526                         continue;       // skip _x, _y, _z vars
1527                 switch(d->type & ~DEF_SAVEGLOBAL)
1528                 {
1529                 case ev_string:
1530                         strcat(tempstring, "string   ");
1531                         break;
1532                 case ev_entity:
1533                         strcat(tempstring, "entity   ");
1534                         break;
1535                 case ev_function:
1536                         strcat(tempstring, "function ");
1537                         break;
1538                 case ev_field:
1539                         strcat(tempstring, "field    ");
1540                         break;
1541                 case ev_void:
1542                         strcat(tempstring, "void     ");
1543                         break;
1544                 case ev_float:
1545                         strcat(tempstring, "float    ");
1546                         break;
1547                 case ev_vector:
1548                         strcat(tempstring, "vector   ");
1549                         break;
1550                 case ev_pointer:
1551                         strcat(tempstring, "pointer  ");
1552                         break;
1553                 default:
1554                         sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1555                         strcat(tempstring, tempstring2);
1556                         break;
1557                 }
1558                 if (strlen(name) > 256)
1559                 {
1560                         strncpy(tempstring2, name, 256);
1561                         tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
1562                         tempstring2[259] = 0;
1563                         name = tempstring2;
1564                 }
1565                 strcat(tempstring, name);
1566                 for (j = strlen(name);j < 25;j++)
1567                         strcat(tempstring, " ");
1568                 sprintf(tempstring2, "%5d", counts[i]);
1569                 strcat(tempstring, tempstring2);
1570                 strcat(tempstring, "\n");
1571                 if (strlen(tempstring) >= 4096)
1572                 {
1573                         Con_Printf("%s", tempstring);
1574                         tempstring[0] = 0;
1575                 }
1576                 if (counts[i])
1577                 {
1578                         used++;
1579                         usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1580                 }
1581         }
1582         Mem_Free(counts);
1583         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);
1584
1585         PRVM_End;
1586 }
1587
1588 void PRVM_Globals_f (void)
1589 {
1590         int i;
1591         // TODO
1592         /*if (!sv.active)
1593         {
1594                 Con_Printf("no progs loaded\n");
1595                 return;
1596         }*/
1597         if(Cmd_Argc () != 2)
1598         {
1599                 Con_Print ("prvm_globals <program name>\n");
1600                 return;
1601         }
1602
1603         PRVM_Begin;
1604         if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1605                 return;
1606
1607         Con_Printf("%s :", PRVM_NAME);
1608
1609         for (i = 0;i < prog->progs->numglobaldefs;i++)
1610                 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1611         Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1612
1613         PRVM_End;
1614 }
1615
1616 /*
1617 ===============
1618 PRVM_Init
1619 ===============
1620 */
1621 void PRVM_Init (void)
1622 {
1623         Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f);
1624         Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f);
1625         Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f);
1626         Cmd_AddCommand ("prvm_profile", PRVM_Profile_f);
1627         Cmd_AddCommand ("prvm_fields", PRVM_Fields_f);
1628         Cmd_AddCommand ("prvm_globals", PRVM_Globals_f);
1629         // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1630         Cvar_RegisterVariable (&prvm_boundscheck);
1631         Cvar_RegisterVariable (&prvm_traceqc);
1632
1633         //VM_Cmd_Init();
1634 }
1635
1636 /*
1637 ===============
1638 PRVM_InitProg
1639 ===============
1640 */
1641 void PRVM_InitProg(int prognr)
1642 {
1643         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1644                 Sys_Error("PRVM_InitProg: Invalid program number %i\n",prognr);
1645
1646         prog = &prog_list[prognr];
1647
1648         memset(prog, 0, sizeof(prvm_prog_t));
1649
1650         PRVM_GCALL(init_cmd)();
1651 }
1652
1653 int PRVM_GetProgNr()
1654 {
1655         return prog - prog_list;
1656 }
1657
1658 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1659 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1660 {
1661         PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1662         return NULL;
1663 }
1664
1665 void PRVM_ProcessError(void)
1666 {
1667         if(prog)
1668                 PRVM_GCALL(error_cmd)();
1669 }
1670
1671 /*
1672 int NUM_FOR_EDICT_ERROR(edict_t *e)
1673 {
1674         Host_Error ("NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, sv.edicts, e - sv.edicts);
1675         return 0;
1676 }
1677
1678 int NUM_FOR_EDICT(edict_t *e)
1679 {
1680         int n;
1681         n = e - sv.edicts;
1682         if ((unsigned int)n >= MAX_EDICTS)
1683                 Host_Error ("NUM_FOR_EDICT: bad pointer");
1684         return n;
1685 }
1686
1687 //int NoCrash_NUM_FOR_EDICT(edict_t *e)
1688 //{
1689 //      return e - sv.edicts;
1690 //}
1691
1692 //#define       EDICT_TO_PROG(e) ((qbyte *)(((edict_t *)e)->v) - (qbyte *)(sv.edictsfields))
1693 //#define PROG_TO_EDICT(e) (sv.edicts + ((e) / (progs->entityfields * 4)))
1694 int EDICT_TO_PROG(edict_t *e)
1695 {
1696         int n;
1697         n = e - sv.edicts;
1698         if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1699                 Host_Error("EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)\n", e, n, sv.edicts);
1700         return n;// EXPERIMENTAL
1701         //return (qbyte *)e->v - (qbyte *)sv.edictsfields;
1702 }
1703 edict_t *PROG_TO_EDICT(int n)
1704 {
1705         if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1706                 Host_Error("PROG_TO_EDICT: invalid edict number %i\n", n);
1707         return sv.edicts + n; // EXPERIMENTAL
1708         //return sv.edicts + ((n) / (progs->entityfields * 4));
1709 }
1710 */
1711