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