/pr_cmds.c
C | 1922 lines | 1372 code | 334 blank | 216 comment | 286 complexity | f92cbccd64fd7cc82dfde7ba1f24005d MD5 | raw file
Possible License(s): GPL-2.0
- /*
- 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 the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include "qwsvdef.h"
- #define RETURN_EDICT(e) (((int *) pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
- #define RETURN_STRING(s) (((int *) pr_globals)[OFS_RETURN] = PR_SetString(s))
- cvar_t sv_aim = {"sv_aim", "2"};
- /********************************** SUPPORT **********************************/
- #define STRINGTEMP_BUFFERS 16
- #define STRINGTEMP_LENGTH 128
- #define MAX_VARSTRING 256
- static char *PR_GetTempString(void){
- char *s;
- static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
- static int pr_string_tempindex = 0;
- s = pr_string_temp[pr_string_tempindex];
- pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
- return s;
- }
- static char *PF_VarString (int first) {
- int i;
- char *s, *out, *outend;
- static char pr_varstring_temp[MAX_VARSTRING];
- out = pr_varstring_temp;
- outend = pr_varstring_temp + sizeof(pr_varstring_temp) - 1;
- for (i = first; i < pr_argc && out < outend; i++) {
- s = G_STRING((OFS_PARM0 + i * 3));
- while (out < outend && *s)
- *out++ = *s++;
- }
- *out++ = 0;
- return pr_varstring_temp;
- }
- static void PR_CheckEmptyString (char *s) {
- if (s[0] <= ' ')
- PR_RunError ("Bad string");
- }
- //for PF_checkclient --->
- #define MAX_CHECK 16
- static byte checkpvs[MAX_MAP_LEAFS / 8];
- static int PF_newcheckclient (int check) {
- int i;
- byte *pvs;
- edict_t *ent;
- mleaf_t *leaf;
- vec3_t org;
- // cycle to the next one
- check = bound(1, check, MAX_CLIENTS);
- i = (check == MAX_CLIENTS) ? 1 : check + 1;
- for ( ; ; i++) {
- if (i == MAX_CLIENTS + 1)
- i = 1;
- ent = EDICT_NUM(i);
- if (i == check)
- break; // didn't find anything else
- if (ent->free)
- continue;
- if (ent->v.health <= 0)
- continue;
- if ((int) ent->v.flags & FL_NOTARGET)
- continue;
- // anything that is a client, or has a client as an enemy
- break;
- }
- // get the PVS for the entity
- VectorAdd (ent->v.origin, ent->v.view_ofs, org);
- leaf = Mod_PointInLeaf (org, sv.worldmodel);
- pvs = Mod_LeafPVS (leaf, sv.worldmodel);
- memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
- return i;
- }
- //for PF_checkclient <---
- //for message writing --->
- #define MSG_BROADCAST 0 // unreliable to all
- #define MSG_ONE 1 // reliable to one (msg_entity)
- #define MSG_ALL 2 // reliable to all
- #define MSG_INIT 3 // write to the init string
- #define MSG_MULTICAST 4 // for multicast()
- static sizebuf_t *WriteDest (void) {
- int dest;
- dest = G_FLOAT(OFS_PARM0);
- switch (dest) {
- case MSG_BROADCAST:
- return &sv.datagram;
-
- case MSG_ONE:
- Host_Error("Shouldn't be at MSG_ONE");
-
- case MSG_ALL:
- return &sv.reliable_datagram;
-
- case MSG_INIT:
- if (sv.state != ss_loading)
- PR_RunError ("PF_Write_*: MSG_INIT can only be written in spawn functions");
- return &sv.signon;
- case MSG_MULTICAST:
- return &sv.multicast;
- default:
- PR_RunError ("WriteDest: bad destination");
- break;
- }
-
- return NULL;
- }
- static client_t *Write_GetClient(void)
- {
- int entnum;
- edict_t *ent;
- ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
- entnum = NUM_FOR_EDICT(ent);
- if (entnum < 1 || entnum > MAX_CLIENTS)
- PR_RunError ("WriteDest: not a client");
- return svs.clients[entnum - 1];
- }
- //for message writing >--
- /********************************** BUILTINS **********************************/
- //void(string e) error = #10
- //This is a TERMINAL error, which will kill off the entire server. Dumps self.
- static void PF_error (void) {
- char *s;
- edict_t *ed;
- s = PF_VarString(0);
- Com_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name) ,s);
- ed = PROG_TO_EDICT(pr_global_struct->self);
- ED_Print (ed);
- Host_Error ("Program error");
- }
- //void(string e) objerror = #11
- //Dumps out self, then an error message. The program is aborted and self is removed, but the level can continue.
- static void PF_objerror (void) {
- char *s;
- edict_t *ed;
- s = PF_VarString(0);
- Com_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name),s);
- ed = PROG_TO_EDICT(pr_global_struct->self);
- ED_Print (ed);
- ED_Free (ed);
- Host_Error ("Program error");
- }
- //void() coredump = #28
- static void PF_coredump (void) {
- ED_PrintEdicts ();
- }
- //void() traceon = #29
- static void PF_traceon (void) {
- pr_trace = true;
- }
- //void() traceoff = #30
- static void PF_traceoff (void) {
- pr_trace = false;
- }
- //void(entity e) debug print an entire entity = #31
- static void PF_eprint (void) {
- ED_PrintNum (G_EDICTNUM(OFS_PARM0));
- }
- //void(entity e, vector o) setorigin = #2
- //This is the only valid way to move an object without using the physics of the world (setting velocity and waiting).
- //Directly changing origin will not set internal links correctly, so clipping would be messed up.
- //This should be called when an object is spawned, and then only if it is teleported.
- static void PF_setorigin (void) {
- edict_t *e;
- float *org;
- e = G_EDICT(OFS_PARM0);
- org = G_VECTOR(OFS_PARM1);
- VectorCopy (org, e->v.origin);
- SV_LinkEdict (e, false);
- }
- //void(entity e, string m) setmodel = #3
- //Also sets size, mins, and maxs for inline bmodels
- static void PF_setmodel (void) {
- edict_t *e;
- char *m, **check;
- int i;
- model_t *mod;
- e = G_EDICT(OFS_PARM0);
- m = G_STRING(OFS_PARM1);
- // check to see if model was properly precached
- for (i = 0, check = sv.model_precache; *check; i++, check++) {
- if (!strcmp(*check, m))
- break;
- }
- if (!*check)
- PR_RunError ("no precache: %s\n", m);
- e->v.model = PR_SetString(m);
- e->v.modelindex = i;
- // if it is an inline model, get the size information for it
- if (m[0] == '*') {
- mod = Mod_ForName (m, true);
- VectorCopy (mod->mins, e->v.mins);
- VectorCopy (mod->maxs, e->v.maxs);
- VectorSubtract (mod->maxs, mod->mins, e->v.size);
- SV_LinkEdict (e, false);
- }
- }
- //void(entity e, vector min, vector max) setsize = #4
- //the size box is rotated by the current angle
- static void PF_setsize (void) {
- edict_t *e;
- float *min, *max;
- e = G_EDICT(OFS_PARM0);
- min = G_VECTOR(OFS_PARM1);
- max = G_VECTOR(OFS_PARM2);
- VectorCopy (min, e->v.mins);
- VectorCopy (max, e->v.maxs);
- VectorSubtract (max, min, e->v.size);
- SV_LinkEdict (e, false);
- }
- //void(string s) bprint3 = #23
- //broadcast print to everyone on server
- static void PF_bprint (void) {
- char *s;
- int level;
- level = G_FLOAT(OFS_PARM0);
- s = PF_VarString(1);
- SV_BroadcastPrintf (level, "%s", s);
- }
- //void(entity client, string s) sprint = #24
- //single print to a specific client
- static void PF_sprint (void) {
- client_t *cl;
- int entnum, level, buflen, len, i;
- char *buf, *str;
- qboolean flush = false, flushboth = false;
- entnum = G_EDICTNUM(OFS_PARM0);
- level = G_FLOAT(OFS_PARM1);
- str = PF_VarString(2);
- if (entnum < 1 || entnum > MAX_CLIENTS) {
- Com_Printf ("tried to sprint to a non-client\n");
- return;
- }
- cl = svs.clients[entnum - 1];
- if (cl == 0)
- return;
- buf = cl->sprint_buf;
- buflen = strlen (buf);
- len = strlen (str);
- // flush the buffer if there's not enough space
- // also flush if sprint level has changed or if str is a colored message
- if (len >= sizeof(cl->sprint_buf) || str[0] == 1 || str[0] == 2) // a colored message
- flushboth = true;
- else if (buflen + len >= sizeof(cl->sprint_buf) || level != cl->sprint_level)
- flush = true;
- if ((flush || flushboth) && buflen) {
- SV_ClientPrintf (cl, cl->sprint_level, "%s", buf);
- buf[0] = 0;
- }
- if (flushboth) {
- SV_ClientPrintf (cl, level, "%s", str);
- return;
- }
- strcat (buf, str);
- cl->sprint_level = level;
- buflen += len;
- // flush complete (\n terminated) strings
- for (i = buflen - 1; i >= 0; i--) {
- if (buf[i] == '\n') {
- buf[i] = 0;
- SV_ClientPrintf (cl, cl->sprint_level, "%s\n", buf);
- // move the remainder to buffer beginning
- strcpy (buf, buf + i + 1);
- return;
- }
- }
- }
- //void(string s) dprint = #25
- static void PF_dprint (void) {
- Com_Printf ("%s",PF_VarString(0));
- }
- //void(entity client, strings) centerprint = #73
- //single print to a specific client
- static void PF_centerprint (void) {
- char *s;
- int entnum;
- client_t *cl;
- entnum = G_EDICTNUM(OFS_PARM0);
- s = PF_VarString(1);
- if (entnum < 1 || entnum > MAX_CLIENTS) {
- Com_Printf ("tried to sprint to a non-client\n");
- return;
- }
- cl = svs.clients[entnum - 1];
- if (cl == 0)
- return;
- ClientReliableWrite_Begin (cl, svc_centerprint, 2 + strlen(s));
- ClientReliableWrite_String (cl, s);
- }
- //void(entity e) makevectors = #1
- //Writes new values for v_forward, v_up, and v_right based on angles
- static void PF_makevectors (void) {
- AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
- }
- //vector(vector v) normalize = #9
- static void PF_normalize (void) {
- float *value1, length2;
- vec3_t newvalue;
- value1 = G_VECTOR(OFS_PARM0);
- if (!(length2 = DotProduct(value1, value1))) {
- VectorClear(newvalue);
- } else {
- length2 = 1 / sqrt(length2);
- VectorScale(value1, length2, newvalue);
- }
- VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
- }
- //float(vector v) vlen = #12
- static void PF_vlen (void) {
- float *value1, length2;
- value1 = G_VECTOR(OFS_PARM0);
- length2 = DotProduct(value1, value1);
- G_FLOAT(OFS_RETURN) = length2 ? sqrt(length2) : 0;
- }
- //float(vector v) vectoyaw = #13
- static void PF_vectoyaw (void) {
- float *value1, yaw;
- value1 = G_VECTOR(OFS_PARM0);
- if (value1[1] == 0 && value1[0] == 0) {
- yaw = 0;
- } else {
- yaw = atan2(value1[1], value1[0]) * 180 / M_PI;
- if (yaw < 0)
- yaw += 360;
- }
- G_FLOAT(OFS_RETURN) = yaw;
- }
- //vector(vector v) vectoangles = #51
- static void PF_vectoangles (void) {
- float *value1, forward, yaw, pitch;
- value1 = G_VECTOR(OFS_PARM0);
- if (value1[1] == 0 && value1[0] == 0) {
- yaw = 0;
- pitch = (value1[2] > 0) ? 90 : 270;
- } else {
- yaw = atan2(value1[1], value1[0]) * 180 / M_PI;
- if (yaw < 0)
- yaw += 360;
- forward = sqrt (value1[0] * value1[0] + value1[1] * value1[1]);
- pitch = atan2(value1[2], forward) * 180 / M_PI;
- if (pitch < 0)
- pitch += 360;
- }
- G_FLOAT(OFS_RETURN + 0) = pitch;
- G_FLOAT(OFS_RETURN + 1) = yaw;
- G_FLOAT(OFS_RETURN + 2) = 0;
- }
- //float() random = #7
- //Returns a number from 0 <= num < 1
- static void PF_random (void) {
- float num;
-
- num = (rand () & 0x7fff) / ((float) 0x7fff);
- G_FLOAT(OFS_RETURN) = num;
- }
- //float(float v) rint = #36
- static void PF_rint (void) {
- float f;
- f = G_FLOAT(OFS_PARM0);
- if (f > 0)
- G_FLOAT(OFS_RETURN) = (int) (f + 0.5);
- else
- G_FLOAT(OFS_RETURN) = (int) (f - 0.5);
- }
- //float(float v) floor = #37
- static void PF_floor (void) {
- G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
- }
- //float(float v) ceil = #38
- static void PF_ceil (void) {
- G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
- }
- //void() ChangeYaw = #49
- //This was a major timewaster in progs, so it was converted to C
- void PF_changeyaw (void) {
- edict_t *ent;
- float ideal, current, move, speed;
- //FIXME, OPTIMISE + changepitch
- ent = PROG_TO_EDICT(pr_global_struct->self);
- current = anglemod(ent->v.angles[1]);
- ideal = ent->v.ideal_yaw;
- speed = ent->v.yaw_speed;
- if (current == ideal)
- return;
- move = ideal - current;
- if (ideal > current) {
- if (move >= 180)
- move = move - 360;
- } else {
- if (move <= -180)
- move = move + 360;
- }
- if (move > 0)
- move = min(move, speed);
- else
- move = max(move, -speed);
- ent->v.angles[1] = anglemod (current + move);
- }
-
- //void(vector pos, string samp, float vol, float atten) ambientsound = #74
- static void PF_ambientsound (void) {
- char **check, *samp;
- float *pos, vol, attenuation;
- int i, soundnum;
- pos = G_VECTOR (OFS_PARM0);
- samp = G_STRING(OFS_PARM1);
- vol = G_FLOAT(OFS_PARM2);
- attenuation = G_FLOAT(OFS_PARM3);
- // check to see if samp was properly precached
- for (soundnum = 0, check = sv.sound_precache; *check; check++, soundnum++) {
- if (!strcmp(*check,samp))
- break;
- }
- if (!*check) {
- Com_Printf ("no precache: %s\n", samp);
- return;
- }
- // add an svc_spawnambient command to the level signon packet
- MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
- for (i = 0; i < 3; i++)
- MSG_WriteCoord(&sv.signon, pos[i]);
- MSG_WriteByte (&sv.signon, soundnum);
- MSG_WriteByte (&sv.signon, vol * 255);
- MSG_WriteByte (&sv.signon, attenuation * 64);
- }
- /*
- void(entity e, float chan, string samp) sound = #8
- Each entity can have eight independant sound sources, like voice,
- weapon, feet, etc.
- Channel 0 is an auto-allocate channel, the others override anything
- already running on that entity/channel pair.
- An attenuation of 0 will play full volume everywhere in the level.
- Larger attenuations will drop off.
- */
- static void PF_sound (void) {
- char *sample;
- int channel, volume;
- edict_t *entity;
- float attenuation;
- entity = G_EDICT(OFS_PARM0);
- channel = G_FLOAT(OFS_PARM1);
- sample = G_STRING(OFS_PARM2);
- volume = G_FLOAT(OFS_PARM3) * 255;
- attenuation = G_FLOAT(OFS_PARM4);
-
- SV_StartSound (entity, channel, sample, volume, attenuation);
- }
- //void() break = #6
- static void PF_break (void) {
- Com_Printf ("break statement\n");
- *((int *) -4) = 0; // dump to debugger
- //PR_RunError ("break statement");
- }
- /*
- entity() clientlist = #17
- Returns a client (or object that has a client enemy) that would be a valid target.
- If there are more than one valid options, they are cycled each frame
- If (self.origin + self.viewofs) is not in the PVS of the current target, it is not returned at all.
- */
- static void PF_checkclient (void) {
- edict_t *ent, *self;
- mleaf_t *leaf;
- int l;
- vec3_t view;
- // find a new check if on a new frame
- if (sv.time - sv.lastchecktime >= 0.1) {
- sv.lastcheck = PF_newcheckclient (sv.lastcheck);
- sv.lastchecktime = sv.time;
- }
- // return check if it might be visible
- ent = EDICT_NUM(sv.lastcheck);
- if (ent->free || ent->v.health <= 0) {
- RETURN_EDICT(sv.edicts);
- return;
- }
- // if current entity can't possibly see the check entity, return 0
- self = PROG_TO_EDICT(pr_global_struct->self);
- VectorAdd (self->v.origin, self->v.view_ofs, view);
- leaf = Mod_PointInLeaf (view, sv.worldmodel);
- l = (leaf - sv.worldmodel->leafs) - 1;
- if (l < 0 || !(checkpvs[l >> 3] & (1 << (l & 7)))) {
- RETURN_EDICT(sv.edicts);
- return;
- }
- // might be able to see it
- RETURN_EDICT(ent);
- }
- //void(entity client, string s)stuffcmd = #21
- //Sends text over to the client's execution buffer
- static void PF_stuffcmd (void) {
- int entnum, buflen, newlen, i;
- client_t *cl;
- char *buf, *str;
- entnum = G_EDICTNUM(OFS_PARM0);
- if (entnum < 1 || entnum > MAX_CLIENTS)
- PR_RunError ("Parm 0 not a client");
- cl = svs.clients[entnum - 1];
- if (cl == 0)
- return;
- str = G_STRING(OFS_PARM1);
- buf = cl->stufftext_buf;
- if (!strcmp(str, "disconnect\n")) {
- // so long and thanks for all the fish
- cl->drop = true;
- buf[0] = 0;
- return;
- }
- buflen = strlen (buf);
- newlen = strlen (str);
- if (buflen + newlen >= MAX_STUFFTEXT - 1) {
- // flush the buffer because there's no space left
- if (buflen) {
- ClientReliableWrite_Begin (cl, svc_stufftext, 2+buflen);
- ClientReliableWrite_String (cl, buf);
- buf[0] = 0;
- }
- if (newlen >= MAX_STUFFTEXT-1) {
- ClientReliableWrite_Begin (cl, svc_stufftext, 2+newlen);
- ClientReliableWrite_String (cl, str);
- return;
- }
- }
- strcat (buf, str);
- buflen += newlen;
- // flush complete (\n terminated) strings
- for (i = buflen - 1; i >= 0; i--) {
- if (buf[i] == '\n') {
- ClientReliableWrite_Begin (cl, svc_stufftext, 2 + (i + 1));
- ClientReliableWrite_SZ (cl, buf, i+1);
- ClientReliableWrite_Byte (cl, 0);
- // move the remainder to buffer beginning
- strcpy (buf, buf + i + 1);
- return;
- }
- }
- }
- //void(string s) localcmd = #46
- //Sends text over to the client's execution buffer
- static void PF_localcmd (void) {
- char *str;
-
- str = G_STRING(OFS_PARM0);
- Cbuf_AddText (str);
- }
- //float(string s) cvar = #45
- static void PF_cvar (void) {
- char *str;
- str = G_STRING(OFS_PARM0);
- //QC queries cvar("pr_checkextension") to see if an extension system is present
- if (!Q_strcasecmp(str, "pr_checkextension")) {
- G_FLOAT(OFS_RETURN) = 1.0;
- return;
- }
- G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
- }
- //float cvar (string) = #72
- static void PF_cvar_set (void) {
- char *var_name, *val;
- cvar_t *var;
- var_name = G_STRING(OFS_PARM0);
- val = G_STRING(OFS_PARM1);
- if (!(var = Cvar_FindVar(var_name))) {
- Com_DPrintf ("PF_cvar_set: variable %s not found\n", var_name);
- return;
- }
- Cvar_Set (var, val);
- }
- //entity(vector org, float rad) findradius = #22
- //Returns a chain of entities that have origins within a spherical area
- static void PF_findradius (void) {
- int i, j;
- float rad, *org;
- vec3_t eorg;
- edict_t *ent, *chain;
- chain = (edict_t *) sv.edicts;
- org = G_VECTOR(OFS_PARM0);
- rad = G_FLOAT(OFS_PARM1);
- ent = NEXT_EDICT(sv.edicts);
- for (i = 1; i < sv.num_edicts; i++, ent = NEXT_EDICT(ent)) {
- if (ent->free)
- continue;
- if (ent->v.solid == SOLID_NOT)
- continue;
- for (j = 0; j < 3; j++)
- eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j]) * 0.5);
- if (DotProduct(eorg, eorg) > rad * rad)
- continue;
- ent->v.chain = EDICT_TO_PROG(chain);
- chain = ent;
- }
- RETURN_EDICT(chain);
- }
- //void(string s) ftos = #26
- static void PF_ftos (void) {
- char *tempstring;
- float v;
- int i;
- v = G_FLOAT(OFS_PARM0);
- tempstring = PR_GetTempString();
- if (v == (int) v) {
- Q_snprintfz (tempstring, STRINGTEMP_LENGTH, "%d", (int) v);
- } else {
- Q_snprintfz (tempstring, STRINGTEMP_LENGTH, "%f", v);
- for (i = strlen(tempstring) - 1; i > 0 && tempstring[i] == '0'; i--)
- tempstring[i] = 0;
- if (tempstring[i] == '.')
- tempstring[i] = 0;
- }
- G_INT(OFS_RETURN) = PR_SetString(tempstring);
- }
- //float(float f) fabs = #43
- static void PF_fabs (void) {
- float v;
- v = G_FLOAT(OFS_PARM0);
- G_FLOAT(OFS_RETURN) = fabs(v);
- }
- //void(string s) vtos = #27
- static void PF_vtos (void) {
- char *s;
- s = PR_GetTempString();
- Q_snprintfz (s, STRINGTEMP_LENGTH,"'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
- G_INT(OFS_RETURN) = PR_SetString(s);
- }
- //entity() spawn = #14
- static void PF_Spawn (void) {
- edict_t *ed;
- ed = ED_Alloc();
- RETURN_EDICT(ed);
- }
- //void(entity e) remove = #15
- static void PF_Remove (void) {
- edict_t *ed;
- ed = G_EDICT(OFS_PARM0);
- ED_Free (ed);
- }
- //entity(entity start, .string fld, string match) find = #18;
- static void PF_Find (void) {
- int e, f;
- char *s, *t;
- edict_t *ed;
- e = G_EDICTNUM(OFS_PARM0);
- f = G_INT(OFS_PARM1);
- s = G_STRING(OFS_PARM2);
- for (e++ ; e < sv.num_edicts ; e++) {
- ed = EDICT_NUM(e);
- if (ed->free)
- continue;
- t = E_STRING(ed,f);
- if (!t)
- continue;
- if (!strcmp(t,s)) {
- RETURN_EDICT(ed);
- return;
- }
- }
- RETURN_EDICT(sv.edicts);
- }
- //string(string s) precache_file = #68
- static void PF_precache_file (void) {
- // precache_file is only used to copy files with qcc, it does nothing
- G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
- }
- //void(string s) precache_sound = #19
- static void PF_precache_sound (void) {
- char *s;
- int i;
- if (sv.state != ss_loading)
- PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
- s = G_STRING(OFS_PARM0);
- G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
- PR_CheckEmptyString (s);
- for (i = 0; i < MAX_SOUNDS; i++) {
- if (!sv.sound_precache[i]) {
- sv.sound_precache[i] = s;
- return;
- }
- if (!strcmp(sv.sound_precache[i], s))
- return;
- }
- PR_RunError ("PF_precache_sound: overflow");
- }
- //void(string s) precache_model = #20
- static void PF_precache_model (void) {
- char *s;
- int i;
- if (sv.state != ss_loading)
- PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
- s = G_STRING(OFS_PARM0);
- G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
- PR_CheckEmptyString (s);
- for (i = 1; i < MAX_MODELS; i++) {
- if (!sv.model_precache[i]) {
- sv.model_precache[i] = s;
- return;
- }
- if (!strcmp(sv.model_precache[i], s))
- return;
- }
- PR_RunError ("PF_precache_model: overflow");
- }
- //float(float yaw, float dist) walkmove = #32
- static void PF_walkmove (void) {
- edict_t *ent;
- float yaw, dist;
- vec3_t move;
- dfunction_t *oldf;
- int oldself;
- ent = PROG_TO_EDICT(pr_global_struct->self);
- yaw = G_FLOAT(OFS_PARM0);
- dist = G_FLOAT(OFS_PARM1);
- if (!((int) ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM))) {
- G_FLOAT(OFS_RETURN) = 0;
- return;
- }
- yaw = yaw * M_PI * 2 / 360;
- move[0] = cos(yaw) * dist;
- move[1] = sin(yaw) * dist;
- move[2] = 0;
- // save program state, because SV_movestep may call other progs
- oldf = pr_xfunction;
- oldself = pr_global_struct->self;
- G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
- // restore program state
- pr_xfunction = oldf;
- pr_global_struct->self = oldself;
- }
- //float() droptofloor = #34
- static void PF_droptofloor (void) {
- edict_t *ent;
- vec3_t end;
- trace_t trace;
- ent = PROG_TO_EDICT(pr_global_struct->self);
- VectorCopy (ent->v.origin, end);
- end[2] -= 256;
- trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
- if (trace.fraction == 1 || trace.allsolid) {
- G_FLOAT(OFS_RETURN) = 0;
- } else {
- VectorCopy (trace.endpos, ent->v.origin);
- SV_LinkEdict (ent, false);
- ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
- ent->v.groundentity = EDICT_TO_PROG(trace.ent);
- G_FLOAT(OFS_RETURN) = 1;
- }
- }
- //void(float style, string value) lightstyle = #35
- static void PF_lightstyle (void) {
- int style, j;
- char *val;
- client_t *client;
- style = G_FLOAT(OFS_PARM0);
- val = G_STRING(OFS_PARM1);
- // change the string in sv
- sv.lightstyles[style] = val;
- // send message to all clients on this server
- if (sv.state != ss_active)
- return;
- for (j = 0; j < MAX_CLIENTS; j++)
- {
- client = svs.clients[j];
- if ( client && client->state == cs_spawned ) {
- ClientReliableWrite_Begin (client, svc_lightstyle, strlen(val)+3);
- ClientReliableWrite_Char (client, style);
- ClientReliableWrite_String (client, val);
- }
- }
- }
- /*
- float(vector v1, vector v2, float tryents) traceline = #16
- Used for use tracing and shot targeting
- Traces are blocked by bbox and exact bsp entityes, and also slide box entities
- if the tryents flag is set.
- */
- static void PF_traceline (void) {
- float *v1, *v2;
- trace_t trace;
- int nomonsters;
- edict_t *ent;
- v1 = G_VECTOR(OFS_PARM0);
- v2 = G_VECTOR(OFS_PARM1);
- nomonsters = G_FLOAT(OFS_PARM2);
- ent = G_EDICT(OFS_PARM3);
- trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
- pr_global_struct->trace_allsolid = trace.allsolid;
- pr_global_struct->trace_startsolid = trace.startsolid;
- pr_global_struct->trace_fraction = trace.fraction;
- pr_global_struct->trace_inwater = trace.inwater;
- pr_global_struct->trace_inopen = trace.inopen;
- VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
- VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
- pr_global_struct->trace_plane_dist = trace.plane.dist;
- if (trace.ent)
- pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
- else
- pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
- }
- //float(entity e) checkbottom = #40
- static void PF_checkbottom (void) {
- edict_t *ent;
- ent = G_EDICT(OFS_PARM0);
- G_FLOAT(OFS_RETURN) = SV_CheckBottom (ent);
- }
- //float(vector v) pointcontents = #41
- static void PF_pointcontents (void) {
- float *v;
- v = G_VECTOR(OFS_PARM0);
- G_FLOAT(OFS_RETURN) = SV_PointContents (v);
- }
- //entity(entity e) nextent = #47
- static void PF_nextent (void) {
- int i;
- edict_t *ent;
- i = G_EDICTNUM(OFS_PARM0);
- while (1) {
- i++;
- if (i == sv.num_edicts) {
- RETURN_EDICT(sv.edicts);
- return;
- }
- ent = EDICT_NUM(i);
- if (!ent->free) {
- RETURN_EDICT(ent);
- return;
- }
- }
- }
- //vector(entity e, float speed) aim = #44
- //Pick a vector for the player to shoot along
- static void PF_aim (void) {
- edict_t *ent, *check, *bestent;
- vec3_t start, dir, end, bestdir;
- int i, j;
- trace_t tr;
- float dist, bestdist, speed;
- char *noaim;
- ent = G_EDICT(OFS_PARM0);
- speed = G_FLOAT(OFS_PARM1);
- VectorCopy (ent->v.origin, start);
- start[2] += 20;
- // noaim option
- i = NUM_FOR_EDICT(ent);
- if (i > 0 && i < MAX_CLIENTS) {
- if (svs.clients[i - 1])
- noaim = Info_ValueForKey (svs.clients[i - 1]->userinfo, "noaim");
- else
- noaim = 0;
- if (atoi(noaim) > 0) {
- VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
- return;
- }
- }
- // try sending a trace straight
- VectorCopy (pr_global_struct->v_forward, dir);
- VectorMA (start, 2048, dir, end);
- tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
- if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM && (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team)) {
- VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
- return;
- }
- // try all possible entities
- VectorCopy (dir, bestdir);
- bestdist = sv_aim.value;
- bestent = NULL;
- check = NEXT_EDICT(sv.edicts);
- for (i = 1; i < sv.num_edicts; i++, check = NEXT_EDICT(check)) {
- if (check->v.takedamage != DAMAGE_AIM)
- continue;
- if (check == ent)
- continue;
- if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team)
- continue; // don't aim at teammate
- for (j = 0; j < 3; j++)
- end[j] = check->v.origin[j] + 0.5 * (check->v.mins[j] + check->v.maxs[j]);
- VectorSubtract (end, start, dir);
- VectorNormalize (dir);
- dist = DotProduct (dir, pr_global_struct->v_forward);
- if (dist < bestdist)
- continue; // to far to turn
- tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
- if (tr.ent == check) {
- // can shoot at this one
- bestdist = dist;
- bestent = check;
- }
- }
- if (bestent) {
- VectorSubtract (bestent->v.origin, ent->v.origin, dir);
- dist = DotProduct (dir, pr_global_struct->v_forward);
- VectorScale (pr_global_struct->v_forward, dist, end);
- end[2] = dir[2];
- VectorNormalize (end);
- VectorCopy (end, G_VECTOR(OFS_RETURN));
- } else {
- VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
- }
- }
- //void(float to, float f) WriteByte = #52
- static void PF_WriteByte (void) {
- if (G_FLOAT(OFS_PARM0) == MSG_ONE)
- {
- client_t *cl = Write_GetClient();
- if (cl)
- {
- ClientReliableCheckBlock(cl, 1);
- ClientReliableWrite_Byte(cl, G_FLOAT(OFS_PARM1));
- }
- }
- else
- {
- MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
- }
- }
- //void(float to, float f) WriteChar = #53
- static void PF_WriteChar (void) {
- if (G_FLOAT(OFS_PARM0) == MSG_ONE)
- {
- client_t *cl = Write_GetClient();
- if (cl)
- {
- ClientReliableCheckBlock(cl, 1);
- ClientReliableWrite_Char(cl, G_FLOAT(OFS_PARM1));
- }
- }
- else
- {
- MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
- }
- }
- //void(float to, float f) WriteShort = #54
- static void PF_WriteShort (void) {
- if (G_FLOAT(OFS_PARM0) == MSG_ONE)
- {
- client_t *cl = Write_GetClient();
- if (cl)
- {
- ClientReliableCheckBlock(cl, 2);
- ClientReliableWrite_Short(cl, G_FLOAT(OFS_PARM1));
- }
- }
- else
- {
- MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
- }
- }
- //void(float to, float f) WriteLong = #55
- static void PF_WriteLong (void) {
- if (G_FLOAT(OFS_PARM0) == MSG_ONE)
- {
- client_t *cl = Write_GetClient();
- if (cl)
- {
- ClientReliableCheckBlock(cl, 4);
- ClientReliableWrite_Long(cl, G_FLOAT(OFS_PARM1));
- }
- }
- else
- {
- MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
- }
- }
- //void(float to, float f) WriteCoord = #56
- static void PF_WriteCoord (void) {
- if (G_FLOAT(OFS_PARM0) == MSG_ONE)
- {
- client_t *cl = Write_GetClient();
- if (cl)
- {
- ClientReliableCheckBlock(cl, 2);
- ClientReliableWrite_Coord(cl, G_FLOAT(OFS_PARM1));
- }
- }
- else
- {
- MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1));
- }
- }
- //void(float to, float f) WriteAngle = #57
- static void PF_WriteAngle (void) {
- if (G_FLOAT(OFS_PARM0) == MSG_ONE)
- {
- client_t *cl = Write_GetClient();
- if (cl)
- {
- ClientReliableCheckBlock(cl, 1);
- ClientReliableWrite_Angle(cl, G_FLOAT(OFS_PARM1));
- }
- }
- else
- {
- MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
- }
- }
- //void(float to, string s) WriteString = #58
- static void PF_WriteString (void) {
- if (G_FLOAT(OFS_PARM0) == MSG_ONE)
- {
- client_t *cl = Write_GetClient();
- if (cl)
- {
- ClientReliableCheckBlock(cl, 1+strlen(G_STRING(OFS_PARM1)));
- ClientReliableWrite_String(cl, G_STRING(OFS_PARM1));
- }
- }
- else
- {
- MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
- }
- }
- //void(float to, entity e) WriteEntity = #59
- static void PF_WriteEntity (void) {
- if (G_FLOAT(OFS_PARM0) == MSG_ONE)
- {
- client_t *cl = Write_GetClient();
- if (cl)
- {
- ClientReliableCheckBlock(cl, 2);
- ClientReliableWrite_Short(cl, SV_TranslateEntnum(G_EDICTNUM(OFS_PARM1)));
- }
- }
- else
- {
- MSG_WriteShort (WriteDest(), SV_TranslateEntnum(G_EDICTNUM(OFS_PARM1)));
- }
- }
- //void(entity e) makestatic = #69
- static void PF_makestatic (void) {
- edict_t *ent;
- int i;
- ent = G_EDICT(OFS_PARM0);
- MSG_WriteByte (&sv.signon, svc_spawnstatic);
- MSG_WriteByte (&sv.signon, SV_ModelIndex(PR_GetString(ent->v.model)));
- MSG_WriteByte (&sv.signon, ent->v.frame);
- MSG_WriteByte (&sv.signon, ent->v.colormap);
- MSG_WriteByte (&sv.signon, ent->v.skin);
- for (i = 0; i < 3; i++) {
- MSG_WriteCoord(&sv.signon, ent->v.origin[i]);
- MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
- }
- // throw the entity away now
- ED_Free (ent);
- }
- //void(entity e) setspawnparms = #78
- static void PF_setspawnparms (void) {
- edict_t *ent;
- int i;
- client_t *client;
- ent = G_EDICT(OFS_PARM0);
- i = NUM_FOR_EDICT(ent);
- if (i < 1 || i > MAX_CLIENTS)
- PR_RunError ("Entity is not a client");
- // copy spawn parms out of the client_t
- client = svs.clients[(i - 1)];
- if (client == 0)
- return;
- for (i = 0; i < NUM_SPAWN_PARMS; i++)
- (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
- }
- //void(string s) changelevel = #70
- static void PF_changelevel (void) {
- char *s;
- static int last_spawncount;
- // make sure we don't issue two changelevels
- if (svs.spawncount == last_spawncount)
- return;
- last_spawncount = svs.spawncount;
- s = G_STRING(OFS_PARM0);
- Cbuf_AddText (va("map %s\n", s));
- }
- //logfrag (string killer, string killee) = #79
- static void PF_logfrag (void) {
- edict_t *ent1, *ent2;
- int e1, e2;
- char *s;
- ent1 = G_EDICT(OFS_PARM0);
- ent2 = G_EDICT(OFS_PARM1);
- e1 = NUM_FOR_EDICT(ent1);
- e2 = NUM_FOR_EDICT(ent2);
- if (e1 < 1 || e1 > MAX_CLIENTS || e2 < 1 || e2 > MAX_CLIENTS)
- return;
- if (svs.clients[e1 - 1] == 0 || svs.clients[e2 - 1] == 0)
- return;
- s = va("\\%s\\%s\\\n", svs.clients[e1-1]->name, svs.clients[e2-1]->name);
- SZ_Print (&svs.log[svs.logsequence & 1], s);
- if (sv_fraglogfile) {
- fprintf (sv_fraglogfile, s);
- fflush (sv_fraglogfile);
- }
- }
- //string(entity e, string key) infokey = #80
- static void PF_infokey (void) {
- edict_t *e;
- int e1, ping;
- char *value, *key;
- static char ov[256];
- e = G_EDICT(OFS_PARM0);
- e1 = NUM_FOR_EDICT(e);
- key = G_STRING(OFS_PARM1);
- if (e1 == 0)
- {
- if ((value = Info_ValueForKey (svs.info, key)) == NULL || !*value)
- value = Info_ValueForKey(localinfo, key);
- }
- else if (e1 <= MAX_CLIENTS && svs.clients[e1 - 1])
- {
- if (!strcmp(key, "ip"))
- {
- Q_strncpyz(ov, NET_BaseAdrToString(&svs.clients[e1 - 1]->netchan.remote_address), sizeof(ov));
- value = ov;
- } else if (!strcmp(key, "ping")) {
- ping = SV_CalcPing (svs.clients[e1 - 1]);
- Q_snprintfz(ov, sizeof(ov), "%d", ping);
- value = ov;
- } else {
- value = Info_ValueForKey (svs.clients[e1 - 1]->userinfo, key);
- }
- } else {
- value = "";
- }
- RETURN_STRING(value);
- }
- //float(string s) stof = #81
- static void PF_stof (void) {
- char *s;
- s = G_STRING(OFS_PARM0);
- G_FLOAT(OFS_RETURN) = atof(s);
- }
- //void(vector where, float set) multicast = #82
- static void PF_multicast (void) {
- float *o;
- int to;
- o = G_VECTOR(OFS_PARM0);
- to = G_FLOAT(OFS_PARM1);
- SV_Multicast (o, to);
- }
- /***************************** BUILTIN EXTENSIONS *****************************/
- //EXTENSION: DP_QC_COPYENTITY
- //void(entity from, entity to) copyentity = #400
- //copies data from one entity to another
- static void PF_copyentity (void) {
- edict_t *in, *out;
- in = G_EDICT(OFS_PARM0);
- out = G_EDICT(OFS_PARM1);
- memcpy(&out->v, &in->v, progs->entityfields * 4);
- }
- //EXTENSION: DP_QC_ETOS
- //string(entity ent) etos = #65
- static void PF_etos (void) {
- char *s;
- s = PR_GetTempString();
- Q_snprintfz (s, STRINGTEMP_LENGTH, "entity %i", G_EDICTNUM(OFS_PARM0));
- G_INT(OFS_RETURN) = PR_SetString(s);
- }
- //EXTENSION: DP_QC_FINDCHAIN
- //entity(string field, string match) findchain = #402
- //chained search for strings in entity fields
- static void PF_findchain (void) {
- int i, f;
- char *s, *t;
- edict_t *ent, *chain;
- chain = (edict_t *) sv.edicts;
- f = G_INT(OFS_PARM0);
- s = G_STRING(OFS_PARM1);
- ent = NEXT_EDICT(sv.edicts);
- for (i = 1; i < sv.num_edicts; i++, ent = NEXT_EDICT(ent)) {
- if (ent->free)
- continue;
- t = E_STRING(ent,f);
- if (!t)
- continue;
- if (strcmp(t, s))
- continue;
- ent->v.chain = EDICT_TO_PROG(chain);
- chain = ent;
- }
- RETURN_EDICT(chain);
- }
- //EXTENSION: DP_QC_FINDCHAINFLOAT
- //entity(string field, float match) findchainfloat = #403
- //chained search for float, int, and entity reference fields
- static void PF_findchainfloat (void) {
- int i, f;
- float s;
- edict_t *ent, *chain;
- chain = (edict_t *) sv.edicts;
- f = G_INT(OFS_PARM0);
- s = G_FLOAT(OFS_PARM1);
- ent = NEXT_EDICT(sv.edicts);
- for (i = 1; i < sv.num_edicts; i++, ent = NEXT_EDICT(ent)) {
- if (ent->free)
- continue;
- if (E_FLOAT(ent, f) != s)
- continue;
- ent->v.chain = EDICT_TO_PROG(chain);
- chain = ent;
- }
- RETURN_EDICT(chain);
- }
- //EXTENSION: DP_QC_FINDFLOAT
- //entity(entity start, float fld, float match) findfloat = #98
- static void PF_FindFloat (void) {
- int e, f;
- float s;
- edict_t *ed;
- e = G_EDICTNUM(OFS_PARM0);
- f = G_INT(OFS_PARM1);
- s = G_FLOAT(OFS_PARM2);
- for (e++; e < sv.num_edicts; e++) {
- ed = EDICT_NUM(e);
- if (ed->free)
- continue;
- if (E_FLOAT(ed,f) == s) {
- RETURN_EDICT(ed);
- return;
- }
- }
- RETURN_EDICT(sv.edicts);
- }
- //EXTENSION: DP_QC_MINMAXBOUND
- //float(float a, floats) min = #94
- static void PF_min (void) {
- int i;
- float f;
- if (pr_argc == 2) {
- G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
- } else if (pr_argc >= 3) {
- f = G_FLOAT(OFS_PARM0);
- for (i = 1; i < pr_argc; i++) {
- if (G_FLOAT((OFS_PARM0 + i * 3)) < f)
- f = G_FLOAT((OFS_PARM0 + i * 3));
- }
- G_FLOAT(OFS_RETURN) = f;
- } else {
- PR_RunError("PF_min: must supply at least 2 floats\n");
- }
- }
- //float(float a, floats) max = #95
- static void PF_max (void) {
- int i;
- float f;
- if (pr_argc == 2) {
- G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
- } else if (pr_argc >= 3) {
- f = G_FLOAT(OFS_PARM0);
- for (i = 1; i < pr_argc; i++) {
- if (G_FLOAT((OFS_PARM0 + i * 3)) > f)
- f = G_FLOAT((OFS_PARM0 + i * 3));
- }
- G_FLOAT(OFS_RETURN) = f;
- } else {
- PR_RunError("PF_min: must supply at least 2 floats\n");
- }
- }
- //float(float minimum, float val, float maximum) bound = #96
- static void PF_bound (void) {
- G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
- }
- //EXTENSION: DP_QC_RANDOMVEC
- //vector() randomvec = #91
- static void PF_randomvec (void) {
- vec3_t temp;
- do {
- temp[0] = (rand() & 32767) * (2.0 / 32767.0) - 1.0;
- temp[1] = (rand() & 32767) * (2.0 / 32767.0) - 1.0;
- temp[2] = (rand() & 32767) * (2.0 / 32767.0) - 1.0;
- } while (DotProduct(temp, temp) >= 1);
- VectorCopy (temp, G_VECTOR(OFS_RETURN));
- }
- //EXTENSION: DP_QC_SINCOSSQRTPOW
- //float(float f) sin = #60
- static void PF_sin (void) {
- G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
- }
- //float(float f) cos = #61
- static void PF_cos (void) {
- G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
- }
- //float(float f) sqrt = #62
- static void PF_sqrt (void) {
- G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
- }
- //float(float f, float f) pow = #97
- static void PF_pow (void) {
- G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
- }
- //EXTENSION: DP_QC_VECTORVECTORS
- //void(vector dir) vectorvectors = #432
- //Writes new values for v_forward, v_up, and v_right based on the given forward vector
- static void PF_vectorvectors (void) {
- VectorCopy(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
- VectorNormalize(pr_global_struct->v_forward);
- VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
- }
- //EXTENSION: FRIK_FILE
- //float(string filename, float mode) fopen = #110
- //void(float fhandle) fclose = #111
- //string(float fhandle) fgets = #112
- //void(float fhandle, string s) fputs = #113
- //string(string s) strzone = #118
- //void(string s) strunzone = #119
- //float(string s) strlen = #114
- static void PF_strlen(void) {
- char *s;
- s = G_STRING(OFS_PARM0);
- G_FLOAT(OFS_RETURN) = strlen(s);
- }
- //string(string s1, string s2) strcat = #115
- static void PF_strcat(void) {
- char *s;
- s = PF_VarString(0);
- G_INT(OFS_RETURN) = PR_SetString(s);
- }
- //returns a section of a string as a tempstring
- static void PF_substring(void) {
- int i, start, length;
- char *s;
- static char string[MAX_VARSTRING];
- s = G_STRING(OFS_PARM0);
- start = G_FLOAT(OFS_PARM1);
- length = G_FLOAT(OFS_PARM2);
- for (i = 0; i < start && *s; i++, s++)
- ;
- for (i = 0; i < MAX_VARSTRING - 1 && *s && i < length; i++, s++)
- string[i] = *s;
- string[i] = 0;
- G_INT(OFS_RETURN) = PR_SetString(string);
- }
- //vector(string s) stov = #117
- //returns vector value from a string
- static void PF_stov(void) {
- int i;
- char *s;
- float *out;
- s = PF_VarString(0);
- out = G_VECTOR(OFS_RETURN);
- VectorClear(out);
- if (*s == '\'')
- s++;
- for (i = 0; i < 3; i++) {
- while (*s == ' ' || *s == '\t')
- s++;
- out[i] = atof (s);
- if (!out[i] && *s != '-' && *s != '+' && (*s < '0' || *s > '9'))
- break; // not a number
- while (*s && *s != ' ' && *s !='\t' && *s != '\'')
- s++;
- if (*s == '\'')
- break;
- }
- }
- //EXTENSION: KRIMZON_SV_PARSECLIENTCOMMAND
- //void(entity e, string s) clientcommand = #440
- //executes a command string as if it came from the specified client
- static void PF_clientcommand (void) {
- client_t *temp_client;
- int i;
- //find client for this entity
- i = NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1;
- if (i < 0 || i >= MAX_CLIENTS)
- PR_RunError("PF_clientcommand: entity is not a client");
- temp_client = sv_client;
- sv_client = svs.clients[i];
- if (sv_client && (sv_client->state == cs_connected || sv_client->state == cs_spawned))
- SV_ExecuteUserCommand (G_STRING(OFS_PARM1), true);
- sv_client = temp_client;
- }
- static char **tokens = NULL;
- static int max_tokens, num_tokens = 0;
- //float(string s) tokenize = #441
- //takes apart a string into individal words (access them with argv), returns number of tokens
- static void PF_tokenize (void) {
- int i;
- char *data, *str;
- str = G_STRING(OFS_PARM0);
- if (tokens) {
- for (i = 0; i < num_tokens; i++)
- Z_Free(tokens[i]);
- Z_Free(tokens);
- num_tokens = 0;
- }
- tokens = Z_Malloc(strlen(str) * sizeof(char *));
- max_tokens = strlen(str);
- for (data = str; (data = COM_Parse(data)) && num_tokens < max_tokens; num_tokens++)
- tokens[num_tokens] = CopyString(com_token);
- G_FLOAT(OFS_RETURN) = num_tokens;
- }
- //string(float n) argv = #442
- //returns a word from the tokenized string (returns nothing for an invalid index)
- static void PF_argv (void) {
- int token_num;
- token_num = G_FLOAT(OFS_PARM0);
- if (token_num >= 0 && token_num < num_tokens)
- G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
- else
- G_INT(OFS_RETURN) = PR_SetString("");
- }
- /****************************** EXTENSION SYSTEM ******************************/
- static char *ENGINE_EXTENSIONS[] = {
- "DP_HALFLIFE_MAP",
- "DP_HALFLIFE_MAP_CVAR",
- "DP_QC_COPYENTITY",
- "DP_QC_ETOS",
- "DP_QC_FINDCHAIN",
- "DP_QC_FINDCHAINFLOAT",
- "DP_QC_FINDFLOAT",
- "DP_QC_MINMAXBOUND",
- "DP_QC_RANDOMVEC",
- "DP_QC_SINCOSSQRTPOW",
- "DP_QC_VECTORVECTORS",
- //"FRIK_FILE", //incomplete
- "KRIMZON_SV_PARSECLIENTCOMMAND",
- NULL,
- };
- //float(string extension) checkextension = #99
- //returns true if the extension is supported by the server
- static void PF_checkextension (void) {
- char **s, *extension;
- qboolean supported = false;
- extension = G_STRING(OFS_PARM0);
- for (s = ENGINE_EXTENSIONS; *s; s++) {
- if (!Q_strcasecmp(*s, extension)) {
- supported = true;
- break;
- }
- }
- G_FLOAT(OFS_RETURN) = supported;
- }
- //=============================================================================
- #define EMPTY_BUILTIN_X10 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
- #define EMPTY_BUILTIN_X20 EMPTY_BUILTIN_X10, EMPTY_BUILTIN_X10
- #define EMPTY_BUILTIN_X50 EMPTY_BUILTIN_X20, EMPTY_BUILTIN_X20, EMPTY_BUILTIN_X10
- #define EMPTY_BUILTIN_X100 EMPTY_BUILTIN_X50, EMPTY_BUILTIN_X50
- builtin_t pr_builtins[] = {
- NULL,
- PF_makevectors, // #1 void(entity e) makevectors;
- PF_setorigin, // #2 void(entity e, vector o) setorigin;
- PF_setmodel, // #3 void(entity e, string m) setmodel;
- PF_setsize, // #4 void(entity e, vector min, vector max) setsize;
- NULL,
- PF_break, // #6 void() break;
- PF_random, // #7 float() random;
- PF_sound, // #8 void(entity e, float chan, string samp) sound;
- PF_normalize, // #9 vector(vector v) normalize;
- PF_error, // #10 void(string e) error;
- PF_objerror, // #11 void(string e) objerror;
- PF_vlen, // #12 float(vector v) vlen;
- PF_vectoyaw, // #13 float(vector v) vectoyaw;
- PF_Spawn, // #14 entity() spawn;
- PF_Remove, // #15 void(entity e) remove;
- PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline;
- PF_checkclient, // #17 entity() clientlist;
- PF_Find, // #18 entity(entity start, .string fld, string match) find;
- PF_precache_sound, // #19 void(string s) precache_sound;
- PF_precache_model, // #20 void(string s) precache_model;
- PF_stuffcmd, // #21 void(entity client, string s)stuffcmd;
- PF_findradius, // #22 entity(vector org, float rad) findradius;
- PF_bprint, // #23 void(string s) bprint3;
- PF_sprint, // #24 void(entity client, string s) sprint;
- PF_dprint, // #25 void(string s) dprint;
- PF_ftos, // #26 void(string s) ftos;
- PF_vtos, // #27 void(string s) vtos;
- PF_coredump, // #28 void() coredump
- PF_traceon, // #29 void() traceon
- PF_traceoff, // #30 void() traceoff
- PF_eprint, // #31 void(entity e) debug print an entire entity
- PF_walkmove, // #32 float(float yaw, float dist) walkmove
- NULL, // #33 float(float yaw, float dist) walkmove
- PF_droptofloor, // #34 float() droptofloor
- PF_lightstyle, // #35 void(float style, string value) lightstyle
- PF_rint, // #36 float(float v) rint
- PF_floor, // #37 float(float v) floor
- PF_ceil, // #38 float(float v) ceil
- NULL,
- PF_checkbottom, // #40 float(entity e) checkbottom
- PF_pointcontents, // #41 float(vector v) pointcontents
- NULL,
- PF_fabs, // #43 float(float f) fabs
- PF_aim, // #44 vector(entity e, float speed) aim
- PF_cvar, // #45 float(string s) cvar
- PF_localcmd, // #46 void(string s) localcmd
- PF_nextent, // #47 entity(entity e) nextent
- NULL,
- PF_changeyaw, // #49 void() ChangeYaw
- NULL,
- PF_vectoangles, // #51 vector(vector v) vectoangles
- PF_WriteByte, // #52 void(float to, float f) WriteByte
- PF_WriteChar, // #53 void(float to, float f) WriteChar
- PF_WriteShort, // #54 void(float to, float f) WriteShort
- PF_WriteLong, // #55 void(float to, float f) WriteLong
- PF_WriteCoord, // #56 void(float to, float f) WriteCoord
- PF_WriteAngle, // #57 void(float to, float f) WriteAngle
- PF_WriteString, // #58 void(float to, string s) WriteString
- PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
- PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
- PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
- PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
- NULL,
- NULL,
- PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
- NULL,
- SV_MoveToGoal, // #67 void(float step) movetogoal
- PF_precache_file, // #68 string(string s) precache_file
- PF_makestatic, // #69 void(entity e) makestatic
- PF_changelevel, // #70 void(string s) changelevel
- NULL,
- PF_cvar_set, // #72 void(string var, string val) cvar_set
- PF_centerprint, // #73 void(entity client, strings) centerprint
- PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
- PF_precache_model, // #75 string(string s) precache_model2
- PF_precache_sound, // #76 string(string s) precache_sound2
- PF_precache_file, // #77 string(string s) precache_file2
- PF_setspawnparms, // #78 void(entity e) setspawnparms
- PF_logfrag, // #79 logfrag (string killer, string killee)
- PF_infokey, // #80 string(entity e, string key) infokey
- PF_stof, // #81 float(string s) stof
- PF_multicast, // #82 void(vector where, float set) multicast
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
- NULL,
- NULL,
- PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
- PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
- PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
- PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
- PF_FindFloat, // #98 entity(entity start, float fld, float match) findfloat (DP_QC_FINDFLOAT)
- PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
- EMPTY_BUILTIN_X10,
- NULL, // #110 float(string filename, float mode) fopen (FRIK_FILE)
- NULL, // #111 void(float fhandle) fclose (FRIK_FILE)
- NULL, // #112 string(float fhandle) fgets (FRIK_FILE)
- NULL, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
- PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
- PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
- PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
- PF_stov, // #117 vector(string s) stov (FRIK_FILE)
- NULL, // #118 string(string s) strzone (FRIK_FILE)
- NULL, // #119 string(string s) strunzone (FRIK_FILE)
- EMPTY_BUILTIN_X10,
- EMPTY_BUILTIN_X20,
- EMPTY_BUILTIN_X50,
- EMPTY_BUILTIN_X100,
- EMPTY_BUILTIN_X100,
- PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
- NULL,
- PF_findchain, // #402 entity(string field, string match) findchain (DP_QC_FINDCHAIN)
- PF_findchainfloat, // #403 entity(float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- EMPTY_BUILTIN_X10,
- EMPTY_BUILTIN_X10,
- NULL,
- NULL,
- PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
- PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
- PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND
- };
- int pr_numbuiltins = sizeof(pr_builtins) / sizeof(pr_builtins[0]);