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