2002-10-23 04:57:08 +00:00
|
|
|
/*
|
|
|
|
pr_parse.c
|
|
|
|
|
|
|
|
map and savegame parsing
|
|
|
|
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2002-10-23 04:57:08 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2013-01-22 05:09:41 +00:00
|
|
|
#include "qfalloca.h"
|
|
|
|
|
2011-08-25 13:35:20 +00:00
|
|
|
#if defined(_WIN32) && defined(HAVE_MALLOC_H)
|
2007-03-22 23:20:57 +00:00
|
|
|
#include <malloc.h>
|
|
|
|
#endif
|
|
|
|
|
2002-10-23 04:57:08 +00:00
|
|
|
#include "QF/dstring.h"
|
2013-01-08 08:20:58 +00:00
|
|
|
#include "QF/mathlib.h"
|
2021-03-21 07:13:03 +00:00
|
|
|
#include "QF/plist.h"
|
2002-10-23 04:57:08 +00:00
|
|
|
#include "QF/progs.h"
|
2004-11-12 02:39:00 +00:00
|
|
|
#include "QF/script.h"
|
2002-10-23 04:57:08 +00:00
|
|
|
#include "QF/sys.h"
|
|
|
|
|
|
|
|
#include "compat.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
PR_UglyValueString
|
|
|
|
|
|
|
|
Returns a string describing *data in a type specific manner
|
|
|
|
Easier to parse than PR_ValueString
|
|
|
|
*/
|
2013-01-08 08:20:58 +00:00
|
|
|
static const char *
|
2020-02-25 16:55:56 +00:00
|
|
|
PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val, dstring_t *line)
|
2002-10-23 04:57:08 +00:00
|
|
|
{
|
2020-02-22 13:33:44 +00:00
|
|
|
pr_def_t *def;
|
2002-10-23 04:57:08 +00:00
|
|
|
dfunction_t *f;
|
|
|
|
|
|
|
|
type &= ~DEF_SAVEGLOBAL;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case ev_string:
|
2022-04-26 06:10:00 +00:00
|
|
|
dsprintf (line, "%s", PR_GetString (pr, PR_PTR (string, val)));
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
case ev_entity:
|
2013-01-08 08:20:58 +00:00
|
|
|
dsprintf (line, "%d",
|
2022-04-26 06:10:00 +00:00
|
|
|
NUM_FOR_BAD_EDICT (pr, PROG_TO_EDICT (pr, PR_PTR (entity, val))));
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
case ev_func:
|
2022-04-26 06:10:00 +00:00
|
|
|
f = pr->pr_functions + PR_PTR (func, val);
|
2021-12-31 06:02:31 +00:00
|
|
|
dsprintf (line, "%s", PR_GetString (pr, f->name));
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
case ev_field:
|
2022-04-26 06:10:00 +00:00
|
|
|
def = PR_FieldAtOfs (pr, PR_PTR (int, val));
|
2020-02-22 13:33:44 +00:00
|
|
|
dsprintf (line, "%s", PR_GetString (pr, def->name));
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
case ev_void:
|
2013-01-08 08:20:58 +00:00
|
|
|
dstring_copystr (line, "void");
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
case ev_float:
|
2022-04-26 06:10:00 +00:00
|
|
|
dsprintf (line, "%.9g", PR_PTR (float, val));
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
2022-01-18 04:21:06 +00:00
|
|
|
case ev_int:
|
2022-04-26 06:10:00 +00:00
|
|
|
dsprintf (line, "%d", PR_PTR (int, val));
|
2013-01-08 09:09:22 +00:00
|
|
|
break;
|
2002-10-23 04:57:08 +00:00
|
|
|
case ev_vector:
|
2022-04-26 06:10:00 +00:00
|
|
|
dsprintf (line, "%.9g %.9g %.9g", VectorExpand (&PR_PTR (float, val)));
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
2022-01-18 06:48:43 +00:00
|
|
|
case ev_quaternion:
|
2022-04-26 06:10:00 +00:00
|
|
|
dsprintf (line, "%.9g %.9g %.9g %.9g", QuatExpand (&PR_PTR (float, val)));
|
2013-01-08 09:09:22 +00:00
|
|
|
break;
|
2002-10-23 04:57:08 +00:00
|
|
|
default:
|
2013-01-08 08:20:58 +00:00
|
|
|
dsprintf (line, "bad type %i", type);
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-01-08 08:20:58 +00:00
|
|
|
return line->str;
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
|
|
|
|
2007-03-10 12:00:59 +00:00
|
|
|
VISIBLE plitem_t *
|
2006-12-09 02:35:44 +00:00
|
|
|
ED_EntityDict (progs_t *pr, edict_t *ed)
|
2002-10-23 04:57:08 +00:00
|
|
|
{
|
2020-02-25 16:55:56 +00:00
|
|
|
dstring_t *dstr = dstring_newstr ();
|
2022-05-12 08:54:23 +00:00
|
|
|
plitem_t *entity = PL_NewDictionary (pr->hashctx);
|
2007-04-06 00:47:41 +00:00
|
|
|
pr_uint_t i;
|
2003-04-17 00:01:48 +00:00
|
|
|
int j;
|
2003-11-21 21:34:53 +00:00
|
|
|
int type;
|
|
|
|
const char *name;
|
2006-12-09 02:35:44 +00:00
|
|
|
const char *value;
|
2003-11-21 21:34:53 +00:00
|
|
|
pr_type_t *v;
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2006-12-09 02:35:44 +00:00
|
|
|
if (!ed->free) {
|
2022-01-26 10:30:25 +00:00
|
|
|
for (i = 0; i < pr->progs->fielddefs.count; i++) {
|
2020-02-22 13:33:44 +00:00
|
|
|
pr_def_t *d = &pr->pr_fielddefs[i];
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2020-02-22 13:33:44 +00:00
|
|
|
name = PR_GetString (pr, d->name);
|
2012-06-10 11:54:40 +00:00
|
|
|
if (!name[0])
|
|
|
|
continue; // skip unnamed fields
|
2006-12-09 02:35:44 +00:00
|
|
|
if (name[strlen (name) - 2] == '_')
|
|
|
|
continue; // skip _x, _y, _z vars
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2013-01-17 05:11:54 +00:00
|
|
|
v = &E_fld (ed, d->ofs);
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2006-12-09 02:35:44 +00:00
|
|
|
// if the value is still all 0, skip the field
|
|
|
|
type = d->type & ~DEF_SAVEGLOBAL;
|
|
|
|
for (j = 0; j < pr_type_size[type]; j++)
|
2022-04-26 06:10:00 +00:00
|
|
|
if (v[j].value)
|
2006-12-09 02:35:44 +00:00
|
|
|
break;
|
|
|
|
if (j == pr_type_size[type])
|
|
|
|
continue;
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2020-02-25 16:55:56 +00:00
|
|
|
value = PR_UglyValueString (pr, type, v, dstr);
|
2006-12-09 06:00:36 +00:00
|
|
|
PL_D_AddObject (entity, name, PL_NewString (value));
|
2006-12-09 02:35:44 +00:00
|
|
|
}
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
2020-02-25 16:55:56 +00:00
|
|
|
dstring_delete (dstr);
|
2006-12-09 02:35:44 +00:00
|
|
|
return entity;
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
ARCHIVING GLOBALS
|
|
|
|
|
|
|
|
FIXME: need to tag constants, doesn't really work
|
|
|
|
*/
|
|
|
|
|
2007-03-10 12:00:59 +00:00
|
|
|
VISIBLE plitem_t *
|
2006-12-09 02:35:44 +00:00
|
|
|
ED_GlobalsDict (progs_t *pr)
|
2002-10-23 04:57:08 +00:00
|
|
|
{
|
2020-02-25 16:55:56 +00:00
|
|
|
dstring_t *dstr = dstring_newstr ();
|
2022-05-12 08:54:23 +00:00
|
|
|
plitem_t *globals = PL_NewDictionary (pr->hashctx);
|
2007-04-06 00:47:41 +00:00
|
|
|
pr_uint_t i;
|
2003-11-21 21:34:53 +00:00
|
|
|
const char *name;
|
2006-12-09 02:35:44 +00:00
|
|
|
const char *value;
|
2020-02-22 13:33:44 +00:00
|
|
|
pr_def_t *def;
|
2003-11-21 21:34:53 +00:00
|
|
|
int type;
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2022-01-26 10:30:25 +00:00
|
|
|
for (i = 0; i < pr->progs->globaldefs.count; i++) {
|
2002-10-23 04:57:08 +00:00
|
|
|
def = &pr->pr_globaldefs[i];
|
|
|
|
type = def->type;
|
|
|
|
if (!(def->type & DEF_SAVEGLOBAL))
|
|
|
|
continue;
|
|
|
|
type &= ~DEF_SAVEGLOBAL;
|
|
|
|
|
|
|
|
if (type != ev_string && type != ev_float && type != ev_entity)
|
|
|
|
continue;
|
|
|
|
|
2020-02-22 13:33:44 +00:00
|
|
|
name = PR_GetString (pr, def->name);
|
2020-02-25 16:55:56 +00:00
|
|
|
value = PR_UglyValueString (pr, type, &pr->pr_globals[def->ofs], dstr);
|
2006-12-09 06:00:36 +00:00
|
|
|
PL_D_AddObject (globals, name, PL_NewString (value));
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
2020-02-25 16:55:56 +00:00
|
|
|
dstring_delete (dstr);
|
2006-12-09 02:35:44 +00:00
|
|
|
return globals;
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-07 05:22:57 +00:00
|
|
|
static int
|
2002-10-23 04:57:08 +00:00
|
|
|
ED_NewString (progs_t *pr, const char *string)
|
|
|
|
{
|
|
|
|
char *new, *new_p;
|
|
|
|
int i, l;
|
|
|
|
|
|
|
|
l = strlen (string) + 1;
|
2004-11-02 04:59:00 +00:00
|
|
|
new = alloca (l);
|
2002-10-23 04:57:08 +00:00
|
|
|
new_p = new;
|
|
|
|
|
|
|
|
for (i = 0; i < l; i++) {
|
|
|
|
if (string[i] == '\\' && i < l - 1) {
|
|
|
|
i++;
|
|
|
|
if (string[i] == 'n')
|
|
|
|
*new_p++ = '\n';
|
|
|
|
else
|
|
|
|
*new_p++ = '\\';
|
|
|
|
} else
|
|
|
|
*new_p++ = string[i];
|
|
|
|
}
|
|
|
|
|
2004-01-07 05:22:57 +00:00
|
|
|
return PR_SetString (pr, new);
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
ED_ParseEval
|
|
|
|
|
|
|
|
Can parse either fields or globals
|
|
|
|
returns false if error
|
|
|
|
*/
|
2023-06-13 09:06:11 +00:00
|
|
|
VISIBLE bool
|
2020-02-22 13:33:44 +00:00
|
|
|
ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s)
|
2002-10-23 04:57:08 +00:00
|
|
|
{
|
2020-02-22 13:33:44 +00:00
|
|
|
pr_def_t *def;
|
2002-10-23 04:57:08 +00:00
|
|
|
pr_type_t *d;
|
|
|
|
dfunction_t *func;
|
|
|
|
|
2023-08-10 22:11:52 +00:00
|
|
|
vec3_t vec = {};
|
|
|
|
char *str = 0;
|
|
|
|
|
2002-10-23 04:57:08 +00:00
|
|
|
d = &base[key->ofs];
|
|
|
|
|
|
|
|
switch (key->type & ~DEF_SAVEGLOBAL) {
|
|
|
|
case ev_string:
|
2022-04-26 06:10:00 +00:00
|
|
|
PR_PTR (string, d) = ED_NewString (pr, s);
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ev_float:
|
2022-04-26 06:10:00 +00:00
|
|
|
PR_PTR (float, d) = atof (s);
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ev_vector:
|
2023-08-10 22:11:52 +00:00
|
|
|
str = alloca (strlen (s) + 1);
|
2022-05-21 03:15:15 +00:00
|
|
|
strcpy (str, s);
|
|
|
|
for (char *v = str; *v; v++) {
|
|
|
|
if (*v == ',') {
|
|
|
|
*v = ' ';
|
|
|
|
}
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
2022-08-19 09:59:51 +00:00
|
|
|
if (sscanf (str, "%f %f %f", VectorExpandAddr (vec)) != 3) {
|
2022-05-21 03:15:15 +00:00
|
|
|
Sys_Printf ("Malformed vector %s\n", s);
|
|
|
|
}
|
|
|
|
VectorCopy (vec, PR_PTR (vector, d));
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ev_entity:
|
2022-04-26 06:10:00 +00:00
|
|
|
PR_PTR (entity, d) = EDICT_TO_PROG (pr, EDICT_NUM (pr, atoi (s)));
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ev_field:
|
2004-11-05 11:49:00 +00:00
|
|
|
def = PR_FindField (pr, s);
|
2002-10-23 04:57:08 +00:00
|
|
|
if (!def) {
|
|
|
|
Sys_Printf ("Can't find field %s\n", s);
|
|
|
|
return false;
|
|
|
|
}
|
2022-04-26 06:10:00 +00:00
|
|
|
PR_PTR (int, d) = G_INT (pr, def->ofs);
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ev_func:
|
2004-11-05 11:49:00 +00:00
|
|
|
func = PR_FindFunction (pr, s);
|
2002-10-23 04:57:08 +00:00
|
|
|
if (!func) {
|
|
|
|
Sys_Printf ("Can't find function %s\n", s);
|
|
|
|
return false;
|
|
|
|
}
|
2022-04-26 06:10:00 +00:00
|
|
|
PR_PTR (func, d) = func - pr->pr_functions;
|
2002-10-23 04:57:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-12-09 00:02:57 +00:00
|
|
|
ED_ParseOld
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2006-12-09 00:02:57 +00:00
|
|
|
The entities are directly placed in the array, rather than allocated with
|
|
|
|
ED_Alloc, because otherwise an error loading the map would have entity
|
|
|
|
number references out of order.
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2006-12-09 00:02:57 +00:00
|
|
|
Creates a server's entity / program execution context by
|
|
|
|
parsing textual entity definitions out of an ent file.
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2006-12-09 00:02:57 +00:00
|
|
|
Used for both fresh maps and savegame loads. A fresh map would also need
|
|
|
|
to call ED_CallSpawnFunctions () to let the objects initialize themselves.
|
|
|
|
*/
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2007-03-10 12:00:59 +00:00
|
|
|
VISIBLE plitem_t *
|
2022-05-12 08:54:23 +00:00
|
|
|
ED_ConvertToPlist (script_t *script, int nohack, struct hashctx_s **hashctx)
|
2006-12-09 00:02:57 +00:00
|
|
|
{
|
2020-02-26 00:46:59 +00:00
|
|
|
dstring_t *dstr = dstring_newstr ();
|
2006-12-09 00:02:57 +00:00
|
|
|
plitem_t *plist = PL_NewArray ();
|
|
|
|
plitem_t *ent;
|
|
|
|
plitem_t *key;
|
|
|
|
plitem_t *value;
|
2013-11-26 05:27:49 +00:00
|
|
|
char *token;
|
2006-12-09 00:02:57 +00:00
|
|
|
int anglehack;
|
2022-05-05 06:36:22 +00:00
|
|
|
const char *msg = "";
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2006-12-09 00:02:57 +00:00
|
|
|
while (Script_GetToken (script, 1)) {
|
2004-11-12 02:39:00 +00:00
|
|
|
token = script->token->str;
|
2022-05-05 06:36:22 +00:00
|
|
|
if (!strequal (token, "{")) {
|
|
|
|
msg = "EOF without closing brace";
|
|
|
|
goto parse_error;
|
|
|
|
}
|
2022-05-12 08:54:23 +00:00
|
|
|
ent = PL_NewDictionary (hashctx);
|
2006-12-09 00:02:57 +00:00
|
|
|
while (1) {
|
2013-11-26 05:27:49 +00:00
|
|
|
int n;
|
|
|
|
|
2022-05-05 06:36:22 +00:00
|
|
|
if (!Script_GetToken (script, 1)) {
|
|
|
|
msg = "EOF without closing brace";
|
|
|
|
goto parse_error;
|
|
|
|
}
|
2006-12-09 00:02:57 +00:00
|
|
|
token = script->token->str;
|
|
|
|
if (strequal (token, "}"))
|
|
|
|
break;
|
2013-11-26 05:27:49 +00:00
|
|
|
// hack to take care of trailing spaces in field names
|
|
|
|
// (looking at you, Rogue)
|
|
|
|
for (n = strlen (token); n && token[n - 1] == ' '; n--) {
|
|
|
|
token[n - 1] = 0;
|
|
|
|
}
|
2006-12-09 00:02:57 +00:00
|
|
|
anglehack = 0;
|
2012-12-30 10:54:45 +00:00
|
|
|
if (!nohack && strequal (token, "angle")) {
|
2006-12-09 00:02:57 +00:00
|
|
|
key = PL_NewString ("angles");
|
|
|
|
anglehack = 1;
|
2012-12-30 10:54:45 +00:00
|
|
|
} else if (!nohack && strequal (token, "light")) {
|
2006-12-09 00:02:57 +00:00
|
|
|
key = PL_NewString ("light_lev");
|
2002-10-23 04:57:08 +00:00
|
|
|
} else {
|
2006-12-09 00:02:57 +00:00
|
|
|
key = PL_NewString (token);
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
2022-05-05 06:36:22 +00:00
|
|
|
if (!Script_TokenAvailable (script, 0)) {
|
|
|
|
msg = "EOL without value";
|
|
|
|
goto parse_error;
|
|
|
|
}
|
2006-12-09 00:02:57 +00:00
|
|
|
Script_GetToken (script, 0);
|
|
|
|
token = script->token->str;
|
2022-05-05 06:36:22 +00:00
|
|
|
if (strequal (token, "}")) {
|
|
|
|
msg = "closing brace without data";
|
|
|
|
goto parse_error;
|
|
|
|
}
|
2020-02-26 00:46:59 +00:00
|
|
|
if (anglehack) {
|
|
|
|
dsprintf (dstr, "0 %s 0", token);
|
|
|
|
value = PL_NewString (dstr->str);
|
|
|
|
} else {
|
2006-12-09 00:02:57 +00:00
|
|
|
value = PL_NewString (token);
|
2020-02-26 00:46:59 +00:00
|
|
|
}
|
2006-12-09 06:00:36 +00:00
|
|
|
PL_D_AddObject (ent, PL_String (key), value);
|
2023-03-12 06:17:28 +00:00
|
|
|
PL_Release (key);
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
2006-12-09 00:02:57 +00:00
|
|
|
PL_A_AddObject (plist, ent);
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
2020-02-26 00:46:59 +00:00
|
|
|
dstring_delete (dstr);
|
2006-12-09 00:02:57 +00:00
|
|
|
return plist;
|
2022-05-05 06:36:22 +00:00
|
|
|
parse_error:
|
|
|
|
Sys_Printf ("%s:%d: %s", script->file, script->line, msg);
|
|
|
|
dstring_delete (dstr);
|
2023-03-12 06:17:28 +00:00
|
|
|
PL_Release (plist);
|
2022-05-05 06:36:22 +00:00
|
|
|
return 0;
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
|
|
|
|
2006-12-09 00:02:57 +00:00
|
|
|
|
2007-03-10 12:00:59 +00:00
|
|
|
VISIBLE void
|
2006-12-09 00:02:57 +00:00
|
|
|
ED_InitGlobals (progs_t *pr, plitem_t *globals)
|
2002-10-23 04:57:08 +00:00
|
|
|
{
|
2020-02-22 13:33:44 +00:00
|
|
|
pr_def_t vector_def;
|
|
|
|
pr_def_t *global;
|
2006-12-09 00:02:57 +00:00
|
|
|
plitem_t *keys;
|
|
|
|
int count;
|
|
|
|
const char *global_name;
|
|
|
|
const char *value;
|
|
|
|
|
|
|
|
keys = PL_D_AllKeys (globals);
|
|
|
|
count = PL_A_NumObjects (keys);
|
|
|
|
while (count--) {
|
|
|
|
global_name = PL_String (PL_ObjectAtIndex (keys, count));
|
|
|
|
value = PL_String (PL_ObjectForKey (globals, global_name));
|
2006-12-09 02:35:44 +00:00
|
|
|
global = PR_FindGlobal (pr, global_name);
|
2011-08-11 06:36:51 +00:00
|
|
|
//FIXME should this be here?
|
|
|
|
//This is a hardcoded fix for a design mistake in the original qcc
|
|
|
|
//(saving global vector components rather than the whole vector).
|
|
|
|
if (!global) {
|
|
|
|
int len = strlen (global_name);
|
|
|
|
const char *tag = global_name + len - 2;
|
|
|
|
if (len > 2 && tag[0] == '_' && strchr ("xyz", tag[1])) {
|
|
|
|
char *vector_name = strdup (global_name);
|
|
|
|
vector_name[len - 2] = 0;
|
|
|
|
global = PR_FindGlobal (pr, vector_name);
|
|
|
|
if (global) {
|
|
|
|
if ((global->type & ~DEF_SAVEGLOBAL) == ev_vector) {
|
|
|
|
vector_def = *global;
|
|
|
|
vector_def.ofs += tag[1] - 'x';
|
|
|
|
vector_def.type = ev_float;
|
|
|
|
global = &vector_def;
|
|
|
|
} else {
|
|
|
|
global = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-12-09 00:02:57 +00:00
|
|
|
if (!global) {
|
|
|
|
Sys_Printf ("'%s' is not a global\n", global_name);
|
2002-10-23 04:57:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
2006-12-09 00:02:57 +00:00
|
|
|
if (!ED_ParseEpair (pr, pr->pr_globals, global, value))
|
2006-12-09 02:35:44 +00:00
|
|
|
PR_Error (pr, "ED_InitGlobals: parse error");
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
2023-03-12 06:17:28 +00:00
|
|
|
PL_Release (keys);
|
2002-10-23 04:57:08 +00:00
|
|
|
}
|
|
|
|
|
2007-03-10 12:00:59 +00:00
|
|
|
VISIBLE void
|
2006-12-09 00:02:57 +00:00
|
|
|
ED_InitEntity (progs_t *pr, plitem_t *entity, edict_t *ent)
|
|
|
|
{
|
2020-02-22 13:33:44 +00:00
|
|
|
pr_def_t *field;
|
2006-12-09 00:02:57 +00:00
|
|
|
plitem_t *keys;
|
|
|
|
const char *field_name;
|
|
|
|
const char *value;
|
|
|
|
int count;
|
2007-03-25 04:15:18 +00:00
|
|
|
int init = 0;
|
2006-12-09 00:02:57 +00:00
|
|
|
|
|
|
|
keys = PL_D_AllKeys (entity);
|
|
|
|
count = PL_A_NumObjects (keys);
|
|
|
|
while (count--) {
|
|
|
|
field_name = PL_String (PL_ObjectAtIndex (keys, count));
|
|
|
|
value = PL_String (PL_ObjectForKey (entity, field_name));
|
|
|
|
field = PR_FindField (pr, field_name);
|
|
|
|
if (!field) {
|
|
|
|
if (!pr->parse_field
|
|
|
|
|| !pr->parse_field (pr, field_name, value)) {
|
|
|
|
Sys_Printf ("'%s' is not a field\n", field_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
2013-01-17 05:11:54 +00:00
|
|
|
if (!ED_ParseEpair (pr, &E_fld (ent, 0), field, value))
|
2006-12-09 00:02:57 +00:00
|
|
|
PR_Error (pr, "ED_InitEntity: parse error");
|
|
|
|
}
|
2007-03-25 04:15:18 +00:00
|
|
|
init = 1;
|
2006-12-09 00:02:57 +00:00
|
|
|
}
|
2023-03-12 06:17:28 +00:00
|
|
|
PL_Release (keys);
|
2007-03-25 04:15:18 +00:00
|
|
|
if (!init)
|
|
|
|
ent->free = 1;
|
2006-12-09 00:02:57 +00:00
|
|
|
}
|
2002-10-23 04:57:08 +00:00
|
|
|
|
2003-07-17 18:27:00 +00:00
|
|
|
static void
|
2006-12-09 00:02:57 +00:00
|
|
|
ED_SpawnEntities (progs_t *pr, plitem_t *entity_list)
|
2002-10-23 04:57:08 +00:00
|
|
|
{
|
2006-12-09 00:02:57 +00:00
|
|
|
edict_t *ent;
|
|
|
|
plitem_t *entity;
|
|
|
|
plitem_t *item;
|
|
|
|
int i;
|
|
|
|
int count;
|
|
|
|
const char *classname;
|
|
|
|
dfunction_t *func;
|
2013-01-17 05:11:54 +00:00
|
|
|
pr_int_t max_edicts = pr->pr_edict_area_size / pr->pr_edict_size;
|
2006-12-09 00:02:57 +00:00
|
|
|
|
2011-04-17 11:06:20 +00:00
|
|
|
max_edicts -= *pr->num_edicts;
|
2006-12-09 00:02:57 +00:00
|
|
|
count = PL_A_NumObjects (entity_list);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
entity = PL_ObjectAtIndex (entity_list, i);
|
|
|
|
|
|
|
|
item = PL_ObjectForKey (entity, "classname");
|
|
|
|
if (!item)
|
|
|
|
PR_Error (pr, "no classname for entity %d", i);
|
|
|
|
classname = PL_String (item);
|
|
|
|
if (strequal (classname, "worldspawn"))
|
2002-10-23 04:57:08 +00:00
|
|
|
ent = EDICT_NUM (pr, 0);
|
|
|
|
else
|
|
|
|
ent = ED_Alloc (pr);
|
2006-12-09 00:02:57 +00:00
|
|
|
|
2012-07-09 06:07:34 +00:00
|
|
|
// don't allow the last edict to be used, as otherwise we can't detect
|
|
|
|
// too many edicts
|
|
|
|
if (NUM_FOR_EDICT (pr, ent) >= pr->max_edicts - 1)
|
|
|
|
PR_Error (pr, "too many entities: %d > %d", count, max_edicts);
|
|
|
|
|
2006-12-09 00:02:57 +00:00
|
|
|
ED_InitEntity (pr, entity, ent);
|
2002-10-23 04:57:08 +00:00
|
|
|
|
|
|
|
// remove things from different skill levels or deathmatch
|
|
|
|
if (pr->prune_edict && pr->prune_edict (pr, ent)) {
|
|
|
|
ED_Free (pr, ent);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2006-12-09 00:02:57 +00:00
|
|
|
//XXX should the field be checked instead of going direct?
|
|
|
|
func = PR_FindFunction (pr, classname);
|
2002-10-23 04:57:08 +00:00
|
|
|
if (!func) {
|
2006-12-09 00:02:57 +00:00
|
|
|
Sys_Printf ("No spawn function for :\n");
|
2021-07-25 00:54:08 +00:00
|
|
|
ED_Print (pr, ent, 0);
|
2002-10-23 04:57:08 +00:00
|
|
|
ED_Free (pr, ent);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pr->globals.self = EDICT_TO_PROG (pr, ent);
|
|
|
|
PR_ExecuteProgram (pr, func - pr->pr_functions);
|
|
|
|
if (pr->flush)
|
|
|
|
pr->flush ();
|
|
|
|
}
|
|
|
|
}
|
2003-07-17 18:27:00 +00:00
|
|
|
|
2010-12-10 03:46:54 +00:00
|
|
|
VISIBLE plitem_t *
|
|
|
|
ED_Parse (progs_t *pr, const char *data)
|
2003-07-17 18:27:00 +00:00
|
|
|
{
|
2004-11-12 02:39:00 +00:00
|
|
|
script_t *script;
|
2010-12-10 03:46:54 +00:00
|
|
|
plitem_t *entity_list = 0;
|
2004-11-12 02:39:00 +00:00
|
|
|
|
|
|
|
script = Script_New ();
|
|
|
|
Script_Start (script, "ent data", data);
|
|
|
|
|
|
|
|
if (Script_GetToken (script, 1)) {
|
2006-12-09 00:02:57 +00:00
|
|
|
if (strequal (script->token->str, "(")) {
|
2004-11-12 02:39:00 +00:00
|
|
|
// new style (plist) entity data
|
2022-05-12 08:54:23 +00:00
|
|
|
entity_list = PL_GetPropertyList (data, pr->hashctx);
|
2004-11-12 02:39:00 +00:00
|
|
|
} else {
|
2021-02-25 02:55:25 +00:00
|
|
|
// old style entity data
|
2004-11-12 02:39:00 +00:00
|
|
|
Script_UngetToken (script);
|
2022-05-12 08:54:23 +00:00
|
|
|
entity_list = ED_ConvertToPlist (script, 0, pr->hashctx);
|
2004-11-12 02:39:00 +00:00
|
|
|
}
|
2003-07-17 18:27:00 +00:00
|
|
|
}
|
2007-10-13 11:32:10 +00:00
|
|
|
Script_Delete (script);
|
2010-12-10 03:46:54 +00:00
|
|
|
return entity_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
VISIBLE void
|
|
|
|
ED_LoadFromFile (progs_t *pr, const char *data)
|
|
|
|
{
|
|
|
|
plitem_t *entity_list;
|
|
|
|
|
|
|
|
if (pr->edict_parse) {
|
|
|
|
PR_PushFrame (pr);
|
|
|
|
PR_RESET_PARAMS (pr);
|
|
|
|
P_INT (pr, 0) = PR_SetTempString (pr, data);
|
2020-02-25 08:28:32 +00:00
|
|
|
pr->pr_argc = 1;
|
2010-12-10 03:46:54 +00:00
|
|
|
PR_ExecuteProgram (pr, pr->edict_parse);
|
|
|
|
PR_PopFrame (pr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
entity_list = ED_Parse (pr, data);
|
|
|
|
if (entity_list) {
|
|
|
|
ED_SpawnEntities (pr, entity_list);
|
2023-03-12 06:17:28 +00:00
|
|
|
PL_Release (entity_list);
|
2010-12-10 03:46:54 +00:00
|
|
|
}
|
2004-11-12 02:39:00 +00:00
|
|
|
}
|
|
|
|
|
2007-03-10 12:00:59 +00:00
|
|
|
VISIBLE void
|
2022-02-14 03:28:38 +00:00
|
|
|
ED_EntityParseFunction (progs_t *pr, void *data)
|
2004-11-12 02:39:00 +00:00
|
|
|
{
|
|
|
|
pr->edict_parse = P_FUNCTION (pr, 0);
|
2003-07-17 18:27:00 +00:00
|
|
|
}
|