2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled autoaim by default
24 cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"};
26 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
27 #define STRINGTEMP_BUFFERS 16
28 #define STRINGTEMP_LENGTH 4096
29 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
30 static int pr_string_tempindex = 0;
32 static char *PR_GetTempString(void)
35 s = pr_string_temp[pr_string_tempindex];
36 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
40 #define RETURN_EDICT(e) (PRVM_G_INT(OFS_RETURN) = PRVM_EDICT_TO_PROG(e))
41 #define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
42 #define PF_ERROR(s) do{Host_Error(s);return;}while(0)
46 ===============================================================================
50 ===============================================================================
54 void PF_VarString(int first, char *out, int outlength)
60 outend = out + outlength - 1;
61 for (i = first;i < pr_argc && out < outend;i++)
63 s = PRVM_G_STRING((OFS_PARM0+i*3));
64 while (out < outend && *s)
70 char *ENGINE_EXTENSIONS =
88 "DP_ENT_CUSTOMCOLORMAP "
89 "DP_ENT_EXTERIORMODELTOCLIENT "
91 "DP_ENT_LOWPRECISION "
94 "DP_GFX_EXTERNALTEXTURES "
96 "DP_GFX_QUAKE3MODELTAGS "
100 "DP_HALFLIFE_MAP_CVAR "
101 "DP_HALFLIFE_SPRITE "
106 "DP_MOVETYPEBOUNCEMISSILE "
113 "DP_QC_FINDCHAINFLAGS "
114 "DP_QC_FINDCHAINFLOAT "
117 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
122 "DP_QC_MULTIPLETEMPSTRINGS "
124 "DP_QC_SINCOSSQRTPOW "
127 "DP_QC_TRACE_MOVETYPE_HITMODEL "
128 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
129 "DP_QC_VECTORVECTORS "
135 "DP_SND_DIRECTIONLESSATTNNONE "
142 "DP_SV_CLIENTCOLORS "
144 "DP_SV_DRAWONLYTOCLIENT "
147 "DP_SV_NODRAWTOCLIENT "
149 "DP_SV_PLAYERPHYSICS "
150 "DP_SV_PRECACHEANYTIME "
152 "DP_SV_ROTATINGBMODEL "
158 "DP_TE_EXPLOSIONRGB "
160 "DP_TE_PARTICLECUBE "
161 "DP_TE_PARTICLERAIN "
162 "DP_TE_PARTICLESNOW "
164 "DP_TE_QUADEFFECTS1 "
167 "DP_TE_STANDARDEFFECTBUILTINS "
170 "KRIMZON_SV_PARSECLIENTCOMMAND "
174 "PRYDON_CLIENTCURSOR "
175 "TENEBRAE_GFX_DLIGHTS "
177 "NEXUIZ_PLAYERMODEL "
180 qboolean checkextension(const char *name)
185 for (e = ENGINE_EXTENSIONS;*e;e++)
192 while (*e && *e != ' ')
194 if (e - start == len)
195 if (!strncasecmp(start, name, len))
205 returns true if the extension is supported by the server
207 checkextension(extensionname)
210 void PF_checkextension (void)
212 PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0));
219 This is a TERMINAL error, which will kill off the entire server.
228 char string[STRINGTEMP_LENGTH];
230 PF_VarString(0, string, sizeof(string));
231 Con_Printf("======SERVER ERROR in %s:\n%s\n", PRVM_GetString(pr_xfunction->s_name), string);
232 ed = PRVM_PROG_TO_EDICT(prog->globals.server->self);
235 PF_ERROR("Program error");
242 Dumps out self, then an error message. The program is aborted and self is
243 removed, but the level can continue.
248 void PF_objerror (void)
251 char string[STRINGTEMP_LENGTH];
253 PF_VarString(0, string, sizeof(string));
254 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PRVM_GetString(pr_xfunction->s_name), string);
255 ed = PRVM_PROG_TO_EDICT(prog->globals.server->self);
265 Writes new values for v_forward, v_up, and v_right based on angles
269 void PF_makevectors (void)
271 AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up);
278 Writes new values for v_forward, v_up, and v_right based on the given forward vector
279 vectorvectors(vector, vector)
282 void PF_vectorvectors (void)
284 VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward);
285 VectorVectors(prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up);
292 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.
294 setorigin (entity, origin)
297 void PF_setorigin (void)
302 e = PRVM_G_EDICT(OFS_PARM0);
303 if (e == prog->edicts)
304 PF_WARNING("setorigin: can not modify world entity\n");
305 if (e->priv.server->free)
306 PF_WARNING("setorigin: can not modify free entity\n");
307 org = PRVM_G_VECTOR(OFS_PARM1);
308 VectorCopy (org, e->fields.server->origin);
309 SV_LinkEdict (e, false);
313 void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
317 for (i=0 ; i<3 ; i++)
319 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
321 // set derived values
322 VectorCopy (min, e->fields.server->mins);
323 VectorCopy (max, e->fields.server->maxs);
324 VectorSubtract (max, min, e->fields.server->size);
326 SV_LinkEdict (e, false);
333 the size box is rotated by the current angle
334 LordHavoc: no it isn't...
336 setsize (entity, minvector, maxvector)
339 void PF_setsize (void)
344 e = PRVM_G_EDICT(OFS_PARM0);
345 if (e == prog->edicts)
346 PF_WARNING("setsize: can not modify world entity\n");
347 if (e->priv.server->free)
348 PF_WARNING("setsize: can not modify free entity\n");
349 min = PRVM_G_VECTOR(OFS_PARM1);
350 max = PRVM_G_VECTOR(OFS_PARM2);
351 SetMinMaxSize (e, min, max, false);
359 setmodel(entity, model)
362 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
363 void PF_setmodel (void)
369 e = PRVM_G_EDICT(OFS_PARM0);
370 if (e == prog->edicts)
371 PF_WARNING("setmodel: can not modify world entity\n");
372 if (e->priv.server->free)
373 PF_WARNING("setmodel: can not modify free entity\n");
374 i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
375 e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
376 e->fields.server->modelindex = i;
382 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
383 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
385 SetMinMaxSize (e, quakemins, quakemaxs, true);
388 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
395 broadcast print to everyone on server
400 void PF_bprint (void)
402 char string[STRINGTEMP_LENGTH];
403 PF_VarString(0, string, sizeof(string));
404 SV_BroadcastPrint(string);
411 single print to a specific client
413 sprint(clientent, value)
416 void PF_sprint (void)
420 char string[STRINGTEMP_LENGTH];
422 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
424 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
426 Con_Print("tried to sprint to a non-client\n");
430 client = svs.clients + entnum-1;
431 PF_VarString(1, string, sizeof(string));
432 MSG_WriteChar(&client->message,svc_print);
433 MSG_WriteString(&client->message, string);
441 single print to a specific client
443 centerprint(clientent, value)
446 void PF_centerprint (void)
450 char string[STRINGTEMP_LENGTH];
452 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
454 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
456 Con_Print("tried to sprint to a non-client\n");
460 client = svs.clients + entnum-1;
461 PF_VarString(1, string, sizeof(string));
462 MSG_WriteChar(&client->message,svc_centerprint);
463 MSG_WriteString(&client->message, string);
471 vector normalize(vector)
474 void PF_normalize (void)
480 value1 = PRVM_G_VECTOR(OFS_PARM0);
482 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
486 newvalue[0] = newvalue[1] = newvalue[2] = 0;
490 newvalue[0] = value1[0] * new;
491 newvalue[1] = value1[1] * new;
492 newvalue[2] = value1[2] * new;
495 VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
510 value1 = PRVM_G_VECTOR(OFS_PARM0);
512 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
515 PRVM_G_FLOAT(OFS_RETURN) = new;
522 float vectoyaw(vector)
525 void PF_vectoyaw (void)
530 value1 = PRVM_G_VECTOR(OFS_PARM0);
532 if (value1[1] == 0 && value1[0] == 0)
536 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
541 PRVM_G_FLOAT(OFS_RETURN) = yaw;
549 vector vectoangles(vector)
552 void PF_vectoangles (void)
554 double value1[3], forward, yaw, pitch;
556 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), value1);
558 if (value1[1] == 0 && value1[0] == 0)
568 // LordHavoc: optimized a bit
571 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
575 else if (value1[1] > 0)
580 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
581 pitch = (atan2(value1[2], forward) * 180 / M_PI);
586 VectorSet(PRVM_G_VECTOR(OFS_RETURN), pitch, yaw, 0);
593 Returns a number from 0<= num < 1
598 void PF_random (void)
600 PRVM_G_FLOAT(OFS_RETURN) = lhrandom(0, 1);
607 particle(origin, color, count)
610 void PF_particle (void)
616 org = PRVM_G_VECTOR(OFS_PARM0);
617 dir = PRVM_G_VECTOR(OFS_PARM1);
618 color = PRVM_G_FLOAT(OFS_PARM2);
619 count = PRVM_G_FLOAT(OFS_PARM3);
620 SV_StartParticle (org, dir, color, count);
630 void PF_ambientsound (void)
634 float vol, attenuation;
637 pos = PRVM_G_VECTOR (OFS_PARM0);
638 samp = PRVM_G_STRING(OFS_PARM1);
639 vol = PRVM_G_FLOAT(OFS_PARM2);
640 attenuation = PRVM_G_FLOAT(OFS_PARM3);
642 // check to see if samp was properly precached
643 soundnum = SV_SoundIndex(samp, 1);
651 // add an svc_spawnambient command to the level signon packet
654 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
656 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
658 MSG_WriteVector(&sv.signon, pos, sv.protocol);
661 MSG_WriteShort (&sv.signon, soundnum);
663 MSG_WriteByte (&sv.signon, soundnum);
665 MSG_WriteByte (&sv.signon, vol*255);
666 MSG_WriteByte (&sv.signon, attenuation*64);
674 Each entity can have eight independant sound sources, like voice,
677 Channel 0 is an auto-allocate channel, the others override anything
678 already running on that entity/channel pair.
680 An attenuation of 0 will play full volume everywhere in the level.
681 Larger attenuations will drop off.
689 prvm_edict_t *entity;
693 entity = PRVM_G_EDICT(OFS_PARM0);
694 channel = PRVM_G_FLOAT(OFS_PARM1);
695 sample = PRVM_G_STRING(OFS_PARM2);
696 volume = PRVM_G_FLOAT(OFS_PARM3) * 255;
697 attenuation = PRVM_G_FLOAT(OFS_PARM4);
699 if (volume < 0 || volume > 255)
700 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
702 if (attenuation < 0 || attenuation > 4)
703 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
705 if (channel < 0 || channel > 7)
706 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
708 SV_StartSound (entity, channel, sample, volume, attenuation);
720 PF_ERROR("break: break statement\n");
727 Used for use tracing and shot targeting
728 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
729 if the tryents flag is set.
731 traceline (vector1, vector2, tryents)
734 void PF_traceline (void)
741 pr_xfunction->builtinsprofile += 30;
743 v1 = PRVM_G_VECTOR(OFS_PARM0);
744 v2 = PRVM_G_VECTOR(OFS_PARM1);
745 move = PRVM_G_FLOAT(OFS_PARM2);
746 ent = PRVM_G_EDICT(OFS_PARM3);
748 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
750 prog->globals.server->trace_allsolid = trace.allsolid;
751 prog->globals.server->trace_startsolid = trace.startsolid;
752 prog->globals.server->trace_fraction = trace.fraction;
753 prog->globals.server->trace_inwater = trace.inwater;
754 prog->globals.server->trace_inopen = trace.inopen;
755 VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
756 VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
757 prog->globals.server->trace_plane_dist = trace.plane.dist;
759 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
761 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
762 // FIXME: add trace_endcontents
770 Used for use tracing and shot targeting
771 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
772 if the tryents flag is set.
774 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
777 // LordHavoc: added this for my own use, VERY useful, similar to traceline
778 void PF_tracebox (void)
780 float *v1, *v2, *m1, *m2;
785 pr_xfunction->builtinsprofile += 30;
787 v1 = PRVM_G_VECTOR(OFS_PARM0);
788 m1 = PRVM_G_VECTOR(OFS_PARM1);
789 m2 = PRVM_G_VECTOR(OFS_PARM2);
790 v2 = PRVM_G_VECTOR(OFS_PARM3);
791 move = PRVM_G_FLOAT(OFS_PARM4);
792 ent = PRVM_G_EDICT(OFS_PARM5);
794 trace = SV_Move (v1, m1, m2, v2, move, ent);
796 prog->globals.server->trace_allsolid = trace.allsolid;
797 prog->globals.server->trace_startsolid = trace.startsolid;
798 prog->globals.server->trace_fraction = trace.fraction;
799 prog->globals.server->trace_inwater = trace.inwater;
800 prog->globals.server->trace_inopen = trace.inopen;
801 VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
802 VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
803 prog->globals.server->trace_plane_dist = trace.plane.dist;
805 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
807 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
810 extern trace_t SV_Trace_Toss (prvm_edict_t *ent, prvm_edict_t *ignore);
811 void PF_tracetoss (void)
815 prvm_edict_t *ignore;
817 pr_xfunction->builtinsprofile += 600;
819 ent = PRVM_G_EDICT(OFS_PARM0);
820 if (ent == prog->edicts)
821 PF_WARNING("tracetoss: can not use world entity\n");
822 ignore = PRVM_G_EDICT(OFS_PARM1);
824 trace = SV_Trace_Toss (ent, ignore);
826 prog->globals.server->trace_allsolid = trace.allsolid;
827 prog->globals.server->trace_startsolid = trace.startsolid;
828 prog->globals.server->trace_fraction = trace.fraction;
829 prog->globals.server->trace_inwater = trace.inwater;
830 prog->globals.server->trace_inopen = trace.inopen;
831 VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
832 VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
833 prog->globals.server->trace_plane_dist = trace.plane.dist;
835 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
837 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
845 Returns true if the given entity can move to the given position from it's
846 current position by walking or rolling.
848 scalar checkpos (entity, vector)
851 void PF_checkpos (void)
855 //============================================================================
858 qbyte checkpvs[MAX_MAP_LEAFS/8];
860 int PF_newcheckclient (int check)
866 // cycle to the next one
868 check = bound(1, check, svs.maxclients);
869 if (check == svs.maxclients)
877 pr_xfunction->builtinsprofile++;
879 if (i == svs.maxclients+1)
881 // look up the client's edict
882 ent = PRVM_EDICT_NUM(i);
883 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
884 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
886 // found a valid client (possibly the same one again)
890 // get the PVS for the entity
891 VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
893 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
894 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
903 Returns a client (or object that has a client enemy) that would be a
906 If there is more than one valid option, they are cycled each frame
908 If (self.origin + self.viewofs) is not in the PVS of the current target,
909 it is not returned at all.
914 int c_invis, c_notvis;
915 void PF_checkclient (void)
917 prvm_edict_t *ent, *self;
920 // find a new check if on a new frame
921 if (sv.time - sv.lastchecktime >= 0.1)
923 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
924 sv.lastchecktime = sv.time;
927 // return check if it might be visible
928 ent = PRVM_EDICT_NUM(sv.lastcheck);
929 if (ent->priv.server->free || ent->fields.server->health <= 0)
931 RETURN_EDICT(prog->edicts);
935 // if current entity can't possibly see the check entity, return 0
936 self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
937 VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
938 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
941 RETURN_EDICT(prog->edicts);
945 // might be able to see it
950 //============================================================================
957 Sends text over to the client's execution buffer
959 stuffcmd (clientent, value)
962 void PF_stuffcmd (void)
968 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
969 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
971 Con_Print("Can't stuffcmd to a non-client\n");
974 str = PRVM_G_STRING(OFS_PARM1);
977 host_client = svs.clients + entnum-1;
978 Host_ClientCommands ("%s", str);
986 Sends text to server console
991 void PF_localcmd (void)
993 Cbuf_AddText(PRVM_G_STRING(OFS_PARM0));
1005 PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0));
1015 void PF_cvar_set (void)
1017 Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1));
1024 Returns a chain of entities that have origins within a spherical area
1026 findradius (origin, radius)
1029 void PF_findradius (void)
1031 prvm_edict_t *ent, *chain;
1032 vec_t radius, radius2;
1033 vec3_t org, eorg, mins, maxs;
1036 prvm_edict_t *touchedicts[MAX_EDICTS];
1038 chain = (prvm_edict_t *)prog->edicts;
1040 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1041 radius = PRVM_G_FLOAT(OFS_PARM1);
1042 radius2 = radius * radius;
1044 mins[0] = org[0] - (radius + 1);
1045 mins[1] = org[1] - (radius + 1);
1046 mins[2] = org[2] - (radius + 1);
1047 maxs[0] = org[0] + (radius + 1);
1048 maxs[1] = org[1] + (radius + 1);
1049 maxs[2] = org[2] + (radius + 1);
1050 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1051 if (numtouchedicts > MAX_EDICTS)
1053 // this never happens
1054 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1055 numtouchedicts = MAX_EDICTS;
1057 for (i = 0;i < numtouchedicts;i++)
1059 ent = touchedicts[i];
1060 pr_xfunction->builtinsprofile++;
1061 // Quake did not return non-solid entities but darkplaces does
1062 // (note: this is the reason you can't blow up fallen zombies)
1063 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
1065 // LordHavoc: compare against bounding box rather than center so it
1066 // doesn't miss large objects, and use DotProduct instead of Length
1067 // for a major speedup
1068 VectorSubtract(org, ent->fields.server->origin, eorg);
1069 if (sv_gameplayfix_findradiusdistancetobox.integer)
1071 eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
1072 eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
1073 eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
1076 VectorMAMAM(1, eorg, 0.5f, ent->fields.server->mins, 0.5f, ent->fields.server->maxs, eorg);
1077 if (DotProduct(eorg, eorg) < radius2)
1079 ent->fields.server->chain = PRVM_EDICT_TO_PROG(chain);
1084 RETURN_EDICT(chain);
1093 void PF_dprint (void)
1095 char string[STRINGTEMP_LENGTH];
1096 if (developer.integer)
1098 PF_VarString(0, string, sizeof(string));
1107 v = PRVM_G_FLOAT(OFS_PARM0);
1109 s = PR_GetTempString();
1110 if ((float)((int)v) == v)
1111 sprintf(s, "%i", (int)v);
1113 sprintf(s, "%f", v);
1114 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s);
1120 v = PRVM_G_FLOAT(OFS_PARM0);
1121 PRVM_G_FLOAT(OFS_RETURN) = fabs(v);
1127 s = PR_GetTempString();
1128 sprintf (s, "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]);
1129 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s);
1135 s = PR_GetTempString();
1136 sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
1137 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s);
1140 void PF_Spawn (void)
1143 pr_xfunction->builtinsprofile += 20;
1148 void PF_Remove (void)
1151 pr_xfunction->builtinsprofile += 20;
1153 ed = PRVM_G_EDICT(OFS_PARM0);
1154 if (ed == prog->edicts)
1155 PF_WARNING("remove: tried to remove world\n");
1156 if (PRVM_NUM_FOR_EDICT(ed) <= svs.maxclients)
1157 PF_WARNING("remove: tried to remove a client\n");
1158 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1159 if (ed->priv.server->free && developer.integer)
1160 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1165 // entity (entity start, .string field, string match) find = #5;
1173 e = PRVM_G_EDICTNUM(OFS_PARM0);
1174 f = PRVM_G_INT(OFS_PARM1);
1175 s = PRVM_G_STRING(OFS_PARM2);
1178 RETURN_EDICT(prog->edicts);
1182 for (e++ ; e < prog->num_edicts ; e++)
1184 pr_xfunction->builtinsprofile++;
1185 ed = PRVM_EDICT_NUM(e);
1186 if (ed->priv.server->free)
1198 RETURN_EDICT(prog->edicts);
1201 // LordHavoc: added this for searching float, int, and entity reference fields
1202 void PF_FindFloat (void)
1209 e = PRVM_G_EDICTNUM(OFS_PARM0);
1210 f = PRVM_G_INT(OFS_PARM1);
1211 s = PRVM_G_FLOAT(OFS_PARM2);
1213 for (e++ ; e < prog->num_edicts ; e++)
1215 pr_xfunction->builtinsprofile++;
1216 ed = PRVM_EDICT_NUM(e);
1217 if (ed->priv.server->free)
1219 if (E_FLOAT(ed,f) == s)
1226 RETURN_EDICT(prog->edicts);
1229 // chained search for strings in entity fields
1230 // entity(.string field, string match) findchain = #402;
1231 void PF_findchain (void)
1236 prvm_edict_t *ent, *chain;
1238 chain = (prvm_edict_t *)prog->edicts;
1240 f = PRVM_G_INT(OFS_PARM0);
1241 s = PRVM_G_STRING(OFS_PARM1);
1244 RETURN_EDICT(prog->edicts);
1248 ent = PRVM_NEXT_EDICT(prog->edicts);
1249 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1251 pr_xfunction->builtinsprofile++;
1252 if (ent->priv.server->free)
1254 t = E_STRING(ent,f);
1260 ent->fields.server->chain = PRVM_EDICT_TO_PROG(chain);
1264 RETURN_EDICT(chain);
1267 // LordHavoc: chained search for float, int, and entity reference fields
1268 // entity(.string field, float match) findchainfloat = #403;
1269 void PF_findchainfloat (void)
1274 prvm_edict_t *ent, *chain;
1276 chain = (prvm_edict_t *)prog->edicts;
1278 f = PRVM_G_INT(OFS_PARM0);
1279 s = PRVM_G_FLOAT(OFS_PARM1);
1281 ent = PRVM_NEXT_EDICT(prog->edicts);
1282 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1284 pr_xfunction->builtinsprofile++;
1285 if (ent->priv.server->free)
1287 if (E_FLOAT(ent,f) != s)
1290 ent->fields.server->chain = PRVM_EDICT_TO_PROG(chain);
1294 RETURN_EDICT(chain);
1297 // LordHavoc: search for flags in float fields
1298 void PF_findflags (void)
1305 e = PRVM_G_EDICTNUM(OFS_PARM0);
1306 f = PRVM_G_INT(OFS_PARM1);
1307 s = (int)PRVM_G_FLOAT(OFS_PARM2);
1309 for (e++ ; e < prog->num_edicts ; e++)
1311 pr_xfunction->builtinsprofile++;
1312 ed = PRVM_EDICT_NUM(e);
1313 if (ed->priv.server->free)
1315 if ((int)E_FLOAT(ed,f) & s)
1322 RETURN_EDICT(prog->edicts);
1325 // LordHavoc: chained search for flags in float fields
1326 void PF_findchainflags (void)
1331 prvm_edict_t *ent, *chain;
1333 chain = (prvm_edict_t *)prog->edicts;
1335 f = PRVM_G_INT(OFS_PARM0);
1336 s = (int)PRVM_G_FLOAT(OFS_PARM1);
1338 ent = PRVM_NEXT_EDICT(prog->edicts);
1339 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1341 pr_xfunction->builtinsprofile++;
1342 if (ent->priv.server->free)
1344 if (!((int)E_FLOAT(ent,f) & s))
1347 ent->fields.server->chain = PRVM_EDICT_TO_PROG(chain);
1351 RETURN_EDICT(chain);
1354 void PF_precache_file (void)
1355 { // precache_file is only used to copy files with qcc, it does nothing
1356 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1360 void PF_precache_sound (void)
1362 SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
1363 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1366 void PF_precache_model (void)
1368 SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
1369 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1373 void PF_coredump (void)
1378 void PF_traceon (void)
1383 void PF_traceoff (void)
1388 void PF_eprint (void)
1390 ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0));
1397 float(float yaw, float dist) walkmove
1400 void PF_walkmove (void)
1408 // assume failure if it returns early
1409 PRVM_G_FLOAT(OFS_RETURN) = 0;
1411 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1412 if (ent == prog->edicts)
1413 PF_WARNING("walkmove: can not modify world entity\n");
1414 if (ent->priv.server->free)
1415 PF_WARNING("walkmove: can not modify free entity\n");
1416 yaw = PRVM_G_FLOAT(OFS_PARM0);
1417 dist = PRVM_G_FLOAT(OFS_PARM1);
1419 if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1422 yaw = yaw*M_PI*2 / 360;
1424 move[0] = cos(yaw)*dist;
1425 move[1] = sin(yaw)*dist;
1428 // save program state, because SV_movestep may call other progs
1429 oldf = pr_xfunction;
1430 oldself = prog->globals.server->self;
1432 PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1435 // restore program state
1436 pr_xfunction = oldf;
1437 prog->globals.server->self = oldself;
1447 void PF_droptofloor (void)
1453 // assume failure if it returns early
1454 PRVM_G_FLOAT(OFS_RETURN) = 0;
1456 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1457 if (ent == prog->edicts)
1458 PF_WARNING("droptofloor: can not modify world entity\n");
1459 if (ent->priv.server->free)
1460 PF_WARNING("droptofloor: can not modify free entity\n");
1462 VectorCopy (ent->fields.server->origin, end);
1465 trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent);
1467 if (trace.fraction != 1)
1469 VectorCopy (trace.endpos, ent->fields.server->origin);
1470 SV_LinkEdict (ent, false);
1471 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
1472 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
1473 PRVM_G_FLOAT(OFS_RETURN) = 1;
1474 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1475 ent->priv.server->suspendedinairflag = true;
1483 void(float style, string value) lightstyle
1486 void PF_lightstyle (void)
1493 style = PRVM_G_FLOAT(OFS_PARM0);
1494 val = PRVM_G_STRING(OFS_PARM1);
1496 // change the string in sv
1497 strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
1499 // send message to all clients on this server
1500 if (sv.state != ss_active)
1503 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1507 MSG_WriteChar (&client->message, svc_lightstyle);
1508 MSG_WriteChar (&client->message,style);
1509 MSG_WriteString (&client->message, val);
1517 f = PRVM_G_FLOAT(OFS_PARM0);
1519 PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1521 PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1523 void PF_floor (void)
1525 PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
1529 PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
1538 void PF_checkbottom (void)
1540 PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1548 void PF_pointcontents (void)
1550 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
1557 entity nextent(entity)
1560 void PF_nextent (void)
1565 i = PRVM_G_EDICTNUM(OFS_PARM0);
1568 pr_xfunction->builtinsprofile++;
1570 if (i == prog->num_edicts)
1572 RETURN_EDICT(prog->edicts);
1575 ent = PRVM_EDICT_NUM(i);
1576 if (!ent->priv.server->free)
1588 Pick a vector for the player to shoot along
1589 vector aim(entity, missilespeed)
1594 prvm_edict_t *ent, *check, *bestent;
1595 vec3_t start, dir, end, bestdir;
1598 float dist, bestdist;
1601 // assume failure if it returns early
1602 VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1603 // if sv_aim is so high it can't possibly accept anything, skip out early
1604 if (sv_aim.value >= 1)
1607 ent = PRVM_G_EDICT(OFS_PARM0);
1608 if (ent == prog->edicts)
1609 PF_WARNING("aim: can not use world entity\n");
1610 if (ent->priv.server->free)
1611 PF_WARNING("aim: can not use free entity\n");
1612 speed = PRVM_G_FLOAT(OFS_PARM1);
1614 VectorCopy (ent->fields.server->origin, start);
1617 // try sending a trace straight
1618 VectorCopy (prog->globals.server->v_forward, dir);
1619 VectorMA (start, 2048, dir, end);
1620 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1621 if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
1622 && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
1624 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1629 // try all possible entities
1630 VectorCopy (dir, bestdir);
1631 bestdist = sv_aim.value;
1634 check = PRVM_NEXT_EDICT(prog->edicts);
1635 for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1637 pr_xfunction->builtinsprofile++;
1638 if (check->fields.server->takedamage != DAMAGE_AIM)
1642 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
1643 continue; // don't aim at teammate
1644 for (j=0 ; j<3 ; j++)
1645 end[j] = check->fields.server->origin[j]
1646 + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
1647 VectorSubtract (end, start, dir);
1648 VectorNormalize (dir);
1649 dist = DotProduct (dir, prog->globals.server->v_forward);
1650 if (dist < bestdist)
1651 continue; // to far to turn
1652 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1653 if (tr.ent == check)
1654 { // can shoot at this one
1662 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
1663 dist = DotProduct (dir, prog->globals.server->v_forward);
1664 VectorScale (prog->globals.server->v_forward, dist, end);
1666 VectorNormalize (end);
1667 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1671 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1679 This was a major timewaster in progs, so it was converted to C
1682 void PF_changeyaw (void)
1685 float ideal, current, move, speed;
1687 ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1688 if (ent == prog->edicts)
1689 PF_WARNING("changeyaw: can not modify world entity\n");
1690 if (ent->priv.server->free)
1691 PF_WARNING("changeyaw: can not modify free entity\n");
1692 current = ANGLEMOD(ent->fields.server->angles[1]);
1693 ideal = ent->fields.server->ideal_yaw;
1694 speed = ent->fields.server->yaw_speed;
1696 if (current == ideal)
1698 move = ideal - current;
1699 if (ideal > current)
1720 ent->fields.server->angles[1] = ANGLEMOD (current + move);
1728 void PF_changepitch (void)
1731 float ideal, current, move, speed;
1734 ent = PRVM_G_EDICT(OFS_PARM0);
1735 if (ent == prog->edicts)
1736 PF_WARNING("changepitch: can not modify world entity\n");
1737 if (ent->priv.server->free)
1738 PF_WARNING("changepitch: can not modify free entity\n");
1739 current = ANGLEMOD( ent->fields.server->angles[0] );
1740 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1741 ideal = val->_float;
1744 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1747 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1748 speed = val->_float;
1751 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1755 if (current == ideal)
1757 move = ideal - current;
1758 if (ideal > current)
1779 ent->fields.server->angles[0] = ANGLEMOD (current + move);
1783 ===============================================================================
1787 ===============================================================================
1790 #define MSG_BROADCAST 0 // unreliable to all
1791 #define MSG_ONE 1 // reliable to one (msg_entity)
1792 #define MSG_ALL 2 // reliable to all
1793 #define MSG_INIT 3 // write to the init string
1795 sizebuf_t *WriteDest (void)
1801 dest = PRVM_G_FLOAT(OFS_PARM0);
1805 return &sv.datagram;
1808 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1809 entnum = PRVM_NUM_FOR_EDICT(ent);
1810 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1811 Host_Error("WriteDest: tried to write to non-client\n");
1812 return &svs.clients[entnum-1].message;
1815 return &sv.reliable_datagram;
1821 Host_Error("WriteDest: bad destination");
1828 void PF_WriteByte (void)
1830 MSG_WriteByte (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1833 void PF_WriteChar (void)
1835 MSG_WriteChar (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1838 void PF_WriteShort (void)
1840 MSG_WriteShort (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1843 void PF_WriteLong (void)
1845 MSG_WriteLong (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1848 void PF_WriteAngle (void)
1850 MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1853 void PF_WriteCoord (void)
1855 MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1858 void PF_WriteString (void)
1860 MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1864 void PF_WriteEntity (void)
1866 MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1869 //=============================================================================
1871 void PF_makestatic (void)
1876 ent = PRVM_G_EDICT(OFS_PARM0);
1877 if (ent == prog->edicts)
1878 PF_WARNING("makestatic: can not modify world entity\n");
1879 if (ent->priv.server->free)
1880 PF_WARNING("makestatic: can not modify free entity\n");
1883 if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1888 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1889 MSG_WriteShort (&sv.signon, ent->fields.server->modelindex);
1890 MSG_WriteShort (&sv.signon, ent->fields.server->frame);
1894 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1895 MSG_WriteByte (&sv.signon, ent->fields.server->modelindex);
1896 MSG_WriteByte (&sv.signon, ent->fields.server->frame);
1899 MSG_WriteByte (&sv.signon, ent->fields.server->colormap);
1900 MSG_WriteByte (&sv.signon, ent->fields.server->skin);
1901 for (i=0 ; i<3 ; i++)
1903 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1904 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1907 // throw the entity away now
1911 //=============================================================================
1918 void PF_setspawnparms (void)
1924 ent = PRVM_G_EDICT(OFS_PARM0);
1925 i = PRVM_NUM_FOR_EDICT(ent);
1926 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1928 Con_Print("tried to setspawnparms on a non-client\n");
1932 // copy spawn parms out of the client_t
1933 client = svs.clients + i-1;
1934 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1935 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1943 void PF_changelevel (void)
1947 // make sure we don't issue two changelevels
1948 if (svs.changelevel_issued)
1950 svs.changelevel_issued = true;
1952 s = PRVM_G_STRING(OFS_PARM0);
1953 Cbuf_AddText (va("changelevel %s\n",s));
1958 PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
1963 PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
1968 PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
1975 Returns a vector of length < 1
1980 void PF_randomvec (void)
1985 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1986 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1987 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1989 while (DotProduct(temp, temp) >= 1);
1990 VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
1997 Returns a color vector indicating the lighting at the requested point.
1999 (Internal Operation note: actually measures the light beneath the point, just like
2000 the model lighting on the client)
2005 void PF_GetLight (void)
2007 vec3_t ambientcolor, diffusecolor, diffusenormal;
2009 p = PRVM_G_VECTOR(OFS_PARM0);
2010 VectorClear(ambientcolor);
2011 VectorClear(diffusecolor);
2012 VectorClear(diffusenormal);
2013 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2014 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2015 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
2018 void PF_registercvar (void)
2020 const char *name, *value;
2021 name = PRVM_G_STRING(OFS_PARM0);
2022 value = PRVM_G_STRING(OFS_PARM1);
2023 PRVM_G_FLOAT(OFS_RETURN) = 0;
2025 // first check to see if it has already been defined
2026 if (Cvar_FindVar (name))
2029 // check for overlap with a command
2030 if (Cmd_Exists (name))
2032 Con_Printf("PF_registercvar: %s is a command\n", name);
2036 Cvar_Get(name, value, 0);
2038 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
2045 returns the minimum of two supplied floats
2052 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2054 PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
2055 else if (pr_argc >= 3)
2058 float f = PRVM_G_FLOAT(OFS_PARM0);
2059 for (i = 1;i < pr_argc;i++)
2060 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f)
2061 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
2062 PRVM_G_FLOAT(OFS_RETURN) = f;
2066 PRVM_G_FLOAT(OFS_RETURN) = 0;
2067 PF_WARNING("min: must supply at least 2 floats\n");
2075 returns the maximum of two supplied floats
2082 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2084 PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
2085 else if (pr_argc >= 3)
2088 float f = PRVM_G_FLOAT(OFS_PARM0);
2089 for (i = 1;i < pr_argc;i++)
2090 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f)
2091 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
2092 PRVM_G_FLOAT(OFS_RETURN) = f;
2096 PRVM_G_FLOAT(OFS_RETURN) = 0;
2097 PF_WARNING("max: must supply at least 2 floats\n");
2105 returns number bounded by supplied range
2107 min(min, value, max)
2110 void PF_bound (void)
2112 PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
2119 returns a raised to power b
2126 PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
2133 copies data from one entity to another
2135 copyentity(src, dst)
2138 void PF_copyentity (void)
2140 prvm_edict_t *in, *out;
2141 in = PRVM_G_EDICT(OFS_PARM0);
2142 if (in == prog->edicts)
2143 PF_WARNING("copyentity: can not read world entity\n");
2144 if (in->priv.server->free)
2145 PF_WARNING("copyentity: can not read free entity\n");
2146 out = PRVM_G_EDICT(OFS_PARM1);
2147 if (out == prog->edicts)
2148 PF_WARNING("copyentity: can not modify world entity\n");
2149 if (out->priv.server->free)
2150 PF_WARNING("copyentity: can not modify free entity\n");
2151 memcpy(out->v, in->v, progs->entityfields * 4);
2158 sets the color of a client and broadcasts the update to all connected clients
2160 setcolor(clientent, value)
2163 void PF_setcolor (void)
2169 entnum = PRVM_G_EDICTNUM(OFS_PARM0);
2170 i = PRVM_G_FLOAT(OFS_PARM1);
2172 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2174 Con_Print("tried to setcolor a non-client\n");
2178 client = svs.clients + entnum-1;
2181 if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2183 client->edict->fields.server->team = (i & 15) + 1;
2186 if (client->old_colors != client->colors)
2188 client->old_colors = client->colors;
2189 // send notification to all clients
2190 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2191 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2192 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2200 effect(origin, modelname, startframe, framecount, framerate)
2203 void PF_effect (void)
2207 s = PRVM_G_STRING(OFS_PARM1);
2209 PF_WARNING("effect: no model specified\n");
2211 i = SV_ModelIndex(s, 1);
2213 PF_WARNING("effect: model not precached\n");
2214 SV_StartEffect(PRVM_G_VECTOR(OFS_PARM0), i, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
2217 void PF_te_blood (void)
2219 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
2221 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2222 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2224 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2225 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2226 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2228 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
2229 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
2230 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
2232 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
2235 void PF_te_bloodshower (void)
2237 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2239 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2240 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2242 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2243 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2244 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2246 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2247 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2248 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2250 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
2252 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2255 void PF_te_explosionrgb (void)
2257 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2258 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2260 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2261 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2262 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2264 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
2265 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
2266 MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
2269 void PF_te_particlecube (void)
2271 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2273 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2274 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2276 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2277 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2278 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2280 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2281 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2282 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2284 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2285 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2286 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2288 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2290 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
2291 // gravity true/false
2292 MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
2294 MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
2297 void PF_te_particlerain (void)
2299 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2301 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2302 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2304 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2305 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2306 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2308 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2309 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2310 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2312 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2313 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2314 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2316 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2318 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
2321 void PF_te_particlesnow (void)
2323 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2325 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2326 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2328 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2330 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2332 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2333 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2334 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2336 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2337 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2338 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2340 MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
2342 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
2345 void PF_te_spark (void)
2347 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
2349 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2350 MSG_WriteByte(&sv.datagram, TE_SPARK);
2352 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2353 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2354 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2356 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
2357 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
2358 MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
2360 MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
2363 void PF_te_gunshotquad (void)
2365 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2366 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2368 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2369 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2370 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2373 void PF_te_spikequad (void)
2375 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2376 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2378 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2379 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2380 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2383 void PF_te_superspikequad (void)
2385 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2386 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2388 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2389 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2390 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2393 void PF_te_explosionquad (void)
2395 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2396 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2398 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2399 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2400 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2403 void PF_te_smallflash (void)
2405 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2406 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2408 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2409 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2410 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2413 void PF_te_customflash (void)
2415 if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2417 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2418 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2420 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2421 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2422 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2424 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2426 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
2428 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
2429 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
2430 MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
2433 void PF_te_gunshot (void)
2435 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2436 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2438 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2439 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2440 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2443 void PF_te_spike (void)
2445 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2446 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2448 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2449 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2450 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2453 void PF_te_superspike (void)
2455 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2456 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2458 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2459 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2460 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2463 void PF_te_explosion (void)
2465 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2466 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2468 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2469 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2470 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2473 void PF_te_tarexplosion (void)
2475 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2476 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2478 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2479 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2480 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2483 void PF_te_wizspike (void)
2485 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2486 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2488 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2489 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2490 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2493 void PF_te_knightspike (void)
2495 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2496 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2498 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2499 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2500 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2503 void PF_te_lavasplash (void)
2505 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2506 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2508 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2509 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2510 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2513 void PF_te_teleport (void)
2515 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2516 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2518 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2519 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2520 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2523 void PF_te_explosion2 (void)
2525 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2526 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2528 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2529 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2530 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2532 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM1));
2533 MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2));
2536 void PF_te_lightning1 (void)
2538 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2539 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2541 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2543 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2544 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2545 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2547 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2548 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2549 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2552 void PF_te_lightning2 (void)
2554 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2555 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2557 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2559 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2560 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2561 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2563 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2564 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2565 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2568 void PF_te_lightning3 (void)
2570 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2571 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2573 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2575 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2576 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2577 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2579 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2580 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2581 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2584 void PF_te_beam (void)
2586 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2587 MSG_WriteByte(&sv.datagram, TE_BEAM);
2589 MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2591 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2592 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2593 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2595 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2596 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2597 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2600 void PF_te_plasmaburn (void)
2602 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2603 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2604 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2605 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2606 MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2609 static void clippointtosurface(msurface_t *surface, vec3_t p, vec3_t out)
2612 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2614 bestdist = 1000000000;
2616 for (i = 0, e = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2618 // clip original point to each triangle of the surface and find the
2619 // triangle that is closest
2620 v[0] = surface->groupmesh->data_vertex3f + e[0] * 3;
2621 v[1] = surface->groupmesh->data_vertex3f + e[1] * 3;
2622 v[2] = surface->groupmesh->data_vertex3f + e[2] * 3;
2623 TriangleNormal(v[0], v[1], v[2], facenormal);
2624 VectorNormalize(facenormal);
2625 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2626 VectorMA(p, offsetdist, facenormal, temp);
2627 for (j = 0, k = 2;j < 3;k = j, j++)
2629 VectorSubtract(v[k], v[j], edgenormal);
2630 CrossProduct(edgenormal, facenormal, sidenormal);
2631 VectorNormalize(sidenormal);
2632 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2634 VectorMA(temp, offsetdist, sidenormal, temp);
2636 dist = VectorDistance2(temp, p);
2637 if (bestdist > dist)
2640 VectorCopy(temp, out);
2645 static msurface_t *getsurface(prvm_edict_t *ed, int surfacenum)
2649 if (!ed || ed->priv.server->free)
2651 modelindex = ed->fields.server->modelindex;
2652 if (modelindex < 1 || modelindex >= MAX_MODELS)
2654 model = sv.models[modelindex];
2655 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2657 return model->data_surfaces + surfacenum + model->firstmodelsurface;
2661 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2662 void PF_getsurfacenumpoints(void)
2664 msurface_t *surface;
2665 // return 0 if no such surface
2666 if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
2668 PRVM_G_FLOAT(OFS_RETURN) = 0;
2672 // note: this (incorrectly) assumes it is a simple polygon
2673 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2675 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2676 void PF_getsurfacepoint(void)
2679 msurface_t *surface;
2681 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2682 ed = PRVM_G_EDICT(OFS_PARM0);
2683 if (!ed || ed->priv.server->free)
2685 if (!(surface = getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
2687 // note: this (incorrectly) assumes it is a simple polygon
2688 pointnum = PRVM_G_FLOAT(OFS_PARM2);
2689 if (pointnum < 0 || pointnum >= surface->num_vertices)
2691 // FIXME: implement rotation/scaling
2692 VectorAdd(&(surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2694 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2695 void PF_getsurfacenormal(void)
2697 msurface_t *surface;
2699 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2700 if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
2702 // FIXME: implement rotation/scaling
2703 // note: this (incorrectly) assumes it is a simple polygon
2704 // note: this only returns the first triangle, so it doesn't work very
2705 // well for curved surfaces or arbitrary meshes
2706 TriangleNormal((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + 3, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
2707 VectorNormalize(normal);
2708 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2710 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2711 void PF_getsurfacetexture(void)
2713 msurface_t *surface;
2714 PRVM_G_INT(OFS_RETURN) = 0;
2715 if (!(surface = getsurface(PRVM_G_EDICT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1))))
2717 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
2719 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2720 void PF_getsurfacenearpoint(void)
2722 int surfacenum, best, modelindex;
2724 vec_t dist, bestdist;
2727 msurface_t *surface;
2729 PRVM_G_FLOAT(OFS_RETURN) = -1;
2730 ed = PRVM_G_EDICT(OFS_PARM0);
2731 point = PRVM_G_VECTOR(OFS_PARM1);
2733 if (!ed || ed->priv.server->free)
2735 modelindex = ed->fields.server->modelindex;
2736 if (modelindex < 1 || modelindex >= MAX_MODELS)
2738 model = sv.models[modelindex];
2739 if (!model->num_surfaces)
2742 // FIXME: implement rotation/scaling
2743 VectorSubtract(point, ed->fields.server->origin, p);
2745 bestdist = 1000000000;
2746 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2748 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2749 // first see if the nearest point on the surface's box is closer than the previous match
2750 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2751 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2752 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2753 dist = VectorLength2(clipped);
2754 if (dist < bestdist)
2756 // it is, check the nearest point on the actual geometry
2757 clippointtosurface(surface, p, clipped);
2758 VectorSubtract(clipped, p, clipped);
2759 dist += VectorLength2(clipped);
2760 if (dist < bestdist)
2762 // that's closer too, store it as the best match
2768 PRVM_G_FLOAT(OFS_RETURN) = best;
2770 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2771 void PF_getsurfaceclippedpoint(void)
2774 msurface_t *surface;
2776 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2777 ed = PRVM_G_EDICT(OFS_PARM0);
2778 if (!ed || ed->priv.server->free)
2780 if (!(surface = getsurface(ed, PRVM_G_FLOAT(OFS_PARM1))))
2782 // FIXME: implement rotation/scaling
2783 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2784 clippointtosurface(surface, p, out);
2785 // FIXME: implement rotation/scaling
2786 VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2789 #define MAX_PRFILES 256
2791 qfile_t *pr_files[MAX_PRFILES];
2793 void PR_Files_Init(void)
2795 memset(pr_files, 0, sizeof(pr_files));
2798 void PR_Files_CloseAll(void)
2801 for (i = 0;i < MAX_PRFILES;i++)
2804 FS_Close(pr_files[i]);
2809 //float(string s) stof = #81; // get numerical value from a string
2812 char string[STRINGTEMP_LENGTH];
2813 PF_VarString(0, string, sizeof(string));
2814 PRVM_G_FLOAT(OFS_RETURN) = atof(string);
2817 //float(string filename, float mode) fopen = #110; // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
2821 const char *modestring, *filename;
2822 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2823 if (pr_files[filenum] == NULL)
2825 if (filenum >= MAX_PRFILES)
2827 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2828 PRVM_G_FLOAT(OFS_RETURN) = -2;
2831 mode = PRVM_G_FLOAT(OFS_PARM1);
2834 case 0: // FILE_READ
2837 case 1: // FILE_APPEND
2840 case 2: // FILE_WRITE
2844 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2845 PRVM_G_FLOAT(OFS_RETURN) = -3;
2848 filename = PRVM_G_STRING(OFS_PARM0);
2849 // -4 failure (dangerous/non-portable filename) removed, FS_Open checks
2850 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false, false);
2852 if (pr_files[filenum] == NULL && modestring == "rb")
2853 pr_files[filenum] = FS_Open(filename, modestring, false, false);
2855 if (pr_files[filenum] == NULL)
2856 PRVM_G_FLOAT(OFS_RETURN) = -1;
2858 PRVM_G_FLOAT(OFS_RETURN) = filenum;
2861 //void(float fhandle) fclose = #111; // closes a file
2862 void PF_fclose(void)
2864 int filenum = PRVM_G_FLOAT(OFS_PARM0);
2865 if (filenum < 0 || filenum >= MAX_PRFILES)
2867 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2870 if (pr_files[filenum] == NULL)
2872 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2875 FS_Close(pr_files[filenum]);
2876 pr_files[filenum] = NULL;
2879 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2883 static char string[STRINGTEMP_LENGTH];
2884 int filenum = PRVM_G_FLOAT(OFS_PARM0);
2885 if (filenum < 0 || filenum >= MAX_PRFILES)
2887 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2890 if (pr_files[filenum] == NULL)
2892 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2898 c = FS_Getc(pr_files[filenum]);
2899 if (c == '\r' || c == '\n' || c < 0)
2901 if (end < STRINGTEMP_LENGTH - 1)
2905 // remove \n following \r
2908 c = FS_Getc(pr_files[filenum]);
2910 FS_UnGetc(pr_files[filenum], (unsigned char)c);
2912 if (developer.integer)
2913 Con_Printf("fgets: %s\n", string);
2915 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(string);
2917 PRVM_G_INT(OFS_RETURN) = 0;
2920 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2924 char string[STRINGTEMP_LENGTH];
2925 int filenum = PRVM_G_FLOAT(OFS_PARM0);
2926 if (filenum < 0 || filenum >= MAX_PRFILES)
2928 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2931 if (pr_files[filenum] == NULL)
2933 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2936 PF_VarString(1, string, sizeof(string));
2937 if ((stringlength = strlen(string)))
2938 FS_Write(pr_files[filenum], string, stringlength);
2939 if (developer.integer)
2940 Con_Printf("fputs: %s\n", string);
2943 //float(string s) strlen = #114; // returns how many characters are in a string
2944 void PF_strlen(void)
2947 s = PRVM_G_STRING(OFS_PARM0);
2949 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
2951 PRVM_G_FLOAT(OFS_RETURN) = 0;
2954 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2955 void PF_strcat(void)
2957 char *s = PR_GetTempString();
2958 PF_VarString(0, s, STRINGTEMP_LENGTH);
2959 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s);
2962 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2963 void PF_substring(void)
2965 int i, start, length;
2967 char *string = PR_GetTempString();
2968 s = PRVM_G_STRING(OFS_PARM0);
2969 start = PRVM_G_FLOAT(OFS_PARM1);
2970 length = PRVM_G_FLOAT(OFS_PARM2);
2973 for (i = 0;i < start && *s;i++, s++);
2974 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
2977 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(string);
2980 //vector(string s) stov = #117; // returns vector value from a string
2983 char string[STRINGTEMP_LENGTH];
2984 PF_VarString(0, string, sizeof(string));
2985 Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
2988 //string(string s) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often)
2989 void PF_strzone(void)
2993 in = PRVM_G_STRING(OFS_PARM0);
2994 out = PR_AllocString(strlen(in) + 1);
2996 PRVM_G_INT(OFS_RETURN) = PR_SetQCString(out);
2999 //void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!)
3000 void PF_strunzone(void)
3002 PR_FreeString((char *)PRVM_G_STRING(OFS_PARM0));
3005 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3006 //this function originally written by KrimZon, made shorter by LordHavoc
3007 void PF_clientcommand (void)
3009 client_t *temp_client;
3012 //find client for this entity
3013 i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
3014 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3016 Con_Print("PF_clientcommand: entity is not a client\n");
3020 temp_client = host_client;
3021 host_client = svs.clients + i;
3022 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
3023 host_client = temp_client;
3026 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3027 //this function originally written by KrimZon, made shorter by LordHavoc
3028 //20040203: rewritten by LordHavoc (no longer uses allocations)
3030 char *tokens[256], tokenbuf[4096];
3031 void PF_tokenize (void)
3035 p = PRVM_G_STRING(OFS_PARM0);
3039 while(COM_ParseToken(&p, false))
3041 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3043 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3045 tokens[num_tokens++] = tokenbuf + pos;
3046 strcpy(tokenbuf + pos, com_token);
3047 pos += strlen(com_token) + 1;
3050 PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
3053 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3054 //this function originally written by KrimZon, made shorter by LordHavoc
3057 int token_num = PRVM_G_FLOAT(OFS_PARM0);
3058 if (token_num >= 0 && token_num < num_tokens)
3059 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tokens[token_num]);
3061 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(NULL);
3064 //void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
3065 void PF_setattachment (void)
3067 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
3068 prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
3069 const char *tagname = PRVM_G_STRING(OFS_PARM2);
3074 if (e == prog->edicts)
3075 PF_WARNING("setattachment: can not modify world entity\n");
3076 if (e->priv.server->free)
3077 PF_WARNING("setattachment: can not modify free entity\n");
3079 if (tagentity == NULL)
3080 tagentity = prog->edicts;
3082 v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity);
3084 fields.server->edict = PRVM_EDICT_TO_PROG(tagentity);
3086 v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index);
3088 fields.server->_float = 0;
3089 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
3091 modelindex = (int)tagentity->fields.server->modelindex;
3092 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3094 fields.server->_float = Mod_Alias_GetTagIndexForName(model, tagentity->fields.server->skin, tagname);
3095 if (fields.server->_float == 0)
3096 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name);
3099 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity));
3103 /////////////////////////////////////////
3104 // DP_MD3_TAGINFO extension coded by VorteX
3106 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
3111 i = e->fields.server->modelindex;
3112 if (i < 1 || i >= MAX_MODELS)
3114 model = sv.models[i];
3116 return Mod_Alias_GetTagIndexForName(model, e->fields.server->skin, tagname);
3119 // Warnings/errors code:
3120 // 0 - normal (everything all-right)
3123 // 3 - null or non-precached model
3124 // 4 - no tags with requested index
3125 // 5 - runaway loop at attachment chain
3126 extern cvar_t cl_bob;
3127 extern cvar_t cl_bobcycle;
3128 extern cvar_t cl_bobup;
3129 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
3132 int modelindex, reqframe, attachloop;
3133 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3134 prvm_edict_t *attachent;
3137 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3139 if (ent == prog->edicts)
3141 if (ent->priv.server->free)
3144 modelindex = (int)ent->fields.server->modelindex;
3145 if (modelindex <= 0 || modelindex > MAX_MODELS)
3148 model = sv.models[modelindex];
3150 if (ent->fields.server->frame >= 0 && ent->fields.server->frame < model->numframes && model->animscenes)
3151 reqframe = model->animscenes[(int)ent->fields.server->frame].firstframe;
3153 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3155 // get initial tag matrix
3158 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
3163 Matrix4x4_CreateIdentity(&tagmatrix);
3165 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3166 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3170 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
3171 val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index);
3172 if (val->_float >= 1 && attachent->fields.server->modelindex >= 1 && attachent->fields.server->modelindex < MAX_MODELS && (model = sv.models[(int)attachent->fields.server->modelindex]) && model->animscenes && attachent->fields.server->frame >= 0 && attachent->fields.server->frame < model->numframes)
3173 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.server->frame].firstframe, val->_float - 1, &attachmatrix);
3175 Matrix4x4_CreateIdentity(&attachmatrix);
3177 // apply transformation by child entity matrix
3178 val = PRVM_GETEDICTFIELDVALUE(ent, eval_scale);
3179 if (val->_float == 0)
3181 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], -ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], val->_float);
3182 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3183 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3184 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3185 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3186 Matrix4x4_Copy(&tagmatrix, out);
3188 // finally transformate by matrix of tag on parent entity
3189 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3190 out->m[0][3] = attachmatrix.m[0][3] + attachmatrix.m[0][0]*tagmatrix.m[0][3] + attachmatrix.m[0][1]*tagmatrix.m[1][3] + attachmatrix.m[0][2]*tagmatrix.m[2][3];
3191 out->m[1][3] = attachmatrix.m[1][3] + attachmatrix.m[1][0]*tagmatrix.m[0][3] + attachmatrix.m[1][1]*tagmatrix.m[1][3] + attachmatrix.m[1][2]*tagmatrix.m[2][3];
3192 out->m[2][3] = attachmatrix.m[2][3] + attachmatrix.m[2][0]*tagmatrix.m[0][3] + attachmatrix.m[2][1]*tagmatrix.m[1][3] + attachmatrix.m[2][2]*tagmatrix.m[2][3];
3193 Matrix4x4_Copy(&tagmatrix, out);
3197 if (attachloop > 255) // prevent runaway looping
3200 while ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3203 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3204 val = PRVM_GETEDICTFIELDVALUE(ent, eval_scale);
3205 if (val->_float == 0)
3207 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3208 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], -ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], val->_float);
3209 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3210 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3211 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3212 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3214 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3215 {// RENDER_VIEWMODEL magic
3216 Matrix4x4_Copy(&tagmatrix, out);
3217 ent = PRVM_EDICT_NUM(val->edict);
3219 val = PRVM_GETEDICTFIELDVALUE(ent, eval_scale);
3220 if (val->_float == 0)
3223 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2] + ent->fields.server->view_ofs[2], ent->fields.server->v_angle[0], ent->fields.server->v_angle[1], ent->fields.server->v_angle[2], val->_float);
3224 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3225 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3226 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3227 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3230 // Cl_bob, ported from rendering code
3231 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
3234 // LordHavoc: this code is *weird*, but not replacable (I think it
3235 // should be done in QC on the server, but oh well, quake is quake)
3236 // LordHavoc: figured out bobup: the time at which the sin is at 180
3237 // degrees (which allows lengthening or squishing the peak or valley)
3238 cycle = sv.time/cl_bobcycle.value;
3239 cycle -= (int)cycle;
3240 if (cycle < cl_bobup.value)
3241 cycle = sin(M_PI * cycle / cl_bobup.value);
3243 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3244 // bob is proportional to velocity in the xy plane
3245 // (don't count Z, or jumping messes it up)
3246 bob = sqrt(ent->fields.server->velocity[0]*ent->fields.server->velocity[0] + ent->fields.server->velocity[1]*ent->fields.server->velocity[1])*cl_bob.value;
3247 bob = bob*0.3 + bob*0.7*cycle;
3248 out->m[2][3] += bound(-7, bob, 4);
3255 //float(entity ent, string tagname) gettagindex;
3257 void PF_gettagindex (void)
3259 prvm_edict_t *ent = PRVM_G_EDICT(OFS_PARM0);
3260 const char *tag_name = PRVM_G_STRING(OFS_PARM1);
3261 int modelindex, tag_index;
3263 if (ent == prog->edicts)
3264 PF_WARNING("gettagindex: can't affect world entity\n");
3265 if (ent->priv.server->free)
3266 PF_WARNING("gettagindex: can't affect free entity\n");
3268 modelindex = (int)ent->fields.server->modelindex;
3270 if (modelindex <= 0 || modelindex > MAX_MODELS)
3271 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
3274 tag_index = SV_GetTagIndex(ent, tag_name);
3276 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
3278 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
3281 //vector(entity ent, float tagindex) gettaginfo;
3282 void PF_gettaginfo (void)
3284 prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
3285 int tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
3286 matrix4x4_t tag_matrix;
3289 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3290 Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
3295 PF_WARNING("gettagindex: can't affect world entity\n");
3298 PF_WARNING("gettagindex: can't affect free entity\n");
3301 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
3304 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
3307 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
3313 /////////////////////////////////////////
3314 // DP_QC_FS_SEARCH extension
3316 // qc fs search handling
3317 #define MAX_SEARCHES 128
3319 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3321 void PR_Search_Init(void)
3323 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3326 void PR_Search_Reset(void)
3329 // reset the fssearch list
3330 for(i = 0; i < MAX_SEARCHES; i++)
3331 if(pr_fssearchlist[i])
3332 FS_FreeSearch(pr_fssearchlist[i]);
3333 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3340 float search_begin(string pattern, float caseinsensitive, float quiet)
3343 void PF_search_begin(void)
3346 const char *pattern;
3347 int caseinsens, quiet;
3349 pattern = PRVM_G_STRING(OFS_PARM0);
3350 if (!pattern || pattern[0] <= ' ')
3351 PF_ERROR("PF_search_begin: Bad string");
3353 caseinsens = PRVM_G_FLOAT(OFS_PARM1);
3354 quiet = PRVM_G_FLOAT(OFS_PARM2);
3356 for(handle = 0; handle < MAX_SEARCHES; handle++)
3357 if(!pr_fssearchlist[handle])
3360 if(handle >= MAX_SEARCHES)
3362 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3363 PRVM_G_FLOAT(OFS_RETURN) = -2;
3367 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3368 PRVM_G_FLOAT(OFS_RETURN) = -1;
3370 PRVM_G_FLOAT(OFS_RETURN) = handle;
3377 void search_end(float handle)
3380 void PF_search_end(void)
3384 handle = PRVM_G_FLOAT(OFS_PARM0);
3386 if(handle < 0 || handle >= MAX_SEARCHES)
3388 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3391 if(pr_fssearchlist[handle] == NULL)
3393 Con_Printf("PF_search_end: no such handle %i\n", handle);
3397 FS_FreeSearch(pr_fssearchlist[handle]);
3398 pr_fssearchlist[handle] = NULL;
3405 float search_getsize(float handle)
3408 void PF_search_getsize(void)
3412 handle = PRVM_G_FLOAT(OFS_PARM0);
3414 if(handle < 0 || handle >= MAX_SEARCHES)
3416 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3419 if(pr_fssearchlist[handle] == NULL)
3421 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3425 PRVM_G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3430 VM_search_getfilename
3432 string search_getfilename(float handle, float num)
3435 void PF_search_getfilename(void)
3437 int handle, filenum;
3440 handle = PRVM_G_FLOAT(OFS_PARM0);
3441 filenum = PRVM_G_FLOAT(OFS_PARM1);
3443 if(handle < 0 || handle >= MAX_SEARCHES)
3445 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3448 if(pr_fssearchlist[handle] == NULL)
3450 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3453 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3455 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3459 tmp = PR_GetTempString();
3460 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3462 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp);
3465 void PF_cvar_string (void)
3471 str = PRVM_G_STRING(OFS_PARM0);
3472 var = Cvar_FindVar (str);
3475 tmp = PR_GetTempString();
3476 strcpy(tmp, var->string);
3480 PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp);
3483 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3484 void PF_dropclient (void)
3487 client_t *oldhostclient;
3488 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
3489 if (clientnum < 0 || clientnum >= svs.maxclients)
3490 PF_WARNING("dropclient: not a client\n");
3491 if (!svs.clients[clientnum].active)
3492 PF_WARNING("dropclient: that client slot is not connected\n");
3493 oldhostclient = host_client;
3494 host_client = svs.clients + clientnum;
3495 SV_DropClient(false);
3496 host_client = oldhostclient;
3499 //entity() spawnclient (DP_SV_BOTCLIENT)
3500 void PF_spawnclient (void)
3504 pr_xfunction->builtinsprofile += 2;
3506 for (i = 0;i < svs.maxclients;i++)
3508 if (!svs.clients[i].active)
3510 pr_xfunction->builtinsprofile += 100;
3511 SV_ConnectClient (i, NULL);
3512 ed = PRVM_EDICT_NUM(i + 1);
3519 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
3520 void PF_clienttype (void)
3523 clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
3524 if (clientnum < 0 || clientnum >= svs.maxclients)
3525 PRVM_G_FLOAT(OFS_RETURN) = 3;
3526 else if (!svs.clients[clientnum].active)
3527 PRVM_G_FLOAT(OFS_RETURN) = 0;
3528 else if (svs.clients[clientnum].netconnection)
3529 PRVM_G_FLOAT(OFS_RETURN) = 1;
3531 PRVM_G_FLOAT(OFS_RETURN) = 2;
3534 builtin_t pr_builtin[] =
3537 PF_makevectors, // #1 void(entity e) makevectors
3538 PF_setorigin, // #2 void(entity e, vector o) setorigin
3539 PF_setmodel, // #3 void(entity e, string m) setmodel
3540 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3541 NULL, // #5 void(entity e, vector min, vector max) setabssize
3542 PF_break, // #6 void() break
3543 PF_random, // #7 float() random
3544 PF_sound, // #8 void(entity e, float chan, string samp) sound
3545 PF_normalize, // #9 vector(vector v) normalize
3546 PF_error, // #10 void(string e) error
3547 PF_objerror, // #11 void(string e) objerror
3548 PF_vlen, // #12 float(vector v) vlen
3549 PF_vectoyaw, // #13 float(vector v) vectoyaw
3550 PF_Spawn, // #14 entity() spawn
3551 PF_Remove, // #15 void(entity e) remove
3552 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3553 PF_checkclient, // #17 entity() clientlist
3554 PF_Find, // #18 entity(entity start, .string fld, string match) find
3555 PF_precache_sound, // #19 void(string s) precache_sound
3556 PF_precache_model, // #20 void(string s) precache_model
3557 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3558 PF_findradius, // #22 entity(vector org, float rad) findradius
3559 PF_bprint, // #23 void(string s) bprint
3560 PF_sprint, // #24 void(entity client, string s) sprint
3561 PF_dprint, // #25 void(string s) dprint
3562 PF_ftos, // #26 void(string s) ftos
3563 PF_vtos, // #27 void(string s) vtos
3564 PF_coredump, // #28 void() coredump
3565 PF_traceon, // #29 void() traceon
3566 PF_traceoff, // #30 void() traceoff
3567 PF_eprint, // #31 void(entity e) eprint
3568 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3570 PF_droptofloor, // #34 float() droptofloor
3571 PF_lightstyle, // #35 void(float style, string value) lightstyle
3572 PF_rint, // #36 float(float v) rint
3573 PF_floor, // #37 float(float v) floor
3574 PF_ceil, // #38 float(float v) ceil
3576 PF_checkbottom, // #40 float(entity e) checkbottom
3577 PF_pointcontents, // #41 float(vector v) pointcontents
3579 PF_fabs, // #43 float(float f) fabs
3580 PF_aim, // #44 vector(entity e, float speed) aim
3581 PF_cvar, // #45 float(string s) cvar
3582 PF_localcmd, // #46 void(string s) localcmd
3583 PF_nextent, // #47 entity(entity e) nextent
3584 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3585 PF_changeyaw, // #49 void() ChangeYaw
3587 PF_vectoangles, // #51 vector(vector v) vectoangles
3588 PF_WriteByte, // #52 void(float to, float f) WriteByte
3589 PF_WriteChar, // #53 void(float to, float f) WriteChar
3590 PF_WriteShort, // #54 void(float to, float f) WriteShort
3591 PF_WriteLong, // #55 void(float to, float f) WriteLong
3592 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3593 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3594 PF_WriteString, // #58 void(float to, string s) WriteString
3595 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3596 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3597 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3598 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3599 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3600 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3601 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3603 SV_MoveToGoal, // #67 void(float step) movetogoal
3604 PF_precache_file, // #68 string(string s) precache_file
3605 PF_makestatic, // #69 void(entity e) makestatic
3606 PF_changelevel, // #70 void(string s) changelevel
3608 PF_cvar_set, // #72 void(string var, string val) cvar_set
3609 PF_centerprint, // #73 void(entity client, strings) centerprint
3610 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3611 PF_precache_model, // #75 string(string s) precache_model2
3612 PF_precache_sound, // #76 string(string s) precache_sound2
3613 PF_precache_file, // #77 string(string s) precache_file2
3614 PF_setspawnparms, // #78 void(entity e) setspawnparms
3617 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3626 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3627 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3628 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3629 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3630 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3631 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3632 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3633 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3634 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3635 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3646 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3647 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3648 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3649 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3650 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3651 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3652 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3653 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3654 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3655 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3656 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3657 a a a a a a a a // #120-199
3658 a a a a a a a a a a // #200-299
3659 a a a a a a a a a a // #300-399
3660 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3661 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3662 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3663 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3664 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3665 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3666 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3667 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3668 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3669 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3670 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3671 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3672 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3673 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3674 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3675 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3676 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3677 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3678 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3679 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3680 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3681 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3682 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3683 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3684 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3685 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3686 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3687 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3688 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3689 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3690 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3691 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3692 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3693 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3694 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3695 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3696 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3697 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3698 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3699 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3700 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3701 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3702 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3703 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3704 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3705 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3706 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3707 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3708 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3709 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3710 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3711 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3712 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3713 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3714 PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3715 PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3720 a a a a // #460-499 (LordHavoc)
3723 builtin_t *pr_builtins = pr_builtin;
3724 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3726 void PR_Cmd_Init(void)
3732 void PR_Cmd_Shutdown(void)
3736 void PR_Cmd_Reset(void)
3739 PR_Files_CloseAll();