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