]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_edict.c
saved a little more memory by not keeping around the basebonepose data
[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 =  PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
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         // server and client qc use a lot of similar fields, so this is combined
1233         prog->fieldoffsets.SendEntity                     = PRVM_ED_FindFieldOffset("SendEntity");
1234         prog->fieldoffsets.Version                        = PRVM_ED_FindFieldOffset("Version");
1235         prog->fieldoffsets.alpha                          = PRVM_ED_FindFieldOffset("alpha");
1236         prog->fieldoffsets.ammo_cells1                    = PRVM_ED_FindFieldOffset("ammo_cells1");
1237         prog->fieldoffsets.ammo_lava_nails                = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1238         prog->fieldoffsets.ammo_multi_rockets             = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1239         prog->fieldoffsets.ammo_nails1                    = PRVM_ED_FindFieldOffset("ammo_nails1");
1240         prog->fieldoffsets.ammo_plasma                    = PRVM_ED_FindFieldOffset("ammo_plasma");
1241         prog->fieldoffsets.ammo_rockets1                  = PRVM_ED_FindFieldOffset("ammo_rockets1");
1242         prog->fieldoffsets.ammo_shells1                   = PRVM_ED_FindFieldOffset("ammo_shells1");
1243         prog->fieldoffsets.angles                         = PRVM_ED_FindFieldOffset("angles");
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.buttonchat                     = PRVM_ED_FindFieldOffset("buttonchat");
1259         prog->fieldoffsets.buttonuse                      = PRVM_ED_FindFieldOffset("buttonuse");
1260         prog->fieldoffsets.chain                          = PRVM_ED_FindFieldOffset("chain");
1261         prog->fieldoffsets.classname                      = PRVM_ED_FindFieldOffset("classname");
1262         prog->fieldoffsets.clientcolors                   = PRVM_ED_FindFieldOffset("clientcolors");
1263         prog->fieldoffsets.color                          = PRVM_ED_FindFieldOffset("color");
1264         prog->fieldoffsets.colormod                       = PRVM_ED_FindFieldOffset("colormod");
1265         prog->fieldoffsets.contentstransition             = PRVM_ED_FindFieldOffset("contentstransition");
1266         prog->fieldoffsets.cursor_active                  = PRVM_ED_FindFieldOffset("cursor_active");
1267         prog->fieldoffsets.cursor_screen                  = PRVM_ED_FindFieldOffset("cursor_screen");
1268         prog->fieldoffsets.cursor_trace_endpos            = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1269         prog->fieldoffsets.cursor_trace_ent               = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1270         prog->fieldoffsets.cursor_trace_start             = PRVM_ED_FindFieldOffset("cursor_trace_start");
1271         prog->fieldoffsets.customizeentityforclient       = PRVM_ED_FindFieldOffset("customizeentityforclient");
1272         prog->fieldoffsets.dimension_hit                  = PRVM_ED_FindFieldOffset("dimension_hit");
1273         prog->fieldoffsets.dimension_solid                = PRVM_ED_FindFieldOffset("dimension_solid");
1274         prog->fieldoffsets.disableclientprediction        = PRVM_ED_FindFieldOffset("disableclientprediction");
1275         prog->fieldoffsets.dphitcontentsmask              = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1276         prog->fieldoffsets.drawonlytoclient               = PRVM_ED_FindFieldOffset("drawonlytoclient");
1277         prog->fieldoffsets.exteriormodeltoclient          = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1278         prog->fieldoffsets.fatness                        = PRVM_ED_FindFieldOffset("fatness");
1279         prog->fieldoffsets.forceshader                    = PRVM_ED_FindFieldOffset("forceshader");
1280         prog->fieldoffsets.frame                          = PRVM_ED_FindFieldOffset("frame");
1281         prog->fieldoffsets.frame1time                     = PRVM_ED_FindFieldOffset("frame1time");
1282         prog->fieldoffsets.frame2                         = PRVM_ED_FindFieldOffset("frame2");
1283         prog->fieldoffsets.frame2time                     = PRVM_ED_FindFieldOffset("frame2time");
1284         prog->fieldoffsets.fullbright                     = PRVM_ED_FindFieldOffset("fullbright");
1285         prog->fieldoffsets.glow_color                     = PRVM_ED_FindFieldOffset("glow_color");
1286         prog->fieldoffsets.glow_size                      = PRVM_ED_FindFieldOffset("glow_size");
1287         prog->fieldoffsets.glow_trail                     = PRVM_ED_FindFieldOffset("glow_trail");
1288         prog->fieldoffsets.gravity                        = PRVM_ED_FindFieldOffset("gravity");
1289         prog->fieldoffsets.groundentity                   = PRVM_ED_FindFieldOffset("groundentity");
1290         prog->fieldoffsets.hull                           = PRVM_ED_FindFieldOffset("hull");
1291         prog->fieldoffsets.ideal_yaw                      = PRVM_ED_FindFieldOffset("ideal_yaw");
1292         prog->fieldoffsets.idealpitch                     = PRVM_ED_FindFieldOffset("idealpitch");
1293         prog->fieldoffsets.items2                         = PRVM_ED_FindFieldOffset("items2");
1294         prog->fieldoffsets.lerpfrac                       = PRVM_ED_FindFieldOffset("lerpfrac");
1295         prog->fieldoffsets.light_lev                      = PRVM_ED_FindFieldOffset("light_lev");
1296         prog->fieldoffsets.movement                       = PRVM_ED_FindFieldOffset("movement");
1297         prog->fieldoffsets.nextthink                      = PRVM_ED_FindFieldOffset("nextthink");
1298         prog->fieldoffsets.nodrawtoclient                 = PRVM_ED_FindFieldOffset("nodrawtoclient");
1299         prog->fieldoffsets.pflags                         = PRVM_ED_FindFieldOffset("pflags");
1300         prog->fieldoffsets.ping                           = PRVM_ED_FindFieldOffset("ping");
1301         prog->fieldoffsets.pitch_speed                    = PRVM_ED_FindFieldOffset("pitch_speed");
1302         prog->fieldoffsets.playermodel                    = PRVM_ED_FindFieldOffset("playermodel");
1303         prog->fieldoffsets.playerskin                     = PRVM_ED_FindFieldOffset("playerskin");
1304         prog->fieldoffsets.pmodel                         = PRVM_ED_FindFieldOffset("pmodel");
1305         prog->fieldoffsets.punchvector                    = PRVM_ED_FindFieldOffset("punchvector");
1306         prog->fieldoffsets.renderamt                      = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1307         prog->fieldoffsets.renderflags                    = PRVM_ED_FindFieldOffset("renderflags");
1308         prog->fieldoffsets.rendermode                     = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1309         prog->fieldoffsets.scale                          = PRVM_ED_FindFieldOffset("scale");
1310         prog->fieldoffsets.style                          = PRVM_ED_FindFieldOffset("style");
1311         prog->fieldoffsets.tag_entity                     = PRVM_ED_FindFieldOffset("tag_entity");
1312         prog->fieldoffsets.tag_index                      = PRVM_ED_FindFieldOffset("tag_index");
1313         prog->fieldoffsets.think                          = PRVM_ED_FindFieldOffset("think");
1314         prog->fieldoffsets.viewmodelforclient             = PRVM_ED_FindFieldOffset("viewmodelforclient");
1315         prog->fieldoffsets.viewzoom                       = PRVM_ED_FindFieldOffset("viewzoom");
1316         prog->fieldoffsets.yaw_speed                      = PRVM_ED_FindFieldOffset("yaw_speed");
1317         prog->funcoffsets.CSQC_ConsoleCommand             = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1318         prog->funcoffsets.CSQC_Ent_Remove                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1319         prog->funcoffsets.CSQC_Ent_Update                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1320         prog->funcoffsets.CSQC_Event                      = PRVM_ED_FindFunctionOffset("CSQC_Event");
1321         prog->funcoffsets.CSQC_Init                       = PRVM_ED_FindFunctionOffset("CSQC_Init");
1322         prog->funcoffsets.CSQC_InputEvent                 = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1323         prog->funcoffsets.CSQC_Parse_CenterPrint          = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1324         prog->funcoffsets.CSQC_Parse_Print                = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1325         prog->funcoffsets.CSQC_Parse_StuffCmd             = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1326         prog->funcoffsets.CSQC_Parse_TempEntity           = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1327         prog->funcoffsets.CSQC_Shutdown                   = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1328         prog->funcoffsets.CSQC_UpdateView                 = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1329         prog->funcoffsets.EndFrame                        = PRVM_ED_FindFunctionOffset("EndFrame");
1330         prog->funcoffsets.RestoreGame                     = PRVM_ED_FindFunctionOffset("RestoreGame");
1331         prog->funcoffsets.SV_ChangeTeam                   = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1332         prog->funcoffsets.SV_ParseClientCommand           = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1333         prog->funcoffsets.SV_PlayerPhysics                = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1334         prog->globaloffsets.SV_InitCmd                    = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1335         prog->globaloffsets.self                          = PRVM_ED_FindGlobalOffset("self");
1336         prog->globaloffsets.time                          = PRVM_ED_FindGlobalOffset("time");
1337         prog->globaloffsets.v_forward                     = PRVM_ED_FindGlobalOffset("v_forward");
1338         prog->globaloffsets.v_right                       = PRVM_ED_FindGlobalOffset("v_right");
1339         prog->globaloffsets.v_up                          = PRVM_ED_FindGlobalOffset("v_up");
1340         prog->globaloffsets.trace_allsolid                = PRVM_ED_FindGlobalOffset("trace_allsolid");
1341         prog->globaloffsets.trace_startsolid              = PRVM_ED_FindGlobalOffset("trace_startsolid");
1342         prog->globaloffsets.trace_fraction                = PRVM_ED_FindGlobalOffset("trace_fraction");
1343         prog->globaloffsets.trace_inwater                 = PRVM_ED_FindGlobalOffset("trace_inwater");
1344         prog->globaloffsets.trace_inopen                  = PRVM_ED_FindGlobalOffset("trace_inopen");
1345         prog->globaloffsets.trace_endpos                  = PRVM_ED_FindGlobalOffset("trace_endpos");
1346         prog->globaloffsets.trace_plane_normal            = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1347         prog->globaloffsets.trace_plane_dist              = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1348         prog->globaloffsets.trace_ent                     = PRVM_ED_FindGlobalOffset("trace_ent");
1349         prog->globaloffsets.trace_dphitcontents           = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1350         prog->globaloffsets.trace_dphitq3surfaceflags     = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1351         prog->globaloffsets.trace_dphittexturename        = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1352         prog->globaloffsets.trace_dpstartcontents         = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1353
1354         // menu qc only uses some functions, nothing else
1355         prog->funcoffsets.m_display                       = PRVM_ED_FindFunctionOffset("m_display");
1356         prog->funcoffsets.m_draw                          = PRVM_ED_FindFunctionOffset("m_draw");
1357         prog->funcoffsets.m_hide                          = PRVM_ED_FindFunctionOffset("m_hide");
1358         prog->funcoffsets.m_init                          = PRVM_ED_FindFunctionOffset("m_init");
1359         prog->funcoffsets.m_keydown                       = PRVM_ED_FindFunctionOffset("m_keydown");
1360         prog->funcoffsets.m_keyup                         = PRVM_ED_FindFunctionOffset("m_keyup");
1361         prog->funcoffsets.m_shutdown                      = PRVM_ED_FindFunctionOffset("m_shutdown");
1362         prog->funcoffsets.m_toggle                        = PRVM_ED_FindFunctionOffset("m_toggle");
1363 }
1364
1365 // not used
1366 /*
1367 typedef struct dpfield_s
1368 {
1369         int type;
1370         char *string;
1371 }
1372 dpfield_t;
1373
1374 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1375
1376 dpfield_t dpfields[] =
1377 {
1378 };
1379 */
1380
1381 /*
1382 ===============
1383 PRVM_ResetProg
1384 ===============
1385 */
1386
1387 void PRVM_ResetProg()
1388 {
1389         PRVM_GCALL(reset_cmd)();
1390         Mem_FreePool(&prog->progs_mempool);
1391         memset(prog,0,sizeof(prvm_prog_t));
1392 }
1393
1394 /*
1395 ===============
1396 PRVM_LoadLNO
1397 ===============
1398 */
1399 void PRVM_LoadLNO( const char *progname ) {
1400         fs_offset_t filesize;
1401         unsigned char *lno;
1402         unsigned int *header;
1403         char filename[512];
1404
1405         FS_StripExtension( progname, filename, sizeof( filename ) );
1406         strlcat( filename, ".lno", sizeof( filename ) );
1407
1408         lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1409         if( !lno ) {
1410                 return;
1411         }
1412
1413 /*
1414 <Spike>    SafeWrite (h, &lnotype, sizeof(int));
1415 <Spike>    SafeWrite (h, &version, sizeof(int));
1416 <Spike>    SafeWrite (h, &numglobaldefs, sizeof(int));
1417 <Spike>    SafeWrite (h, &numpr_globals, sizeof(int));
1418 <Spike>    SafeWrite (h, &numfielddefs, sizeof(int));
1419 <Spike>    SafeWrite (h, &numstatements, sizeof(int));
1420 <Spike>    SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1421 */
1422         if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1423                 Mem_Free(lno);
1424                 return;
1425         }
1426
1427         header = (unsigned int *) lno;
1428         if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1429                 LittleLong( header[ 1 ] ) == 1 &&
1430                 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1431                 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1432                 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1433                 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1434         {
1435                 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1436                 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1437         }
1438         Mem_Free( lno );
1439 }
1440
1441 /*
1442 ===============
1443 PRVM_LoadProgs
1444 ===============
1445 */
1446 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1447 {
1448         int i;
1449         dstatement_t *st;
1450         ddef_t *infielddefs;
1451         dfunction_t *dfunctions;
1452         fs_offset_t filesize;
1453
1454         if( prog->loaded ) {
1455                 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1456         }
1457
1458         prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1459         if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1460                 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1461
1462         Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1463
1464         prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1465
1466 // byte swap the header
1467         for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1468                 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1469
1470         if (prog->progs->version != PROG_VERSION)
1471                 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1472         if (prog->progs->crc != prog->headercrc)
1473                 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1474
1475         //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1476         dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1477
1478         prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1479         prog->stringssize = 0;
1480         for (i = 0;i < prog->progs->numstrings;i++)
1481         {
1482                 if (prog->progs->ofs_strings + prog->stringssize >= (int)filesize)
1483                         PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1484                 prog->stringssize += (int)strlen (prog->strings + prog->stringssize) + 1;
1485         }
1486         prog->numknownstrings = 0;
1487         prog->maxknownstrings = 0;
1488         prog->knownstrings = NULL;
1489         prog->knownstrings_freeable = NULL;
1490
1491         prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1492
1493         // we need to expand the fielddefs list to include all the engine fields,
1494         // so allocate a new place for it
1495         infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1496         //                                                                                              ( + DPFIELDS                       )
1497         prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1498
1499         prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1500
1501         prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1502
1503         // moved edict_size calculation down below field adding code
1504
1505         //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1506         prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1507
1508 // byte swap the lumps
1509         for (i=0 ; i<prog->progs->numstatements ; i++)
1510         {
1511                 prog->statements[i].op = LittleShort(prog->statements[i].op);
1512                 prog->statements[i].a = LittleShort(prog->statements[i].a);
1513                 prog->statements[i].b = LittleShort(prog->statements[i].b);
1514                 prog->statements[i].c = LittleShort(prog->statements[i].c);
1515         }
1516
1517         prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1518         for (i = 0;i < prog->progs->numfunctions;i++)
1519         {
1520                 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1521                 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1522                 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1523                 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1524                 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1525                 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1526                 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1527         }
1528
1529         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1530         {
1531                 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1532                 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1533                 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1534         }
1535
1536         // copy the progs fields to the new fields list
1537         for (i = 0;i < prog->progs->numfielddefs;i++)
1538         {
1539                 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1540                 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1541                         PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1542                 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1543                 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1544         }
1545
1546         // append the required fields
1547         for (i = 0;i < (int) numrequiredfields;i++)
1548         {
1549                 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1550                 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1551                 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1552                 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1553                         prog->progs->entityfields += 3;
1554                 else
1555                         prog->progs->entityfields++;
1556                 prog->progs->numfielddefs++;
1557         }
1558
1559         // check required functions
1560         for(i=0 ; i < numrequiredfunc ; i++)
1561                 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1562                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1563
1564         // check required globals
1565         for(i=0 ; i < numrequiredglobals ; i++)
1566                 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1567                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1568
1569         for (i=0 ; i<prog->progs->numglobals ; i++)
1570                 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1571
1572         // moved edict_size calculation down here, below field adding code
1573         // LordHavoc: this no longer includes the prvm_edict_t header
1574         prog->edict_size = prog->progs->entityfields * 4;
1575         prog->edictareasize = prog->edict_size * prog->limit_edicts;
1576
1577         // LordHavoc: bounds check anything static
1578         for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1579         {
1580                 switch (st->op)
1581                 {
1582                 case OP_IF:
1583                 case OP_IFNOT:
1584                         if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1585                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1586                         break;
1587                 case OP_GOTO:
1588                         if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1589                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1590                         break;
1591                 // global global global
1592                 case OP_ADD_F:
1593                 case OP_ADD_V:
1594                 case OP_SUB_F:
1595                 case OP_SUB_V:
1596                 case OP_MUL_F:
1597                 case OP_MUL_V:
1598                 case OP_MUL_FV:
1599                 case OP_MUL_VF:
1600                 case OP_DIV_F:
1601                 case OP_BITAND:
1602                 case OP_BITOR:
1603                 case OP_GE:
1604                 case OP_LE:
1605                 case OP_GT:
1606                 case OP_LT:
1607                 case OP_AND:
1608                 case OP_OR:
1609                 case OP_EQ_F:
1610                 case OP_EQ_V:
1611                 case OP_EQ_S:
1612                 case OP_EQ_E:
1613                 case OP_EQ_FNC:
1614                 case OP_NE_F:
1615                 case OP_NE_V:
1616                 case OP_NE_S:
1617                 case OP_NE_E:
1618                 case OP_NE_FNC:
1619                 case OP_ADDRESS:
1620                 case OP_LOAD_F:
1621                 case OP_LOAD_FLD:
1622                 case OP_LOAD_ENT:
1623                 case OP_LOAD_S:
1624                 case OP_LOAD_FNC:
1625                 case OP_LOAD_V:
1626                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1627                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1628                         break;
1629                 // global none global
1630                 case OP_NOT_F:
1631                 case OP_NOT_V:
1632                 case OP_NOT_S:
1633                 case OP_NOT_FNC:
1634                 case OP_NOT_ENT:
1635                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1636                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1637                         break;
1638                 // 2 globals
1639                 case OP_STOREP_F:
1640                 case OP_STOREP_ENT:
1641                 case OP_STOREP_FLD:
1642                 case OP_STOREP_S:
1643                 case OP_STOREP_FNC:
1644                 case OP_STORE_F:
1645                 case OP_STORE_ENT:
1646                 case OP_STORE_FLD:
1647                 case OP_STORE_S:
1648                 case OP_STORE_FNC:
1649                 case OP_STATE:
1650                 case OP_STOREP_V:
1651                 case OP_STORE_V:
1652                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1653                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1654                         break;
1655                 // 1 global
1656                 case OP_CALL0:
1657                 case OP_CALL1:
1658                 case OP_CALL2:
1659                 case OP_CALL3:
1660                 case OP_CALL4:
1661                 case OP_CALL5:
1662                 case OP_CALL6:
1663                 case OP_CALL7:
1664                 case OP_CALL8:
1665                 case OP_DONE:
1666                 case OP_RETURN:
1667                         if ((unsigned short) st->a >= prog->progs->numglobals)
1668                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1669                         break;
1670                 default:
1671                         Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1672                         break;
1673                 }
1674         }
1675
1676         PRVM_LoadLNO(filename);
1677
1678         PRVM_Init_Exec();
1679
1680         prog->loaded = TRUE;
1681
1682         // set flags & ddef_ts in prog
1683
1684         prog->flag = 0;
1685
1686         PRVM_FindOffsets();
1687
1688         PRVM_GCALL(init_cmd)();
1689
1690         // init mempools
1691         PRVM_MEM_Alloc();
1692 }
1693
1694
1695 void PRVM_Fields_f (void)
1696 {
1697         int i, j, ednum, used, usedamount;
1698         int *counts;
1699         char tempstring[MAX_INPUTLINE], tempstring2[260];
1700         const char *name;
1701         prvm_edict_t *ed;
1702         ddef_t *d;
1703         int *v;
1704
1705         // TODO
1706         /*
1707         if (!sv.active)
1708         {
1709                 Con_Print("no progs loaded\n");
1710                 return;
1711         }
1712         */
1713
1714         if(Cmd_Argc() != 2)
1715         {
1716                 Con_Print("prvm_fields <program name>\n");
1717                 return;
1718         }
1719
1720         PRVM_Begin;
1721         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1722                 return;
1723
1724         counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1725         for (ednum = 0;ednum < prog->max_edicts;ednum++)
1726         {
1727                 ed = PRVM_EDICT_NUM(ednum);
1728                 if (ed->priv.required->free)
1729                         continue;
1730                 for (i = 1;i < prog->progs->numfielddefs;i++)
1731                 {
1732                         d = &prog->fielddefs[i];
1733                         name = PRVM_GetString(d->s_name);
1734                         if (name[strlen(name)-2] == '_')
1735                                 continue;       // skip _x, _y, _z vars
1736                         v = (int *)((char *)ed->fields.vp + d->ofs*4);
1737                         // if the value is still all 0, skip the field
1738                         for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1739                         {
1740                                 if (v[j])
1741                                 {
1742                                         counts[i]++;
1743                                         break;
1744                                 }
1745                         }
1746                 }
1747         }
1748         used = 0;
1749         usedamount = 0;
1750         tempstring[0] = 0;
1751         for (i = 0;i < prog->progs->numfielddefs;i++)
1752         {
1753                 d = &prog->fielddefs[i];
1754                 name = PRVM_GetString(d->s_name);
1755                 if (name[strlen(name)-2] == '_')
1756                         continue;       // skip _x, _y, _z vars
1757                 switch(d->type & ~DEF_SAVEGLOBAL)
1758                 {
1759                 case ev_string:
1760                         strlcat(tempstring, "string   ", sizeof(tempstring));
1761                         break;
1762                 case ev_entity:
1763                         strlcat(tempstring, "entity   ", sizeof(tempstring));
1764                         break;
1765                 case ev_function:
1766                         strlcat(tempstring, "function ", sizeof(tempstring));
1767                         break;
1768                 case ev_field:
1769                         strlcat(tempstring, "field    ", sizeof(tempstring));
1770                         break;
1771                 case ev_void:
1772                         strlcat(tempstring, "void     ", sizeof(tempstring));
1773                         break;
1774                 case ev_float:
1775                         strlcat(tempstring, "float    ", sizeof(tempstring));
1776                         break;
1777                 case ev_vector:
1778                         strlcat(tempstring, "vector   ", sizeof(tempstring));
1779                         break;
1780                 case ev_pointer:
1781                         strlcat(tempstring, "pointer  ", sizeof(tempstring));
1782                         break;
1783                 default:
1784                         sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1785                         strlcat(tempstring, tempstring2, sizeof(tempstring));
1786                         break;
1787                 }
1788                 if (strlen(name) > sizeof(tempstring2)-4)
1789                 {
1790                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
1791                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1792                         tempstring2[sizeof(tempstring2)-1] = 0;
1793                         name = tempstring2;
1794                 }
1795                 strlcat(tempstring, name, sizeof(tempstring));
1796                 for (j = (int)strlen(name);j < 25;j++)
1797                         strlcat(tempstring, " ", sizeof(tempstring));
1798                 sprintf(tempstring2, "%5d", counts[i]);
1799                 strlcat(tempstring, tempstring2, sizeof(tempstring));
1800                 strlcat(tempstring, "\n", sizeof(tempstring));
1801                 if (strlen(tempstring) >= sizeof(tempstring)/2)
1802                 {
1803                         Con_Print(tempstring);
1804                         tempstring[0] = 0;
1805                 }
1806                 if (counts[i])
1807                 {
1808                         used++;
1809                         usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1810                 }
1811         }
1812         Mem_Free(counts);
1813         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);
1814
1815         PRVM_End;
1816 }
1817
1818 void PRVM_Globals_f (void)
1819 {
1820         int i;
1821         // TODO
1822         /*if (!sv.active)
1823         {
1824                 Con_Print("no progs loaded\n");
1825                 return;
1826         }*/
1827         if(Cmd_Argc () != 2)
1828         {
1829                 Con_Print("prvm_globals <program name>\n");
1830                 return;
1831         }
1832
1833         PRVM_Begin;
1834         if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1835                 return;
1836
1837         Con_Printf("%s :", PRVM_NAME);
1838
1839         for (i = 0;i < prog->progs->numglobaldefs;i++)
1840                 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1841         Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1842
1843         PRVM_End;
1844 }
1845
1846 /*
1847 ===============
1848 PRVM_Global
1849 ===============
1850 */
1851 void PRVM_Global_f(void)
1852 {
1853         ddef_t *global;
1854         if( Cmd_Argc() != 3 ) {
1855                 Con_Printf( "prvm_global <program name> <global name>\n" );
1856                 return;
1857         }
1858
1859         PRVM_Begin;
1860         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1861                 return;
1862
1863         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1864         if( !global )
1865                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1866         else
1867                 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
1868         PRVM_End;
1869 }
1870
1871 /*
1872 ===============
1873 PRVM_GlobalSet
1874 ===============
1875 */
1876 void PRVM_GlobalSet_f(void)
1877 {
1878         ddef_t *global;
1879         if( Cmd_Argc() != 4 ) {
1880                 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
1881                 return;
1882         }
1883
1884         PRVM_Begin;
1885         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1886                 return;
1887
1888         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1889         if( !global )
1890                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1891         else
1892                 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
1893         PRVM_End;
1894 }
1895
1896 /*
1897 ===============
1898 PRVM_Init
1899 ===============
1900 */
1901 void PRVM_Init (void)
1902 {
1903         Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
1904         Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "set a property on an entity number in the selected VM (server, client, menu)");
1905         Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
1906         Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
1907         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)");
1908         Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
1909         Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
1910         Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
1911         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)");
1912         Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
1913         // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1914         Cvar_RegisterVariable (&prvm_boundscheck);
1915         Cvar_RegisterVariable (&prvm_traceqc);
1916         Cvar_RegisterVariable (&prvm_statementprofiling);
1917
1918         //VM_Cmd_Init();
1919 }
1920
1921 /*
1922 ===============
1923 PRVM_InitProg
1924 ===============
1925 */
1926 void PRVM_InitProg(int prognr)
1927 {
1928         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1929                 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
1930
1931         prog = &prog_list[prognr];
1932
1933         if(prog->loaded)
1934                 PRVM_ResetProg();
1935
1936         memset(prog, 0, sizeof(prvm_prog_t));
1937
1938         prog->error_cmd = Host_Error;
1939 }
1940
1941 int PRVM_GetProgNr()
1942 {
1943         return prog - prog_list;
1944 }
1945
1946 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
1947 {
1948         return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
1949 }
1950
1951 void _PRVM_Free(void *buffer, const char *filename, int fileline)
1952 {
1953         _Mem_Free(buffer, filename, fileline);
1954 }
1955
1956 void _PRVM_FreeAll(const char *filename, int fileline)
1957 {
1958         prog->progs = NULL;
1959         prog->fielddefs = NULL;
1960         prog->functions = NULL;
1961         _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
1962 }
1963
1964 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1965 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1966 {
1967         PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1968         return NULL;
1969 }
1970
1971 /*
1972 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
1973 {
1974         PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
1975         return 0;
1976 }
1977
1978 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
1979 {
1980         int n;
1981         n = e - prog->edicts;
1982         if ((unsigned int)n >= prog->limit_edicts)
1983                 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
1984         return n;
1985 }
1986
1987 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
1988 //{
1989 //      return e - prog->edicts;
1990 //}
1991
1992 //#define       PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
1993 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
1994 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
1995 {
1996         int n;
1997         n = e - prog->edicts;
1998         if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1999                 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
2000         return n;// EXPERIMENTAL
2001         //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2002 }
2003 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2004 {
2005         if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2006                 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2007         return prog->edicts + n; // EXPERIMENTAL
2008         //return prog->edicts + ((n) / (progs->entityfields * 4));
2009 }
2010 */
2011
2012
2013 sizebuf_t vm_tempstringsbuf;
2014
2015 const char *PRVM_GetString(int num)
2016 {
2017         if (num >= 0)
2018         {
2019                 if (num < prog->stringssize)
2020                         return prog->strings + num;
2021                 else
2022 #if 1
2023                 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2024                 {
2025                         num -= prog->stringssize;
2026                         if (num < vm_tempstringsbuf.cursize)
2027                                 return (char *)vm_tempstringsbuf.data + num;
2028                         else
2029                         {
2030                                 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
2031                                 return "";
2032                         }
2033                 }
2034                 else
2035 #endif
2036                 {
2037                         VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)", num, prog->stringssize);
2038                         return "";
2039                 }
2040         }
2041         else
2042         {
2043                 num = -1 - num;
2044 #if 0
2045                 if (num >= (1<<30))
2046                 {
2047                         // special range reserved for tempstrings
2048                         num -= (1<<30);
2049                         if (num < vm_tempstringsbuf.cursize)
2050                                 return (char *)vm_tempstringsbuf.data + num;
2051                         else
2052                         {
2053                                 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
2054                                 return "";
2055                         }
2056                 }
2057                 else
2058 #endif
2059                 if (num < prog->numknownstrings)
2060                 {
2061                         if (!prog->knownstrings[num])
2062                                 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)", num);
2063                         return prog->knownstrings[num];
2064                 }
2065                 else
2066                 {
2067                         VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)", num, prog->numknownstrings);
2068                         return "";
2069                 }
2070         }
2071 }
2072
2073 int PRVM_SetEngineString(const char *s)
2074 {
2075         int i;
2076         if (!s)
2077                 return 0;
2078         if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2079                 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2080         // if it's in the tempstrings area, use a reserved range
2081         // (otherwise we'd get millions of useless string offsets cluttering the database)
2082         if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2083 #if 1
2084                 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2085 #else
2086                 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2087 #endif
2088         // see if it's a known string address
2089         for (i = 0;i < prog->numknownstrings;i++)
2090                 if (prog->knownstrings[i] == s)
2091                         return -1 - i;
2092         // new unknown engine string
2093         if (developer.integer >= 200)
2094                 Con_Printf("new engine string %p = \"%s\"\n", s, s);
2095         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2096                 if (!prog->knownstrings[i])
2097                         break;
2098         if (i >= prog->numknownstrings)
2099         {
2100                 if (i >= prog->maxknownstrings)
2101                 {
2102                         const char **oldstrings = prog->knownstrings;
2103                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2104                         prog->maxknownstrings += 128;
2105                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2106                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2107                         if (prog->numknownstrings)
2108                         {
2109                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2110                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2111                         }
2112                 }
2113                 prog->numknownstrings++;
2114         }
2115         prog->firstfreeknownstring = i + 1;
2116         prog->knownstrings[i] = s;
2117         return -1 - i;
2118 }
2119
2120 // temp string handling
2121
2122 // all tempstrings go into this buffer consecutively, and it is reset
2123 // whenever PRVM_ExecuteProgram returns to the engine
2124 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2125 //  restores it on return, so multiple recursive calls can share the same
2126 //  buffer)
2127 // the buffer size is automatically grown as needed
2128
2129 int PRVM_SetTempString(const char *s)
2130 {
2131         int size;
2132         char *t;
2133         if (!s)
2134                 return 0;
2135         size = (int)strlen(s) + 1;
2136         if (developer.integer >= 300)
2137                 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2138         if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2139         {
2140                 sizebuf_t old = vm_tempstringsbuf;
2141                 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2142                         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);
2143                 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2144                 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2145                         vm_tempstringsbuf.maxsize *= 2;
2146                 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2147                 {
2148                         if (developer.integer >= 100)
2149                                 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2150                         vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2151                         if (old.cursize)
2152                                 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2153                         if (old.data)
2154                                 Mem_Free(old.data);
2155                 }
2156         }
2157         t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2158         memcpy(t, s, size);
2159         vm_tempstringsbuf.cursize += size;
2160         return PRVM_SetEngineString(t);
2161 }
2162
2163 int PRVM_AllocString(size_t bufferlength, char **pointer)
2164 {
2165         int i;
2166         if (!bufferlength)
2167                 return 0;
2168         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2169                 if (!prog->knownstrings[i])
2170                         break;
2171         if (i >= prog->numknownstrings)
2172         {
2173                 if (i >= prog->maxknownstrings)
2174                 {
2175                         const char **oldstrings = prog->knownstrings;
2176                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2177                         prog->maxknownstrings += 128;
2178                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2179                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2180                         if (prog->numknownstrings)
2181                         {
2182                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2183                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2184                         }
2185                 }
2186                 prog->numknownstrings++;
2187         }
2188         prog->firstfreeknownstring = i + 1;
2189         prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2190         prog->knownstrings_freeable[i] = true;
2191         if (pointer)
2192                 *pointer = (char *)(prog->knownstrings[i]);
2193         return -1 - i;
2194 }
2195
2196 void PRVM_FreeString(int num)
2197 {
2198         if (num == 0)
2199                 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2200         else if (num >= 0 && num < prog->stringssize)
2201                 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2202         else if (num < 0 && num >= -prog->numknownstrings)
2203         {
2204                 num = -1 - num;
2205                 if (!prog->knownstrings[num])
2206                         PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2207                 if (!prog->knownstrings[num])
2208                         PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2209                 PRVM_Free((char *)prog->knownstrings[num]);
2210                 prog->knownstrings[num] = NULL;
2211                 prog->knownstrings_freeable[num] = false;
2212                 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2213         }
2214         else
2215                 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);
2216 }
2217