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 mempool_t *pr_strings_mempool;
28 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
29 #define STRINGTEMP_BUFFERS 16
30 #define STRINGTEMP_LENGTH 4096
31 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
32 static int pr_string_tempindex = 0;
34 static char *PR_GetTempString(void)
37 s = pr_string_temp[pr_string_tempindex];
38 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
42 #define RETURN_EDICT(e) (G_INT(OFS_RETURN) = EDICT_TO_PROG(e))
43 #define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
44 #define PF_ERROR(s) do{Host_Error(s);return;}while(0)
48 ===============================================================================
52 ===============================================================================
56 void PF_VarString(int first, char *out, int outlength)
62 outend = out + outlength - 1;
63 for (i = first;i < pr_argc && out < outend;i++)
65 s = G_STRING((OFS_PARM0+i*3));
66 while (out < outend && *s)
72 char *ENGINE_EXTENSIONS =
84 "DP_ENT_CUSTOMCOLORMAP "
85 "DP_ENT_EXTERIORMODELTOCLIENT "
87 "DP_ENT_LOWPRECISION "
90 "DP_GFX_EXTERNALTEXTURES "
92 "DP_GFX_QUAKE3MODELTAGS "
96 "DP_HALFLIFE_MAP_CVAR "
101 "DP_MOVETYPEBOUNCEMISSILE "
108 "DP_QC_FINDCHAINFLAGS "
109 "DP_QC_FINDCHAINFLOAT "
112 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
117 "DP_QC_MULTIPLETEMPSTRINGS "
119 "DP_QC_SINCOSSQRTPOW "
122 "DP_QC_TRACE_MOVETYPE_HITMODEL "
123 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
124 "DP_QC_VECTORVECTORS "
128 "DP_SND_DIRECTIONLESSATTNNONE "
133 "DP_SV_DRAWONLYTOCLIENT "
135 "DP_SV_EXTERIORMODELTOCLIENT "
136 "DP_SV_NODRAWTOCLIENT "
137 "DP_SV_PLAYERPHYSICS "
138 "DP_SV_ROTATINGBMODEL "
144 "DP_TE_EXPLOSIONRGB "
146 "DP_TE_PARTICLECUBE "
147 "DP_TE_PARTICLERAIN "
148 "DP_TE_PARTICLESNOW "
150 "DP_TE_QUADEFFECTS1 "
153 "DP_TE_STANDARDEFFECTBUILTINS "
156 "KRIMZON_SV_PARSECLIENTCOMMAND "
160 "TENEBRAE_GFX_DLIGHTS "
164 qboolean checkextension(char *name)
169 for (e = ENGINE_EXTENSIONS;*e;e++)
176 while (*e && *e != ' ')
178 if (e - start == len)
179 if (!strncasecmp(start, name, len))
189 returns true if the extension is supported by the server
191 checkextension(extensionname)
194 void PF_checkextension (void)
196 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
203 This is a TERMINAL error, which will kill off the entire server.
212 char string[STRINGTEMP_LENGTH];
214 PF_VarString(0, string, sizeof(string));
215 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
216 ed = PROG_TO_EDICT(pr_global_struct->self);
219 PF_ERROR("Program error");
226 Dumps out self, then an error message. The program is aborted and self is
227 removed, but the level can continue.
232 void PF_objerror (void)
235 char string[STRINGTEMP_LENGTH];
237 PF_VarString(0, string, sizeof(string));
238 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
239 ed = PROG_TO_EDICT(pr_global_struct->self);
249 Writes new values for v_forward, v_up, and v_right based on angles
253 void PF_makevectors (void)
255 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
262 Writes new values for v_forward, v_up, and v_right based on the given forward vector
263 vectorvectors(vector, vector)
266 void PF_vectorvectors (void)
268 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
269 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
276 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.
278 setorigin (entity, origin)
281 void PF_setorigin (void)
286 e = G_EDICT(OFS_PARM0);
288 PF_WARNING("setorigin: can not modify world entity\n");
290 PF_WARNING("setorigin: can not modify free entity\n");
291 org = G_VECTOR(OFS_PARM1);
292 VectorCopy (org, e->v->origin);
293 SV_LinkEdict (e, false);
297 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
301 for (i=0 ; i<3 ; i++)
303 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
305 // set derived values
306 VectorCopy (min, e->v->mins);
307 VectorCopy (max, e->v->maxs);
308 VectorSubtract (max, min, e->v->size);
310 SV_LinkEdict (e, false);
317 the size box is rotated by the current angle
318 LordHavoc: no it isn't...
320 setsize (entity, minvector, maxvector)
323 void PF_setsize (void)
328 e = G_EDICT(OFS_PARM0);
330 PF_WARNING("setsize: can not modify world entity\n");
332 PF_WARNING("setsize: can not modify free entity\n");
333 min = G_VECTOR(OFS_PARM1);
334 max = G_VECTOR(OFS_PARM2);
335 SetMinMaxSize (e, min, max, false);
343 setmodel(entity, model)
346 void PF_setmodel (void)
353 e = G_EDICT(OFS_PARM0);
355 PF_WARNING("setmodel: can not modify world entity\n");
357 PF_WARNING("setmodel: can not modify free entity\n");
358 m = G_STRING(OFS_PARM1);
360 // check to see if model was properly precached
361 for (i=0, check = sv.model_precache ; *check ; i++, check++)
362 if (!strcmp(*check, m))
366 PF_WARNING(va("setmodel: no precache for model \"%s\"\n", m));
369 e->v->model = PR_SetString(*check);
370 e->v->modelindex = i;
372 mod = sv.models[ (int)e->v->modelindex];
375 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
377 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
384 broadcast print to everyone on server
389 void PF_bprint (void)
391 char string[STRINGTEMP_LENGTH];
392 PF_VarString(0, string, sizeof(string));
393 SV_BroadcastPrint(string);
400 single print to a specific client
402 sprint(clientent, value)
405 void PF_sprint (void)
409 char string[STRINGTEMP_LENGTH];
411 entnum = G_EDICTNUM(OFS_PARM0);
413 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
415 Con_Print("tried to sprint to a non-client\n");
419 client = svs.clients + entnum-1;
420 if (!client->netconnection)
422 PF_VarString(1, string, sizeof(string));
423 MSG_WriteChar(&client->message,svc_print);
424 MSG_WriteString(&client->message, string);
432 single print to a specific client
434 centerprint(clientent, value)
437 void PF_centerprint (void)
441 char string[STRINGTEMP_LENGTH];
443 entnum = G_EDICTNUM(OFS_PARM0);
445 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
447 Con_Print("tried to sprint to a non-client\n");
451 client = svs.clients + entnum-1;
452 if (!client->netconnection)
454 PF_VarString(1, string, sizeof(string));
455 MSG_WriteChar(&client->message,svc_centerprint);
456 MSG_WriteString(&client->message, string);
464 vector normalize(vector)
467 void PF_normalize (void)
473 value1 = G_VECTOR(OFS_PARM0);
475 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
479 newvalue[0] = newvalue[1] = newvalue[2] = 0;
483 newvalue[0] = value1[0] * new;
484 newvalue[1] = value1[1] * new;
485 newvalue[2] = value1[2] * new;
488 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
503 value1 = G_VECTOR(OFS_PARM0);
505 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
508 G_FLOAT(OFS_RETURN) = new;
515 float vectoyaw(vector)
518 void PF_vectoyaw (void)
523 value1 = G_VECTOR(OFS_PARM0);
525 if (value1[1] == 0 && value1[0] == 0)
529 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
534 G_FLOAT(OFS_RETURN) = yaw;
542 vector vectoangles(vector)
545 void PF_vectoangles (void)
547 double value1[3], forward, yaw, pitch;
549 VectorCopy(G_VECTOR(OFS_PARM0), value1);
551 if (value1[1] == 0 && value1[0] == 0)
561 // LordHavoc: optimized a bit
564 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
568 else if (value1[1] > 0)
573 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
574 pitch = (atan2(value1[2], forward) * 180 / M_PI);
579 VectorSet(G_VECTOR(OFS_RETURN), pitch, yaw, 0);
586 Returns a number from 0<= num < 1
591 void PF_random (void)
595 num = (rand ()&0x7fff) / ((float)0x7fff);
597 G_FLOAT(OFS_RETURN) = num;
604 particle(origin, color, count)
607 void PF_particle (void)
613 org = G_VECTOR(OFS_PARM0);
614 dir = G_VECTOR(OFS_PARM1);
615 color = G_FLOAT(OFS_PARM2);
616 count = G_FLOAT(OFS_PARM3);
617 SV_StartParticle (org, dir, color, count);
627 void PF_ambientsound (void)
632 float vol, attenuation;
635 pos = G_VECTOR (OFS_PARM0);
636 samp = G_STRING(OFS_PARM1);
637 vol = G_FLOAT(OFS_PARM2);
638 attenuation = G_FLOAT(OFS_PARM3);
640 // check to see if samp was properly precached
641 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
642 if (!strcmp(*check,samp))
647 Con_Printf("no precache: %s\n", samp);
655 // add an svc_spawnambient command to the level signon packet
658 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
660 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
662 MSG_WriteVector(&sv.signon, pos, sv.protocol);
665 MSG_WriteShort (&sv.signon, soundnum);
667 MSG_WriteByte (&sv.signon, soundnum);
669 MSG_WriteByte (&sv.signon, vol*255);
670 MSG_WriteByte (&sv.signon, attenuation*64);
678 Each entity can have eight independant sound sources, like voice,
681 Channel 0 is an auto-allocate channel, the others override anything
682 already running on that entity/channel pair.
684 An attenuation of 0 will play full volume everywhere in the level.
685 Larger attenuations will drop off.
697 entity = G_EDICT(OFS_PARM0);
698 channel = G_FLOAT(OFS_PARM1);
699 sample = G_STRING(OFS_PARM2);
700 volume = G_FLOAT(OFS_PARM3) * 255;
701 attenuation = G_FLOAT(OFS_PARM4);
703 if (volume < 0 || volume > 255)
704 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
706 if (attenuation < 0 || attenuation > 4)
707 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
709 if (channel < 0 || channel > 7)
710 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
712 SV_StartSound (entity, channel, sample, volume, attenuation);
724 PF_ERROR("break: break statement\n");
731 Used for use tracing and shot targeting
732 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
733 if the tryents flag is set.
735 traceline (vector1, vector2, tryents)
738 void PF_traceline (void)
745 pr_xfunction->builtinsprofile += 30;
747 v1 = G_VECTOR(OFS_PARM0);
748 v2 = G_VECTOR(OFS_PARM1);
749 move = G_FLOAT(OFS_PARM2);
750 ent = G_EDICT(OFS_PARM3);
752 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
754 pr_global_struct->trace_allsolid = trace.allsolid;
755 pr_global_struct->trace_startsolid = trace.startsolid;
756 pr_global_struct->trace_fraction = trace.fraction;
757 pr_global_struct->trace_inwater = trace.inwater;
758 pr_global_struct->trace_inopen = trace.inopen;
759 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
760 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
761 pr_global_struct->trace_plane_dist = trace.plane.dist;
763 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
765 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
766 // FIXME: add trace_endcontents
774 Used for use tracing and shot targeting
775 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
776 if the tryents flag is set.
778 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
781 // LordHavoc: added this for my own use, VERY useful, similar to traceline
782 void PF_tracebox (void)
784 float *v1, *v2, *m1, *m2;
789 pr_xfunction->builtinsprofile += 30;
791 v1 = G_VECTOR(OFS_PARM0);
792 m1 = G_VECTOR(OFS_PARM1);
793 m2 = G_VECTOR(OFS_PARM2);
794 v2 = G_VECTOR(OFS_PARM3);
795 move = G_FLOAT(OFS_PARM4);
796 ent = G_EDICT(OFS_PARM5);
798 trace = SV_Move (v1, m1, m2, v2, move, ent);
800 pr_global_struct->trace_allsolid = trace.allsolid;
801 pr_global_struct->trace_startsolid = trace.startsolid;
802 pr_global_struct->trace_fraction = trace.fraction;
803 pr_global_struct->trace_inwater = trace.inwater;
804 pr_global_struct->trace_inopen = trace.inopen;
805 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
806 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
807 pr_global_struct->trace_plane_dist = trace.plane.dist;
809 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
811 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
814 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
815 void PF_TraceToss (void)
821 pr_xfunction->builtinsprofile += 600;
823 ent = G_EDICT(OFS_PARM0);
824 if (ent == sv.edicts)
825 PF_WARNING("tracetoss: can not use world entity\n");
826 ignore = G_EDICT(OFS_PARM1);
828 trace = SV_Trace_Toss (ent, ignore);
830 pr_global_struct->trace_allsolid = trace.allsolid;
831 pr_global_struct->trace_startsolid = trace.startsolid;
832 pr_global_struct->trace_fraction = trace.fraction;
833 pr_global_struct->trace_inwater = trace.inwater;
834 pr_global_struct->trace_inopen = trace.inopen;
835 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
836 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
837 pr_global_struct->trace_plane_dist = trace.plane.dist;
839 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
841 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
849 Returns true if the given entity can move to the given position from it's
850 current position by walking or rolling.
852 scalar checkpos (entity, vector)
855 void PF_checkpos (void)
859 //============================================================================
862 qbyte checkpvs[MAX_MAP_LEAFS/8];
864 int PF_newcheckclient (int check)
870 // cycle to the next one
872 check = bound(1, check, svs.maxclients);
873 if (check == svs.maxclients)
881 pr_xfunction->builtinsprofile++;
883 if (i == svs.maxclients+1)
885 // look up the client's edict
887 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
888 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
890 // found a valid client (possibly the same one again)
894 // get the PVS for the entity
895 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
897 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
898 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
907 Returns a client (or object that has a client enemy) that would be a
910 If there is more than one valid option, they are cycled each frame
912 If (self.origin + self.viewofs) is not in the PVS of the current target,
913 it is not returned at all.
918 int c_invis, c_notvis;
919 void PF_checkclient (void)
924 // find a new check if on a new frame
925 if (sv.time - sv.lastchecktime >= 0.1)
927 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
928 sv.lastchecktime = sv.time;
931 // return check if it might be visible
932 ent = EDICT_NUM(sv.lastcheck);
933 if (ent->e->free || ent->v->health <= 0)
935 RETURN_EDICT(sv.edicts);
939 // if current entity can't possibly see the check entity, return 0
940 self = PROG_TO_EDICT(pr_global_struct->self);
941 VectorAdd(self->v->origin, self->v->view_ofs, view);
942 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
945 RETURN_EDICT(sv.edicts);
949 // might be able to see it
954 //============================================================================
961 Sends text over to the client's execution buffer
963 stuffcmd (clientent, value)
966 void PF_stuffcmd (void)
972 entnum = G_EDICTNUM(OFS_PARM0);
973 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
975 Con_Print("Can't stuffcmd to a non-client\n");
978 str = G_STRING(OFS_PARM1);
981 if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
982 Host_ClientCommands ("%s", str);
990 Sends text to server console
995 void PF_localcmd (void)
997 Cbuf_AddText(G_STRING(OFS_PARM0));
1009 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1019 void PF_cvar_set (void)
1021 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1028 Returns a chain of entities that have origins within a spherical area
1030 findradius (origin, radius)
1033 void PF_findradius (void)
1035 edict_t *ent, *chain;
1036 vec_t radius, radius2;
1037 vec3_t org, eorg, mins, maxs;
1040 edict_t *touchedicts[MAX_EDICTS];
1042 chain = (edict_t *)sv.edicts;
1044 VectorCopy(G_VECTOR(OFS_PARM0), org);
1045 radius = G_FLOAT(OFS_PARM1);
1046 radius2 = radius * radius;
1048 mins[0] = org[0] - radius;
1049 mins[1] = org[1] - radius;
1050 mins[2] = org[2] - radius;
1051 maxs[0] = org[0] + radius;
1052 maxs[1] = org[1] + radius;
1053 maxs[2] = org[2] + radius;
1054 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1055 if (numtouchedicts > MAX_EDICTS)
1057 // this never happens
1058 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1059 numtouchedicts = MAX_EDICTS;
1061 for (i = 0;i < numtouchedicts;i++)
1063 ent = touchedicts[i];
1064 pr_xfunction->builtinsprofile++;
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 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1069 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1070 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1071 if (DotProduct(eorg, eorg) < radius2)
1073 ent->v->chain = EDICT_TO_PROG(chain);
1078 RETURN_EDICT(chain);
1087 void PF_dprint (void)
1089 char string[STRINGTEMP_LENGTH];
1090 if (developer.integer)
1092 PF_VarString(0, string, sizeof(string));
1101 v = G_FLOAT(OFS_PARM0);
1103 s = PR_GetTempString();
1104 if ((float)((int)v) == v)
1105 sprintf(s, "%i", (int)v);
1107 sprintf(s, "%f", v);
1108 G_INT(OFS_RETURN) = PR_SetString(s);
1114 v = G_FLOAT(OFS_PARM0);
1115 G_FLOAT(OFS_RETURN) = fabs(v);
1121 s = PR_GetTempString();
1122 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1123 G_INT(OFS_RETURN) = PR_SetString(s);
1129 s = PR_GetTempString();
1130 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1131 G_INT(OFS_RETURN) = PR_SetString(s);
1134 void PF_Spawn (void)
1137 pr_xfunction->builtinsprofile += 20;
1142 void PF_Remove (void)
1145 pr_xfunction->builtinsprofile += 20;
1147 ed = G_EDICT(OFS_PARM0);
1148 if (ed == sv.edicts)
1149 PF_WARNING("remove: tried to remove world\n");
1150 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1151 PF_WARNING("remove: tried to remove a client\n");
1152 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1153 if (ed->e->free && developer.integer)
1154 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1159 // entity (entity start, .string field, string match) find = #5;
1167 e = G_EDICTNUM(OFS_PARM0);
1168 f = G_INT(OFS_PARM1);
1169 s = G_STRING(OFS_PARM2);
1172 RETURN_EDICT(sv.edicts);
1176 for (e++ ; e < sv.num_edicts ; e++)
1178 pr_xfunction->builtinsprofile++;
1192 RETURN_EDICT(sv.edicts);
1195 // LordHavoc: added this for searching float, int, and entity reference fields
1196 void PF_FindFloat (void)
1203 e = G_EDICTNUM(OFS_PARM0);
1204 f = G_INT(OFS_PARM1);
1205 s = G_FLOAT(OFS_PARM2);
1207 for (e++ ; e < sv.num_edicts ; e++)
1209 pr_xfunction->builtinsprofile++;
1213 if (E_FLOAT(ed,f) == s)
1220 RETURN_EDICT(sv.edicts);
1223 // chained search for strings in entity fields
1224 // entity(.string field, string match) findchain = #402;
1225 void PF_findchain (void)
1230 edict_t *ent, *chain;
1232 chain = (edict_t *)sv.edicts;
1234 f = G_INT(OFS_PARM0);
1235 s = G_STRING(OFS_PARM1);
1238 RETURN_EDICT(sv.edicts);
1242 ent = NEXT_EDICT(sv.edicts);
1243 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1245 pr_xfunction->builtinsprofile++;
1248 t = E_STRING(ent,f);
1254 ent->v->chain = EDICT_TO_PROG(chain);
1258 RETURN_EDICT(chain);
1261 // LordHavoc: chained search for float, int, and entity reference fields
1262 // entity(.string field, float match) findchainfloat = #403;
1263 void PF_findchainfloat (void)
1268 edict_t *ent, *chain;
1270 chain = (edict_t *)sv.edicts;
1272 f = G_INT(OFS_PARM0);
1273 s = G_FLOAT(OFS_PARM1);
1275 ent = NEXT_EDICT(sv.edicts);
1276 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1278 pr_xfunction->builtinsprofile++;
1281 if (E_FLOAT(ent,f) != s)
1284 ent->v->chain = EDICT_TO_PROG(chain);
1288 RETURN_EDICT(chain);
1291 // LordHavoc: search for flags in float fields
1292 void PF_findflags (void)
1299 e = G_EDICTNUM(OFS_PARM0);
1300 f = G_INT(OFS_PARM1);
1301 s = (int)G_FLOAT(OFS_PARM2);
1303 for (e++ ; e < sv.num_edicts ; e++)
1305 pr_xfunction->builtinsprofile++;
1309 if ((int)E_FLOAT(ed,f) & s)
1316 RETURN_EDICT(sv.edicts);
1319 // LordHavoc: chained search for flags in float fields
1320 void PF_findchainflags (void)
1325 edict_t *ent, *chain;
1327 chain = (edict_t *)sv.edicts;
1329 f = G_INT(OFS_PARM0);
1330 s = (int)G_FLOAT(OFS_PARM1);
1332 ent = NEXT_EDICT(sv.edicts);
1333 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1335 pr_xfunction->builtinsprofile++;
1338 if (!((int)E_FLOAT(ent,f) & s))
1341 ent->v->chain = EDICT_TO_PROG(chain);
1345 RETURN_EDICT(chain);
1348 void PR_CheckEmptyString (char *s)
1351 PF_ERROR("Bad string");
1354 void PF_precache_file (void)
1355 { // precache_file is only used to copy files with qcc, it does nothing
1356 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1359 void PF_precache_sound (void)
1363 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS);
1365 if (sv.state != ss_loading)
1366 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1368 s = G_STRING(OFS_PARM0);
1369 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1370 PR_CheckEmptyString (s);
1372 for (i=0 ; i<limit ; i++)
1374 if (!sv.sound_precache[i])
1376 sv.sound_precache[i] = s;
1379 if (!strcmp(sv.sound_precache[i], s))
1382 PF_ERROR("PF_precache_sound: overflow");
1385 void PF_precache_model (void)
1389 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS);
1391 if (sv.state != ss_loading)
1392 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1394 s = G_STRING(OFS_PARM0);
1395 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1397 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1398 PR_CheckEmptyString (s);
1400 for (i = 0;i < limit;i++)
1402 if (!sv.model_precache[i])
1404 sv.model_precache[i] = s;
1405 sv.models[i] = Mod_ForName (s, true, false, false);
1408 if (!strcmp(sv.model_precache[i], s))
1411 PF_ERROR("PF_precache_model: overflow");
1415 void PF_coredump (void)
1420 void PF_traceon (void)
1425 void PF_traceoff (void)
1430 void PF_eprint (void)
1432 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1439 float(float yaw, float dist) walkmove
1442 void PF_walkmove (void)
1450 // assume failure if it returns early
1451 G_FLOAT(OFS_RETURN) = 0;
1453 ent = PROG_TO_EDICT(pr_global_struct->self);
1454 if (ent == sv.edicts)
1455 PF_WARNING("walkmove: can not modify world entity\n");
1457 PF_WARNING("walkmove: can not modify free entity\n");
1458 yaw = G_FLOAT(OFS_PARM0);
1459 dist = G_FLOAT(OFS_PARM1);
1461 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1464 yaw = yaw*M_PI*2 / 360;
1466 move[0] = cos(yaw)*dist;
1467 move[1] = sin(yaw)*dist;
1470 // save program state, because SV_movestep may call other progs
1471 oldf = pr_xfunction;
1472 oldself = pr_global_struct->self;
1474 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1477 // restore program state
1478 pr_xfunction = oldf;
1479 pr_global_struct->self = oldself;
1489 void PF_droptofloor (void)
1495 // assume failure if it returns early
1496 G_FLOAT(OFS_RETURN) = 0;
1498 ent = PROG_TO_EDICT(pr_global_struct->self);
1499 if (ent == sv.edicts)
1500 PF_WARNING("droptofloor: can not modify world entity\n");
1502 PF_WARNING("droptofloor: can not modify free entity\n");
1504 VectorCopy (ent->v->origin, end);
1507 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1509 if (trace.fraction != 1)
1511 VectorCopy (trace.endpos, ent->v->origin);
1512 SV_LinkEdict (ent, false);
1513 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1514 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1515 G_FLOAT(OFS_RETURN) = 1;
1516 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1517 ent->e->suspendedinairflag = true;
1525 void(float style, string value) lightstyle
1528 void PF_lightstyle (void)
1535 style = G_FLOAT(OFS_PARM0);
1536 val = G_STRING(OFS_PARM1);
1538 // change the string in sv
1539 sv.lightstyles[style] = val;
1541 // send message to all clients on this server
1542 if (sv.state != ss_active)
1545 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1547 if (client->netconnection)
1549 MSG_WriteChar (&client->message, svc_lightstyle);
1550 MSG_WriteChar (&client->message,style);
1551 MSG_WriteString (&client->message, val);
1559 f = G_FLOAT(OFS_PARM0);
1561 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1563 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1565 void PF_floor (void)
1567 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1571 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1580 void PF_checkbottom (void)
1582 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1590 void PF_pointcontents (void)
1592 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1599 entity nextent(entity)
1602 void PF_nextent (void)
1607 i = G_EDICTNUM(OFS_PARM0);
1610 pr_xfunction->builtinsprofile++;
1612 if (i == sv.num_edicts)
1614 RETURN_EDICT(sv.edicts);
1630 Pick a vector for the player to shoot along
1631 vector aim(entity, missilespeed)
1636 edict_t *ent, *check, *bestent;
1637 vec3_t start, dir, end, bestdir;
1640 float dist, bestdist;
1643 // assume failure if it returns early
1644 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1645 // if sv_aim is so high it can't possibly accept anything, skip out early
1646 if (sv_aim.value >= 1)
1649 ent = G_EDICT(OFS_PARM0);
1650 if (ent == sv.edicts)
1651 PF_WARNING("aim: can not use world entity\n");
1653 PF_WARNING("aim: can not use free entity\n");
1654 speed = G_FLOAT(OFS_PARM1);
1656 VectorCopy (ent->v->origin, start);
1659 // try sending a trace straight
1660 VectorCopy (pr_global_struct->v_forward, dir);
1661 VectorMA (start, 2048, dir, end);
1662 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1663 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1664 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1666 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1671 // try all possible entities
1672 VectorCopy (dir, bestdir);
1673 bestdist = sv_aim.value;
1676 check = NEXT_EDICT(sv.edicts);
1677 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1679 pr_xfunction->builtinsprofile++;
1680 if (check->v->takedamage != DAMAGE_AIM)
1684 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1685 continue; // don't aim at teammate
1686 for (j=0 ; j<3 ; j++)
1687 end[j] = check->v->origin[j]
1688 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1689 VectorSubtract (end, start, dir);
1690 VectorNormalize (dir);
1691 dist = DotProduct (dir, pr_global_struct->v_forward);
1692 if (dist < bestdist)
1693 continue; // to far to turn
1694 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1695 if (tr.ent == check)
1696 { // can shoot at this one
1704 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1705 dist = DotProduct (dir, pr_global_struct->v_forward);
1706 VectorScale (pr_global_struct->v_forward, dist, end);
1708 VectorNormalize (end);
1709 VectorCopy (end, G_VECTOR(OFS_RETURN));
1713 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1721 This was a major timewaster in progs, so it was converted to C
1724 void PF_changeyaw (void)
1727 float ideal, current, move, speed;
1729 ent = PROG_TO_EDICT(pr_global_struct->self);
1730 if (ent == sv.edicts)
1731 PF_WARNING("changeyaw: can not modify world entity\n");
1733 PF_WARNING("changeyaw: can not modify free entity\n");
1734 current = ANGLEMOD(ent->v->angles[1]);
1735 ideal = ent->v->ideal_yaw;
1736 speed = ent->v->yaw_speed;
1738 if (current == ideal)
1740 move = ideal - current;
1741 if (ideal > current)
1762 ent->v->angles[1] = ANGLEMOD (current + move);
1770 void PF_changepitch (void)
1773 float ideal, current, move, speed;
1776 ent = G_EDICT(OFS_PARM0);
1777 if (ent == sv.edicts)
1778 PF_WARNING("changepitch: can not modify world entity\n");
1780 PF_WARNING("changepitch: can not modify free entity\n");
1781 current = ANGLEMOD( ent->v->angles[0] );
1782 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1783 ideal = val->_float;
1786 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1789 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1790 speed = val->_float;
1793 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1797 if (current == ideal)
1799 move = ideal - current;
1800 if (ideal > current)
1821 ent->v->angles[0] = ANGLEMOD (current + move);
1825 ===============================================================================
1829 ===============================================================================
1832 #define MSG_BROADCAST 0 // unreliable to all
1833 #define MSG_ONE 1 // reliable to one (msg_entity)
1834 #define MSG_ALL 2 // reliable to all
1835 #define MSG_INIT 3 // write to the init string
1837 sizebuf_t *WriteDest (void)
1843 dest = G_FLOAT(OFS_PARM0);
1847 return &sv.datagram;
1850 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1851 entnum = NUM_FOR_EDICT(ent);
1852 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1853 Host_Error("WriteDest: tried to write to non-client\n");
1854 return &svs.clients[entnum-1].message;
1857 return &sv.reliable_datagram;
1863 Host_Error("WriteDest: bad destination");
1870 void PF_WriteByte (void)
1872 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1875 void PF_WriteChar (void)
1877 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1880 void PF_WriteShort (void)
1882 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1885 void PF_WriteLong (void)
1887 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1890 void PF_WriteAngle (void)
1892 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1895 void PF_WriteCoord (void)
1897 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1900 void PF_WriteString (void)
1902 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1906 void PF_WriteEntity (void)
1908 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1911 //=============================================================================
1913 void PF_makestatic (void)
1918 ent = G_EDICT(OFS_PARM0);
1919 if (ent == sv.edicts)
1920 PF_WARNING("makestatic: can not modify world entity\n");
1922 PF_WARNING("makestatic: can not modify free entity\n");
1925 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1930 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1931 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1932 MSG_WriteShort (&sv.signon, ent->v->frame);
1936 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1937 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1938 MSG_WriteByte (&sv.signon, ent->v->frame);
1941 MSG_WriteByte (&sv.signon, ent->v->colormap);
1942 MSG_WriteByte (&sv.signon, ent->v->skin);
1943 for (i=0 ; i<3 ; i++)
1945 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1946 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1949 // throw the entity away now
1953 //=============================================================================
1960 void PF_setspawnparms (void)
1966 ent = G_EDICT(OFS_PARM0);
1967 i = NUM_FOR_EDICT(ent);
1968 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1970 Con_Print("tried to setspawnparms on a non-client\n");
1974 // copy spawn parms out of the client_t
1975 client = svs.clients + i-1;
1976 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1977 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1985 void PF_changelevel (void)
1989 // make sure we don't issue two changelevels
1990 if (svs.changelevel_issued)
1992 svs.changelevel_issued = true;
1994 s = G_STRING(OFS_PARM0);
1995 Cbuf_AddText (va("changelevel %s\n",s));
2000 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
2005 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
2010 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
2017 Returns a vector of length < 1
2022 void PF_randomvec (void)
2027 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2028 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2029 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2031 while (DotProduct(temp, temp) >= 1);
2032 VectorCopy (temp, G_VECTOR(OFS_RETURN));
2039 Returns a color vector indicating the lighting at the requested point.
2041 (Internal Operation note: actually measures the light beneath the point, just like
2042 the model lighting on the client)
2047 void PF_GetLight (void)
2049 vec3_t ambientcolor, diffusecolor, diffusenormal;
2051 p = G_VECTOR(OFS_PARM0);
2052 VectorClear(ambientcolor);
2053 VectorClear(diffusecolor);
2054 VectorClear(diffusenormal);
2055 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2056 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2057 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2060 void PF_registercvar (void)
2063 name = G_STRING(OFS_PARM0);
2064 value = G_STRING(OFS_PARM1);
2065 G_FLOAT(OFS_RETURN) = 0;
2067 // first check to see if it has already been defined
2068 if (Cvar_FindVar (name))
2071 // check for overlap with a command
2072 if (Cmd_Exists (name))
2074 Con_Printf("PF_registercvar: %s is a command\n", name);
2078 Cvar_Get(name, value, 0);
2080 G_FLOAT(OFS_RETURN) = 1; // success
2087 returns the minimum of two supplied floats
2094 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2096 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2097 else if (pr_argc >= 3)
2100 float f = G_FLOAT(OFS_PARM0);
2101 for (i = 1;i < pr_argc;i++)
2102 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2103 f = G_FLOAT((OFS_PARM0+i*3));
2104 G_FLOAT(OFS_RETURN) = f;
2108 G_FLOAT(OFS_RETURN) = 0;
2109 PF_WARNING("min: must supply at least 2 floats\n");
2117 returns the maximum of two supplied floats
2124 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2126 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2127 else if (pr_argc >= 3)
2130 float f = G_FLOAT(OFS_PARM0);
2131 for (i = 1;i < pr_argc;i++)
2132 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2133 f = G_FLOAT((OFS_PARM0+i*3));
2134 G_FLOAT(OFS_RETURN) = f;
2138 G_FLOAT(OFS_RETURN) = 0;
2139 PF_WARNING("max: must supply at least 2 floats\n");
2147 returns number bounded by supplied range
2149 min(min, value, max)
2152 void PF_bound (void)
2154 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2161 returns a raised to power b
2168 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2175 copies data from one entity to another
2177 copyentity(src, dst)
2180 void PF_copyentity (void)
2183 in = G_EDICT(OFS_PARM0);
2184 if (in == sv.edicts)
2185 PF_WARNING("copyentity: can not read world entity\n");
2187 PF_WARNING("copyentity: can not read free entity\n");
2188 out = G_EDICT(OFS_PARM1);
2189 if (out == sv.edicts)
2190 PF_WARNING("copyentity: can not modify world entity\n");
2192 PF_WARNING("copyentity: can not modify free entity\n");
2193 memcpy(out->v, in->v, progs->entityfields * 4);
2200 sets the color of a client and broadcasts the update to all connected clients
2202 setcolor(clientent, value)
2205 void PF_setcolor (void)
2211 entnum = G_EDICTNUM(OFS_PARM0);
2212 i = G_FLOAT(OFS_PARM1);
2214 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2216 Con_Print("tried to setcolor a non-client\n");
2220 client = svs.clients + entnum-1;
2221 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2224 client->old_colors = i;
2225 client->edict->v->team = (i & 15) + 1;
2227 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2228 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2229 MSG_WriteByte (&sv.reliable_datagram, i);
2236 effect(origin, modelname, startframe, framecount, framerate)
2239 void PF_effect (void)
2243 s = G_STRING(OFS_PARM1);
2245 PF_WARNING("effect: no model specified\n");
2247 i = SV_ModelIndex(s);
2249 PF_WARNING("effect: model not precached\n");
2250 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2253 void PF_te_blood (void)
2255 if (G_FLOAT(OFS_PARM2) < 1)
2257 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2258 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2260 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2261 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2262 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2264 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2265 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2266 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2268 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2271 void PF_te_bloodshower (void)
2273 if (G_FLOAT(OFS_PARM3) < 1)
2275 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2276 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2278 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2279 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2280 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2282 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2283 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2284 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2286 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2288 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2291 void PF_te_explosionrgb (void)
2293 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2294 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2296 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2297 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2298 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2300 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2301 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2302 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2305 void PF_te_particlecube (void)
2307 if (G_FLOAT(OFS_PARM3) < 1)
2309 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2310 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2312 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2313 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2314 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2316 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2317 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2318 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2320 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2321 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2322 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2324 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2326 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2327 // gravity true/false
2328 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2330 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2333 void PF_te_particlerain (void)
2335 if (G_FLOAT(OFS_PARM3) < 1)
2337 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2338 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2340 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2341 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2342 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2344 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2345 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2346 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2348 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2349 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2350 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2352 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2354 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2357 void PF_te_particlesnow (void)
2359 if (G_FLOAT(OFS_PARM3) < 1)
2361 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2362 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2364 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2365 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2366 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2368 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2369 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2370 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2372 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2373 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2374 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2376 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2378 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2381 void PF_te_spark (void)
2383 if (G_FLOAT(OFS_PARM2) < 1)
2385 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2386 MSG_WriteByte(&sv.datagram, TE_SPARK);
2388 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2389 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2390 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2392 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2393 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2394 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2396 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2399 void PF_te_gunshotquad (void)
2401 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2402 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2404 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2405 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2406 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2409 void PF_te_spikequad (void)
2411 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2412 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2414 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2415 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2416 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2419 void PF_te_superspikequad (void)
2421 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2422 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2424 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2425 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2426 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2429 void PF_te_explosionquad (void)
2431 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2432 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2434 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2435 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2436 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2439 void PF_te_smallflash (void)
2441 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2442 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2444 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2445 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2446 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2449 void PF_te_customflash (void)
2451 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2453 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2454 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2456 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2457 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2458 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2460 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2462 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2464 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2465 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2466 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2469 void PF_te_gunshot (void)
2471 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2472 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2474 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2475 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2476 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2479 void PF_te_spike (void)
2481 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2482 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2484 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2485 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2486 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2489 void PF_te_superspike (void)
2491 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2492 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2494 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2495 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2496 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2499 void PF_te_explosion (void)
2501 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2502 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2504 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2505 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2506 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2509 void PF_te_tarexplosion (void)
2511 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2512 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2514 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2515 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2516 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2519 void PF_te_wizspike (void)
2521 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2522 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2524 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2525 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2526 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2529 void PF_te_knightspike (void)
2531 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2532 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2534 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2535 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2536 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2539 void PF_te_lavasplash (void)
2541 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2542 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2544 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2545 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2546 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2549 void PF_te_teleport (void)
2551 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2552 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2554 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2555 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2556 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2559 void PF_te_explosion2 (void)
2561 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2562 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2564 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2565 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2566 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2568 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2569 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2572 void PF_te_lightning1 (void)
2574 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2575 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2577 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2579 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2580 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2581 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2583 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2584 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2585 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2588 void PF_te_lightning2 (void)
2590 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2591 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2593 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2595 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2596 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2597 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2599 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2600 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2601 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2604 void PF_te_lightning3 (void)
2606 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2607 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2609 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2611 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2612 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2613 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2615 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2616 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2617 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2620 void PF_te_beam (void)
2622 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2623 MSG_WriteByte(&sv.datagram, TE_BEAM);
2625 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2627 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2628 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2629 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2631 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2632 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2633 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2636 void PF_te_plasmaburn (void)
2638 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2639 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2640 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2641 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2642 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2645 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2648 vec3_t v1, clipplanenormal, normal;
2649 vec_t clipplanedist, clipdist;
2651 if (surf->flags & SURF_PLANEBACK)
2652 VectorNegate(surf->plane->normal, normal);
2654 VectorCopy(surf->plane->normal, normal);
2655 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2657 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2658 VectorNormalizeFast(v1);
2659 CrossProduct(v1, normal, clipplanenormal);
2660 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2661 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2664 clipdist = -clipdist;
2665 VectorMA(out, clipdist, clipplanenormal, out);
2670 static msurface_t *getsurface(edict_t *ed, int surfnum)
2674 if (!ed || ed->e->free)
2676 modelindex = ed->v->modelindex;
2677 if (modelindex < 1 || modelindex >= MAX_MODELS)
2679 model = sv.models[modelindex];
2680 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2682 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2686 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2687 void PF_getsurfacenumpoints(void)
2690 // return 0 if no such surface
2691 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2693 G_FLOAT(OFS_RETURN) = 0;
2697 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2699 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2700 void PF_getsurfacepoint(void)
2705 VectorClear(G_VECTOR(OFS_RETURN));
2706 ed = G_EDICT(OFS_PARM0);
2707 if (!ed || ed->e->free)
2709 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2711 pointnum = G_FLOAT(OFS_PARM2);
2712 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2714 // FIXME: implement rotation/scaling
2715 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2717 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2718 void PF_getsurfacenormal(void)
2721 VectorClear(G_VECTOR(OFS_RETURN));
2722 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2724 // FIXME: implement rotation/scaling
2725 if (surf->flags & SURF_PLANEBACK)
2726 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2728 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2730 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2731 void PF_getsurfacetexture(void)
2734 G_INT(OFS_RETURN) = 0;
2735 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2737 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2739 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2740 void PF_getsurfacenearpoint(void)
2742 int surfnum, best, modelindex;
2744 vec_t dist, bestdist;
2749 G_FLOAT(OFS_RETURN) = -1;
2750 ed = G_EDICT(OFS_PARM0);
2751 point = G_VECTOR(OFS_PARM1);
2753 if (!ed || ed->e->free)
2755 modelindex = ed->v->modelindex;
2756 if (modelindex < 1 || modelindex >= MAX_MODELS)
2758 model = sv.models[modelindex];
2759 if (!model->brushq1.numsurfaces)
2762 // FIXME: implement rotation/scaling
2763 VectorSubtract(point, ed->v->origin, p);
2765 bestdist = 1000000000;
2766 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2768 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2769 dist = PlaneDiff(p, surf->plane);
2771 if (dist < bestdist)
2773 clippointtosurface(surf, p, clipped);
2774 VectorSubtract(clipped, p, clipped);
2775 dist += DotProduct(clipped, clipped);
2776 if (dist < bestdist)
2783 G_FLOAT(OFS_RETURN) = best;
2785 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2786 void PF_getsurfaceclippedpoint(void)
2791 VectorClear(G_VECTOR(OFS_RETURN));
2792 ed = G_EDICT(OFS_PARM0);
2793 if (!ed || ed->e->free)
2795 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2797 // FIXME: implement rotation/scaling
2798 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2799 clippointtosurface(surf, p, out);
2800 // FIXME: implement rotation/scaling
2801 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2804 #define MAX_PRFILES 256
2806 qfile_t *pr_files[MAX_PRFILES];
2808 void PR_Files_Init(void)
2810 memset(pr_files, 0, sizeof(pr_files));
2813 void PR_Files_CloseAll(void)
2816 for (i = 0;i < MAX_PRFILES;i++)
2819 FS_Close(pr_files[i]);
2824 //float(string s) stof = #81; // get numerical value from a string
2827 char string[STRINGTEMP_LENGTH];
2828 PF_VarString(0, string, sizeof(string));
2829 G_FLOAT(OFS_RETURN) = atof(string);
2832 //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
2835 int filenum, mode, i;
2836 char *modestring, *filename;
2837 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2838 if (pr_files[filenum] == NULL)
2840 if (filenum >= MAX_PRFILES)
2842 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2843 G_FLOAT(OFS_RETURN) = -2;
2846 mode = G_FLOAT(OFS_PARM1);
2849 case 0: // FILE_READ
2852 case 1: // FILE_APPEND
2855 case 2: // FILE_WRITE
2859 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2860 G_FLOAT(OFS_RETURN) = -3;
2863 filename = G_STRING(OFS_PARM0);
2864 // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2865 // ../ is parent directory on many platforms
2866 // // is parent directory on Amiga
2867 // / at the beginning of a path is root on unix, and parent directory on Amiga
2868 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2869 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2870 for (i = 0;filename[i];i++)
2872 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2874 Con_Printf("PF_fopen: dangerous/confusing/annoying/non-portable filename \"%s\" not allowed. (contains control characters or // or .. or : or \\ or begins with /)\n", filename);
2875 G_FLOAT(OFS_RETURN) = -4;
2879 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2881 if (pr_files[filenum] == NULL && modestring == "rb")
2882 pr_files[filenum] = FS_Open(filename, modestring, false);
2884 if (pr_files[filenum] == NULL)
2885 G_FLOAT(OFS_RETURN) = -1;
2887 G_FLOAT(OFS_RETURN) = filenum;
2890 //void(float fhandle) fclose = #111; // closes a file
2891 void PF_fclose(void)
2893 int filenum = G_FLOAT(OFS_PARM0);
2894 if (filenum < 0 || filenum >= MAX_PRFILES)
2896 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2899 if (pr_files[filenum] == NULL)
2901 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2904 FS_Close(pr_files[filenum]);
2905 pr_files[filenum] = NULL;
2908 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2912 static char string[STRINGTEMP_LENGTH];
2913 int filenum = G_FLOAT(OFS_PARM0);
2914 if (filenum < 0 || filenum >= MAX_PRFILES)
2916 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2919 if (pr_files[filenum] == NULL)
2921 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2927 c = FS_Getc(pr_files[filenum]);
2928 if (c == '\r' || c == '\n' || c < 0)
2930 if (end < STRINGTEMP_LENGTH - 1)
2934 // remove \n following \r
2936 c = FS_Getc(pr_files[filenum]);
2937 if (developer.integer)
2938 Con_Printf("fgets: %s\n", string);
2940 G_INT(OFS_RETURN) = PR_SetString(string);
2942 G_INT(OFS_RETURN) = 0;
2945 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2949 char string[STRINGTEMP_LENGTH];
2950 int filenum = G_FLOAT(OFS_PARM0);
2951 if (filenum < 0 || filenum >= MAX_PRFILES)
2953 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2956 if (pr_files[filenum] == NULL)
2958 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2961 PF_VarString(1, string, sizeof(string));
2962 if ((stringlength = strlen(string)))
2963 FS_Write(pr_files[filenum], string, stringlength);
2964 if (developer.integer)
2965 Con_Printf("fputs: %s\n", string);
2968 //float(string s) strlen = #114; // returns how many characters are in a string
2969 void PF_strlen(void)
2972 s = G_STRING(OFS_PARM0);
2974 G_FLOAT(OFS_RETURN) = strlen(s);
2976 G_FLOAT(OFS_RETURN) = 0;
2979 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2980 void PF_strcat(void)
2982 char *s = PR_GetTempString();
2983 PF_VarString(0, s, STRINGTEMP_LENGTH);
2984 G_INT(OFS_RETURN) = PR_SetString(s);
2987 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2988 void PF_substring(void)
2990 int i, start, length;
2991 char *s, *string = PR_GetTempString();
2992 s = G_STRING(OFS_PARM0);
2993 start = G_FLOAT(OFS_PARM1);
2994 length = G_FLOAT(OFS_PARM2);
2997 for (i = 0;i < start && *s;i++, s++);
2998 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
3001 G_INT(OFS_RETURN) = PR_SetString(string);
3004 //vector(string s) stov = #117; // returns vector value from a string
3007 char string[STRINGTEMP_LENGTH];
3008 PF_VarString(0, string, sizeof(string));
3009 Math_atov(string, G_VECTOR(OFS_RETURN));
3012 //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)
3013 void PF_strzone(void)
3016 in = G_STRING(OFS_PARM0);
3017 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
3019 G_INT(OFS_RETURN) = PR_SetString(out);
3022 //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!!!)
3023 void PF_strunzone(void)
3025 Mem_Free(G_STRING(OFS_PARM0));
3028 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3029 //this function originally written by KrimZon, made shorter by LordHavoc
3030 void PF_clientcommand (void)
3032 client_t *temp_client;
3035 //find client for this entity
3036 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3037 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3039 Con_Print("PF_clientcommand: entity is not a client\n");
3043 temp_client = host_client;
3044 host_client = svs.clients + i;
3045 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3046 host_client = temp_client;
3049 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3050 //this function originally written by KrimZon, made shorter by LordHavoc
3051 //20040203: rewritten by LordHavoc (no longer uses allocations)
3053 char *tokens[256], tokenbuf[4096];
3054 void PF_tokenize (void)
3058 p = G_STRING(OFS_PARM0);
3062 while(COM_ParseToken(&p, false))
3064 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3066 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3068 tokens[num_tokens++] = tokenbuf + pos;
3069 strcpy(tokenbuf + pos, com_token);
3070 pos += strlen(com_token) + 1;
3073 G_FLOAT(OFS_RETURN) = num_tokens;
3076 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3077 //this function originally written by KrimZon, made shorter by LordHavoc
3080 int token_num = G_FLOAT(OFS_PARM0);
3081 if (token_num >= 0 && token_num < num_tokens)
3082 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3084 G_INT(OFS_RETURN) = PR_SetString("");
3087 //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)
3088 void PF_setattachment (void)
3090 edict_t *e = G_EDICT(OFS_PARM0);
3091 edict_t *tagentity = G_EDICT(OFS_PARM1);
3092 char *tagname = G_STRING(OFS_PARM2);
3098 PF_WARNING("setattachment: can not modify world entity\n");
3100 PF_WARNING("setattachment: can not modify free entity\n");
3102 if (tagentity == NULL)
3103 tagentity = sv.edicts;
3105 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3107 v->edict = EDICT_TO_PROG(tagentity);
3109 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3112 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3114 modelindex = (int)tagentity->v->modelindex;
3115 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3117 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3118 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3119 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3121 // FIXME: use a model function to get tag info (need to handle skeletal)
3122 if (v->_float == 0 && model->alias.aliasnum_tags)
3123 for (i = 0;i < model->alias.aliasnum_tags;i++)
3124 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3127 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", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity), model->name);
3130 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity));
3134 /////////////////////////////////////////
3135 // DP_MD3_TAGINFO extension coded by VorteX
3137 //float(entity ent, string tagname) gettagindex;
3138 void PF_gettagindex (void)
3140 edict_t *e = G_EDICT(OFS_PARM0);
3141 const char *tagname = G_STRING(OFS_PARM1);
3142 int modelindex, tagindex, i;
3146 PF_WARNING("gettagindex: can't affect world entity\n");
3148 PF_WARNING("gettagindex: can't affect free entity\n");
3150 modelindex = (int)e->v->modelindex;
3151 if (modelindex <= 0 || modelindex > MAX_MODELS)
3153 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3156 model = sv.models[modelindex];
3159 if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3161 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3163 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3172 for (i = 0;i < model->alias.aliasnum_tags; i++)
3174 if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3182 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(e), tagname);
3183 G_FLOAT(OFS_RETURN) = tagindex + 1;
3186 // Warnings/errors code:
3187 // 0 - normal (everything all-right)
3190 // 3 - null or non-precached model
3191 // 4 - no tags with requested index
3192 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3196 int modelindex, tagsnum, reqframe;
3197 matrix4x4_t entitymatrix, tagmatrix;
3200 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3202 if (ent == sv.edicts)
3207 modelindex = (int)ent->v->modelindex;
3208 if (modelindex <= 0 || modelindex > MAX_MODELS)
3211 model = sv.models[modelindex];
3212 tagsnum = model->alias.aliasnum_tags;
3214 if (tagindex <= 0 || tagindex > tagsnum)
3216 if (tagsnum && tagindex) // Only appear if model has no tags or not-null tag requested
3221 if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3222 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3224 reqframe = ent->v->frame;
3226 // just reusing a temp
3227 modelindex = (tagindex - 1) + ent->v->frame*tagsnum;
3229 // transform tag by its own entity matrix
3230 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[modelindex].matrix);
3231 // FIXME: add scale parameter
3233 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3234 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2], -ent->v->angles[0], ent->v->angles[1], ent->v->angles[2], scale);
3235 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3236 // True origin for rotation (Matrix4x4_Concat creates wrong), this is done using all rotation matrix
3237 out->m[0][3] = entitymatrix.m[0][3] + scale*tagmatrix.m[0][3]*(entitymatrix.m[0][0] + entitymatrix.m[0][1] + entitymatrix.m[0][2]);
3238 out->m[1][3] = entitymatrix.m[1][3] + scale*tagmatrix.m[1][3]*(entitymatrix.m[1][0] + entitymatrix.m[1][1] + entitymatrix.m[1][2]);
3239 out->m[2][3] = entitymatrix.m[2][3] + scale*tagmatrix.m[2][3]*(entitymatrix.m[2][0] + entitymatrix.m[2][1] + entitymatrix.m[2][2]);
3240 /* Optimised variant with only v_forward using
3241 out->m[0][3] = entitymatrix.m[0][3] + scale*entitymatrix.m[0][0]*tagmatrix.m[0][3];
3242 out->m[1][3] = entitymatrix.m[1][3] + scale*entitymatrix.m[1][0]*tagmatrix.m[1][3];
3243 out->m[2][3] = entitymatrix.m[2][3] + scale*entitymatrix.m[2][0]*tagmatrix.m[2][3];
3246 // additional actions for render-view entities
3247 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3248 {// RENDER_VIEWMODEL
3249 ent = EDICT_NUM(val->edict);
3250 // FIXME: "circle" bug, add bobbing (cl_bob), add scale parameter
3252 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2] + ent->v->view_ofs[2], ent->v->v_angle[0], ent->v->v_angle[1], ent->v->v_angle[2], scale);
3253 Matrix4x4_Concat(out, &entitymatrix, out);
3254 out->m[0][3] = entitymatrix.m[0][3] + scale*entitymatrix.m[0][0]*out->m[0][3];
3255 out->m[1][3] = entitymatrix.m[1][3] + scale*entitymatrix.m[1][0]*out->m[1][3];
3256 out->m[2][3] = entitymatrix.m[2][3] + scale*entitymatrix.m[2][0]*out->m[2][3];
3257 Con_DPrintf("SV_GetTagMatrix: returned origin is %f %f %f\n", out->m[0][3], out->m[1][3], out->m[2][3]);
3260 // RENDER_VIEWMODEL can't be attached by tag, right?
3261 val = GETEDICTFIELDVALUE(ent, eval_tag_entity);
3263 {// DP_GFX_QUAKE3MODELTAGS
3266 ent = EDICT_NUM(val->edict);
3267 // FIXME: add scale parameter
3268 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2], -ent->v->angles[0], ent->v->angles[1], ent->v->angles[2], scale);
3269 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3270 // True origin for rotation (Matrix4x4_Concat creates wrong), this is done using all rotation matrix
3271 out->m[0][3] = entitymatrix.m[0][3] + scale*tagmatrix.m[0][3]*(entitymatrix.m[0][0] + entitymatrix.m[0][1] + entitymatrix.m[0][2]);
3272 out->m[1][3] = entitymatrix.m[1][3] + scale*tagmatrix.m[1][3]*(entitymatrix.m[1][0] + entitymatrix.m[1][1] + entitymatrix.m[1][2]);
3273 out->m[2][3] = entitymatrix.m[2][3] + scale*tagmatrix.m[2][3]*(entitymatrix.m[2][0] + entitymatrix.m[2][1] + entitymatrix.m[2][2]);
3275 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3280 //vector(entity ent, float tagindex) gettaginfo;
3281 void PF_gettaginfo (void)
3283 edict_t *e = G_EDICT(OFS_PARM0);
3284 int tagindex = (int)G_FLOAT(OFS_PARM1);
3285 matrix4x4_t tag_matrix;
3288 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3289 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3294 PF_WARNING("gettagindex: can't affect world entity\n");
3297 PF_WARNING("gettagindex: can't affect free entity\n");
3300 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3303 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3309 /////////////////////////////////////////
3310 // DP_QC_FS_SEARCH extension
3312 // qc fs search handling
3313 #define MAX_SEARCHES 128
3315 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3317 void PR_Search_Init(void)
3319 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3322 void PR_Search_Reset(void)
3325 // reset the fssearch list
3326 for(i = 0; i < MAX_SEARCHES; i++)
3327 if(pr_fssearchlist[i])
3328 FS_FreeSearch(pr_fssearchlist[i]);
3329 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3336 float search_begin(string pattern, float caseinsensitive, float quiet)
3339 void PF_search_begin(void)
3343 int caseinsens, quiet;
3345 pattern = G_STRING(OFS_PARM0);
3347 PR_CheckEmptyString(pattern);
3349 caseinsens = G_FLOAT(OFS_PARM1);
3350 quiet = G_FLOAT(OFS_PARM2);
3352 for(handle = 0; handle < MAX_SEARCHES; handle++)
3353 if(!pr_fssearchlist[handle])
3356 if(handle >= MAX_SEARCHES)
3358 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3359 G_FLOAT(OFS_RETURN) = -2;
3363 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3364 G_FLOAT(OFS_RETURN) = -1;
3366 G_FLOAT(OFS_RETURN) = handle;
3373 void search_end(float handle)
3376 void PF_search_end(void)
3380 handle = G_FLOAT(OFS_PARM0);
3382 if(handle < 0 || handle >= MAX_SEARCHES)
3384 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3387 if(pr_fssearchlist[handle] == NULL)
3389 Con_Printf("PF_search_end: no such handle %i\n", handle);
3393 FS_FreeSearch(pr_fssearchlist[handle]);
3394 pr_fssearchlist[handle] = NULL;
3401 float search_getsize(float handle)
3404 void PF_search_getsize(void)
3408 handle = G_FLOAT(OFS_PARM0);
3410 if(handle < 0 || handle >= MAX_SEARCHES)
3412 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3415 if(pr_fssearchlist[handle] == NULL)
3417 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3421 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3426 VM_search_getfilename
3428 string search_getfilename(float handle, float num)
3431 void PF_search_getfilename(void)
3433 int handle, filenum;
3436 handle = G_FLOAT(OFS_PARM0);
3437 filenum = G_FLOAT(OFS_PARM1);
3439 if(handle < 0 || handle >= MAX_SEARCHES)
3441 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3444 if(pr_fssearchlist[handle] == NULL)
3446 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3449 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3451 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3455 tmp = PR_GetTempString();
3456 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3458 G_INT(OFS_RETURN) = PR_SetString(tmp);
3461 void PF_cvar_string (void)
3467 str = G_STRING(OFS_PARM0);
3468 var = Cvar_FindVar (str);
3471 tmp = PR_GetTempString();
3472 strcpy(tmp, var->string);
3476 G_INT(OFS_RETURN) = PR_SetString(tmp);
3481 builtin_t pr_builtin[] =
3484 PF_makevectors, // #1 void(entity e) makevectors
3485 PF_setorigin, // #2 void(entity e, vector o) setorigin
3486 PF_setmodel, // #3 void(entity e, string m) setmodel
3487 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3488 NULL, // #5 void(entity e, vector min, vector max) setabssize
3489 PF_break, // #6 void() break
3490 PF_random, // #7 float() random
3491 PF_sound, // #8 void(entity e, float chan, string samp) sound
3492 PF_normalize, // #9 vector(vector v) normalize
3493 PF_error, // #10 void(string e) error
3494 PF_objerror, // #11 void(string e) objerror
3495 PF_vlen, // #12 float(vector v) vlen
3496 PF_vectoyaw, // #13 float(vector v) vectoyaw
3497 PF_Spawn, // #14 entity() spawn
3498 PF_Remove, // #15 void(entity e) remove
3499 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3500 PF_checkclient, // #17 entity() clientlist
3501 PF_Find, // #18 entity(entity start, .string fld, string match) find
3502 PF_precache_sound, // #19 void(string s) precache_sound
3503 PF_precache_model, // #20 void(string s) precache_model
3504 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3505 PF_findradius, // #22 entity(vector org, float rad) findradius
3506 PF_bprint, // #23 void(string s) bprint
3507 PF_sprint, // #24 void(entity client, string s) sprint
3508 PF_dprint, // #25 void(string s) dprint
3509 PF_ftos, // #26 void(string s) ftos
3510 PF_vtos, // #27 void(string s) vtos
3511 PF_coredump, // #28 void() coredump
3512 PF_traceon, // #29 void() traceon
3513 PF_traceoff, // #30 void() traceoff
3514 PF_eprint, // #31 void(entity e) eprint
3515 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3517 PF_droptofloor, // #34 float() droptofloor
3518 PF_lightstyle, // #35 void(float style, string value) lightstyle
3519 PF_rint, // #36 float(float v) rint
3520 PF_floor, // #37 float(float v) floor
3521 PF_ceil, // #38 float(float v) ceil
3523 PF_checkbottom, // #40 float(entity e) checkbottom
3524 PF_pointcontents , // #41 float(vector v) pointcontents
3526 PF_fabs, // #43 float(float f) fabs
3527 PF_aim, // #44 vector(entity e, float speed) aim
3528 PF_cvar, // #45 float(string s) cvar
3529 PF_localcmd, // #46 void(string s) localcmd
3530 PF_nextent, // #47 entity(entity e) nextent
3531 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3532 PF_changeyaw, // #49 void() ChangeYaw
3534 PF_vectoangles, // #51 vector(vector v) vectoangles
3535 PF_WriteByte, // #52 void(float to, float f) WriteByte
3536 PF_WriteChar, // #53 void(float to, float f) WriteChar
3537 PF_WriteShort, // #54 void(float to, float f) WriteShort
3538 PF_WriteLong, // #55 void(float to, float f) WriteLong
3539 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3540 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3541 PF_WriteString, // #58 void(float to, string s) WriteString
3542 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3543 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3544 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3545 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3546 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3547 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3548 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3550 SV_MoveToGoal, // #67 void(float step) movetogoal
3551 PF_precache_file, // #68 string(string s) precache_file
3552 PF_makestatic, // #69 void(entity e) makestatic
3553 PF_changelevel, // #70 void(string s) changelevel
3555 PF_cvar_set, // #72 void(string var, string val) cvar_set
3556 PF_centerprint, // #73 void(entity client, strings) centerprint
3557 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3558 PF_precache_model, // #75 string(string s) precache_model2
3559 PF_precache_sound, // #76 string(string s) precache_sound2
3560 PF_precache_file, // #77 string(string s) precache_file2
3561 PF_setspawnparms, // #78 void(entity e) setspawnparms
3564 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3573 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3574 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3575 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3576 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3577 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3578 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3579 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3580 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3581 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3582 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3593 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3594 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3595 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3596 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3597 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3598 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3599 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3600 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3601 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3602 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3603 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3604 a a a a a a a a // #120-199
3605 a a a a a a a a a a // #200-299
3606 a a a a a a a a a a // #300-399
3607 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3608 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3609 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3610 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3611 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3612 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3613 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3614 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3615 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3616 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3617 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3618 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3619 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3620 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3621 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3622 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3623 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3624 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3625 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3626 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3627 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3628 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3629 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3630 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3631 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3632 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3633 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3634 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3635 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3636 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3637 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3638 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3639 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3640 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3641 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3642 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3643 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3644 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3645 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3646 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3647 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3648 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3649 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3650 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3651 PF_search_begin, // #444
3652 PF_search_end, // #445
3653 PF_search_getsize, // #446
3654 PF_search_getfilename, // #447
3655 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3656 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3657 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3658 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3659 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3667 a a a a // #460-499 (LordHavoc)
3670 builtin_t *pr_builtins = pr_builtin;
3671 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3673 void PR_Cmd_Init(void)
3675 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3680 void PR_Cmd_Reset(void)
3682 Mem_EmptyPool(pr_strings_mempool);
3684 PR_Files_CloseAll();