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