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;
2223 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2225 client->edict->v->team = (i & 15) + 1;
2228 if (client->old_colors != client->colors)
2230 client->old_colors = client->colors;
2231 // send notification to all clients
2232 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2233 MSG_WriteByte (&sv.reliable_datagram, client->number);
2234 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2242 effect(origin, modelname, startframe, framecount, framerate)
2245 void PF_effect (void)
2249 s = G_STRING(OFS_PARM1);
2251 PF_WARNING("effect: no model specified\n");
2253 i = SV_ModelIndex(s);
2255 PF_WARNING("effect: model not precached\n");
2256 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2259 void PF_te_blood (void)
2261 if (G_FLOAT(OFS_PARM2) < 1)
2263 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2264 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2266 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2267 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2268 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2270 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2271 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2272 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2274 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2277 void PF_te_bloodshower (void)
2279 if (G_FLOAT(OFS_PARM3) < 1)
2281 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2282 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2284 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2285 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2286 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2288 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2289 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2290 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2292 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2294 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2297 void PF_te_explosionrgb (void)
2299 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2300 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2302 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2303 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2304 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2306 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2307 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2308 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2311 void PF_te_particlecube (void)
2313 if (G_FLOAT(OFS_PARM3) < 1)
2315 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2316 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2318 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2319 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2320 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2322 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2323 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2324 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2326 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2327 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2328 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2330 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2332 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2333 // gravity true/false
2334 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2336 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2339 void PF_te_particlerain (void)
2341 if (G_FLOAT(OFS_PARM3) < 1)
2343 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2344 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2346 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2347 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2348 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2350 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2351 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2352 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2354 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2355 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2356 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2358 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2360 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2363 void PF_te_particlesnow (void)
2365 if (G_FLOAT(OFS_PARM3) < 1)
2367 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2368 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2370 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2371 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2372 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2374 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2375 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2376 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2378 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2379 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2380 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2382 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2384 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2387 void PF_te_spark (void)
2389 if (G_FLOAT(OFS_PARM2) < 1)
2391 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2392 MSG_WriteByte(&sv.datagram, TE_SPARK);
2394 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2395 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2396 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2398 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2399 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2400 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2402 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2405 void PF_te_gunshotquad (void)
2407 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2408 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2410 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2411 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2412 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2415 void PF_te_spikequad (void)
2417 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2418 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2420 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2421 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2422 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2425 void PF_te_superspikequad (void)
2427 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2428 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2430 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2431 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2432 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2435 void PF_te_explosionquad (void)
2437 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2438 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2440 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2441 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2442 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2445 void PF_te_smallflash (void)
2447 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2448 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2450 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2451 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2452 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2455 void PF_te_customflash (void)
2457 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2459 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2460 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2462 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2463 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2464 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2466 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2468 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2470 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2471 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2472 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2475 void PF_te_gunshot (void)
2477 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2478 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2480 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2481 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2482 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2485 void PF_te_spike (void)
2487 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2488 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2490 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2491 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2492 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2495 void PF_te_superspike (void)
2497 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2498 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2500 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2501 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2502 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2505 void PF_te_explosion (void)
2507 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2508 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2510 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2511 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2512 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2515 void PF_te_tarexplosion (void)
2517 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2518 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2520 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2521 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2522 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2525 void PF_te_wizspike (void)
2527 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2528 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2530 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2531 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2532 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2535 void PF_te_knightspike (void)
2537 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2538 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2540 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2541 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2542 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2545 void PF_te_lavasplash (void)
2547 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2548 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2550 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2551 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2552 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2555 void PF_te_teleport (void)
2557 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2558 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2560 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2561 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2562 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2565 void PF_te_explosion2 (void)
2567 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2568 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2570 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2571 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2572 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2574 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2575 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2578 void PF_te_lightning1 (void)
2580 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2581 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2583 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2585 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2586 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2587 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2589 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2590 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2591 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2594 void PF_te_lightning2 (void)
2596 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2597 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2599 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2601 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2602 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2603 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2605 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2606 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2607 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2610 void PF_te_lightning3 (void)
2612 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2613 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2615 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2617 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2618 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2619 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2621 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2622 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2623 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2626 void PF_te_beam (void)
2628 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2629 MSG_WriteByte(&sv.datagram, TE_BEAM);
2631 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2633 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2634 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2635 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2637 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2638 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2639 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2642 void PF_te_plasmaburn (void)
2644 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2645 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2646 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2647 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2648 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2651 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2654 vec3_t v1, clipplanenormal, normal;
2655 vec_t clipplanedist, clipdist;
2657 if (surf->flags & SURF_PLANEBACK)
2658 VectorNegate(surf->plane->normal, normal);
2660 VectorCopy(surf->plane->normal, normal);
2661 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2663 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2664 VectorNormalizeFast(v1);
2665 CrossProduct(v1, normal, clipplanenormal);
2666 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2667 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2670 clipdist = -clipdist;
2671 VectorMA(out, clipdist, clipplanenormal, out);
2676 static msurface_t *getsurface(edict_t *ed, int surfnum)
2680 if (!ed || ed->e->free)
2682 modelindex = ed->v->modelindex;
2683 if (modelindex < 1 || modelindex >= MAX_MODELS)
2685 model = sv.models[modelindex];
2686 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2688 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2692 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2693 void PF_getsurfacenumpoints(void)
2696 // return 0 if no such surface
2697 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2699 G_FLOAT(OFS_RETURN) = 0;
2703 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2705 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2706 void PF_getsurfacepoint(void)
2711 VectorClear(G_VECTOR(OFS_RETURN));
2712 ed = G_EDICT(OFS_PARM0);
2713 if (!ed || ed->e->free)
2715 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2717 pointnum = G_FLOAT(OFS_PARM2);
2718 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2720 // FIXME: implement rotation/scaling
2721 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2723 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2724 void PF_getsurfacenormal(void)
2727 VectorClear(G_VECTOR(OFS_RETURN));
2728 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2730 // FIXME: implement rotation/scaling
2731 if (surf->flags & SURF_PLANEBACK)
2732 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2734 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2736 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2737 void PF_getsurfacetexture(void)
2740 G_INT(OFS_RETURN) = 0;
2741 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2743 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2745 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2746 void PF_getsurfacenearpoint(void)
2748 int surfnum, best, modelindex;
2750 vec_t dist, bestdist;
2755 G_FLOAT(OFS_RETURN) = -1;
2756 ed = G_EDICT(OFS_PARM0);
2757 point = G_VECTOR(OFS_PARM1);
2759 if (!ed || ed->e->free)
2761 modelindex = ed->v->modelindex;
2762 if (modelindex < 1 || modelindex >= MAX_MODELS)
2764 model = sv.models[modelindex];
2765 if (!model->brushq1.numsurfaces)
2768 // FIXME: implement rotation/scaling
2769 VectorSubtract(point, ed->v->origin, p);
2771 bestdist = 1000000000;
2772 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2774 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2775 dist = PlaneDiff(p, surf->plane);
2777 if (dist < bestdist)
2779 clippointtosurface(surf, p, clipped);
2780 VectorSubtract(clipped, p, clipped);
2781 dist += DotProduct(clipped, clipped);
2782 if (dist < bestdist)
2789 G_FLOAT(OFS_RETURN) = best;
2791 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2792 void PF_getsurfaceclippedpoint(void)
2797 VectorClear(G_VECTOR(OFS_RETURN));
2798 ed = G_EDICT(OFS_PARM0);
2799 if (!ed || ed->e->free)
2801 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2803 // FIXME: implement rotation/scaling
2804 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2805 clippointtosurface(surf, p, out);
2806 // FIXME: implement rotation/scaling
2807 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2810 #define MAX_PRFILES 256
2812 qfile_t *pr_files[MAX_PRFILES];
2814 void PR_Files_Init(void)
2816 memset(pr_files, 0, sizeof(pr_files));
2819 void PR_Files_CloseAll(void)
2822 for (i = 0;i < MAX_PRFILES;i++)
2825 FS_Close(pr_files[i]);
2830 //float(string s) stof = #81; // get numerical value from a string
2833 char string[STRINGTEMP_LENGTH];
2834 PF_VarString(0, string, sizeof(string));
2835 G_FLOAT(OFS_RETURN) = atof(string);
2838 //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
2841 int filenum, mode, i;
2842 char *modestring, *filename;
2843 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2844 if (pr_files[filenum] == NULL)
2846 if (filenum >= MAX_PRFILES)
2848 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2849 G_FLOAT(OFS_RETURN) = -2;
2852 mode = G_FLOAT(OFS_PARM1);
2855 case 0: // FILE_READ
2858 case 1: // FILE_APPEND
2861 case 2: // FILE_WRITE
2865 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2866 G_FLOAT(OFS_RETURN) = -3;
2869 filename = G_STRING(OFS_PARM0);
2870 // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2871 // ../ is parent directory on many platforms
2872 // // is parent directory on Amiga
2873 // / at the beginning of a path is root on unix, and parent directory on Amiga
2874 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2875 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2876 for (i = 0;filename[i];i++)
2878 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2880 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);
2881 G_FLOAT(OFS_RETURN) = -4;
2885 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2887 if (pr_files[filenum] == NULL && modestring == "rb")
2888 pr_files[filenum] = FS_Open(filename, modestring, false);
2890 if (pr_files[filenum] == NULL)
2891 G_FLOAT(OFS_RETURN) = -1;
2893 G_FLOAT(OFS_RETURN) = filenum;
2896 //void(float fhandle) fclose = #111; // closes a file
2897 void PF_fclose(void)
2899 int filenum = G_FLOAT(OFS_PARM0);
2900 if (filenum < 0 || filenum >= MAX_PRFILES)
2902 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2905 if (pr_files[filenum] == NULL)
2907 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2910 FS_Close(pr_files[filenum]);
2911 pr_files[filenum] = NULL;
2914 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2918 static char string[STRINGTEMP_LENGTH];
2919 int filenum = G_FLOAT(OFS_PARM0);
2920 if (filenum < 0 || filenum >= MAX_PRFILES)
2922 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2925 if (pr_files[filenum] == NULL)
2927 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2933 c = FS_Getc(pr_files[filenum]);
2934 if (c == '\r' || c == '\n' || c < 0)
2936 if (end < STRINGTEMP_LENGTH - 1)
2940 // remove \n following \r
2942 c = FS_Getc(pr_files[filenum]);
2943 if (developer.integer)
2944 Con_Printf("fgets: %s\n", string);
2946 G_INT(OFS_RETURN) = PR_SetString(string);
2948 G_INT(OFS_RETURN) = 0;
2951 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2955 char string[STRINGTEMP_LENGTH];
2956 int filenum = G_FLOAT(OFS_PARM0);
2957 if (filenum < 0 || filenum >= MAX_PRFILES)
2959 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2962 if (pr_files[filenum] == NULL)
2964 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2967 PF_VarString(1, string, sizeof(string));
2968 if ((stringlength = strlen(string)))
2969 FS_Write(pr_files[filenum], string, stringlength);
2970 if (developer.integer)
2971 Con_Printf("fputs: %s\n", string);
2974 //float(string s) strlen = #114; // returns how many characters are in a string
2975 void PF_strlen(void)
2978 s = G_STRING(OFS_PARM0);
2980 G_FLOAT(OFS_RETURN) = strlen(s);
2982 G_FLOAT(OFS_RETURN) = 0;
2985 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2986 void PF_strcat(void)
2988 char *s = PR_GetTempString();
2989 PF_VarString(0, s, STRINGTEMP_LENGTH);
2990 G_INT(OFS_RETURN) = PR_SetString(s);
2993 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2994 void PF_substring(void)
2996 int i, start, length;
2997 char *s, *string = PR_GetTempString();
2998 s = G_STRING(OFS_PARM0);
2999 start = G_FLOAT(OFS_PARM1);
3000 length = G_FLOAT(OFS_PARM2);
3003 for (i = 0;i < start && *s;i++, s++);
3004 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
3007 G_INT(OFS_RETURN) = PR_SetString(string);
3010 //vector(string s) stov = #117; // returns vector value from a string
3013 char string[STRINGTEMP_LENGTH];
3014 PF_VarString(0, string, sizeof(string));
3015 Math_atov(string, G_VECTOR(OFS_RETURN));
3018 //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)
3019 void PF_strzone(void)
3022 in = G_STRING(OFS_PARM0);
3023 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
3025 G_INT(OFS_RETURN) = PR_SetString(out);
3028 //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!!!)
3029 void PF_strunzone(void)
3031 Mem_Free(G_STRING(OFS_PARM0));
3034 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3035 //this function originally written by KrimZon, made shorter by LordHavoc
3036 void PF_clientcommand (void)
3038 client_t *temp_client;
3041 //find client for this entity
3042 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3043 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3045 Con_Print("PF_clientcommand: entity is not a client\n");
3049 temp_client = host_client;
3050 host_client = svs.clients + i;
3051 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3052 host_client = temp_client;
3055 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3056 //this function originally written by KrimZon, made shorter by LordHavoc
3057 //20040203: rewritten by LordHavoc (no longer uses allocations)
3059 char *tokens[256], tokenbuf[4096];
3060 void PF_tokenize (void)
3064 p = G_STRING(OFS_PARM0);
3068 while(COM_ParseToken(&p, false))
3070 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3072 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3074 tokens[num_tokens++] = tokenbuf + pos;
3075 strcpy(tokenbuf + pos, com_token);
3076 pos += strlen(com_token) + 1;
3079 G_FLOAT(OFS_RETURN) = num_tokens;
3082 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3083 //this function originally written by KrimZon, made shorter by LordHavoc
3086 int token_num = G_FLOAT(OFS_PARM0);
3087 if (token_num >= 0 && token_num < num_tokens)
3088 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3090 G_INT(OFS_RETURN) = PR_SetString("");
3093 //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)
3094 void PF_setattachment (void)
3096 edict_t *e = G_EDICT(OFS_PARM0);
3097 edict_t *tagentity = G_EDICT(OFS_PARM1);
3098 char *tagname = G_STRING(OFS_PARM2);
3104 PF_WARNING("setattachment: can not modify world entity\n");
3106 PF_WARNING("setattachment: can not modify free entity\n");
3108 if (tagentity == NULL)
3109 tagentity = sv.edicts;
3111 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3113 v->edict = EDICT_TO_PROG(tagentity);
3115 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3118 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3120 modelindex = (int)tagentity->v->modelindex;
3121 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3123 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3124 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3125 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3127 // FIXME: use a model function to get tag info (need to handle skeletal)
3128 if (v->_float == 0 && model->alias.aliasnum_tags)
3129 for (i = 0;i < model->alias.aliasnum_tags;i++)
3130 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3133 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);
3136 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));
3140 /////////////////////////////////////////
3141 // DP_MD3_TAGINFO extension coded by VorteX
3143 //float(entity ent, string tagname) gettagindex;
3144 void PF_gettagindex (void)
3146 edict_t *e = G_EDICT(OFS_PARM0);
3147 const char *tagname = G_STRING(OFS_PARM1);
3148 int modelindex, tagindex, i;
3152 PF_WARNING("gettagindex: can't affect world entity\n");
3154 PF_WARNING("gettagindex: can't affect free entity\n");
3156 modelindex = (int)e->v->modelindex;
3157 if (modelindex <= 0 || modelindex > MAX_MODELS)
3159 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3162 model = sv.models[modelindex];
3165 if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3167 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3169 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3178 for (i = 0;i < model->alias.aliasnum_tags; i++)
3180 if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3188 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(e), tagname);
3189 G_FLOAT(OFS_RETURN) = tagindex + 1;
3192 // Warnings/errors code:
3193 // 0 - normal (everything all-right)
3196 // 3 - null or non-precached model
3197 // 4 - no tags with requested index
3198 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3202 int modelindex, tagsnum, reqframe;
3203 matrix4x4_t entitymatrix, tagmatrix;
3206 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3208 if (ent == sv.edicts)
3213 modelindex = (int)ent->v->modelindex;
3214 if (modelindex <= 0 || modelindex > MAX_MODELS)
3217 model = sv.models[modelindex];
3218 tagsnum = model->alias.aliasnum_tags;
3220 if (tagindex <= 0 || tagindex > tagsnum)
3222 if (tagsnum && tagindex) // Only appear if model has no tags or not-null tag requested
3227 if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3228 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
3230 reqframe = ent->v->frame;
3232 // just reusing a temp
3233 modelindex = (tagindex - 1) + ent->v->frame*tagsnum;
3235 // transform tag by its own entity matrix
3236 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[modelindex].matrix);
3237 // FIXME: add scale parameter
3239 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3240 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);
3241 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3242 // True origin for rotation (Matrix4x4_Concat creates wrong), this is done using all rotation matrix
3243 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]);
3244 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]);
3245 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]);
3246 /* Optimised variant with only v_forward using
3247 out->m[0][3] = entitymatrix.m[0][3] + scale*entitymatrix.m[0][0]*tagmatrix.m[0][3];
3248 out->m[1][3] = entitymatrix.m[1][3] + scale*entitymatrix.m[1][0]*tagmatrix.m[1][3];
3249 out->m[2][3] = entitymatrix.m[2][3] + scale*entitymatrix.m[2][0]*tagmatrix.m[2][3];
3252 // additional actions for render-view entities
3253 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3254 {// RENDER_VIEWMODEL
3255 ent = EDICT_NUM(val->edict);
3256 // FIXME: "circle" bug, add bobbing (cl_bob), add scale parameter
3258 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);
3259 Matrix4x4_Concat(out, &entitymatrix, out);
3260 out->m[0][3] = entitymatrix.m[0][3] + scale*entitymatrix.m[0][0]*out->m[0][3];
3261 out->m[1][3] = entitymatrix.m[1][3] + scale*entitymatrix.m[1][0]*out->m[1][3];
3262 out->m[2][3] = entitymatrix.m[2][3] + scale*entitymatrix.m[2][0]*out->m[2][3];
3263 Con_DPrintf("SV_GetTagMatrix: returned origin is %f %f %f\n", out->m[0][3], out->m[1][3], out->m[2][3]);
3266 // RENDER_VIEWMODEL can't be attached by tag, right?
3267 val = GETEDICTFIELDVALUE(ent, eval_tag_entity);
3269 {// DP_GFX_QUAKE3MODELTAGS
3272 ent = EDICT_NUM(val->edict);
3273 // FIXME: add scale parameter
3274 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);
3275 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3276 // True origin for rotation (Matrix4x4_Concat creates wrong), this is done using all rotation matrix
3277 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]);
3278 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]);
3279 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]);
3281 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3286 //vector(entity ent, float tagindex) gettaginfo;
3287 void PF_gettaginfo (void)
3289 edict_t *e = G_EDICT(OFS_PARM0);
3290 int tagindex = (int)G_FLOAT(OFS_PARM1);
3291 matrix4x4_t tag_matrix;
3294 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3295 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3300 PF_WARNING("gettagindex: can't affect world entity\n");
3303 PF_WARNING("gettagindex: can't affect free entity\n");
3306 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3309 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3315 /////////////////////////////////////////
3316 // DP_QC_FS_SEARCH extension
3318 // qc fs search handling
3319 #define MAX_SEARCHES 128
3321 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3323 void PR_Search_Init(void)
3325 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3328 void PR_Search_Reset(void)
3331 // reset the fssearch list
3332 for(i = 0; i < MAX_SEARCHES; i++)
3333 if(pr_fssearchlist[i])
3334 FS_FreeSearch(pr_fssearchlist[i]);
3335 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3342 float search_begin(string pattern, float caseinsensitive, float quiet)
3345 void PF_search_begin(void)
3349 int caseinsens, quiet;
3351 pattern = G_STRING(OFS_PARM0);
3353 PR_CheckEmptyString(pattern);
3355 caseinsens = G_FLOAT(OFS_PARM1);
3356 quiet = G_FLOAT(OFS_PARM2);
3358 for(handle = 0; handle < MAX_SEARCHES; handle++)
3359 if(!pr_fssearchlist[handle])
3362 if(handle >= MAX_SEARCHES)
3364 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3365 G_FLOAT(OFS_RETURN) = -2;
3369 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3370 G_FLOAT(OFS_RETURN) = -1;
3372 G_FLOAT(OFS_RETURN) = handle;
3379 void search_end(float handle)
3382 void PF_search_end(void)
3386 handle = G_FLOAT(OFS_PARM0);
3388 if(handle < 0 || handle >= MAX_SEARCHES)
3390 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3393 if(pr_fssearchlist[handle] == NULL)
3395 Con_Printf("PF_search_end: no such handle %i\n", handle);
3399 FS_FreeSearch(pr_fssearchlist[handle]);
3400 pr_fssearchlist[handle] = NULL;
3407 float search_getsize(float handle)
3410 void PF_search_getsize(void)
3414 handle = G_FLOAT(OFS_PARM0);
3416 if(handle < 0 || handle >= MAX_SEARCHES)
3418 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3421 if(pr_fssearchlist[handle] == NULL)
3423 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3427 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3432 VM_search_getfilename
3434 string search_getfilename(float handle, float num)
3437 void PF_search_getfilename(void)
3439 int handle, filenum;
3442 handle = G_FLOAT(OFS_PARM0);
3443 filenum = G_FLOAT(OFS_PARM1);
3445 if(handle < 0 || handle >= MAX_SEARCHES)
3447 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3450 if(pr_fssearchlist[handle] == NULL)
3452 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3455 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3457 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3461 tmp = PR_GetTempString();
3462 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3464 G_INT(OFS_RETURN) = PR_SetString(tmp);
3467 void PF_cvar_string (void)
3473 str = G_STRING(OFS_PARM0);
3474 var = Cvar_FindVar (str);
3477 tmp = PR_GetTempString();
3478 strcpy(tmp, var->string);
3482 G_INT(OFS_RETURN) = PR_SetString(tmp);
3487 builtin_t pr_builtin[] =
3490 PF_makevectors, // #1 void(entity e) makevectors
3491 PF_setorigin, // #2 void(entity e, vector o) setorigin
3492 PF_setmodel, // #3 void(entity e, string m) setmodel
3493 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3494 NULL, // #5 void(entity e, vector min, vector max) setabssize
3495 PF_break, // #6 void() break
3496 PF_random, // #7 float() random
3497 PF_sound, // #8 void(entity e, float chan, string samp) sound
3498 PF_normalize, // #9 vector(vector v) normalize
3499 PF_error, // #10 void(string e) error
3500 PF_objerror, // #11 void(string e) objerror
3501 PF_vlen, // #12 float(vector v) vlen
3502 PF_vectoyaw, // #13 float(vector v) vectoyaw
3503 PF_Spawn, // #14 entity() spawn
3504 PF_Remove, // #15 void(entity e) remove
3505 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3506 PF_checkclient, // #17 entity() clientlist
3507 PF_Find, // #18 entity(entity start, .string fld, string match) find
3508 PF_precache_sound, // #19 void(string s) precache_sound
3509 PF_precache_model, // #20 void(string s) precache_model
3510 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3511 PF_findradius, // #22 entity(vector org, float rad) findradius
3512 PF_bprint, // #23 void(string s) bprint
3513 PF_sprint, // #24 void(entity client, string s) sprint
3514 PF_dprint, // #25 void(string s) dprint
3515 PF_ftos, // #26 void(string s) ftos
3516 PF_vtos, // #27 void(string s) vtos
3517 PF_coredump, // #28 void() coredump
3518 PF_traceon, // #29 void() traceon
3519 PF_traceoff, // #30 void() traceoff
3520 PF_eprint, // #31 void(entity e) eprint
3521 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3523 PF_droptofloor, // #34 float() droptofloor
3524 PF_lightstyle, // #35 void(float style, string value) lightstyle
3525 PF_rint, // #36 float(float v) rint
3526 PF_floor, // #37 float(float v) floor
3527 PF_ceil, // #38 float(float v) ceil
3529 PF_checkbottom, // #40 float(entity e) checkbottom
3530 PF_pointcontents , // #41 float(vector v) pointcontents
3532 PF_fabs, // #43 float(float f) fabs
3533 PF_aim, // #44 vector(entity e, float speed) aim
3534 PF_cvar, // #45 float(string s) cvar
3535 PF_localcmd, // #46 void(string s) localcmd
3536 PF_nextent, // #47 entity(entity e) nextent
3537 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3538 PF_changeyaw, // #49 void() ChangeYaw
3540 PF_vectoangles, // #51 vector(vector v) vectoangles
3541 PF_WriteByte, // #52 void(float to, float f) WriteByte
3542 PF_WriteChar, // #53 void(float to, float f) WriteChar
3543 PF_WriteShort, // #54 void(float to, float f) WriteShort
3544 PF_WriteLong, // #55 void(float to, float f) WriteLong
3545 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3546 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3547 PF_WriteString, // #58 void(float to, string s) WriteString
3548 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3549 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3550 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3551 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3552 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3553 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3554 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3556 SV_MoveToGoal, // #67 void(float step) movetogoal
3557 PF_precache_file, // #68 string(string s) precache_file
3558 PF_makestatic, // #69 void(entity e) makestatic
3559 PF_changelevel, // #70 void(string s) changelevel
3561 PF_cvar_set, // #72 void(string var, string val) cvar_set
3562 PF_centerprint, // #73 void(entity client, strings) centerprint
3563 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3564 PF_precache_model, // #75 string(string s) precache_model2
3565 PF_precache_sound, // #76 string(string s) precache_sound2
3566 PF_precache_file, // #77 string(string s) precache_file2
3567 PF_setspawnparms, // #78 void(entity e) setspawnparms
3570 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3579 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3580 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3581 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3582 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3583 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3584 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3585 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3586 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3587 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3588 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3599 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3600 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3601 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3602 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3603 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3604 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3605 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3606 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3607 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3608 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3609 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3610 a a a a a a a a // #120-199
3611 a a a a a a a a a a // #200-299
3612 a a a a a a a a a a // #300-399
3613 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3614 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3615 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3616 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3617 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3618 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3619 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3620 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3621 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3622 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3623 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3624 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3625 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3626 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3627 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3628 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3629 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3630 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3631 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3632 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3633 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3634 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3635 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3636 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3637 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3638 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3639 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3640 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3641 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3642 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3643 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3644 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3645 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3646 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3647 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3648 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3649 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3650 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3651 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3652 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3653 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3654 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3655 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3656 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3657 PF_search_begin, // #444
3658 PF_search_end, // #445
3659 PF_search_getsize, // #446
3660 PF_search_getfilename, // #447
3661 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3662 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3663 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3664 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3665 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3673 a a a a // #460-499 (LordHavoc)
3676 builtin_t *pr_builtins = pr_builtin;
3677 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3679 void PR_Cmd_Init(void)
3681 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3686 void PR_Cmd_Reset(void)
3688 Mem_EmptyPool(pr_strings_mempool);
3690 PR_Files_CloseAll();