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 =
86 "DP_ENT_CUSTOMCOLORMAP "
87 "DP_ENT_EXTERIORMODELTOCLIENT "
89 "DP_ENT_LOWPRECISION "
92 "DP_GFX_EXTERNALTEXTURES "
94 "DP_GFX_QUAKE3MODELTAGS "
98 "DP_HALFLIFE_MAP_CVAR "
103 "DP_MOVETYPEBOUNCEMISSILE "
110 "DP_QC_FINDCHAINFLAGS "
111 "DP_QC_FINDCHAINFLOAT "
114 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
119 "DP_QC_MULTIPLETEMPSTRINGS "
121 "DP_QC_SINCOSSQRTPOW "
124 "DP_QC_TRACE_MOVETYPE_HITMODEL "
125 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
126 "DP_QC_VECTORVECTORS "
130 "DP_SND_DIRECTIONLESSATTNNONE "
136 "DP_SV_CLIENTCOLORS "
138 "DP_SV_DRAWONLYTOCLIENT "
141 "DP_SV_NODRAWTOCLIENT "
143 "DP_SV_PLAYERPHYSICS "
145 "DP_SV_ROTATINGBMODEL "
151 "DP_TE_EXPLOSIONRGB "
153 "DP_TE_PARTICLECUBE "
154 "DP_TE_PARTICLERAIN "
155 "DP_TE_PARTICLESNOW "
157 "DP_TE_QUADEFFECTS1 "
160 "DP_TE_STANDARDEFFECTBUILTINS "
163 "KRIMZON_SV_PARSECLIENTCOMMAND "
167 "TENEBRAE_GFX_DLIGHTS "
171 qboolean checkextension(char *name)
176 for (e = ENGINE_EXTENSIONS;*e;e++)
183 while (*e && *e != ' ')
185 if (e - start == len)
186 if (!strncasecmp(start, name, len))
196 returns true if the extension is supported by the server
198 checkextension(extensionname)
201 void PF_checkextension (void)
203 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
210 This is a TERMINAL error, which will kill off the entire server.
219 char string[STRINGTEMP_LENGTH];
221 PF_VarString(0, string, sizeof(string));
222 Con_Printf("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
223 ed = PROG_TO_EDICT(pr_global_struct->self);
226 PF_ERROR("Program error");
233 Dumps out self, then an error message. The program is aborted and self is
234 removed, but the level can continue.
239 void PF_objerror (void)
242 char string[STRINGTEMP_LENGTH];
244 PF_VarString(0, string, sizeof(string));
245 Con_Printf("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string);
246 ed = PROG_TO_EDICT(pr_global_struct->self);
256 Writes new values for v_forward, v_up, and v_right based on angles
260 void PF_makevectors (void)
262 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
269 Writes new values for v_forward, v_up, and v_right based on the given forward vector
270 vectorvectors(vector, vector)
273 void PF_vectorvectors (void)
275 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
276 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
283 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.
285 setorigin (entity, origin)
288 void PF_setorigin (void)
293 e = G_EDICT(OFS_PARM0);
295 PF_WARNING("setorigin: can not modify world entity\n");
297 PF_WARNING("setorigin: can not modify free entity\n");
298 org = G_VECTOR(OFS_PARM1);
299 VectorCopy (org, e->v->origin);
300 SV_LinkEdict (e, false);
304 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
308 for (i=0 ; i<3 ; i++)
310 PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
312 // set derived values
313 VectorCopy (min, e->v->mins);
314 VectorCopy (max, e->v->maxs);
315 VectorSubtract (max, min, e->v->size);
317 SV_LinkEdict (e, false);
324 the size box is rotated by the current angle
325 LordHavoc: no it isn't...
327 setsize (entity, minvector, maxvector)
330 void PF_setsize (void)
335 e = G_EDICT(OFS_PARM0);
337 PF_WARNING("setsize: can not modify world entity\n");
339 PF_WARNING("setsize: can not modify free entity\n");
340 min = G_VECTOR(OFS_PARM1);
341 max = G_VECTOR(OFS_PARM2);
342 SetMinMaxSize (e, min, max, false);
350 setmodel(entity, model)
353 void PF_setmodel (void)
360 e = G_EDICT(OFS_PARM0);
362 PF_WARNING("setmodel: can not modify world entity\n");
364 PF_WARNING("setmodel: can not modify free entity\n");
365 m = G_STRING(OFS_PARM1);
367 // check to see if model was properly precached
368 for (i=0, check = sv.model_precache ; *check ; i++, check++)
369 if (!strcmp(*check, m))
373 PF_WARNING(va("setmodel: no precache for model \"%s\"\n", m));
376 e->v->model = PR_SetString(*check);
377 e->v->modelindex = i;
379 mod = sv.models[ (int)e->v->modelindex];
382 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
384 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
391 broadcast print to everyone on server
396 void PF_bprint (void)
398 char string[STRINGTEMP_LENGTH];
399 PF_VarString(0, string, sizeof(string));
400 SV_BroadcastPrint(string);
407 single print to a specific client
409 sprint(clientent, value)
412 void PF_sprint (void)
416 char string[STRINGTEMP_LENGTH];
418 entnum = G_EDICTNUM(OFS_PARM0);
420 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
422 Con_Print("tried to sprint to a non-client\n");
426 client = svs.clients + entnum-1;
427 if (!client->netconnection)
429 PF_VarString(1, string, sizeof(string));
430 MSG_WriteChar(&client->message,svc_print);
431 MSG_WriteString(&client->message, string);
439 single print to a specific client
441 centerprint(clientent, value)
444 void PF_centerprint (void)
448 char string[STRINGTEMP_LENGTH];
450 entnum = G_EDICTNUM(OFS_PARM0);
452 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
454 Con_Print("tried to sprint to a non-client\n");
458 client = svs.clients + entnum-1;
459 if (!client->netconnection)
461 PF_VarString(1, string, sizeof(string));
462 MSG_WriteChar(&client->message,svc_centerprint);
463 MSG_WriteString(&client->message, string);
471 vector normalize(vector)
474 void PF_normalize (void)
480 value1 = G_VECTOR(OFS_PARM0);
482 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
486 newvalue[0] = newvalue[1] = newvalue[2] = 0;
490 newvalue[0] = value1[0] * new;
491 newvalue[1] = value1[1] * new;
492 newvalue[2] = value1[2] * new;
495 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
510 value1 = G_VECTOR(OFS_PARM0);
512 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
515 G_FLOAT(OFS_RETURN) = new;
522 float vectoyaw(vector)
525 void PF_vectoyaw (void)
530 value1 = G_VECTOR(OFS_PARM0);
532 if (value1[1] == 0 && value1[0] == 0)
536 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
541 G_FLOAT(OFS_RETURN) = yaw;
549 vector vectoangles(vector)
552 void PF_vectoangles (void)
554 double value1[3], forward, yaw, pitch;
556 VectorCopy(G_VECTOR(OFS_PARM0), value1);
558 if (value1[1] == 0 && value1[0] == 0)
568 // LordHavoc: optimized a bit
571 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
575 else if (value1[1] > 0)
580 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
581 pitch = (atan2(value1[2], forward) * 180 / M_PI);
586 VectorSet(G_VECTOR(OFS_RETURN), pitch, yaw, 0);
593 Returns a number from 0<= num < 1
598 void PF_random (void)
602 num = (rand ()&0x7fff) / ((float)0x7fff);
604 G_FLOAT(OFS_RETURN) = num;
611 particle(origin, color, count)
614 void PF_particle (void)
620 org = G_VECTOR(OFS_PARM0);
621 dir = G_VECTOR(OFS_PARM1);
622 color = G_FLOAT(OFS_PARM2);
623 count = G_FLOAT(OFS_PARM3);
624 SV_StartParticle (org, dir, color, count);
634 void PF_ambientsound (void)
639 float vol, attenuation;
642 pos = G_VECTOR (OFS_PARM0);
643 samp = G_STRING(OFS_PARM1);
644 vol = G_FLOAT(OFS_PARM2);
645 attenuation = G_FLOAT(OFS_PARM3);
647 // check to see if samp was properly precached
648 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
649 if (!strcmp(*check,samp))
654 Con_Printf("no precache: %s\n", samp);
662 // add an svc_spawnambient command to the level signon packet
665 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
667 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
669 MSG_WriteVector(&sv.signon, pos, sv.protocol);
672 MSG_WriteShort (&sv.signon, soundnum);
674 MSG_WriteByte (&sv.signon, soundnum);
676 MSG_WriteByte (&sv.signon, vol*255);
677 MSG_WriteByte (&sv.signon, attenuation*64);
685 Each entity can have eight independant sound sources, like voice,
688 Channel 0 is an auto-allocate channel, the others override anything
689 already running on that entity/channel pair.
691 An attenuation of 0 will play full volume everywhere in the level.
692 Larger attenuations will drop off.
704 entity = G_EDICT(OFS_PARM0);
705 channel = G_FLOAT(OFS_PARM1);
706 sample = G_STRING(OFS_PARM2);
707 volume = G_FLOAT(OFS_PARM3) * 255;
708 attenuation = G_FLOAT(OFS_PARM4);
710 if (volume < 0 || volume > 255)
711 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
713 if (attenuation < 0 || attenuation > 4)
714 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
716 if (channel < 0 || channel > 7)
717 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
719 SV_StartSound (entity, channel, sample, volume, attenuation);
731 PF_ERROR("break: break statement\n");
738 Used for use tracing and shot targeting
739 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
740 if the tryents flag is set.
742 traceline (vector1, vector2, tryents)
745 void PF_traceline (void)
752 pr_xfunction->builtinsprofile += 30;
754 v1 = G_VECTOR(OFS_PARM0);
755 v2 = G_VECTOR(OFS_PARM1);
756 move = G_FLOAT(OFS_PARM2);
757 ent = G_EDICT(OFS_PARM3);
759 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
761 pr_global_struct->trace_allsolid = trace.allsolid;
762 pr_global_struct->trace_startsolid = trace.startsolid;
763 pr_global_struct->trace_fraction = trace.fraction;
764 pr_global_struct->trace_inwater = trace.inwater;
765 pr_global_struct->trace_inopen = trace.inopen;
766 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
767 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
768 pr_global_struct->trace_plane_dist = trace.plane.dist;
770 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
772 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
773 // FIXME: add trace_endcontents
781 Used for use tracing and shot targeting
782 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
783 if the tryents flag is set.
785 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
788 // LordHavoc: added this for my own use, VERY useful, similar to traceline
789 void PF_tracebox (void)
791 float *v1, *v2, *m1, *m2;
796 pr_xfunction->builtinsprofile += 30;
798 v1 = G_VECTOR(OFS_PARM0);
799 m1 = G_VECTOR(OFS_PARM1);
800 m2 = G_VECTOR(OFS_PARM2);
801 v2 = G_VECTOR(OFS_PARM3);
802 move = G_FLOAT(OFS_PARM4);
803 ent = G_EDICT(OFS_PARM5);
805 trace = SV_Move (v1, m1, m2, v2, move, ent);
807 pr_global_struct->trace_allsolid = trace.allsolid;
808 pr_global_struct->trace_startsolid = trace.startsolid;
809 pr_global_struct->trace_fraction = trace.fraction;
810 pr_global_struct->trace_inwater = trace.inwater;
811 pr_global_struct->trace_inopen = trace.inopen;
812 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
813 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
814 pr_global_struct->trace_plane_dist = trace.plane.dist;
816 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
818 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
821 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
822 void PF_TraceToss (void)
828 pr_xfunction->builtinsprofile += 600;
830 ent = G_EDICT(OFS_PARM0);
831 if (ent == sv.edicts)
832 PF_WARNING("tracetoss: can not use world entity\n");
833 ignore = G_EDICT(OFS_PARM1);
835 trace = SV_Trace_Toss (ent, ignore);
837 pr_global_struct->trace_allsolid = trace.allsolid;
838 pr_global_struct->trace_startsolid = trace.startsolid;
839 pr_global_struct->trace_fraction = trace.fraction;
840 pr_global_struct->trace_inwater = trace.inwater;
841 pr_global_struct->trace_inopen = trace.inopen;
842 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
843 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
844 pr_global_struct->trace_plane_dist = trace.plane.dist;
846 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
848 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
856 Returns true if the given entity can move to the given position from it's
857 current position by walking or rolling.
859 scalar checkpos (entity, vector)
862 void PF_checkpos (void)
866 //============================================================================
869 qbyte checkpvs[MAX_MAP_LEAFS/8];
871 int PF_newcheckclient (int check)
877 // cycle to the next one
879 check = bound(1, check, svs.maxclients);
880 if (check == svs.maxclients)
888 pr_xfunction->builtinsprofile++;
890 if (i == svs.maxclients+1)
892 // look up the client's edict
894 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
895 if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET)))
897 // found a valid client (possibly the same one again)
901 // get the PVS for the entity
902 VectorAdd(ent->v->origin, ent->v->view_ofs, org);
904 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
905 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
914 Returns a client (or object that has a client enemy) that would be a
917 If there is more than one valid option, they are cycled each frame
919 If (self.origin + self.viewofs) is not in the PVS of the current target,
920 it is not returned at all.
925 int c_invis, c_notvis;
926 void PF_checkclient (void)
931 // find a new check if on a new frame
932 if (sv.time - sv.lastchecktime >= 0.1)
934 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
935 sv.lastchecktime = sv.time;
938 // return check if it might be visible
939 ent = EDICT_NUM(sv.lastcheck);
940 if (ent->e->free || ent->v->health <= 0)
942 RETURN_EDICT(sv.edicts);
946 // if current entity can't possibly see the check entity, return 0
947 self = PROG_TO_EDICT(pr_global_struct->self);
948 VectorAdd(self->v->origin, self->v->view_ofs, view);
949 if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
952 RETURN_EDICT(sv.edicts);
956 // might be able to see it
961 //============================================================================
968 Sends text over to the client's execution buffer
970 stuffcmd (clientent, value)
973 void PF_stuffcmd (void)
979 entnum = G_EDICTNUM(OFS_PARM0);
980 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
982 Con_Print("Can't stuffcmd to a non-client\n");
985 str = G_STRING(OFS_PARM1);
988 if ((host_client = svs.clients + entnum-1) && host_client->netconnection)
989 Host_ClientCommands ("%s", str);
997 Sends text to server console
1002 void PF_localcmd (void)
1004 Cbuf_AddText(G_STRING(OFS_PARM0));
1016 G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0));
1026 void PF_cvar_set (void)
1028 Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1));
1035 Returns a chain of entities that have origins within a spherical area
1037 findradius (origin, radius)
1040 void PF_findradius (void)
1042 edict_t *ent, *chain;
1043 vec_t radius, radius2;
1044 vec3_t org, eorg, mins, maxs;
1047 edict_t *touchedicts[MAX_EDICTS];
1049 chain = (edict_t *)sv.edicts;
1051 VectorCopy(G_VECTOR(OFS_PARM0), org);
1052 radius = G_FLOAT(OFS_PARM1);
1053 radius2 = radius * radius;
1055 mins[0] = org[0] - radius;
1056 mins[1] = org[1] - radius;
1057 mins[2] = org[2] - radius;
1058 maxs[0] = org[0] + radius;
1059 maxs[1] = org[1] + radius;
1060 maxs[2] = org[2] + radius;
1061 numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
1062 if (numtouchedicts > MAX_EDICTS)
1064 // this never happens
1065 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
1066 numtouchedicts = MAX_EDICTS;
1068 for (i = 0;i < numtouchedicts;i++)
1070 ent = touchedicts[i];
1071 pr_xfunction->builtinsprofile++;
1072 // LordHavoc: compare against bounding box rather than center so it
1073 // doesn't miss large objects, and use DotProduct instead of Length
1074 // for a major speedup
1075 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1076 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1077 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1078 if (DotProduct(eorg, eorg) < radius2)
1080 ent->v->chain = EDICT_TO_PROG(chain);
1085 RETURN_EDICT(chain);
1094 void PF_dprint (void)
1096 char string[STRINGTEMP_LENGTH];
1097 if (developer.integer)
1099 PF_VarString(0, string, sizeof(string));
1108 v = G_FLOAT(OFS_PARM0);
1110 s = PR_GetTempString();
1111 if ((float)((int)v) == v)
1112 sprintf(s, "%i", (int)v);
1114 sprintf(s, "%f", v);
1115 G_INT(OFS_RETURN) = PR_SetString(s);
1121 v = G_FLOAT(OFS_PARM0);
1122 G_FLOAT(OFS_RETURN) = fabs(v);
1128 s = PR_GetTempString();
1129 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1130 G_INT(OFS_RETURN) = PR_SetString(s);
1136 s = PR_GetTempString();
1137 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1138 G_INT(OFS_RETURN) = PR_SetString(s);
1141 void PF_Spawn (void)
1144 pr_xfunction->builtinsprofile += 20;
1149 void PF_Remove (void)
1152 pr_xfunction->builtinsprofile += 20;
1154 ed = G_EDICT(OFS_PARM0);
1155 if (ed == sv.edicts)
1156 PF_WARNING("remove: tried to remove world\n");
1157 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1158 PF_WARNING("remove: tried to remove a client\n");
1159 // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
1160 if (ed->e->free && developer.integer)
1161 PF_WARNING("remove: tried to remove an entity that was already removed\n");
1166 // entity (entity start, .string field, string match) find = #5;
1174 e = G_EDICTNUM(OFS_PARM0);
1175 f = G_INT(OFS_PARM1);
1176 s = G_STRING(OFS_PARM2);
1179 RETURN_EDICT(sv.edicts);
1183 for (e++ ; e < sv.num_edicts ; e++)
1185 pr_xfunction->builtinsprofile++;
1199 RETURN_EDICT(sv.edicts);
1202 // LordHavoc: added this for searching float, int, and entity reference fields
1203 void PF_FindFloat (void)
1210 e = G_EDICTNUM(OFS_PARM0);
1211 f = G_INT(OFS_PARM1);
1212 s = G_FLOAT(OFS_PARM2);
1214 for (e++ ; e < sv.num_edicts ; e++)
1216 pr_xfunction->builtinsprofile++;
1220 if (E_FLOAT(ed,f) == s)
1227 RETURN_EDICT(sv.edicts);
1230 // chained search for strings in entity fields
1231 // entity(.string field, string match) findchain = #402;
1232 void PF_findchain (void)
1237 edict_t *ent, *chain;
1239 chain = (edict_t *)sv.edicts;
1241 f = G_INT(OFS_PARM0);
1242 s = G_STRING(OFS_PARM1);
1245 RETURN_EDICT(sv.edicts);
1249 ent = NEXT_EDICT(sv.edicts);
1250 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1252 pr_xfunction->builtinsprofile++;
1255 t = E_STRING(ent,f);
1261 ent->v->chain = EDICT_TO_PROG(chain);
1265 RETURN_EDICT(chain);
1268 // LordHavoc: chained search for float, int, and entity reference fields
1269 // entity(.string field, float match) findchainfloat = #403;
1270 void PF_findchainfloat (void)
1275 edict_t *ent, *chain;
1277 chain = (edict_t *)sv.edicts;
1279 f = G_INT(OFS_PARM0);
1280 s = G_FLOAT(OFS_PARM1);
1282 ent = NEXT_EDICT(sv.edicts);
1283 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1285 pr_xfunction->builtinsprofile++;
1288 if (E_FLOAT(ent,f) != s)
1291 ent->v->chain = EDICT_TO_PROG(chain);
1295 RETURN_EDICT(chain);
1298 // LordHavoc: search for flags in float fields
1299 void PF_findflags (void)
1306 e = G_EDICTNUM(OFS_PARM0);
1307 f = G_INT(OFS_PARM1);
1308 s = (int)G_FLOAT(OFS_PARM2);
1310 for (e++ ; e < sv.num_edicts ; e++)
1312 pr_xfunction->builtinsprofile++;
1316 if ((int)E_FLOAT(ed,f) & s)
1323 RETURN_EDICT(sv.edicts);
1326 // LordHavoc: chained search for flags in float fields
1327 void PF_findchainflags (void)
1332 edict_t *ent, *chain;
1334 chain = (edict_t *)sv.edicts;
1336 f = G_INT(OFS_PARM0);
1337 s = (int)G_FLOAT(OFS_PARM1);
1339 ent = NEXT_EDICT(sv.edicts);
1340 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1342 pr_xfunction->builtinsprofile++;
1345 if (!((int)E_FLOAT(ent,f) & s))
1348 ent->v->chain = EDICT_TO_PROG(chain);
1352 RETURN_EDICT(chain);
1355 void PR_CheckEmptyString (char *s)
1358 PF_ERROR("Bad string");
1361 void PF_precache_file (void)
1362 { // precache_file is only used to copy files with qcc, it does nothing
1363 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1366 void PF_precache_sound (void)
1370 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS);
1372 if (sv.state != ss_loading)
1373 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1375 s = G_STRING(OFS_PARM0);
1376 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1377 PR_CheckEmptyString (s);
1379 for (i=0 ; i<limit ; i++)
1381 if (!sv.sound_precache[i])
1383 sv.sound_precache[i] = s;
1386 if (!strcmp(sv.sound_precache[i], s))
1389 PF_ERROR("PF_precache_sound: overflow");
1392 void PF_precache_model (void)
1396 int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS);
1398 if (sv.state != ss_loading)
1399 PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
1401 s = G_STRING(OFS_PARM0);
1402 if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
1404 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1405 PR_CheckEmptyString (s);
1407 for (i = 0;i < limit;i++)
1409 if (!sv.model_precache[i])
1411 sv.model_precache[i] = s;
1412 sv.models[i] = Mod_ForName (s, true, false, false);
1415 if (!strcmp(sv.model_precache[i], s))
1418 PF_ERROR("PF_precache_model: overflow");
1422 void PF_coredump (void)
1427 void PF_traceon (void)
1432 void PF_traceoff (void)
1437 void PF_eprint (void)
1439 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1446 float(float yaw, float dist) walkmove
1449 void PF_walkmove (void)
1457 // assume failure if it returns early
1458 G_FLOAT(OFS_RETURN) = 0;
1460 ent = PROG_TO_EDICT(pr_global_struct->self);
1461 if (ent == sv.edicts)
1462 PF_WARNING("walkmove: can not modify world entity\n");
1464 PF_WARNING("walkmove: can not modify free entity\n");
1465 yaw = G_FLOAT(OFS_PARM0);
1466 dist = G_FLOAT(OFS_PARM1);
1468 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1471 yaw = yaw*M_PI*2 / 360;
1473 move[0] = cos(yaw)*dist;
1474 move[1] = sin(yaw)*dist;
1477 // save program state, because SV_movestep may call other progs
1478 oldf = pr_xfunction;
1479 oldself = pr_global_struct->self;
1481 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1484 // restore program state
1485 pr_xfunction = oldf;
1486 pr_global_struct->self = oldself;
1496 void PF_droptofloor (void)
1502 // assume failure if it returns early
1503 G_FLOAT(OFS_RETURN) = 0;
1505 ent = PROG_TO_EDICT(pr_global_struct->self);
1506 if (ent == sv.edicts)
1507 PF_WARNING("droptofloor: can not modify world entity\n");
1509 PF_WARNING("droptofloor: can not modify free entity\n");
1511 VectorCopy (ent->v->origin, end);
1514 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1516 if (trace.fraction != 1)
1518 VectorCopy (trace.endpos, ent->v->origin);
1519 SV_LinkEdict (ent, false);
1520 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1521 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1522 G_FLOAT(OFS_RETURN) = 1;
1523 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1524 ent->e->suspendedinairflag = true;
1532 void(float style, string value) lightstyle
1535 void PF_lightstyle (void)
1542 style = G_FLOAT(OFS_PARM0);
1543 val = G_STRING(OFS_PARM1);
1545 // change the string in sv
1546 sv.lightstyles[style] = val;
1548 // send message to all clients on this server
1549 if (sv.state != ss_active)
1552 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1554 if (client->netconnection)
1556 MSG_WriteChar (&client->message, svc_lightstyle);
1557 MSG_WriteChar (&client->message,style);
1558 MSG_WriteString (&client->message, val);
1566 f = G_FLOAT(OFS_PARM0);
1568 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1570 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1572 void PF_floor (void)
1574 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1578 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1587 void PF_checkbottom (void)
1589 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1597 void PF_pointcontents (void)
1599 G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0));
1606 entity nextent(entity)
1609 void PF_nextent (void)
1614 i = G_EDICTNUM(OFS_PARM0);
1617 pr_xfunction->builtinsprofile++;
1619 if (i == sv.num_edicts)
1621 RETURN_EDICT(sv.edicts);
1637 Pick a vector for the player to shoot along
1638 vector aim(entity, missilespeed)
1643 edict_t *ent, *check, *bestent;
1644 vec3_t start, dir, end, bestdir;
1647 float dist, bestdist;
1650 // assume failure if it returns early
1651 VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1652 // if sv_aim is so high it can't possibly accept anything, skip out early
1653 if (sv_aim.value >= 1)
1656 ent = G_EDICT(OFS_PARM0);
1657 if (ent == sv.edicts)
1658 PF_WARNING("aim: can not use world entity\n");
1660 PF_WARNING("aim: can not use free entity\n");
1661 speed = G_FLOAT(OFS_PARM1);
1663 VectorCopy (ent->v->origin, start);
1666 // try sending a trace straight
1667 VectorCopy (pr_global_struct->v_forward, dir);
1668 VectorMA (start, 2048, dir, end);
1669 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1670 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1671 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1673 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1678 // try all possible entities
1679 VectorCopy (dir, bestdir);
1680 bestdist = sv_aim.value;
1683 check = NEXT_EDICT(sv.edicts);
1684 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1686 pr_xfunction->builtinsprofile++;
1687 if (check->v->takedamage != DAMAGE_AIM)
1691 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1692 continue; // don't aim at teammate
1693 for (j=0 ; j<3 ; j++)
1694 end[j] = check->v->origin[j]
1695 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1696 VectorSubtract (end, start, dir);
1697 VectorNormalize (dir);
1698 dist = DotProduct (dir, pr_global_struct->v_forward);
1699 if (dist < bestdist)
1700 continue; // to far to turn
1701 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1702 if (tr.ent == check)
1703 { // can shoot at this one
1711 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1712 dist = DotProduct (dir, pr_global_struct->v_forward);
1713 VectorScale (pr_global_struct->v_forward, dist, end);
1715 VectorNormalize (end);
1716 VectorCopy (end, G_VECTOR(OFS_RETURN));
1720 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1728 This was a major timewaster in progs, so it was converted to C
1731 void PF_changeyaw (void)
1734 float ideal, current, move, speed;
1736 ent = PROG_TO_EDICT(pr_global_struct->self);
1737 if (ent == sv.edicts)
1738 PF_WARNING("changeyaw: can not modify world entity\n");
1740 PF_WARNING("changeyaw: can not modify free entity\n");
1741 current = ANGLEMOD(ent->v->angles[1]);
1742 ideal = ent->v->ideal_yaw;
1743 speed = ent->v->yaw_speed;
1745 if (current == ideal)
1747 move = ideal - current;
1748 if (ideal > current)
1769 ent->v->angles[1] = ANGLEMOD (current + move);
1777 void PF_changepitch (void)
1780 float ideal, current, move, speed;
1783 ent = G_EDICT(OFS_PARM0);
1784 if (ent == sv.edicts)
1785 PF_WARNING("changepitch: can not modify world entity\n");
1787 PF_WARNING("changepitch: can not modify free entity\n");
1788 current = ANGLEMOD( ent->v->angles[0] );
1789 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1790 ideal = val->_float;
1793 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1796 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1797 speed = val->_float;
1800 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1804 if (current == ideal)
1806 move = ideal - current;
1807 if (ideal > current)
1828 ent->v->angles[0] = ANGLEMOD (current + move);
1832 ===============================================================================
1836 ===============================================================================
1839 #define MSG_BROADCAST 0 // unreliable to all
1840 #define MSG_ONE 1 // reliable to one (msg_entity)
1841 #define MSG_ALL 2 // reliable to all
1842 #define MSG_INIT 3 // write to the init string
1844 sizebuf_t *WriteDest (void)
1850 dest = G_FLOAT(OFS_PARM0);
1854 return &sv.datagram;
1857 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1858 entnum = NUM_FOR_EDICT(ent);
1859 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1860 Host_Error("WriteDest: tried to write to non-client\n");
1861 return &svs.clients[entnum-1].message;
1864 return &sv.reliable_datagram;
1870 Host_Error("WriteDest: bad destination");
1877 void PF_WriteByte (void)
1879 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1882 void PF_WriteChar (void)
1884 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1887 void PF_WriteShort (void)
1889 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1892 void PF_WriteLong (void)
1894 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1897 void PF_WriteAngle (void)
1899 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1902 void PF_WriteCoord (void)
1904 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
1907 void PF_WriteString (void)
1909 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1913 void PF_WriteEntity (void)
1915 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1918 //=============================================================================
1920 void PF_makestatic (void)
1925 ent = G_EDICT(OFS_PARM0);
1926 if (ent == sv.edicts)
1927 PF_WARNING("makestatic: can not modify world entity\n");
1929 PF_WARNING("makestatic: can not modify free entity\n");
1932 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1937 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1938 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1939 MSG_WriteShort (&sv.signon, ent->v->frame);
1943 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1944 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1945 MSG_WriteByte (&sv.signon, ent->v->frame);
1948 MSG_WriteByte (&sv.signon, ent->v->colormap);
1949 MSG_WriteByte (&sv.signon, ent->v->skin);
1950 for (i=0 ; i<3 ; i++)
1952 MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
1953 MSG_WriteAngle(&sv.signon, ent->v->angles[i], sv.protocol);
1956 // throw the entity away now
1960 //=============================================================================
1967 void PF_setspawnparms (void)
1973 ent = G_EDICT(OFS_PARM0);
1974 i = NUM_FOR_EDICT(ent);
1975 if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1977 Con_Print("tried to setspawnparms on a non-client\n");
1981 // copy spawn parms out of the client_t
1982 client = svs.clients + i-1;
1983 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1984 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1992 void PF_changelevel (void)
1996 // make sure we don't issue two changelevels
1997 if (svs.changelevel_issued)
1999 svs.changelevel_issued = true;
2001 s = G_STRING(OFS_PARM0);
2002 Cbuf_AddText (va("changelevel %s\n",s));
2007 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
2012 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
2017 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
2024 Returns a vector of length < 1
2029 void PF_randomvec (void)
2034 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2035 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2036 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
2038 while (DotProduct(temp, temp) >= 1);
2039 VectorCopy (temp, G_VECTOR(OFS_RETURN));
2046 Returns a color vector indicating the lighting at the requested point.
2048 (Internal Operation note: actually measures the light beneath the point, just like
2049 the model lighting on the client)
2054 void PF_GetLight (void)
2056 vec3_t ambientcolor, diffusecolor, diffusenormal;
2058 p = G_VECTOR(OFS_PARM0);
2059 VectorClear(ambientcolor);
2060 VectorClear(diffusecolor);
2061 VectorClear(diffusenormal);
2062 if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
2063 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
2064 VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN));
2067 void PF_registercvar (void)
2070 name = G_STRING(OFS_PARM0);
2071 value = G_STRING(OFS_PARM1);
2072 G_FLOAT(OFS_RETURN) = 0;
2074 // first check to see if it has already been defined
2075 if (Cvar_FindVar (name))
2078 // check for overlap with a command
2079 if (Cmd_Exists (name))
2081 Con_Printf("PF_registercvar: %s is a command\n", name);
2085 Cvar_Get(name, value, 0);
2087 G_FLOAT(OFS_RETURN) = 1; // success
2094 returns the minimum of two supplied floats
2101 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2103 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2104 else if (pr_argc >= 3)
2107 float f = G_FLOAT(OFS_PARM0);
2108 for (i = 1;i < pr_argc;i++)
2109 if (G_FLOAT((OFS_PARM0+i*3)) < f)
2110 f = G_FLOAT((OFS_PARM0+i*3));
2111 G_FLOAT(OFS_RETURN) = f;
2115 G_FLOAT(OFS_RETURN) = 0;
2116 PF_WARNING("min: must supply at least 2 floats\n");
2124 returns the maximum of two supplied floats
2131 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2133 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2134 else if (pr_argc >= 3)
2137 float f = G_FLOAT(OFS_PARM0);
2138 for (i = 1;i < pr_argc;i++)
2139 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2140 f = G_FLOAT((OFS_PARM0+i*3));
2141 G_FLOAT(OFS_RETURN) = f;
2145 G_FLOAT(OFS_RETURN) = 0;
2146 PF_WARNING("max: must supply at least 2 floats\n");
2154 returns number bounded by supplied range
2156 min(min, value, max)
2159 void PF_bound (void)
2161 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2168 returns a raised to power b
2175 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2182 copies data from one entity to another
2184 copyentity(src, dst)
2187 void PF_copyentity (void)
2190 in = G_EDICT(OFS_PARM0);
2191 if (in == sv.edicts)
2192 PF_WARNING("copyentity: can not read world entity\n");
2194 PF_WARNING("copyentity: can not read free entity\n");
2195 out = G_EDICT(OFS_PARM1);
2196 if (out == sv.edicts)
2197 PF_WARNING("copyentity: can not modify world entity\n");
2199 PF_WARNING("copyentity: can not modify free entity\n");
2200 memcpy(out->v, in->v, progs->entityfields * 4);
2207 sets the color of a client and broadcasts the update to all connected clients
2209 setcolor(clientent, value)
2212 void PF_setcolor (void)
2218 entnum = G_EDICTNUM(OFS_PARM0);
2219 i = G_FLOAT(OFS_PARM1);
2221 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
2223 Con_Print("tried to setcolor a non-client\n");
2227 client = svs.clients + entnum-1;
2230 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
2232 client->edict->v->team = (i & 15) + 1;
2235 if (client->old_colors != client->colors)
2237 client->old_colors = client->colors;
2238 // send notification to all clients
2239 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2240 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
2241 MSG_WriteByte (&sv.reliable_datagram, client->colors);
2249 effect(origin, modelname, startframe, framecount, framerate)
2252 void PF_effect (void)
2256 s = G_STRING(OFS_PARM1);
2258 PF_WARNING("effect: no model specified\n");
2260 i = SV_ModelIndex(s);
2262 PF_WARNING("effect: model not precached\n");
2263 SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2266 void PF_te_blood (void)
2268 if (G_FLOAT(OFS_PARM2) < 1)
2270 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2271 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2273 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2274 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2275 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2277 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2278 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2279 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2281 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2284 void PF_te_bloodshower (void)
2286 if (G_FLOAT(OFS_PARM3) < 1)
2288 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2289 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2291 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2292 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2293 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2295 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2296 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2297 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2299 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
2301 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2304 void PF_te_explosionrgb (void)
2306 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2307 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2309 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2310 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2311 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2313 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2314 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2315 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2318 void PF_te_particlecube (void)
2320 if (G_FLOAT(OFS_PARM3) < 1)
2322 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2323 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2325 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2326 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2327 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2329 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2330 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2331 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2333 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2334 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2335 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2337 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2339 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2340 // gravity true/false
2341 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2343 MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
2346 void PF_te_particlerain (void)
2348 if (G_FLOAT(OFS_PARM3) < 1)
2350 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2351 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2353 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2354 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2355 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2357 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2358 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2359 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2361 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2362 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2363 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2365 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2367 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2370 void PF_te_particlesnow (void)
2372 if (G_FLOAT(OFS_PARM3) < 1)
2374 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2375 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2377 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2378 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2379 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2381 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2382 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2383 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2385 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2386 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2387 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2389 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2391 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2394 void PF_te_spark (void)
2396 if (G_FLOAT(OFS_PARM2) < 1)
2398 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2399 MSG_WriteByte(&sv.datagram, TE_SPARK);
2401 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2402 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2403 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2405 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2406 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2407 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2409 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2412 void PF_te_gunshotquad (void)
2414 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2415 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2417 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2418 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2419 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2422 void PF_te_spikequad (void)
2424 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2425 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2427 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2428 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2429 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2432 void PF_te_superspikequad (void)
2434 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2435 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2437 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2438 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2439 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2442 void PF_te_explosionquad (void)
2444 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2445 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2447 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2448 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2449 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2452 void PF_te_smallflash (void)
2454 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2455 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2457 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2458 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2459 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2462 void PF_te_customflash (void)
2464 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2466 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2467 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2469 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2470 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2471 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2473 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2475 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2477 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2478 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2479 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2482 void PF_te_gunshot (void)
2484 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2485 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2487 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2488 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2489 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2492 void PF_te_spike (void)
2494 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2495 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2497 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2498 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2499 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2502 void PF_te_superspike (void)
2504 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2505 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2507 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2508 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2509 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2512 void PF_te_explosion (void)
2514 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2515 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2517 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2518 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2519 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2522 void PF_te_tarexplosion (void)
2524 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2525 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2527 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2528 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2529 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2532 void PF_te_wizspike (void)
2534 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2535 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2537 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2538 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2539 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2542 void PF_te_knightspike (void)
2544 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2545 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2547 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2548 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2549 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2552 void PF_te_lavasplash (void)
2554 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2555 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2557 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2558 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2559 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2562 void PF_te_teleport (void)
2564 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2565 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2567 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2568 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2569 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2572 void PF_te_explosion2 (void)
2574 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2575 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2577 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2578 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2579 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2581 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2582 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
2585 void PF_te_lightning1 (void)
2587 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2588 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2590 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2592 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2593 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2594 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2596 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2597 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2598 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2601 void PF_te_lightning2 (void)
2603 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2604 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2606 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2608 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2609 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2610 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2612 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2613 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2614 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2617 void PF_te_lightning3 (void)
2619 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2620 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2622 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2624 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2625 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2626 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2628 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2629 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2630 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2633 void PF_te_beam (void)
2635 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2636 MSG_WriteByte(&sv.datagram, TE_BEAM);
2638 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2640 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
2641 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
2642 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
2644 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
2645 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
2646 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
2649 void PF_te_plasmaburn (void)
2651 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2652 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2653 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
2654 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
2655 MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
2658 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2661 vec3_t v1, clipplanenormal, normal;
2662 vec_t clipplanedist, clipdist;
2664 if (surf->flags & SURF_PLANEBACK)
2665 VectorNegate(surf->plane->normal, normal);
2667 VectorCopy(surf->plane->normal, normal);
2668 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2670 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2671 VectorNormalizeFast(v1);
2672 CrossProduct(v1, normal, clipplanenormal);
2673 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2674 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2677 clipdist = -clipdist;
2678 VectorMA(out, clipdist, clipplanenormal, out);
2683 static msurface_t *getsurface(edict_t *ed, int surfnum)
2687 if (!ed || ed->e->free)
2689 modelindex = ed->v->modelindex;
2690 if (modelindex < 1 || modelindex >= MAX_MODELS)
2692 model = sv.models[modelindex];
2693 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2695 return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2699 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2700 void PF_getsurfacenumpoints(void)
2703 // return 0 if no such surface
2704 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2706 G_FLOAT(OFS_RETURN) = 0;
2710 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2712 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2713 void PF_getsurfacepoint(void)
2718 VectorClear(G_VECTOR(OFS_RETURN));
2719 ed = G_EDICT(OFS_PARM0);
2720 if (!ed || ed->e->free)
2722 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2724 pointnum = G_FLOAT(OFS_PARM2);
2725 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2727 // FIXME: implement rotation/scaling
2728 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2730 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2731 void PF_getsurfacenormal(void)
2734 VectorClear(G_VECTOR(OFS_RETURN));
2735 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2737 // FIXME: implement rotation/scaling
2738 if (surf->flags & SURF_PLANEBACK)
2739 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2741 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2743 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2744 void PF_getsurfacetexture(void)
2747 G_INT(OFS_RETURN) = 0;
2748 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2750 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2752 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2753 void PF_getsurfacenearpoint(void)
2755 int surfnum, best, modelindex;
2757 vec_t dist, bestdist;
2762 G_FLOAT(OFS_RETURN) = -1;
2763 ed = G_EDICT(OFS_PARM0);
2764 point = G_VECTOR(OFS_PARM1);
2766 if (!ed || ed->e->free)
2768 modelindex = ed->v->modelindex;
2769 if (modelindex < 1 || modelindex >= MAX_MODELS)
2771 model = sv.models[modelindex];
2772 if (!model->brushq1.numsurfaces)
2775 // FIXME: implement rotation/scaling
2776 VectorSubtract(point, ed->v->origin, p);
2778 bestdist = 1000000000;
2779 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2781 surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
2782 dist = PlaneDiff(p, surf->plane);
2784 if (dist < bestdist)
2786 clippointtosurface(surf, p, clipped);
2787 VectorSubtract(clipped, p, clipped);
2788 dist += DotProduct(clipped, clipped);
2789 if (dist < bestdist)
2796 G_FLOAT(OFS_RETURN) = best;
2798 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2799 void PF_getsurfaceclippedpoint(void)
2804 VectorClear(G_VECTOR(OFS_RETURN));
2805 ed = G_EDICT(OFS_PARM0);
2806 if (!ed || ed->e->free)
2808 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2810 // FIXME: implement rotation/scaling
2811 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2812 clippointtosurface(surf, p, out);
2813 // FIXME: implement rotation/scaling
2814 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2817 #define MAX_PRFILES 256
2819 qfile_t *pr_files[MAX_PRFILES];
2821 void PR_Files_Init(void)
2823 memset(pr_files, 0, sizeof(pr_files));
2826 void PR_Files_CloseAll(void)
2829 for (i = 0;i < MAX_PRFILES;i++)
2832 FS_Close(pr_files[i]);
2837 //float(string s) stof = #81; // get numerical value from a string
2840 char string[STRINGTEMP_LENGTH];
2841 PF_VarString(0, string, sizeof(string));
2842 G_FLOAT(OFS_RETURN) = atof(string);
2845 //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
2848 int filenum, mode, i;
2849 char *modestring, *filename;
2850 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2851 if (pr_files[filenum] == NULL)
2853 if (filenum >= MAX_PRFILES)
2855 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2856 G_FLOAT(OFS_RETURN) = -2;
2859 mode = G_FLOAT(OFS_PARM1);
2862 case 0: // FILE_READ
2865 case 1: // FILE_APPEND
2868 case 2: // FILE_WRITE
2872 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2873 G_FLOAT(OFS_RETURN) = -3;
2876 filename = G_STRING(OFS_PARM0);
2877 // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
2878 // ../ is parent directory on many platforms
2879 // // is parent directory on Amiga
2880 // / at the beginning of a path is root on unix, and parent directory on Amiga
2881 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2882 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2883 for (i = 0;filename[i];i++)
2885 if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
2887 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);
2888 G_FLOAT(OFS_RETURN) = -4;
2892 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2894 if (pr_files[filenum] == NULL && modestring == "rb")
2895 pr_files[filenum] = FS_Open(filename, modestring, false);
2897 if (pr_files[filenum] == NULL)
2898 G_FLOAT(OFS_RETURN) = -1;
2900 G_FLOAT(OFS_RETURN) = filenum;
2903 //void(float fhandle) fclose = #111; // closes a file
2904 void PF_fclose(void)
2906 int filenum = G_FLOAT(OFS_PARM0);
2907 if (filenum < 0 || filenum >= MAX_PRFILES)
2909 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2912 if (pr_files[filenum] == NULL)
2914 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2917 FS_Close(pr_files[filenum]);
2918 pr_files[filenum] = NULL;
2921 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2925 static char string[STRINGTEMP_LENGTH];
2926 int filenum = G_FLOAT(OFS_PARM0);
2927 if (filenum < 0 || filenum >= MAX_PRFILES)
2929 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2932 if (pr_files[filenum] == NULL)
2934 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2940 c = FS_Getc(pr_files[filenum]);
2941 if (c == '\r' || c == '\n' || c < 0)
2943 if (end < STRINGTEMP_LENGTH - 1)
2947 // remove \n following \r
2949 c = FS_Getc(pr_files[filenum]);
2950 if (developer.integer)
2951 Con_Printf("fgets: %s\n", string);
2953 G_INT(OFS_RETURN) = PR_SetString(string);
2955 G_INT(OFS_RETURN) = 0;
2958 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2962 char string[STRINGTEMP_LENGTH];
2963 int filenum = G_FLOAT(OFS_PARM0);
2964 if (filenum < 0 || filenum >= MAX_PRFILES)
2966 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2969 if (pr_files[filenum] == NULL)
2971 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2974 PF_VarString(1, string, sizeof(string));
2975 if ((stringlength = strlen(string)))
2976 FS_Write(pr_files[filenum], string, stringlength);
2977 if (developer.integer)
2978 Con_Printf("fputs: %s\n", string);
2981 //float(string s) strlen = #114; // returns how many characters are in a string
2982 void PF_strlen(void)
2985 s = G_STRING(OFS_PARM0);
2987 G_FLOAT(OFS_RETURN) = strlen(s);
2989 G_FLOAT(OFS_RETURN) = 0;
2992 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2993 void PF_strcat(void)
2995 char *s = PR_GetTempString();
2996 PF_VarString(0, s, STRINGTEMP_LENGTH);
2997 G_INT(OFS_RETURN) = PR_SetString(s);
3000 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
3001 void PF_substring(void)
3003 int i, start, length;
3004 char *s, *string = PR_GetTempString();
3005 s = G_STRING(OFS_PARM0);
3006 start = G_FLOAT(OFS_PARM1);
3007 length = G_FLOAT(OFS_PARM2);
3010 for (i = 0;i < start && *s;i++, s++);
3011 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
3014 G_INT(OFS_RETURN) = PR_SetString(string);
3017 //vector(string s) stov = #117; // returns vector value from a string
3020 char string[STRINGTEMP_LENGTH];
3021 PF_VarString(0, string, sizeof(string));
3022 Math_atov(string, G_VECTOR(OFS_RETURN));
3025 //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)
3026 void PF_strzone(void)
3029 in = G_STRING(OFS_PARM0);
3030 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
3032 G_INT(OFS_RETURN) = PR_SetString(out);
3035 //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!!!)
3036 void PF_strunzone(void)
3038 Mem_Free(G_STRING(OFS_PARM0));
3041 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
3042 //this function originally written by KrimZon, made shorter by LordHavoc
3043 void PF_clientcommand (void)
3045 client_t *temp_client;
3048 //find client for this entity
3049 i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1);
3050 if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
3052 Con_Print("PF_clientcommand: entity is not a client\n");
3056 temp_client = host_client;
3057 host_client = svs.clients + i;
3058 Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client);
3059 host_client = temp_client;
3062 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
3063 //this function originally written by KrimZon, made shorter by LordHavoc
3064 //20040203: rewritten by LordHavoc (no longer uses allocations)
3066 char *tokens[256], tokenbuf[4096];
3067 void PF_tokenize (void)
3071 p = G_STRING(OFS_PARM0);
3075 while(COM_ParseToken(&p, false))
3077 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
3079 if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
3081 tokens[num_tokens++] = tokenbuf + pos;
3082 strcpy(tokenbuf + pos, com_token);
3083 pos += strlen(com_token) + 1;
3086 G_FLOAT(OFS_RETURN) = num_tokens;
3089 //string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
3090 //this function originally written by KrimZon, made shorter by LordHavoc
3093 int token_num = G_FLOAT(OFS_PARM0);
3094 if (token_num >= 0 && token_num < num_tokens)
3095 G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]);
3097 G_INT(OFS_RETURN) = PR_SetString("");
3100 //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)
3101 void PF_setattachment (void)
3103 edict_t *e = G_EDICT(OFS_PARM0);
3104 edict_t *tagentity = G_EDICT(OFS_PARM1);
3105 char *tagname = G_STRING(OFS_PARM2);
3111 PF_WARNING("setattachment: can not modify world entity\n");
3113 PF_WARNING("setattachment: can not modify free entity\n");
3115 if (tagentity == NULL)
3116 tagentity = sv.edicts;
3118 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
3120 v->edict = EDICT_TO_PROG(tagentity);
3122 v = GETEDICTFIELDVALUE(e, eval_tag_index);
3125 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
3127 modelindex = (int)tagentity->v->modelindex;
3128 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
3130 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
3131 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
3132 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
3134 // FIXME: use a model function to get tag info (need to handle skeletal)
3135 if (v->_float == 0 && model->alias.aliasnum_tags)
3136 for (i = 0;i < model->alias.aliasnum_tags;i++)
3137 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
3140 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);
3143 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));
3147 /////////////////////////////////////////
3148 // DP_MD3_TAGINFO extension coded by VorteX
3150 int SV_GetTagIndex (edict_t *e, char *tagname)
3155 model = sv.models[(int)e->v->modelindex];
3158 if (model->data_overridetagnamesforskin && (unsigned int)e->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames)
3160 for (i = 0; i < model->data_overridetagnamesforskin[(unsigned int)e->v->skin].num_overridetagnames; i++)
3162 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)e->v->skin].data_overridetagnames[i].name))
3171 for (i = 0;i < model->alias.aliasnum_tags; i++)
3173 if (!(strcmp(tagname, model->alias.aliasdata_tags[i].name)))
3180 return tagindex + 1;
3183 // Warnings/errors code:
3184 // 0 - normal (everything all-right)
3187 // 3 - null or non-precached model
3188 // 4 - no tags with requested index
3189 // 5 - runaway loop at attachment chain
3190 extern cvar_t cl_bob;
3191 extern cvar_t cl_bobcycle;
3192 extern cvar_t cl_bobup;
3193 int SV_GetTagMatrix (matrix4x4_t *out, edict_t *ent, int tagindex)
3196 int modelindex, reqtag, reqframe, attachloop;
3197 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3201 Matrix4x4_CreateIdentity(out); // warnings and errors return identical matrix
3203 if (ent == sv.edicts)
3208 modelindex = (int)ent->v->modelindex;
3209 if (modelindex <= 0 || modelindex > MAX_MODELS)
3212 model = sv.models[modelindex];
3213 reqtag = model->alias.aliasnum_tags;
3215 if (tagindex <= 0 || tagindex > reqtag)
3217 if (reqtag && tagindex) // Only appear if model has no tags or not-null tag requested
3222 if (ent->v->frame < 0 || ent->v->frame > model->alias.aliasnum_tagframes)
3223 reqframe = model->numframes - 1; // if model has wrong frame, engine automatically switches to model last frame
3225 reqframe = ent->v->frame;
3227 // get initial tag matrix
3230 reqtag = (tagindex - 1) + ent->v->frame*model->alias.aliasnum_tags;
3231 Matrix4x4_Copy(&tagmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3234 Matrix4x4_CreateIdentity(&tagmatrix);
3236 if ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
3237 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
3241 attachent = EDICT_NUM(val->edict); // to this it entity our entity is attached
3242 val = GETEDICTFIELDVALUE(ent, eval_tag_index);
3244 {// got tagname on parent entity attachment tag via tag_index (and got it's matrix)
3245 model = sv.models[(int)attachent->v->modelindex];
3246 reqtag = (val->_float - 1) + attachent->v->frame*model->alias.aliasnum_tags;
3247 Matrix4x4_Copy(&attachmatrix, &model->alias.aliasdata_tags[reqtag].matrix);
3250 Matrix4x4_CreateIdentity(&attachmatrix);
3252 // apply transformation by child entity matrix
3253 val = GETEDICTFIELDVALUE(ent, eval_scale);
3254 if (val->_float == 0)
3256 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], val->_float);
3257 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3258 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3259 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3260 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3261 Matrix4x4_Copy(&tagmatrix, out);
3263 // finally transformate by matrix of tag on parent entity
3264 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
3265 out->m[0][3] = attachmatrix.m[0][3] + attachmatrix.m[0][0]*tagmatrix.m[0][3] + attachmatrix.m[0][1]*tagmatrix.m[1][3] + attachmatrix.m[0][2]*tagmatrix.m[2][3];
3266 out->m[1][3] = attachmatrix.m[1][3] + attachmatrix.m[1][0]*tagmatrix.m[0][3] + attachmatrix.m[1][1]*tagmatrix.m[1][3] + attachmatrix.m[1][2]*tagmatrix.m[2][3];
3267 out->m[2][3] = attachmatrix.m[2][3] + attachmatrix.m[2][0]*tagmatrix.m[0][3] + attachmatrix.m[2][1]*tagmatrix.m[1][3] + attachmatrix.m[2][2]*tagmatrix.m[2][3];
3268 Matrix4x4_Copy(&tagmatrix, out);
3272 if (attachloop > 255) // prevent runaway looping
3275 while ((val = GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict);
3278 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
3279 val = GETEDICTFIELDVALUE(ent, eval_scale);
3280 if (val->_float == 0)
3282 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
3283 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], val->_float);
3284 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3285 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3286 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3287 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3289 if ((val = GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
3290 {// RENDER_VIEWMODEL magic
3291 Matrix4x4_Copy(&tagmatrix, out);
3292 ent = EDICT_NUM(val->edict);
3294 val = GETEDICTFIELDVALUE(ent, eval_scale);
3295 if (val->_float == 0)
3298 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], val->_float);
3299 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3300 out->m[0][3] = entitymatrix.m[0][3] + val->_float*(entitymatrix.m[0][0]*tagmatrix.m[0][3] + entitymatrix.m[0][1]*tagmatrix.m[1][3] + entitymatrix.m[0][2]*tagmatrix.m[2][3]);
3301 out->m[1][3] = entitymatrix.m[1][3] + val->_float*(entitymatrix.m[1][0]*tagmatrix.m[0][3] + entitymatrix.m[1][1]*tagmatrix.m[1][3] + entitymatrix.m[1][2]*tagmatrix.m[2][3]);
3302 out->m[2][3] = entitymatrix.m[2][3] + val->_float*(entitymatrix.m[2][0]*tagmatrix.m[0][3] + entitymatrix.m[2][1]*tagmatrix.m[1][3] + entitymatrix.m[2][2]*tagmatrix.m[2][3]);
3305 // Cl_bob, ported from rendering code
3306 if (ent->v->health > 0 && cl_bob.value && cl_bobcycle.value)
3309 // LordHavoc: this code is *weird*, but not replacable (I think it
3310 // should be done in QC on the server, but oh well, quake is quake)
3311 // LordHavoc: figured out bobup: the time at which the sin is at 180
3312 // degrees (which allows lengthening or squishing the peak or valley)
3313 cycle = sv.time/cl_bobcycle.value;
3314 cycle -= (int)cycle;
3315 if (cycle < cl_bobup.value)
3316 cycle = sin(M_PI * cycle / cl_bobup.value);
3318 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3319 // bob is proportional to velocity in the xy plane
3320 // (don't count Z, or jumping messes it up)
3321 bob = sqrt(ent->v->velocity[0]*ent->v->velocity[0] + ent->v->velocity[1]*ent->v->velocity[1])*cl_bob.value;
3322 bob = bob*0.3 + bob*0.7*cycle;
3323 out->m[2][3] += bound(-7, bob, 4);
3330 //float(entity ent, string tagname) gettagindex;
3332 void PF_gettagindex (void)
3334 edict_t *ent = G_EDICT(OFS_PARM0);
3335 char *tag_name = G_STRING(OFS_PARM1);
3336 int modelindex, tag_index;
3338 if (ent == sv.edicts)
3339 PF_WARNING("gettagindex: can't affect world entity\n");
3341 PF_WARNING("gettagindex: can't affect free entity\n");
3343 modelindex = (int)ent->v->modelindex;
3345 if (modelindex <= 0 || modelindex > MAX_MODELS)
3346 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(ent));
3349 tag_index = SV_GetTagIndex(ent, tag_name);
3351 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", NUM_FOR_EDICT(ent), tag_name);
3353 G_FLOAT(OFS_RETURN) = tag_index;
3356 //vector(entity ent, float tagindex) gettaginfo;
3357 void PF_gettaginfo (void)
3359 edict_t *e = G_EDICT(OFS_PARM0);
3360 int tagindex = (int)G_FLOAT(OFS_PARM1);
3361 matrix4x4_t tag_matrix;
3364 returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
3365 Matrix4x4_ToVectors(&tag_matrix, pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up, G_VECTOR(OFS_RETURN));
3370 PF_WARNING("gettagindex: can't affect world entity\n");
3373 PF_WARNING("gettagindex: can't affect free entity\n");
3376 Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", NUM_FOR_EDICT(e));
3379 Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", NUM_FOR_EDICT(e), tagindex);
3382 Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", NUM_FOR_EDICT(e));
3388 /////////////////////////////////////////
3389 // DP_QC_FS_SEARCH extension
3391 // qc fs search handling
3392 #define MAX_SEARCHES 128
3394 fssearch_t *pr_fssearchlist[MAX_SEARCHES];
3396 void PR_Search_Init(void)
3398 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3401 void PR_Search_Reset(void)
3404 // reset the fssearch list
3405 for(i = 0; i < MAX_SEARCHES; i++)
3406 if(pr_fssearchlist[i])
3407 FS_FreeSearch(pr_fssearchlist[i]);
3408 memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
3415 float search_begin(string pattern, float caseinsensitive, float quiet)
3418 void PF_search_begin(void)
3422 int caseinsens, quiet;
3424 pattern = G_STRING(OFS_PARM0);
3426 PR_CheckEmptyString(pattern);
3428 caseinsens = G_FLOAT(OFS_PARM1);
3429 quiet = G_FLOAT(OFS_PARM2);
3431 for(handle = 0; handle < MAX_SEARCHES; handle++)
3432 if(!pr_fssearchlist[handle])
3435 if(handle >= MAX_SEARCHES)
3437 Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
3438 G_FLOAT(OFS_RETURN) = -2;
3442 if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
3443 G_FLOAT(OFS_RETURN) = -1;
3445 G_FLOAT(OFS_RETURN) = handle;
3452 void search_end(float handle)
3455 void PF_search_end(void)
3459 handle = G_FLOAT(OFS_PARM0);
3461 if(handle < 0 || handle >= MAX_SEARCHES)
3463 Con_Printf("PF_search_end: invalid handle %i\n", handle);
3466 if(pr_fssearchlist[handle] == NULL)
3468 Con_Printf("PF_search_end: no such handle %i\n", handle);
3472 FS_FreeSearch(pr_fssearchlist[handle]);
3473 pr_fssearchlist[handle] = NULL;
3480 float search_getsize(float handle)
3483 void PF_search_getsize(void)
3487 handle = G_FLOAT(OFS_PARM0);
3489 if(handle < 0 || handle >= MAX_SEARCHES)
3491 Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
3494 if(pr_fssearchlist[handle] == NULL)
3496 Con_Printf("PF_search_getsize: no such handle %i\n", handle);
3500 G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
3505 VM_search_getfilename
3507 string search_getfilename(float handle, float num)
3510 void PF_search_getfilename(void)
3512 int handle, filenum;
3515 handle = G_FLOAT(OFS_PARM0);
3516 filenum = G_FLOAT(OFS_PARM1);
3518 if(handle < 0 || handle >= MAX_SEARCHES)
3520 Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
3523 if(pr_fssearchlist[handle] == NULL)
3525 Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
3528 if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
3530 Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
3534 tmp = PR_GetTempString();
3535 strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
3537 G_INT(OFS_RETURN) = PR_SetString(tmp);
3540 void PF_cvar_string (void)
3546 str = G_STRING(OFS_PARM0);
3547 var = Cvar_FindVar (str);
3550 tmp = PR_GetTempString();
3551 strcpy(tmp, var->string);
3555 G_INT(OFS_RETURN) = PR_SetString(tmp);
3558 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
3559 void PF_dropclient (void)
3562 client_t *oldhostclient;
3563 clientnum = G_EDICTNUM(OFS_PARM0) - 1;
3564 if (clientnum < 0 || clientnum >= svs.maxclients)
3565 PF_WARNING("dropclient: not a client\n");
3566 if (!svs.clients[clientnum].active)
3567 PF_WARNING("dropclient: that client slot is not connected\n");
3568 oldhostclient = host_client;
3569 host_client = svs.clients + clientnum;
3570 SV_DropClient(false);
3571 host_client = oldhostclient;
3575 builtin_t pr_builtin[] =
3578 PF_makevectors, // #1 void(entity e) makevectors
3579 PF_setorigin, // #2 void(entity e, vector o) setorigin
3580 PF_setmodel, // #3 void(entity e, string m) setmodel
3581 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
3582 NULL, // #5 void(entity e, vector min, vector max) setabssize
3583 PF_break, // #6 void() break
3584 PF_random, // #7 float() random
3585 PF_sound, // #8 void(entity e, float chan, string samp) sound
3586 PF_normalize, // #9 vector(vector v) normalize
3587 PF_error, // #10 void(string e) error
3588 PF_objerror, // #11 void(string e) objerror
3589 PF_vlen, // #12 float(vector v) vlen
3590 PF_vectoyaw, // #13 float(vector v) vectoyaw
3591 PF_Spawn, // #14 entity() spawn
3592 PF_Remove, // #15 void(entity e) remove
3593 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
3594 PF_checkclient, // #17 entity() clientlist
3595 PF_Find, // #18 entity(entity start, .string fld, string match) find
3596 PF_precache_sound, // #19 void(string s) precache_sound
3597 PF_precache_model, // #20 void(string s) precache_model
3598 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
3599 PF_findradius, // #22 entity(vector org, float rad) findradius
3600 PF_bprint, // #23 void(string s) bprint
3601 PF_sprint, // #24 void(entity client, string s) sprint
3602 PF_dprint, // #25 void(string s) dprint
3603 PF_ftos, // #26 void(string s) ftos
3604 PF_vtos, // #27 void(string s) vtos
3605 PF_coredump, // #28 void() coredump
3606 PF_traceon, // #29 void() traceon
3607 PF_traceoff, // #30 void() traceoff
3608 PF_eprint, // #31 void(entity e) eprint
3609 PF_walkmove, // #32 float(float yaw, float dist) walkmove
3611 PF_droptofloor, // #34 float() droptofloor
3612 PF_lightstyle, // #35 void(float style, string value) lightstyle
3613 PF_rint, // #36 float(float v) rint
3614 PF_floor, // #37 float(float v) floor
3615 PF_ceil, // #38 float(float v) ceil
3617 PF_checkbottom, // #40 float(entity e) checkbottom
3618 PF_pointcontents , // #41 float(vector v) pointcontents
3620 PF_fabs, // #43 float(float f) fabs
3621 PF_aim, // #44 vector(entity e, float speed) aim
3622 PF_cvar, // #45 float(string s) cvar
3623 PF_localcmd, // #46 void(string s) localcmd
3624 PF_nextent, // #47 entity(entity e) nextent
3625 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
3626 PF_changeyaw, // #49 void() ChangeYaw
3628 PF_vectoangles, // #51 vector(vector v) vectoangles
3629 PF_WriteByte, // #52 void(float to, float f) WriteByte
3630 PF_WriteChar, // #53 void(float to, float f) WriteChar
3631 PF_WriteShort, // #54 void(float to, float f) WriteShort
3632 PF_WriteLong, // #55 void(float to, float f) WriteLong
3633 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
3634 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
3635 PF_WriteString, // #58 void(float to, string s) WriteString
3636 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
3637 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
3638 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
3639 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
3640 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
3641 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
3642 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
3644 SV_MoveToGoal, // #67 void(float step) movetogoal
3645 PF_precache_file, // #68 string(string s) precache_file
3646 PF_makestatic, // #69 void(entity e) makestatic
3647 PF_changelevel, // #70 void(string s) changelevel
3649 PF_cvar_set, // #72 void(string var, string val) cvar_set
3650 PF_centerprint, // #73 void(entity client, strings) centerprint
3651 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
3652 PF_precache_model, // #75 string(string s) precache_model2
3653 PF_precache_sound, // #76 string(string s) precache_sound2
3654 PF_precache_file, // #77 string(string s) precache_file2
3655 PF_setspawnparms, // #78 void(entity e) setspawnparms
3658 PF_stof, // #81 float(string s) stof (FRIK_FILE)
3667 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
3668 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
3669 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
3670 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
3671 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
3672 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
3673 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
3674 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
3675 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
3676 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3687 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3688 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3689 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3690 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3691 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3692 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3693 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3694 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3695 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3696 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3697 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3698 a a a a a a a a // #120-199
3699 a a a a a a a a a a // #200-299
3700 a a a a a a a a a a // #300-399
3701 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3702 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3703 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3704 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3705 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3706 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3707 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3708 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3709 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3710 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3711 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3712 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3713 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3714 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3715 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3716 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3717 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3718 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3719 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3720 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3721 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3722 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3723 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3724 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3725 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3726 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3727 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3728 PF_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3729 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3730 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3731 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3732 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3733 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3734 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3735 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3736 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3737 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3738 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3739 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3740 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3741 PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3742 PF_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3743 PF_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3744 PF_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3745 PF_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3746 PF_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3747 PF_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3748 PF_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3749 PF_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3750 PF_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3751 PF_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3752 PF_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3753 PF_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3754 PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3761 a a a a // #460-499 (LordHavoc)
3764 builtin_t *pr_builtins = pr_builtin;
3765 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3767 void PR_Cmd_Init(void)
3769 pr_strings_mempool = Mem_AllocPool("pr_stringszone", 0, NULL);
3774 void PR_Cmd_Reset(void)
3776 Mem_EmptyPool(pr_strings_mempool);
3778 PR_Files_CloseAll();