1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2010-2014 QuakeSpasm developers
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
15 See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21 */
22 // sv_edict.c -- entity dictionary
23
24 #include "quakedef.h"
25
26
27 int type_size[8] = {
28 1, // ev_void
29 1, // sizeof(string_t) / 4 // ev_string
30 1, // ev_float
31 3, // ev_vector
32 1, // ev_entity
33 1, // ev_field
34 1, // sizeof(func_t) / 4 // ev_function
35 1 // sizeof(void *) / 4 // ev_pointer
36 };
37
38 static ddef_t *ED_FieldAtOfs (int ofs);
39
40 cvar_t nomonsters = {"nomonsters", "0", CVAR_NONE};
41 cvar_t gamecfg = {"gamecfg", "0", CVAR_NONE};
42 cvar_t scratch1 = {"scratch1", "0", CVAR_NONE};
43 cvar_t scratch2 = {"scratch2", "0", CVAR_NONE};
44 cvar_t scratch3 = {"scratch3", "0", CVAR_NONE};
45 cvar_t scratch4 = {"scratch4", "0", CVAR_NONE};
46 cvar_t savedgamecfg = {"savedgamecfg", "0", CVAR_ARCHIVE};
47 cvar_t saved1 = {"saved1", "0", CVAR_ARCHIVE};
48 cvar_t saved2 = {"saved2", "0", CVAR_ARCHIVE};
49 cvar_t saved3 = {"saved3", "0", CVAR_ARCHIVE};
50 cvar_t saved4 = {"saved4", "0", CVAR_ARCHIVE};
51
52 /*
53 =================
54 ED_ClearEdict
55
56 Sets everything to NULL
57 =================
58 */
ED_ClearEdict(edict_t * e)59 void ED_ClearEdict (edict_t *e)
60 {
61 memset (&e->v, 0, qcvm->progs->entityfields * 4);
62 e->free = false;
63 }
64
65 /*
66 =================
67 ED_Alloc
68
69 Either finds a free edict, or allocates a new one.
70 Try to avoid reusing an entity that was recently freed, because it
71 can cause the client to think the entity morphed into something else
72 instead of being removed and recreated, which can cause interpolated
73 angles and bad trails.
74 =================
75 */
ED_Alloc(void)76 edict_t *ED_Alloc (void)
77 {
78 int i;
79 edict_t *e;
80
81 for (i = qcvm->reserved_edicts; i < qcvm->num_edicts; i++)
82 {
83 e = EDICT_NUM(i);
84 // the first couple seconds of server time can involve a lot of
85 // freeing and allocating, so relax the replacement policy
86 if (e->free && ( e->freetime < 2 || qcvm->time - e->freetime > 0.5 ) )
87 {
88 ED_ClearEdict (e);
89 return e;
90 }
91 }
92
93 if (i == qcvm->max_edicts) //johnfitz -- use sv.max_edicts instead of MAX_EDICTS
94 Host_Error ("ED_Alloc: no free edicts (max_edicts is %i)", qcvm->max_edicts);
95
96 qcvm->num_edicts++;
97 e = EDICT_NUM(i);
98 memset(e, 0, qcvm->edict_size); // ericw -- switched sv.edicts to malloc(), so we are accessing uninitialized memory and must fully zero it, not just ED_ClearEdict
99
100 return e;
101 }
102
103 /*
104 =================
105 ED_Free
106
107 Marks the edict as free
108 FIXME: walk all entities and NULL out references to this entity
109 =================
110 */
ED_Free(edict_t * ed)111 void ED_Free (edict_t *ed)
112 {
113 SV_UnlinkEdict (ed); // unlink from world bsp
114
115 ed->free = true;
116 ed->v.model = 0;
117 ed->v.takedamage = 0;
118 ed->v.modelindex = 0;
119 ed->v.colormap = 0;
120 ed->v.skin = 0;
121 ed->v.frame = 0;
122 VectorCopy (vec3_origin, ed->v.origin);
123 VectorCopy (vec3_origin, ed->v.angles);
124 ed->v.nextthink = -1;
125 ed->v.solid = 0;
126 ed->alpha = ENTALPHA_DEFAULT; //johnfitz -- reset alpha for next entity
127
128 ed->freetime = qcvm->time;
129 }
130
131 //===========================================================================
132
133 /*
134 ============
135 ED_GlobalAtOfs
136 ============
137 */
ED_GlobalAtOfs(int ofs)138 static ddef_t *ED_GlobalAtOfs (int ofs)
139 {
140 ddef_t *def;
141 int i;
142
143 for (i = 0; i < qcvm->progs->numglobaldefs; i++)
144 {
145 def = &qcvm->globaldefs[i];
146 if (def->ofs == ofs)
147 return def;
148 }
149 return NULL;
150 }
151
152 /*
153 ============
154 ED_FieldAtOfs
155 ============
156 */
ED_FieldAtOfs(int ofs)157 static ddef_t *ED_FieldAtOfs (int ofs)
158 {
159 ddef_t *def;
160 int i;
161
162 for (i = 0; i < qcvm->progs->numfielddefs; i++)
163 {
164 def = &qcvm->fielddefs[i];
165 if (def->ofs == ofs)
166 return def;
167 }
168 return NULL;
169 }
170
171 /*
172 ============
173 ED_FindField
174 ============
175 */
ED_FindField(const char * name)176 ddef_t *ED_FindField (const char *name)
177 {
178 ddef_t *def;
179 int i;
180
181 for (i = 0; i < qcvm->progs->numfielddefs; i++)
182 {
183 def = &qcvm->fielddefs[i];
184 if ( !strcmp(PR_GetString(def->s_name), name) )
185 return def;
186 }
187 return NULL;
188 }
189
190 /*
191 */
ED_FindFieldOffset(const char * name)192 int ED_FindFieldOffset (const char *name)
193 {
194 ddef_t *def = ED_FindField(name);
195 if (!def)
196 return -1;
197 return def->ofs;
198 }
199
200 /*
201 ============
202 ED_FindGlobal
203 ============
204 */
ED_FindGlobal(const char * name)205 ddef_t *ED_FindGlobal (const char *name)
206 {
207 ddef_t *def;
208 int i;
209
210 for (i = 0; i < qcvm->progs->numglobaldefs; i++)
211 {
212 def = &qcvm->globaldefs[i];
213 if ( !strcmp(PR_GetString(def->s_name), name) )
214 return def;
215 }
216 return NULL;
217 }
218
219
220 /*
221 ============
222 ED_FindFunction
223 ============
224 */
ED_FindFunction(const char * fn_name)225 dfunction_t *ED_FindFunction (const char *fn_name)
226 {
227 dfunction_t *func;
228 int i;
229
230 for (i = 0; i < qcvm->progs->numfunctions; i++)
231 {
232 func = &qcvm->functions[i];
233 if ( !strcmp(PR_GetString(func->s_name), fn_name) )
234 return func;
235 }
236 return NULL;
237 }
238
239 /*
240 ============
241 GetEdictFieldValue
242 ============
243 */
GetEdictFieldValue(edict_t * ed,int fldofs)244 eval_t *GetEdictFieldValue(edict_t *ed, int fldofs)
245 {
246 if (fldofs < 0)
247 return NULL;
248
249 return (eval_t *)((char *)&ed->v + fldofs*4);
250 }
251
252
253 /*
254 ============
255 PR_ValueString
256 (etype_t type, eval_t *val)
257
258 Returns a string describing *data in a type specific manner
259 =============
260 */
PR_ValueString(int type,eval_t * val)261 static const char *PR_ValueString (int type, eval_t *val)
262 {
263 static char line[512];
264 ddef_t *def;
265 dfunction_t *f;
266
267 type &= ~DEF_SAVEGLOBAL;
268
269 switch (type)
270 {
271 case ev_string:
272 sprintf (line, "%s", PR_GetString(val->string));
273 break;
274 case ev_entity:
275 sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) );
276 break;
277 case ev_function:
278 f = qcvm->functions + val->function;
279 sprintf (line, "%s()", PR_GetString(f->s_name));
280 break;
281 case ev_field:
282 def = ED_FieldAtOfs ( val->_int );
283 sprintf (line, ".%s", PR_GetString(def->s_name));
284 break;
285 case ev_void:
286 sprintf (line, "void");
287 break;
288 case ev_float:
289 sprintf (line, "%5.1f", val->_float);
290 break;
291 case ev_ext_integer:
292 sprintf (line, "%i", val->_int);
293 break;
294 case ev_vector:
295 sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]);
296 break;
297 case ev_pointer:
298 sprintf (line, "pointer");
299 break;
300 default:
301 sprintf (line, "bad type %i", type);
302 break;
303 }
304
305 return line;
306 }
307
308 /*
309 ============
310 PR_UglyValueString
311 (etype_t type, eval_t *val)
312
313 Returns a string describing *data in a type specific manner
314 Easier to parse than PR_ValueString
315 =============
316 */
PR_UglyValueString(int type,eval_t * val)317 const char *PR_UglyValueString (int type, eval_t *val)
318 {
319 static char line[1024];
320 ddef_t *def;
321 dfunction_t *f;
322
323 type &= ~DEF_SAVEGLOBAL;
324
325 switch (type)
326 {
327 case ev_string:
328 q_snprintf (line, sizeof(line), "%s", PR_GetString(val->string));
329 break;
330 case ev_entity:
331 q_snprintf (line, sizeof(line), "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)));
332 break;
333 case ev_function:
334 f = qcvm->functions + val->function;
335 q_snprintf (line, sizeof(line), "%s", PR_GetString(f->s_name));
336 break;
337 case ev_field:
338 def = ED_FieldAtOfs ( val->_int );
339 q_snprintf (line, sizeof(line), "%s", PR_GetString(def->s_name));
340 break;
341 case ev_void:
342 q_snprintf (line, sizeof(line), "void");
343 break;
344 case ev_float:
345 q_snprintf (line, sizeof(line), "%f", val->_float);
346 break;
347 case ev_ext_integer:
348 sprintf (line, "%i", val->_int);
349 break;
350 case ev_vector:
351 q_snprintf (line, sizeof(line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
352 break;
353 default:
354 q_snprintf (line, sizeof(line), "bad type %i", type);
355 break;
356 }
357
358 return line;
359 }
360
361 /*
362 ============
363 PR_GlobalString
364
365 Returns a string with a description and the contents of a global,
366 padded to 20 field width
367 ============
368 */
PR_GlobalString(int ofs)369 const char *PR_GlobalString (int ofs)
370 {
371 static char line[512];
372 const char *s;
373 int i;
374 ddef_t *def;
375 void *val;
376
377 val = (void *)&qcvm->globals[ofs];
378 def = ED_GlobalAtOfs(ofs);
379 if (!def)
380 sprintf (line,"%i(?)", ofs);
381 else
382 {
383 s = PR_ValueString (def->type, (eval_t *)val);
384 sprintf (line,"%i(%s)%s", ofs, PR_GetString(def->s_name), s);
385 }
386
387 i = strlen(line);
388 for ( ; i < 20; i++)
389 strcat (line, " ");
390 strcat (line, " ");
391
392 return line;
393 }
394
PR_GlobalStringNoContents(int ofs)395 const char *PR_GlobalStringNoContents (int ofs)
396 {
397 static char line[512];
398 int i;
399 ddef_t *def;
400
401 def = ED_GlobalAtOfs(ofs);
402 if (!def)
403 sprintf (line,"%i(?)", ofs);
404 else
405 sprintf (line,"%i(%s)", ofs, PR_GetString(def->s_name));
406
407 i = strlen(line);
408 for ( ; i < 20; i++)
409 strcat (line, " ");
410 strcat (line, " ");
411
412 return line;
413 }
414
415
416 /*
417 =============
418 ED_Print
419
420 For debugging
421 =============
422 */
ED_Print(edict_t * ed)423 void ED_Print (edict_t *ed)
424 {
425 ddef_t *d;
426 int *v;
427 int i, j, l;
428 const char *name;
429 int type;
430
431 if (ed->free)
432 {
433 Con_Printf ("FREE\n");
434 return;
435 }
436
437 Con_SafePrintf("\nEDICT %i:\n", NUM_FOR_EDICT(ed)); //johnfitz -- was Con_Printf
438 for (i = 1; i < qcvm->progs->numfielddefs; i++)
439 {
440 d = &qcvm->fielddefs[i];
441 name = PR_GetString(d->s_name);
442 l = strlen (name);
443 if (l > 1 && name[l - 2] == '_')
444 continue; // skip _x, _y, _z vars
445
446 v = (int *)((char *)&ed->v + d->ofs*4);
447
448 // if the value is still all 0, skip the field
449 type = d->type & ~DEF_SAVEGLOBAL;
450
451 for (j = 0; j < type_size[type]; j++)
452 {
453 if (v[j])
454 break;
455 }
456 if (j == type_size[type])
457 continue;
458
459 Con_SafePrintf ("%s", name); //johnfitz -- was Con_Printf
460 while (l++ < 15)
461 Con_SafePrintf (" "); //johnfitz -- was Con_Printf
462
463 Con_SafePrintf ("%s\n", PR_ValueString(d->type, (eval_t *)v)); //johnfitz -- was Con_Printf
464 }
465 }
466
467 /*
468 =============
469 ED_Write
470
471 For savegames
472 =============
473 */
ED_Write(FILE * f,edict_t * ed)474 void ED_Write (FILE *f, edict_t *ed)
475 {
476 ddef_t *d;
477 int *v;
478 int i, j;
479 const char *name;
480 int type;
481
482 fprintf (f, "{\n");
483
484 if (ed->free)
485 {
486 fprintf (f, "}\n");
487 return;
488 }
489
490 for (i = 1; i < qcvm->progs->numfielddefs; i++)
491 {
492 d = &qcvm->fielddefs[i];
493 name = PR_GetString(d->s_name);
494 j = strlen (name);
495 if (j > 1 && name[j - 2] == '_')
496 continue; // skip _x, _y, _z vars
497
498 v = (int *)((char *)&ed->v + d->ofs*4);
499
500 // if the value is still all 0, skip the field
501 type = d->type & ~DEF_SAVEGLOBAL;
502 for (j = 0; j < type_size[type]; j++)
503 {
504 if (v[j])
505 break;
506 }
507 if (j == type_size[type])
508 continue;
509
510 fprintf (f, "\"%s\" ", name);
511 fprintf (f, "\"%s\"\n", PR_UglyValueString(d->type, (eval_t *)v));
512 }
513
514 //johnfitz -- save entity alpha manually when progs.dat doesn't know about alpha
515 if (qcvm->extfields.alpha<0 && ed->alpha != ENTALPHA_DEFAULT)
516 fprintf (f, "\"alpha\" \"%f\"\n", ENTALPHA_TOSAVE(ed->alpha));
517 //johnfitz
518
519 fprintf (f, "}\n");
520 }
521
ED_PrintNum(int ent)522 void ED_PrintNum (int ent)
523 {
524 ED_Print (EDICT_NUM(ent));
525 }
526
527 /*
528 =============
529 ED_PrintEdicts
530
531 For debugging, prints all the entities in the current server
532 =============
533 */
ED_PrintEdicts(void)534 void ED_PrintEdicts (void)
535 {
536 int i;
537
538 if (!sv.active)
539 return;
540
541 PR_SwitchQCVM(&sv.qcvm);
542 Con_Printf ("%i entities\n", qcvm->num_edicts);
543 for (i = 0; i < qcvm->num_edicts; i++)
544 ED_PrintNum (i);
545 PR_SwitchQCVM(NULL);
546 }
547
548 /*
549 =============
550 ED_PrintEdict_f
551
552 For debugging, prints a single edicy
553 =============
554 */
ED_PrintEdict_f(void)555 static void ED_PrintEdict_f (void)
556 {
557 int i;
558
559 if (!sv.active)
560 return;
561
562 i = Q_atoi (Cmd_Argv(1));
563 PR_SwitchQCVM(&sv.qcvm);
564 if (i < 0 || i >= qcvm->num_edicts)
565 Con_Printf("Bad edict number\n");
566 else
567 {
568 if (Cmd_Argc() == 2 || svs.maxclients != 1) //edict N
569 ED_PrintNum (i);
570 else //edict N FLD ...
571 {
572 ddef_t *def = ED_FindField(Cmd_Argv(2));
573 if (!def)
574 Con_Printf("Field %s not defined\n", Cmd_Argv(2));
575 else if (Cmd_Argc() < 4)
576 Con_Printf("Edict %u.%s==%s\n", i, PR_GetString(def->s_name), PR_UglyValueString(def->type&~DEF_SAVEGLOBAL, (eval_t *)((char *)&EDICT_NUM(i)->v + def->ofs*4)));
577 else
578 ED_ParseEpair((void *)&EDICT_NUM(i)->v, def, Cmd_Argv(3), false);
579 }
580
581 }
582 PR_SwitchQCVM(NULL);
583 }
584
585 /*
586 =============
587 ED_Count
588
589 For debugging
590 =============
591 */
ED_Count(void)592 static void ED_Count (void)
593 {
594 edict_t *ent;
595 int i, active, models, solid, step;
596
597 if (!sv.active)
598 return;
599
600 PR_SwitchQCVM(&sv.qcvm);
601 active = models = solid = step = 0;
602 for (i = 0; i < qcvm->num_edicts; i++)
603 {
604 ent = EDICT_NUM(i);
605 if (ent->free)
606 continue;
607 active++;
608 if (ent->v.solid)
609 solid++;
610 if (ent->v.model)
611 models++;
612 if (ent->v.movetype == MOVETYPE_STEP)
613 step++;
614 }
615
616 Con_Printf ("num_edicts:%3i\n", qcvm->num_edicts);
617 Con_Printf ("active :%3i\n", active);
618 Con_Printf ("view :%3i\n", models);
619 Con_Printf ("touch :%3i\n", solid);
620 Con_Printf ("step :%3i\n", step);
621 PR_SwitchQCVM(NULL);
622 }
623
624
625 /*
626 ==============================================================================
627
628 ARCHIVING GLOBALS
629
630 FIXME: need to tag constants, doesn't really work
631 ==============================================================================
632 */
633
634 /*
635 =============
636 ED_WriteGlobals
637 =============
638 */
ED_WriteGlobals(FILE * f)639 void ED_WriteGlobals (FILE *f)
640 {
641 ddef_t *def;
642 int i;
643 const char *name;
644 int type;
645
646 fprintf (f, "{\n");
647 for (i = 0; i < qcvm->progs->numglobaldefs; i++)
648 {
649 def = &qcvm->globaldefs[i];
650 type = def->type;
651 if ( !(def->type & DEF_SAVEGLOBAL) )
652 continue;
653 type &= ~DEF_SAVEGLOBAL;
654
655 if (type != ev_string && type != ev_float && type != ev_ext_integer && type != ev_entity)
656 continue;
657
658 name = PR_GetString(def->s_name);
659 fprintf (f, "\"%s\" ", name);
660 fprintf (f, "\"%s\"\n", PR_UglyValueString(type, (eval_t *)&qcvm->globals[def->ofs]));
661 }
662 fprintf (f, "}\n");
663 }
664
665 /*
666 =============
667 ED_ParseGlobals
668 =============
669 */
ED_ParseGlobals(const char * data)670 const char *ED_ParseGlobals (const char *data)
671 {
672 char keyname[64];
673 ddef_t *key;
674
675 while (1)
676 {
677 // parse key
678 data = COM_Parse (data);
679 if (com_token[0] == '}')
680 break;
681 if (!data)
682 Host_Error ("ED_ParseEntity: EOF without closing brace");
683
684 q_strlcpy (keyname, com_token, sizeof(keyname));
685
686 // parse value
687 data = COM_Parse (data);
688 if (!data)
689 Host_Error ("ED_ParseEntity: EOF without closing brace");
690
691 if (com_token[0] == '}')
692 Host_Error ("ED_ParseEntity: closing brace without data");
693
694 key = ED_FindGlobal (keyname);
695 if (!key)
696 {
697 Con_Printf ("'%s' is not a global\n", keyname);
698 continue;
699 }
700
701 if (!ED_ParseEpair ((void *)qcvm->globals, key, com_token, false))
702 Host_Error ("ED_ParseGlobals: parse error");
703 }
704 return data;
705 }
706
707 //============================================================================
708
709
710 /*
711 =============
712 ED_NewString
713 =============
714 */
ED_NewString(const char * string)715 static string_t ED_NewString (const char *string)
716 {
717 char *new_p;
718 int i, l;
719 string_t num;
720
721 l = strlen(string) + 1;
722 num = PR_AllocString (l, &new_p);
723
724 for (i = 0; i < l; i++)
725 {
726 if (string[i] == '\\' && i < l-1)
727 {
728 i++;
729 if (string[i] == 'n')
730 *new_p++ = '\n';
731 else
732 *new_p++ = '\\';
733 }
734 else
735 *new_p++ = string[i];
736 }
737
738 return num;
739 }
ED_RezoneString(string_t * ref,const char * str)740 static void ED_RezoneString (string_t *ref, const char *str)
741 {
742 char *buf;
743 size_t len = strlen(str)+1;
744 size_t id;
745
746 if (*ref)
747 { //if the reference is already a zoned string then free it first.
748 id = -1-*ref;
749 if (id < qcvm->knownzonesize && (qcvm->knownzone[id>>3] & (1u<<(id&7))))
750 { //okay, it was zoned.
751 qcvm->knownzone[id>>3] &= ~(1u<<(id&7));
752 buf = (char*)PR_GetString(*ref);
753 PR_ClearEngineString(*ref);
754 Z_Free(buf);
755 }
756 // else
757 // Con_Warning("ED_RezoneString: string wasn't strzoned\n"); //warnings would trigger from the default cvar value that autocvars are initialised with
758 }
759
760 buf = Z_Malloc(len);
761 memcpy(buf, str, len);
762 id = -1-(*ref = PR_SetEngineString(buf));
763 //make sure its flagged as zoned so we can clean up properly after.
764 if (id >= qcvm->knownzonesize)
765 {
766 qcvm->knownzonesize = (id+32)&~7;
767 qcvm->knownzone = Z_Realloc(qcvm->knownzone, (qcvm->knownzonesize+7)>>3);
768 }
769 qcvm->knownzone[id>>3] |= 1u<<(id&7);
770 }
771
772 /*
773 =============
774 ED_ParseEval
775
776 Can parse either fields or globals
777 returns false if error
778 =============
779 */
ED_ParseEpair(void * base,ddef_t * key,const char * s,qboolean zoned)780 qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s, qboolean zoned)
781 {
782 int i;
783 char string[128];
784 ddef_t *def;
785 char *v, *w;
786 char *end;
787 void *d;
788 dfunction_t *func;
789
790 d = (void *)((int *)base + key->ofs);
791
792 switch (key->type & ~DEF_SAVEGLOBAL)
793 {
794 case ev_string:
795 if (zoned) //zoned version allows us to change the strings more freely
796 ED_RezoneString((string_t *)d, s);
797 else
798 *(string_t *)d = ED_NewString(s);
799 break;
800
801 case ev_float:
802 *(float *)d = atof (s);
803 break;
804
805 case ev_ext_integer:
806 *(int *)d = atoi (s);
807 break;
808
809 case ev_vector:
810 q_strlcpy (string, s, sizeof(string));
811 end = (char *)string + strlen(string);
812 v = string;
813 w = string;
814
815 for (i = 0; i < 3 && (w <= end); i++) // ericw -- added (w <= end) check
816 {
817 // set v to the next space (or 0 byte), and change that char to a 0 byte
818 while (*v && *v != ' ')
819 v++;
820 *v = 0;
821 ((float *)d)[i] = atof (w);
822 w = v = v+1;
823 }
824 // ericw -- fill remaining elements to 0 in case we hit the end of string
825 // before reading 3 floats.
826 if (i < 3)
827 {
828 Con_DWarning ("Avoided reading garbage for \"%s\" \"%s\"\n", PR_GetString(key->s_name), s);
829 for (; i < 3; i++)
830 ((float *)d)[i] = 0.0f;
831 }
832 break;
833
834 case ev_entity:
835 if (!strncmp(s, "entity ", 7)) //Spike: putentityfieldstring/etc should be able to cope with etos's weirdness.
836 s += 7;
837 *(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s)));
838 break;
839
840 case ev_field:
841 def = ED_FindField (s);
842 if (!def)
843 {
844 //johnfitz -- HACK -- suppress error becuase fog/sky fields might not be mentioned in defs.qc
845 if (strncmp(s, "sky", 3) && strcmp(s, "fog"))
846 Con_DPrintf ("Can't find field %s\n", s);
847 return false;
848 }
849 *(int *)d = G_INT(def->ofs);
850 break;
851
852 case ev_function:
853 func = ED_FindFunction (s);
854 if (!func)
855 {
856 Con_Printf ("Can't find function %s\n", s);
857 return false;
858 }
859 *(func_t *)d = func - qcvm->functions;
860 break;
861
862 default:
863 break;
864 }
865 return true;
866 }
867
868 /*
869 ====================
870 ED_ParseEdict
871
872 Parses an edict out of the given string, returning the new position
873 ed should be a properly initialized empty edict.
874 Used for initial level load and for savegames.
875 ====================
876 */
ED_ParseEdict(const char * data,edict_t * ent)877 const char *ED_ParseEdict (const char *data, edict_t *ent)
878 {
879 ddef_t *key;
880 char keyname[256];
881 qboolean anglehack, init;
882 int n;
883
884 init = false;
885
886 // clear it
887 if (ent != qcvm->edicts) // hack
888 memset (&ent->v, 0, qcvm->progs->entityfields * 4);
889
890 // go through all the dictionary pairs
891 while (1)
892 {
893 // parse key
894 data = COM_Parse (data);
895 if (com_token[0] == '}')
896 break;
897 if (!data)
898 Host_Error ("ED_ParseEntity: EOF without closing brace");
899
900 // anglehack is to allow QuakeEd to write single scalar angles
901 // and allow them to be turned into vectors. (FIXME...)
902 if (!strcmp(com_token, "angle"))
903 {
904 strcpy (com_token, "angles");
905 anglehack = true;
906 }
907 else
908 anglehack = false;
909
910 // FIXME: change light to _light to get rid of this hack
911 if (!strcmp(com_token, "light"))
912 strcpy (com_token, "light_lev"); // hack for single light def
913
914 q_strlcpy (keyname, com_token, sizeof(keyname));
915
916 // another hack to fix keynames with trailing spaces
917 n = strlen(keyname);
918 while (n && keyname[n-1] == ' ')
919 {
920 keyname[n-1] = 0;
921 n--;
922 }
923
924 // parse value
925 data = COM_Parse (data);
926 if (!data)
927 Host_Error ("ED_ParseEntity: EOF without closing brace");
928
929 if (com_token[0] == '}')
930 Host_Error ("ED_ParseEntity: closing brace without data");
931
932 init = true;
933
934 // keynames with a leading underscore are used for utility comments,
935 // and are immediately discarded by quake
936 if (keyname[0] == '_')
937 continue;
938
939 //johnfitz -- hack to support .alpha even when progs.dat doesn't know about it
940 if (!strcmp(keyname, "alpha"))
941 ent->alpha = ENTALPHA_ENCODE(atof(com_token));
942 //johnfitz
943
944 key = ED_FindField (keyname);
945 if (!key)
946 {
947 #ifdef PSET_SCRIPT
948 eval_t *val;
949 if (!strcmp(keyname, "traileffect") && qcvm == &sv.qcvm && sv.state == ss_loading)
950 {
951 if ((val = GetEdictFieldValue(ent, qcvm->extfields.traileffectnum)))
952 val->_float = PF_SV_ForceParticlePrecache(com_token);
953 }
954 else if (!strcmp(keyname, "emiteffect") && qcvm == &sv.qcvm && sv.state == ss_loading)
955 {
956 if ((val = GetEdictFieldValue(ent, qcvm->extfields.emiteffectnum)))
957 val->_float = PF_SV_ForceParticlePrecache(com_token);
958 }
959 //johnfitz -- HACK -- suppress error becuase fog/sky/alpha fields might not be mentioned in defs.qc
960 else
961 #endif
962 if (strncmp(keyname, "sky", 3) && strcmp(keyname, "fog") && strcmp(keyname, "alpha"))
963 Con_DPrintf ("\"%s\" is not a field\n", keyname); //johnfitz -- was Con_Printf
964 continue;
965 }
966
967 if (anglehack)
968 {
969 char temp[32];
970 strcpy (temp, com_token);
971 sprintf (com_token, "0 %s 0", temp);
972 }
973
974 if (!ED_ParseEpair ((void *)&ent->v, key, com_token, qcvm != &sv.qcvm))
975 Host_Error ("ED_ParseEdict: parse error");
976 }
977
978 if (!init)
979 ent->free = true;
980
981 return data;
982 }
983
984
985 /*
986 ================
987 ED_LoadFromFile
988
989 The entities are directly placed in the array, rather than allocated with
990 ED_Alloc, because otherwise an error loading the map would have entity
991 number references out of order.
992
993 Creates a server's entity / program execution context by
994 parsing textual entity definitions out of an ent file.
995
996 Used for both fresh maps and savegame loads. A fresh map would also need
997 to call ED_CallSpawnFunctions () to let the objects initialize themselves.
998 ================
999 */
ED_LoadFromFile(const char * data)1000 void ED_LoadFromFile (const char *data)
1001 {
1002 dfunction_t *func;
1003 edict_t *ent = NULL;
1004 int inhibit = 0;
1005 int usingspawnfunc = 0;
1006
1007 pr_global_struct->time = qcvm->time;
1008
1009 // parse ents
1010 while (1)
1011 {
1012 // parse the opening brace
1013 data = COM_Parse (data);
1014 if (!data)
1015 break;
1016 if (com_token[0] != '{')
1017 Host_Error ("ED_LoadFromFile: found %s when expecting {",com_token);
1018
1019 if (!ent)
1020 ent = EDICT_NUM(0);
1021 else
1022 ent = ED_Alloc ();
1023 data = ED_ParseEdict (data, ent);
1024
1025 // remove things from different skill levels or deathmatch
1026 if (deathmatch.value)
1027 {
1028 if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
1029 {
1030 ED_Free (ent);
1031 inhibit++;
1032 continue;
1033 }
1034 }
1035 else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY))
1036 || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM))
1037 || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) )
1038 {
1039 ED_Free (ent);
1040 inhibit++;
1041 continue;
1042 }
1043
1044 //
1045 // immediately call spawn function
1046 //
1047 if (!ent->v.classname)
1048 {
1049 Con_SafePrintf ("No classname for:\n"); //johnfitz -- was Con_Printf
1050 ED_Print (ent);
1051 ED_Free (ent);
1052 continue;
1053 }
1054
1055 // look for the spawn function
1056 //
1057 func = ED_FindFunction (va("spawnfunc_%s", PR_GetString(ent->v.classname)));
1058 if (func)
1059 {
1060 if (!usingspawnfunc++)
1061 Con_DPrintf2 ("Using DP_SV_SPAWNFUNC_PREFIX\n");
1062 }
1063 else
1064 func = ED_FindFunction ( PR_GetString(ent->v.classname) );
1065
1066 if (!func)
1067 {
1068 Con_SafePrintf ("No spawn function for:\n"); //johnfitz -- was Con_Printf
1069 ED_Print (ent);
1070 ED_Free (ent);
1071 continue;
1072 }
1073
1074 pr_global_struct->self = EDICT_TO_PROG(ent);
1075 PR_ExecuteProgram (func - qcvm->functions);
1076 }
1077
1078 Con_DPrintf ("%i entities inhibited\n", inhibit);
1079 }
1080
1081
1082 #ifndef PR_SwitchQCVM
1083 qcvm_t *qcvm;
1084 globalvars_t *pr_global_struct;
PR_SwitchQCVM(qcvm_t * nvm)1085 void PR_SwitchQCVM(qcvm_t *nvm)
1086 {
1087 if (qcvm && nvm)
1088 Sys_Error("PR_SwitchQCVM: A qcvm was already active");
1089 qcvm = nvm;
1090 if (qcvm)
1091 pr_global_struct = (globalvars_t*)qcvm->globals;
1092 else
1093 pr_global_struct = NULL;
1094 }
1095 #endif
1096
PR_ClearProgs(qcvm_t * vm)1097 void PR_ClearProgs(qcvm_t *vm)
1098 {
1099 qcvm_t *oldvm = qcvm;
1100 if (!vm->progs)
1101 return; //wasn't loaded.
1102 qcvm = NULL;
1103 PR_SwitchQCVM(vm);
1104 PR_ShutdownExtensions();
1105
1106 if (qcvm->knownstrings)
1107 Z_Free ((void *)qcvm->knownstrings);
1108 free(qcvm->edicts); // ericw -- sv.edicts switched to use malloc()
1109 if (qcvm->fielddefs != (ddef_t *)((byte *)qcvm->progs + qcvm->progs->ofs_fielddefs))
1110 free(qcvm->fielddefs);
1111 free(qcvm->progs); // spike -- pr_progs switched to use malloc (so menuqc doesn't end up stuck on the early hunk nor wiped on every map change)
1112 memset(qcvm, 0, sizeof(*qcvm));
1113
1114 qcvm = NULL;
1115 PR_SwitchQCVM(oldvm);
1116 }
1117
1118 //makes sure extension fields are actually registered so they can be used for mappers without qc changes. eg so scale can be used.
PR_MergeEngineFieldDefs(void)1119 static void PR_MergeEngineFieldDefs (void)
1120 {
1121 struct {
1122 const char *fname;
1123 etype_t type;
1124 int newidx;
1125 } extrafields[] =
1126 { //table of engine fields to add. we'll be using ED_FindFieldOffset for these later.
1127 //this is useful for fields that should be defined for mappers which are not defined by the mod.
1128 //future note: mutators will need to edit the mutator's globaldefs table too. remember to handle vectors and their 3 globals too.
1129 {"alpha", ev_float}, //just because we can (though its already handled in a weird hacky way)
1130 {"scale", ev_float}, //hurrah for being able to rescale entities.
1131 {"emiteffectnum", ev_float}, //constantly emitting particles, even without moving.
1132 {"traileffectnum", ev_float}, //custom effect for trails
1133 //{"glow_size", ev_float}, //deprecated particle trail rubbish
1134 //{"glow_color", ev_float}, //deprecated particle trail rubbish
1135 {"tag_entity", ev_float}, //for setattachment to not bug out when omitted.
1136 {"tag_index", ev_float}, //for setattachment to not bug out when omitted.
1137 {"modelflags", ev_float}, //deprecated rubbish to fill the high 8 bits of effects.
1138 //{"vw_index", ev_float}, //modelindex2
1139 //{"pflags", ev_float}, //for rtlights
1140 //{"drawflags", ev_float}, //hexen2 compat
1141 //{"abslight", ev_float}, //hexen2 compat
1142 {"colormod", ev_vector}, //lighting tints
1143 //{"glowmod", ev_vector}, //fullbright tints
1144 //{"fatness", ev_float}, //bloated rendering...
1145 //{"gravitydir", ev_vector}, //says which direction gravity should act for this ent...
1146
1147 };
1148 int maxofs = qcvm->progs->entityfields;
1149 int maxdefs = qcvm->progs->numfielddefs;
1150 unsigned int j, a;
1151
1152 //figure out where stuff goes
1153 for (j = 0; j < countof(extrafields); j++)
1154 {
1155 extrafields[j].newidx = ED_FindFieldOffset(extrafields[j].fname);
1156 if (extrafields[j].newidx < 0)
1157 {
1158 extrafields[j].newidx = maxofs;
1159 maxdefs++;
1160 if (extrafields[j].type == ev_vector)
1161 maxdefs+=3;
1162 maxofs+=type_size[extrafields[j].type];
1163 }
1164 }
1165
1166 if (maxdefs != qcvm->progs->numfielddefs)
1167 { //we now know how many entries we need to add...
1168 ddef_t *olddefs = qcvm->fielddefs;
1169 qcvm->fielddefs = malloc(maxdefs * sizeof(*qcvm->fielddefs));
1170 memcpy(qcvm->fielddefs, olddefs, qcvm->progs->numfielddefs*sizeof(*qcvm->fielddefs));
1171 if (olddefs != (ddef_t *)((byte *)qcvm->progs + qcvm->progs->ofs_fielddefs))
1172 free(olddefs);
1173
1174 //allocate the extra defs
1175 for (j = 0; j < countof(extrafields); j++)
1176 {
1177 if (extrafields[j].newidx >= qcvm->progs->entityfields && extrafields[j].newidx < maxofs)
1178 { //looks like its new. make sure ED_FindField can find it.
1179 qcvm->fielddefs[qcvm->progs->numfielddefs].ofs = extrafields[j].newidx;
1180 qcvm->fielddefs[qcvm->progs->numfielddefs].type = extrafields[j].type;
1181 qcvm->fielddefs[qcvm->progs->numfielddefs].s_name = ED_NewString(extrafields[j].fname);
1182 qcvm->progs->numfielddefs++;
1183
1184 if (extrafields[j].type == ev_vector)
1185 { //vectors are weird and annoying.
1186 for (a = 0; a < 3; a++)
1187 {
1188 qcvm->fielddefs[qcvm->progs->numfielddefs].ofs = extrafields[j].newidx+a;
1189 qcvm->fielddefs[qcvm->progs->numfielddefs].type = ev_float;
1190 qcvm->fielddefs[qcvm->progs->numfielddefs].s_name = ED_NewString(va("%s_%c", extrafields[j].fname, 'x'+a));
1191 qcvm->progs->numfielddefs++;
1192 }
1193 }
1194 }
1195 }
1196 qcvm->progs->entityfields = maxofs;
1197 }
1198 }
1199
1200 /*
1201 ===============
1202 PR_PatchRereleaseBuiltins
1203
1204 Quake 2021 release update 1 adds bprint/sprint/centerprint builtins with new id's
1205 (see https://steamcommunity.com/games/2310/announcements/detail/2943653788150871156)
1206 This function patches them back to use the old indices
1207 ===============
1208 */
PR_PatchRereleaseBuiltins(void)1209 static void PR_PatchRereleaseBuiltins (void)
1210 {
1211 dfunction_t *f;
1212 if (qcvm != &sv.qcvm)
1213 return;
1214 if ((f = ED_FindFunction ("centerprint")) != NULL && f->first_statement == -90)
1215 f->first_statement = -73;
1216 if ((f = ED_FindFunction ("bprint")) != NULL && f->first_statement == -91)
1217 f->first_statement = -23;
1218 if ((f = ED_FindFunction ("sprint")) != NULL && f->first_statement == -92)
1219 f->first_statement = -24;
1220 }
1221
1222 /*
1223 ===============
1224 PR_LoadProgs
1225 ===============
1226 */
PR_LoadProgs(const char * filename,qboolean fatal,unsigned int needcrc,builtin_t * builtins,size_t numbuiltins)1227 qboolean PR_LoadProgs (const char *filename, qboolean fatal, unsigned int needcrc, builtin_t *builtins, size_t numbuiltins)
1228 {
1229 int i;
1230
1231 PR_ClearProgs(qcvm); //just in case.
1232
1233 qcvm->progs = (dprograms_t *)COM_LoadMallocFile(filename, NULL);
1234 if (!qcvm->progs)
1235 return false;
1236
1237 qcvm->progssize = com_filesize;
1238 CRC_Init (&qcvm->progscrc);
1239 for (i = 0; i < com_filesize; i++)
1240 CRC_ProcessByte (&qcvm->progscrc, ((byte *)qcvm->progs)[i]);
1241 qcvm->progshash = Com_BlockChecksum(qcvm->progs, com_filesize);
1242
1243 // byte swap the header
1244 for (i = 0; i < (int) sizeof(*qcvm->progs) / 4; i++)
1245 ((int *)qcvm->progs)[i] = LittleLong ( ((int *)qcvm->progs)[i] );
1246
1247 if (qcvm->progs->version != PROG_VERSION)
1248 {
1249 if (fatal)
1250 Host_Error ("%s has wrong version number (%i should be %i)", filename, qcvm->progs->version, PROG_VERSION);
1251 else
1252 {
1253 Con_Printf("%s ABI set not supported\n", filename);
1254 qcvm->progs = NULL;
1255 return false;
1256 }
1257 }
1258 if (qcvm->progs->crc != needcrc)
1259 {
1260 if (fatal)
1261 Host_Error ("%s system vars have been modified, progdefs.h is out of date", filename);
1262 else
1263 {
1264 switch(qcvm->progs->crc)
1265 {
1266 case 22390: //full csqc
1267 Con_Printf("%s - full csqc is not supported\n", filename);
1268 break;
1269 case 52195: //dp csqc
1270 Con_Printf("%s - obsolete csqc is not supported\n", filename);
1271 break;
1272 case 54730: //quakeworld
1273 Con_Printf("%s - quakeworld gamecode is not supported\n", filename);
1274 break;
1275 case 26940: //prerelease
1276 Con_Printf("%s - prerelease gamecode is not supported\n", filename);
1277 break;
1278 case 32401: //tenebrae
1279 Con_Printf("%s - tenebrae gamecode is not supported\n", filename);
1280 break;
1281 case 38488: //hexen2 release
1282 case 26905: //hexen2 mission pack
1283 case 14046: //hexen2 demo
1284 Con_Printf("%s - hexen2 gamecode is not supported\n", filename);
1285 break;
1286 //case 5927: //nq PROGHEADER_CRC as above. shouldn't happen, obviously.
1287 default:
1288 Con_Printf("%s system vars are not supported\n", filename);
1289 break;
1290 }
1291 qcvm->progs = NULL;
1292 return false;
1293 }
1294 }
1295 Con_DPrintf ("%s occupies %iK.\n", filename, com_filesize/1024);
1296
1297 qcvm->functions = (dfunction_t *)((byte *)qcvm->progs + qcvm->progs->ofs_functions);
1298 qcvm->strings = (char *)qcvm->progs + qcvm->progs->ofs_strings;
1299 if (qcvm->progs->ofs_strings + qcvm->progs->numstrings >= com_filesize)
1300 Host_Error ("%s strings go past end of file\n", filename);
1301
1302 qcvm->globaldefs = (ddef_t *)((byte *)qcvm->progs + qcvm->progs->ofs_globaldefs);
1303 qcvm->fielddefs = (ddef_t *)((byte *)qcvm->progs + qcvm->progs->ofs_fielddefs);
1304 qcvm->statements = (dstatement_t *)((byte *)qcvm->progs + qcvm->progs->ofs_statements);
1305
1306 qcvm->globals = (float *)((byte *)qcvm->progs + qcvm->progs->ofs_globals);
1307 pr_global_struct = (globalvars_t*)qcvm->globals;
1308
1309 qcvm->stringssize = qcvm->progs->numstrings;
1310
1311 // byte swap the lumps
1312 for (i = 0; i < qcvm->progs->numstatements; i++)
1313 {
1314 qcvm->statements[i].op = LittleShort(qcvm->statements[i].op);
1315 qcvm->statements[i].a = LittleShort(qcvm->statements[i].a);
1316 qcvm->statements[i].b = LittleShort(qcvm->statements[i].b);
1317 qcvm->statements[i].c = LittleShort(qcvm->statements[i].c);
1318 }
1319
1320 for (i = 0; i < qcvm->progs->numfunctions; i++)
1321 {
1322 qcvm->functions[i].first_statement = LittleLong (qcvm->functions[i].first_statement);
1323 qcvm->functions[i].parm_start = LittleLong (qcvm->functions[i].parm_start);
1324 qcvm->functions[i].s_name = LittleLong (qcvm->functions[i].s_name);
1325 qcvm->functions[i].s_file = LittleLong (qcvm->functions[i].s_file);
1326 qcvm->functions[i].numparms = LittleLong (qcvm->functions[i].numparms);
1327 qcvm->functions[i].locals = LittleLong (qcvm->functions[i].locals);
1328 }
1329
1330 for (i = 0; i < qcvm->progs->numglobaldefs; i++)
1331 {
1332 qcvm->globaldefs[i].type = LittleShort (qcvm->globaldefs[i].type);
1333 qcvm->globaldefs[i].ofs = LittleShort (qcvm->globaldefs[i].ofs);
1334 qcvm->globaldefs[i].s_name = LittleLong (qcvm->globaldefs[i].s_name);
1335 }
1336
1337 for (i = 0; i < qcvm->progs->numfielddefs; i++)
1338 {
1339 qcvm->fielddefs[i].type = LittleShort (qcvm->fielddefs[i].type);
1340 if (qcvm->fielddefs[i].type & DEF_SAVEGLOBAL)
1341 Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
1342 qcvm->fielddefs[i].ofs = LittleShort (qcvm->fielddefs[i].ofs);
1343 qcvm->fielddefs[i].s_name = LittleLong (qcvm->fielddefs[i].s_name);
1344 }
1345
1346 for (i = 0; i < qcvm->progs->numglobals; i++)
1347 ((int *)qcvm->globals)[i] = LittleLong (((int *)qcvm->globals)[i]);
1348
1349 memcpy(qcvm->builtins, builtins, numbuiltins*sizeof(qcvm->builtins[0]));
1350 qcvm->numbuiltins = numbuiltins;
1351
1352 //spike: detect extended fields from progs
1353 PR_MergeEngineFieldDefs();
1354 #define QCEXTFIELD(n,t) qcvm->extfields.n = ED_FindFieldOffset(#n);
1355 QCEXTFIELDS_ALL
1356 QCEXTFIELDS_GAME
1357 QCEXTFIELDS_SS
1358 #undef QCEXTFIELD
1359
1360 qcvm->edict_size = qcvm->progs->entityfields * 4 + sizeof(edict_t) - sizeof(entvars_t);
1361 // round off to next highest whole word address (esp for Alpha)
1362 // this ensures that pointers in the engine data area are always
1363 // properly aligned
1364 qcvm->edict_size += sizeof(void *) - 1;
1365 qcvm->edict_size &= ~(sizeof(void *) - 1);
1366
1367 PR_SetEngineString("");
1368 PR_EnableExtensions(qcvm->globaldefs);
1369 PR_PatchRereleaseBuiltins();
1370
1371 return true;
1372 }
1373
1374
1375 /*
1376 ===============
1377 PR_Init
1378 ===============
1379 */
PR_Init(void)1380 void PR_Init (void)
1381 {
1382 Cmd_AddCommand ("edict", ED_PrintEdict_f);
1383 Cmd_AddCommand ("edicts", ED_PrintEdicts);
1384 Cmd_AddCommand ("edictcount", ED_Count);
1385 Cmd_AddCommand ("profile", PR_Profile_f);
1386 Cmd_AddCommand ("pr_dumpplatform", PR_DumpPlatform_f);
1387 Cvar_RegisterVariable (&nomonsters);
1388 Cvar_RegisterVariable (&gamecfg);
1389 Cvar_RegisterVariable (&scratch1);
1390 Cvar_RegisterVariable (&scratch2);
1391 Cvar_RegisterVariable (&scratch3);
1392 Cvar_RegisterVariable (&scratch4);
1393 Cvar_RegisterVariable (&savedgamecfg);
1394 Cvar_RegisterVariable (&saved1);
1395 Cvar_RegisterVariable (&saved2);
1396 Cvar_RegisterVariable (&saved3);
1397 Cvar_RegisterVariable (&saved4);
1398
1399 PR_InitExtensions();
1400 }
1401
1402
EDICT_NUM(int n)1403 edict_t *EDICT_NUM(int n)
1404 {
1405 if (n < 0 || n >= qcvm->max_edicts)
1406 Host_Error ("EDICT_NUM: bad number %i", n);
1407 return (edict_t *)((byte *)qcvm->edicts + (n)*qcvm->edict_size);
1408 }
1409
NUM_FOR_EDICT(edict_t * e)1410 int NUM_FOR_EDICT(edict_t *e)
1411 {
1412 int b;
1413
1414 b = (byte *)e - (byte *)qcvm->edicts;
1415 b = b / qcvm->edict_size;
1416
1417 if (b < 0 || b >= qcvm->num_edicts)
1418 Host_Error ("NUM_FOR_EDICT: bad pointer");
1419 return b;
1420 }
1421
1422 //===========================================================================
1423
1424
1425 #define PR_STRING_ALLOCSLOTS 256
1426
PR_AllocStringSlots(void)1427 static void PR_AllocStringSlots (void)
1428 {
1429 qcvm->maxknownstrings += PR_STRING_ALLOCSLOTS;
1430 Con_DPrintf2("PR_AllocStringSlots: realloc'ing for %d slots\n", qcvm->maxknownstrings);
1431 qcvm->knownstrings = (const char **) Z_Realloc ((void *)qcvm->knownstrings, qcvm->maxknownstrings * sizeof(char *));
1432 }
1433
PR_GetString(int num)1434 const char *PR_GetString (int num)
1435 {
1436 if (num >= 0 && num < qcvm->stringssize)
1437 return qcvm->strings + num;
1438 else if (num < 0 && num >= -qcvm->numknownstrings)
1439 {
1440 if (!qcvm->knownstrings[-1 - num])
1441 {
1442 Host_Error ("PR_GetString: attempt to get a non-existant string %d\n", num);
1443 return "";
1444 }
1445 return qcvm->knownstrings[-1 - num];
1446 }
1447 else
1448 {
1449 return qcvm->strings;
1450 Host_Error("PR_GetString: invalid string offset %d\n", num);
1451 return "";
1452 }
1453 }
1454
PR_ClearEngineString(int num)1455 void PR_ClearEngineString(int num)
1456 {
1457 if (num < 0 && num >= -qcvm->numknownstrings)
1458 {
1459 num = -1 - num;
1460 qcvm->knownstrings[num] = NULL;
1461 if (qcvm->freeknownstrings > num)
1462 qcvm->freeknownstrings = num;
1463 }
1464 }
1465
PR_SetEngineString(const char * s)1466 int PR_SetEngineString (const char *s)
1467 {
1468 int i;
1469
1470 if (!s)
1471 return 0;
1472 #if 0 /* can't: sv.model_precache & sv.sound_precache points to pr_strings */
1473 if (s >= qcvm->strings && s <= qcvm->strings + qcvm->stringssize)
1474 Host_Error("PR_SetEngineString: \"%s\" in pr_strings area\n", s);
1475 #else
1476 if (s >= qcvm->strings && s <= qcvm->strings + qcvm->stringssize - 2)
1477 return (int)(s - qcvm->strings);
1478 #endif
1479 for (i = 0; i < qcvm->numknownstrings; i++)
1480 {
1481 if (qcvm->knownstrings[i] == s)
1482 return -1 - i;
1483 }
1484 // new unknown engine string
1485 //Con_DPrintf ("PR_SetEngineString: new engine string %p\n", s);
1486 for (i = qcvm->freeknownstrings; ; i++)
1487 {
1488 if (i < qcvm->numknownstrings)
1489 {
1490 if (qcvm->knownstrings[i])
1491 continue;
1492 }
1493 else
1494 {
1495 if (i >= qcvm->maxknownstrings)
1496 PR_AllocStringSlots();
1497 qcvm->numknownstrings++;
1498 }
1499 break;
1500 }
1501 qcvm->freeknownstrings = i+1;
1502 qcvm->knownstrings[i] = s;
1503 return -1 - i;
1504 }
1505
PR_AllocString(int size,char ** ptr)1506 int PR_AllocString (int size, char **ptr)
1507 {
1508 int i;
1509
1510 if (!size)
1511 return 0;
1512 for (i = 0; i < qcvm->numknownstrings; i++)
1513 {
1514 if (!qcvm->knownstrings[i])
1515 break;
1516 }
1517 // if (i >= pr_numknownstrings)
1518 // {
1519 if (i >= qcvm->maxknownstrings)
1520 PR_AllocStringSlots();
1521 qcvm->numknownstrings++;
1522 // }
1523 qcvm->knownstrings[i] = (char *)Hunk_AllocName(size, "string");
1524 if (ptr)
1525 *ptr = (char *) qcvm->knownstrings[i];
1526 return -1 - i;
1527 }
1528
1529