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