/quakeforge/branches/release_0_5_2/libs/gamecode/builtins/pr_cmds.c
C | 882 lines | 636 code | 100 blank | 146 comment | 123 complexity | ecd491048070ca0291f9fd80b08768a0 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, AGPL-3.0, AGPL-1.0, Unlicense
- /*
- pr_cmds.c
- (description)
- 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
- */
- static const char rcsid[] =
- "$Id: pr_cmds.c 8463 2002-09-07 06:48:15Z taniwha $";
- #ifdef HAVE_CONFIG_H
- # include "config.h"
- #endif
- #ifdef HAVE_ERRNO_H
- # include <errno.h>
- #endif
- #ifdef HAVE_STRING_H
- # include <string.h>
- #endif
- #ifdef HAVE_STRINGS_H
- # include <strings.h>
- #endif
- #include <stdlib.h>
- #include "QF/clip_hull.h"
- #include "QF/cmd.h"
- #include "QF/cvar.h"
- #include "QF/mathlib.h"
- #include "QF/msg.h"
- #include "QF/progs.h"
- #include "QF/sys.h"
- #include "QF/va.h"
- #include "QF/zone.h"
- #include "compat.h"
- const char *pr_gametype = "";
- /* BUILT-IN FUNCTIONS */
- // FIXME: Hunk_TempAlloc, Sys_Printf, Cvar_*, PR_SetString, PR_RunError, ED_PrintEdicts, PF_traceon, PF_traceoff, ED_PrintNum, PR_FindBuiltin isn't threadsafe/reentrant
- const char *
- PF_VarString (progs_t *pr, int first)
- {
- char *out;
- int len, i;
- for (len = 0, i = first; i < pr->pr_argc; i++)
- len += strlen (G_STRING (pr, (OFS_PARM0 + i * 3)));
- out = Hunk_TempAlloc (len + 1);
- out[0] = 0;
- for (i = first; i < pr->pr_argc; i++)
- strcat (out, G_STRING (pr, (OFS_PARM0 + i * 3)));
- return out;
- }
- /*
- PF_normalize
- vector normalize(vector)
- */
- void
- PF_normalize (progs_t *pr)
- {
- float new;
- float *value1;
- vec3_t newvalue;
- value1 = P_VECTOR (pr, 0);
- new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2] *
- value1[2];
- new = sqrt (new);
- if (new == 0)
- newvalue[0] = newvalue[1] = newvalue[2] = 0;
- else {
- new = 1 / new;
- newvalue[0] = value1[0] * new;
- newvalue[1] = value1[1] * new;
- newvalue[2] = value1[2] * new;
- }
- VectorCopy (newvalue, R_VECTOR (pr));
- }
- /*
- PF_vlen
- scalar vlen(vector)
- */
- void
- PF_vlen (progs_t *pr)
- {
- float new;
- float *value1;
- value1 = P_VECTOR (pr, 0);
- new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2] *
- value1[2];
- new = sqrt (new);
- R_FLOAT (pr) = new;
- }
- /*
- PF_vectoyaw
- float vectoyaw(vector)
- */
- void
- PF_vectoyaw (progs_t *pr)
- {
- float yaw;
- float *value1;
- value1 = P_VECTOR (pr, 0);
- if (value1[1] == 0 && value1[0] == 0)
- yaw = 0;
- else {
- yaw = (int) (atan2 (value1[1], value1[0]) * 180 / M_PI);
- if (yaw < 0)
- yaw += 360;
- }
- R_FLOAT (pr) = yaw;
- }
- /*
- PF_vectoangles
- vector vectoangles(vector)
- */
- void
- PF_vectoangles (progs_t *pr)
- {
- float forward, pitch, yaw;
- float *value1;
- value1 = P_VECTOR (pr, 0);
- if (value1[1] == 0 && value1[0] == 0) {
- yaw = 0;
- if (value1[2] > 0)
- pitch = 90;
- else
- pitch = 270;
- } else {
- yaw = (int) (atan2 (value1[1], value1[0]) * 180 / M_PI);
- if (yaw < 0)
- yaw += 360;
- forward = sqrt (value1[0] * value1[0] + value1[1] * value1[1]);
- pitch = (int) (atan2 (value1[2], forward) * 180 / M_PI);
- if (pitch < 0)
- pitch += 360;
- }
- R_VECTOR (pr)[0] = pitch;
- R_VECTOR (pr)[1] = yaw;
- R_VECTOR (pr)[2] = 0;
- }
- /*
- PF_Random
- Returns a number from 0<= num < 1
- random()
- */
- void
- PF_random (progs_t *pr)
- {
- float num;
- num = (rand () & 0x7fff) / ((float) 0x7fff);
- R_FLOAT (pr) = num;
- }
- /*
- PF_break
- break()
- */
- void
- PF_break (progs_t *pr)
- {
- Sys_Printf ("break statement\n");
- //*(int *) -4 = 0; // dump to debugger
- PR_DumpState (pr);
- // PR_RunError (pr, "break statement");
- }
- #if 0
- /*
- PF_localcmd
- Sends text to the host's execution buffer
- localcmd (string)
- */
- void
- PF_localcmd (progs_t *pr)
- {
- const char *str;
- str = P_STRING (pr, 0);
- Cbuf_AddText (str);
- }
- #endif
- /*
- PF_cvar
- float cvar (string)
- */
- void
- PF_cvar (progs_t *pr)
- {
- const char *str;
- str = P_STRING (pr, 0);
- R_FLOAT (pr) = Cvar_VariableValue (str);
- }
- /*
- PF_cvar_set
- float cvar (string)
- */
- void
- PF_cvar_set (progs_t *pr)
- {
- const char *var_name, *val;
- cvar_t *var;
- var_name = P_STRING (pr, 0);
- val = P_STRING (pr, 1);
- var = Cvar_FindVar (var_name);
- if (!var)
- var = Cvar_FindAlias (var_name);
- if (!var) {
- Sys_Printf ("PF_cvar_set: variable %s not found\n", var_name);
- return;
- }
- Cvar_Set (var, val);
- }
- void
- PF_fabs (progs_t *pr)
- {
- float v;
- v = P_FLOAT (pr, 0);
- R_FLOAT (pr) = fabs (v);
- }
- // entity (entity start, .string field, string match) find = #5;
- void
- PF_Find (progs_t *pr)
- {
- const char *s = 0, *t; // ev_string
- int i; // ev_vector
- int e, f;
- etype_t type;
- ddef_t *field_def;
- edict_t *ed;
- e = P_EDICTNUM (pr, 0);
- f = P_INT (pr, 1);
- field_def = ED_FieldAtOfs (pr, f);
- if (!field_def)
- PR_RunError (pr, "PF_Find: bad search field");
- type = field_def->type & ~DEF_SAVEGLOBAL;
- if (type == ev_string) {
- s = P_STRING (pr, 2);
- if (!s)
- PR_RunError (pr, "PF_Find: bad search string");
- }
- for (e++; e < *pr->num_edicts; e++) {
- ed = EDICT_NUM (pr, e);
- if (ed->free)
- continue;
- switch (type) {
- case ev_string:
- t = E_STRING (pr, ed, f);
- if (!t)
- continue;
- if (strcmp (t, s))
- continue;
- RETURN_EDICT (pr, ed);
- return;
- case ev_float:
- if (P_FLOAT (pr, 2) != E_FLOAT (ed, f))
- continue;
- RETURN_EDICT (pr, ed);
- return;
- case ev_vector:
- for (i = 0; i <= 2; i++)
- if (P_FLOAT (pr, 2 + i) != E_FLOAT (ed, f + i))
- continue;
- RETURN_EDICT (pr, ed);
- return;
- case ev_integer:
- case ev_entity:
- if (P_INT (pr, 2) != E_INT (ed, f))
- continue;
- RETURN_EDICT (pr, ed);
- return;
- default:
- PR_Error (pr, "PF_Find: unsupported search field");
- }
- }
- RETURN_EDICT (pr, *pr->edicts);
- }
- void
- PF_coredump (progs_t *pr)
- {
- ED_PrintEdicts (pr, "");
- }
- void
- PF_traceon (progs_t *pr)
- {
- pr->pr_trace = true;
- }
- void
- PF_traceoff (progs_t *pr)
- {
- pr->pr_trace = false;
- }
- void
- PF_eprint (progs_t *pr)
- {
- ED_PrintNum (pr, P_EDICTNUM (pr, 0));
- }
- void
- PF_dprint (progs_t *pr)
- {
- Sys_Printf ("%s", PF_VarString (pr, 0));
- }
- void
- PF_rint (progs_t *pr)
- {
- float f;
- f = P_FLOAT (pr, 0);
- if (f > 0)
- R_FLOAT (pr) = (int) (f + 0.5);
- else
- R_FLOAT (pr) = (int) (f - 0.5);
- }
- void
- PF_floor (progs_t *pr)
- {
- R_FLOAT (pr) = floor (P_FLOAT (pr, 0));
- }
- void
- PF_ceil (progs_t *pr)
- {
- R_FLOAT (pr) = ceil (P_FLOAT (pr, 0));
- }
- /*
- PF_nextent
- entity nextent(entity)
- */
- void
- PF_nextent (progs_t *pr)
- {
- int i;
- edict_t *ent;
- i = P_EDICTNUM (pr, 0);
- while (1) {
- i++;
- if (i == *pr->num_edicts) {
- RETURN_EDICT (pr, *pr->edicts);
- return;
- }
- ent = EDICT_NUM (pr, i);
- if (!ent->free) {
- RETURN_EDICT (pr, ent);
- return;
- }
- }
- }
- // we assume that ints are smaller than floats
- #ifdef FLT_MAX_10_EXP
- # define STRING_BUF (FLT_MAX_10_EXP + 8)
- #else
- # define STRING_BUF 128
- #endif
- /*
- PF_ftoi
- integer (float f) ftoi
- */
- void
- PF_ftoi (progs_t *pr)
- {
- R_INT (pr) = P_FLOAT (pr, 0);
- }
- /*
- PF_ftos
- string (float f) ftos
- */
- void
- PF_ftos (progs_t *pr)
- {
- char string[STRING_BUF];
- int i;
- // trimming 0s idea thanks to Maddes
- i = snprintf (string, sizeof (string), "%1.6f", P_FLOAT (pr, 0)) - 1;
- for (; i > 0; i--) {
- if (string[i] == '0')
- string[i] = '\0';
- else if (string[i] == '.') {
- string[i] = '\0';
- break;
- } else
- break;
- }
- RETURN_STRING (pr, string);
- }
- /*
- PF_itof
- float (integer i) itof
- */
- void
- PF_itof (progs_t *pr)
- {
- R_FLOAT (pr) = P_INT (pr, 0);
- }
- /*
- PF_itos
- string (integer i) itos
- */
- void
- PF_itos (progs_t *pr)
- {
- char string[STRING_BUF];
- snprintf (string, sizeof (string), "%d", P_INT (pr, 0));
- RETURN_STRING (pr, string);
- }
- /*
- PF_stof
- float (string s) stof
- */
- void
- PF_stof (progs_t *pr)
- {
- R_FLOAT (pr) = atof (P_STRING (pr, 0));
- }
- /*
- PF_stoi
- integer (string s) stoi
- */
- void
- PF_stoi (progs_t *pr)
- {
- R_INT (pr) = atoi (P_STRING (pr, 0));
- }
- /*
- PF_stov
- vector (string s) stov
- */
- void
- PF_stov (progs_t *pr)
- {
- float v[3] = {0, 0, 0};
- sscanf (P_STRING (pr, 0), "'%f %f %f'", v, v + 1, v + 2);
- RETURN_VECTOR (pr, v);
- }
- /*
- PF_vtos
- string (vector v) vtos
- */
- void
- PF_vtos (progs_t *pr)
- {
- char string[STRING_BUF * 3 + 5];
- snprintf (string, sizeof (string), "'%5.1f %5.1f %5.1f'",
- P_VECTOR (pr, 0)[0],
- P_VECTOR (pr, 0)[1],
- P_VECTOR (pr, 0)[2]);
- RETURN_STRING (pr, string);
- }
- /*
- PF_strlen
- float(string s) strlen
- */
- void
- PF_strlen (progs_t *pr)
- {
- const char *s;
- s = P_STRING (pr, 0);
- R_FLOAT (pr) = strlen(s);
- }
- /*
- PF_charcount
- float(string char, string s) charcount
- */
- void
- PF_charcount (progs_t *pr)
- {
- char goal;
- const char *s;
- int count;
- goal = (P_STRING (pr, 0))[0];
- if (goal == '\0') {
- R_FLOAT (pr) = 0;
- return;
- }
- count = 0;
- s = P_STRING (pr, 1);
- while (*s) {
- if (*s == goal)
- count++;
- s++;
- }
- R_FLOAT (pr) = count;
- }
- #if (INT_MAX == 2147483647) && (INT_MIN == -2147483648)
- # define INT_WIDTH 11
- #else /* I hope... */
- # define INT_WIDTH 20
- #endif
- #define MAX_ARG 23
- void
- PF_sprintf (progs_t *pr)
- {
- char *format;
- char *c; // current
- char *out = 0;
- char new_format[INT_WIDTH * 2 + 9]; // "%0-+ #." and conversion
- int fmt_alternate, fmt_leadzero, fmt_leftjust, fmt_minwidth,
- fmt_precision, fmt_signed, fmt_space, fmt_type, looping,
- new_format_i, ret;
- int curarg = 3, out_max = 32, out_size = 0;
- format = P_STRING (pr, 0);
- c = format;
- out = malloc (out_max);
- if (!out)
- goto mallocerror;
- while (*c) {
- if (*c == '%' && c[1] != '%' && c[1] != 's') {
- c++;
- if (curarg > MAX_ARG)
- goto maxargs;
- // flags
- looping = 1;
- fmt_leadzero = 0;
- fmt_leftjust = 0;
- fmt_signed = 0;
- fmt_space = 0;
- fmt_alternate = 0;
- while (looping) {
- switch (*c) {
- case '0': fmt_leadzero = 1; break;
- case '-': fmt_leftjust = 1; break;
- case '+': fmt_signed = 1; break;
- case ' ': fmt_space = 1; break;
- case '#': fmt_alternate = 1; break;
- case '\0': goto endofstring;
- default: looping = 0; continue;
- }
- c++;
- }
- // minimum field width
- fmt_minwidth = 0;
- if (*c >= '1' && *c <= '9')
- while (*c >= '0' && *c <= '9') {
- fmt_minwidth *= 10;
- fmt_minwidth += *c - '0';
- c++;
- }
- else if (*c == '*') {
- fmt_minwidth = P_INT (pr, 0 + curarg);
- curarg += 3;
- }
- // precision
- fmt_precision = -1;
- if (*c == '.') {
- c++;
- if (*c >= '0' && *c <= '9') {
- fmt_precision = 0;
- while (*c >= '0' && *c <= '9') {
- fmt_precision *= 10;
- fmt_precision += *c - '0';
- c++;
- }
- } else if (*c == '*') {
- fmt_precision = P_INT (pr, 0 + curarg);
- curarg += 3;
- }
- }
- if (!*c)
- goto endofstring;
- // length? Nope, not in QC
- fmt_type = *c++;
- // some preperation
- if (fmt_precision < 0)
- switch (fmt_type) {
- case 'i': fmt_precision = 0; break;
- case 'f': fmt_precision = 6; break;
- case 'v': fmt_precision = 1; break;
- }
- // built the format string
- new_format_i = 0;
- new_format[new_format_i++] = '%';
- if (fmt_leadzero) new_format[new_format_i++] = '0';
- if (fmt_leftjust) new_format[new_format_i++] = '-';
- if (fmt_signed) new_format[new_format_i++] = '+';
- if (fmt_space) new_format[new_format_i++] = ' ';
- if (fmt_alternate) new_format[new_format_i++] = '#';
- if (fmt_minwidth)
- if ((new_format_i += snprintf (new_format + new_format_i,
- sizeof (new_format) -
- new_format_i,
- "%d", fmt_minwidth))
- >= sizeof (new_format))
- PR_Error (pr, "PF_sprintf: new_format overflowed?!");
- if (fmt_type != 'i') {
- new_format[new_format_i++] = '.';
- if ((new_format_i += snprintf (new_format + new_format_i,
- sizeof (new_format)
- - new_format_i,
- "%d", fmt_precision))
- >= sizeof (new_format))
- PR_Error (pr, "PF_sprintf: new_format overflowed?!");
- }
- switch (fmt_type) {
- case 'i': new_format[new_format_i++] = 'd'; break;
- case 'f':
- case 'v': new_format[new_format_i++] = 'f'; break;
- default: PR_Error (pr, "PF_sprintf: unknown type '%c'!", *c);
- }
- new_format[new_format_i++] = '\0';
- switch (fmt_type) {
- case 'i':
- while ((ret = snprintf (&out[out_size], out_max - out_size,
- new_format,
- P_INT (pr, 0 + curarg)))
- >= out_max - out_size) {
- char *o;
- out_max *= 2;
- o = realloc (out, out_max);
- if (!o)
- goto mallocerror;
- out = o;
- }
- out_size += ret;
- curarg += 3;
- break;
- case 'f':
- while ((ret = snprintf (&out[out_size], out_max - out_size,
- new_format,
- P_FLOAT (pr, 0 + curarg)))
- >= out_max - out_size) {
- char *o;
- out_max *= 2;
- o = realloc (out, out_max);
- if (!o)
- goto mallocerror;
- out = o;
- }
- out_size += ret;
- curarg += 3;
- break;
- case 'v': {
- int i;
- for (i = 0; i <= 2; i++) {
- if (curarg > MAX_ARG)
- goto maxargs;
- while ((ret = snprintf (&out[out_size],
- out_max - out_size, new_format,
- P_FLOAT (pr, 0 +
- curarg)))
- >= out_max - out_size) {
- char *o;
- out_max *= 2;
- o = realloc (out, out_max);
- if (!o)
- goto mallocerror;
- out = o;
- }
- out_size += ret;
- curarg++;
- i++;
- }
- break;
- }
- }
- } else if (*c == '%' && *(c + 1) == 's') {
- char *s;
- if (curarg > MAX_ARG)
- goto maxargs;
- s = P_STRING (pr, 0 + curarg);
- while ((ret = snprintf (&out[out_size], out_max - out_size, "%s",
- s))
- >= out_max - out_size) {
- char *o;
- out_max *= 2;
- o = realloc (out, out_max);
- if (!o)
- goto mallocerror;
- out = o;
- }
- out_size += ret;
- curarg += 3;
- c += 2;
- } else {
- if (*c == '%')
- c++;
- if (out_size == out_max) {
- char *o;
- out_max *= 2;
- o = realloc (out, out_max);
- if (!o)
- goto mallocerror;
- out = o;
- }
- out[out_size] = *c;
- out_size++;
- c++;
- }
- }
- if (out_size == out_max) {
- char *o;
- out_max *= 2;
- o = realloc (out, out_max);
- if (!o)
- goto mallocerror;
- out = o;
- }
- out[out_size] = '\0';
- RETURN_STRING (pr, out);
- free (out);
- return;
- mallocerror:
- // if (errno == ENOMEM)
- // hopefully we can free up some mem so it can be used during shutdown
- // free (out);
- PR_Error (pr, "PF_sprintf: memory allocation error!\n");
- endofstring:
- PR_Error (pr, "PF_sprintf: unexpected end of string!\n");
- maxargs:
- PR_Error (pr, "PF_sprintf: argument limit exceeded\n");
- }
- void
- PR_gametype (progs_t *pr)
- {
- RETURN_STRING (pr, pr_gametype);
- }
- void
- PR_Cmds_Init (progs_t *pr)
- {
- PR_AddBuiltin (pr, "break", PF_break, 6); // void () break
- PR_AddBuiltin (pr, "random", PF_random, 7); // float () random
- PR_AddBuiltin (pr, "normalize", PF_normalize, 9); // vector (vector v) normalize
- PR_AddBuiltin (pr, "vlen", PF_vlen, 12); // float (vector v) vlen
- PR_AddBuiltin (pr, "vectoyaw", PF_vectoyaw, 13); // float (vector v) vectoyaw
- PR_AddBuiltin (pr, "find", PF_Find, 18); // entity (entity start, .(...) fld, ... match) find
- PR_AddBuiltin (pr, "dprint", PF_dprint, 25); // void (string s) dprint
- PR_AddBuiltin (pr, "coredump", PF_coredump, 28); // void () coredump
- PR_AddBuiltin (pr, "traceon", PF_traceon, 29); // void () traceon
- PR_AddBuiltin (pr, "traceoff", PF_traceoff, 30); // void () traceoff
- PR_AddBuiltin (pr, "eprint", PF_eprint, 31); // void (entity e) eprint
- PR_AddBuiltin (pr, "rint", PF_rint, 36); // float (float v) rint
- PR_AddBuiltin (pr, "floor", PF_floor, 37); // float (float v) floor
- PR_AddBuiltin (pr, "ceil", PF_ceil, 38); // float (float v) ceil
- PR_AddBuiltin (pr, "fabs", PF_fabs, 43); // float (float f) fabs
- PR_AddBuiltin (pr, "cvar", PF_cvar, 45); // float (string s) cvar
- #if 0
- PR_AddBuiltin (pr, "localcmd", PF_localcmd, 46); // void (string s) localcmd
- #endif
- PR_AddBuiltin (pr, "nextent", PF_nextent, 47); // entity (entity e) nextent
- PR_AddBuiltin (pr, "vectoangles", PF_vectoangles, 51); // vector (vector v) vectoangles
- PR_AddBuiltin (pr, "cvar_set", PF_cvar_set, 72); // void (string var, string val) cvar_set
- PR_AddBuiltin (pr, "strlen", PF_strlen, 100); // float (string s) strlen
- PR_AddBuiltin (pr, "charcount", PF_charcount, 101); // float (string goal, string s) charcount
- PR_AddBuiltin (pr, "sprintf", PF_sprintf, 109); // string (...) sprintf
- PR_AddBuiltin (pr, "ftos", PF_ftos, 26); // string (float f) ftos
- PR_AddBuiltin (pr, "ftoi", PF_ftoi, 110); // integer (float f) ftoi
- PR_AddBuiltin (pr, "itof", PF_itof, 111); // float (integer i) itof
- PR_AddBuiltin (pr, "itos", PF_itos, 112); // string (integer i) itos
- PR_AddBuiltin (pr, "stof", PF_stof, 81); // float (string s) stof
- PR_AddBuiltin (pr, "stoi", PF_stoi, 113); // integer (string s) stoi
- PR_AddBuiltin (pr, "stov", PF_stov, 114); // vector (string s) stov
- PR_AddBuiltin (pr, "vtos", PF_vtos, 27); // string (vector v) vtos
- PR_AddBuiltin (pr, "gametype", PR_gametype, 115); // string () gametype
- };