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 #define MAX_VARSTRING 4096
30 char pr_varstring_temp[MAX_VARSTRING];
32 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
36 ===============================================================================
40 ===============================================================================
44 char *PF_VarString (int first)
50 for (i = first;i < pr_argc;i++)
52 // LordHavoc: FIXME: this is just a strlcat inlined
53 s = G_STRING((OFS_PARM0+i*3));
55 if (j > MAX_VARSTRING - 1 - end)
56 j = MAX_VARSTRING - 1 - end;
59 memcpy(pr_varstring_temp + end, s, j);
63 pr_varstring_temp[end] = 0;
64 return pr_varstring_temp;
67 char *ENGINE_EXTENSIONS =
76 "DP_ENT_CUSTOMCOLORMAP "
77 "DP_ENT_EXTERIORMODELTOCLIENT "
78 "DP_ENT_LOWPRECISION "
91 "DP_QC_FINDCHAINFLOAT "
97 "DP_QC_SINCOSSQRTPOW "
100 "DP_QC_VECTORVECTORS "
105 "DP_SV_DRAWONLYTOCLIENT "
107 "DP_SV_EXTERIORMODELTOCLIENT "
108 "DP_SV_NODRAWTOCLIENT "
109 "DP_SV_PLAYERPHYSICS "
114 "DP_TE_EXPLOSIONRGB "
116 "DP_TE_PARTICLECUBE "
117 "DP_TE_PARTICLERAIN "
118 "DP_TE_PARTICLESNOW "
126 qboolean checkextension(char *name)
131 for (e = ENGINE_EXTENSIONS;*e;e++)
138 while (*e && *e != ' ')
140 if (e - start == len)
141 if (!strncasecmp(start, name, len))
151 returns true if the extension is supported by the server
153 checkextension(extensionname)
156 void PF_checkextension (void)
158 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
165 This is a TERMINAL error, which will kill off the entire server.
177 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
178 ed = PROG_TO_EDICT(pr_global_struct->self);
181 Host_Error ("Program error");
188 Dumps out self, then an error message. The program is aborted and self is
189 removed, but the level can continue.
194 void PF_objerror (void)
200 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
201 ed = PROG_TO_EDICT(pr_global_struct->self);
211 Writes new values for v_forward, v_up, and v_right based on angles
215 void PF_makevectors (void)
217 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
224 Writes new values for v_forward, v_up, and v_right based on the given forward vector
225 vectorvectors(vector, vector)
228 void PF_vectorvectors (void)
230 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
231 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
238 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.
240 setorigin (entity, origin)
243 void PF_setorigin (void)
248 e = G_EDICT(OFS_PARM0);
249 org = G_VECTOR(OFS_PARM1);
250 VectorCopy (org, e->v->origin);
251 SV_LinkEdict (e, false);
255 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
259 for (i=0 ; i<3 ; i++)
261 Host_Error ("backwards mins/maxs");
263 // set derived values
264 VectorCopy (min, e->v->mins);
265 VectorCopy (max, e->v->maxs);
266 VectorSubtract (max, min, e->v->size);
268 SV_LinkEdict (e, false);
275 the size box is rotated by the current angle
276 LordHavoc: no it isn't...
278 setsize (entity, minvector, maxvector)
281 void PF_setsize (void)
286 e = G_EDICT(OFS_PARM0);
287 min = G_VECTOR(OFS_PARM1);
288 max = G_VECTOR(OFS_PARM2);
289 SetMinMaxSize (e, min, max, false);
297 setmodel(entity, model)
300 void PF_setmodel (void)
307 e = G_EDICT(OFS_PARM0);
308 m = G_STRING(OFS_PARM1);
310 // check to see if model was properly precached
311 for (i=0, check = sv.model_precache ; *check ; i++, check++)
312 if (!strcmp(*check, m))
316 Host_Error ("no precache: %s\n", m);
319 e->v->model = PR_SetString(*check);
320 e->v->modelindex = i;
322 mod = sv.models[ (int)e->v->modelindex];
325 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
327 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
334 broadcast print to everyone on server
339 void PF_bprint (void)
344 SV_BroadcastPrintf ("%s", s);
351 single print to a specific client
353 sprint(clientent, value)
356 void PF_sprint (void)
362 entnum = G_EDICTNUM(OFS_PARM0);
365 if (entnum < 1 || entnum > svs.maxclients)
367 Con_Printf ("tried to sprint to a non-client\n");
371 client = &svs.clients[entnum-1];
373 MSG_WriteChar (&client->message,svc_print);
374 MSG_WriteString (&client->message, s );
382 single print to a specific client
384 centerprint(clientent, value)
387 void PF_centerprint (void)
393 entnum = G_EDICTNUM(OFS_PARM0);
396 if (entnum < 1 || entnum > svs.maxclients)
398 Con_Printf ("tried to sprint to a non-client\n");
402 client = &svs.clients[entnum-1];
404 MSG_WriteChar (&client->message,svc_centerprint);
405 MSG_WriteString (&client->message, s );
413 vector normalize(vector)
416 void PF_normalize (void)
422 value1 = G_VECTOR(OFS_PARM0);
424 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
428 newvalue[0] = newvalue[1] = newvalue[2] = 0;
432 newvalue[0] = value1[0] * new;
433 newvalue[1] = value1[1] * new;
434 newvalue[2] = value1[2] * new;
437 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
452 value1 = G_VECTOR(OFS_PARM0);
454 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
457 G_FLOAT(OFS_RETURN) = new;
464 float vectoyaw(vector)
467 void PF_vectoyaw (void)
472 value1 = G_VECTOR(OFS_PARM0);
474 if (value1[1] == 0 && value1[0] == 0)
478 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
483 G_FLOAT(OFS_RETURN) = yaw;
491 vector vectoangles(vector)
494 void PF_vectoangles (void)
500 value1 = G_VECTOR(OFS_PARM0);
502 if (value1[1] == 0 && value1[0] == 0)
512 // LordHavoc: optimized a bit
515 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
519 else if (value1[1] > 0)
524 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
525 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
530 G_FLOAT(OFS_RETURN+0) = pitch;
531 G_FLOAT(OFS_RETURN+1) = yaw;
532 G_FLOAT(OFS_RETURN+2) = 0;
539 Returns a number from 0<= num < 1
544 void PF_random (void)
548 num = (rand ()&0x7fff) / ((float)0x7fff);
550 G_FLOAT(OFS_RETURN) = num;
557 particle(origin, color, count)
560 void PF_particle (void)
566 org = G_VECTOR(OFS_PARM0);
567 dir = G_VECTOR(OFS_PARM1);
568 color = G_FLOAT(OFS_PARM2);
569 count = G_FLOAT(OFS_PARM3);
570 SV_StartParticle (org, dir, color, count);
580 void PF_ambientsound (void)
585 float vol, attenuation;
586 int i, soundnum, large;
588 pos = G_VECTOR (OFS_PARM0);
589 samp = G_STRING(OFS_PARM1);
590 vol = G_FLOAT(OFS_PARM2);
591 attenuation = G_FLOAT(OFS_PARM3);
593 // check to see if samp was properly precached
594 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
595 if (!strcmp(*check,samp))
600 Con_Printf ("no precache: %s\n", samp);
608 // add an svc_spawnambient command to the level signon packet
611 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
613 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
615 for (i=0 ; i<3 ; i++)
616 MSG_WriteDPCoord(&sv.signon, pos[i]);
619 MSG_WriteShort (&sv.signon, soundnum);
621 MSG_WriteByte (&sv.signon, soundnum);
623 MSG_WriteByte (&sv.signon, vol*255);
624 MSG_WriteByte (&sv.signon, attenuation*64);
632 Each entity can have eight independant sound sources, like voice,
635 Channel 0 is an auto-allocate channel, the others override anything
636 already running on that entity/channel pair.
638 An attenuation of 0 will play full volume everywhere in the level.
639 Larger attenuations will drop off.
651 entity = G_EDICT(OFS_PARM0);
652 channel = G_FLOAT(OFS_PARM1);
653 sample = G_STRING(OFS_PARM2);
654 volume = G_FLOAT(OFS_PARM3) * 255;
655 attenuation = G_FLOAT(OFS_PARM4);
657 if (volume < 0 || volume > 255)
658 Host_Error ("SV_StartSound: volume = %i", volume);
660 if (attenuation < 0 || attenuation > 4)
661 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
663 if (channel < 0 || channel > 7)
664 Host_Error ("SV_StartSound: channel = %i", channel);
666 SV_StartSound (entity, channel, sample, volume, attenuation);
678 Host_Error ("break statement");
685 Used for use tracing and shot targeting
686 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
687 if the tryents flag is set.
689 traceline (vector1, vector2, tryents)
692 void PF_traceline (void)
699 pr_xfunction->builtinsprofile += 30;
701 v1 = G_VECTOR(OFS_PARM0);
702 v2 = G_VECTOR(OFS_PARM1);
703 nomonsters = G_FLOAT(OFS_PARM2);
704 ent = G_EDICT(OFS_PARM3);
706 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
708 pr_global_struct->trace_allsolid = trace.allsolid;
709 pr_global_struct->trace_startsolid = trace.startsolid;
710 pr_global_struct->trace_fraction = trace.fraction;
711 pr_global_struct->trace_inwater = trace.inwater;
712 pr_global_struct->trace_inopen = trace.inopen;
713 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
714 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
715 pr_global_struct->trace_plane_dist = trace.plane.dist;
717 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
719 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
720 // FIXME: add trace_endcontents
728 Used for use tracing and shot targeting
729 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
730 if the tryents flag is set.
732 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
735 // LordHavoc: added this for my own use, VERY useful, similar to traceline
736 void PF_tracebox (void)
738 float *v1, *v2, *m1, *m2;
743 pr_xfunction->builtinsprofile += 30;
745 v1 = G_VECTOR(OFS_PARM0);
746 m1 = G_VECTOR(OFS_PARM1);
747 m2 = G_VECTOR(OFS_PARM2);
748 v2 = G_VECTOR(OFS_PARM3);
749 nomonsters = G_FLOAT(OFS_PARM4);
750 ent = G_EDICT(OFS_PARM5);
752 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, 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);
768 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
769 void PF_TraceToss (void)
775 pr_xfunction->builtinsprofile += 600;
777 ent = G_EDICT(OFS_PARM0);
778 ignore = G_EDICT(OFS_PARM1);
780 trace = SV_Trace_Toss (ent, ignore);
782 pr_global_struct->trace_allsolid = trace.allsolid;
783 pr_global_struct->trace_startsolid = trace.startsolid;
784 pr_global_struct->trace_fraction = trace.fraction;
785 pr_global_struct->trace_inwater = trace.inwater;
786 pr_global_struct->trace_inopen = trace.inopen;
787 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
788 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
789 pr_global_struct->trace_plane_dist = trace.plane.dist;
791 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
793 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
801 Returns true if the given entity can move to the given position from it's
802 current position by walking or rolling.
804 scalar checkpos (entity, vector)
807 void PF_checkpos (void)
811 //============================================================================
813 qbyte checkpvs[MAX_MAP_LEAFS/8];
815 int PF_newcheckclient (int check)
823 // cycle to the next one
827 if (check > svs.maxclients)
828 check = svs.maxclients;
830 if (check == svs.maxclients)
837 pr_xfunction->builtinsprofile++;
838 if (i == svs.maxclients+1)
844 break; // didn't find anything else
848 if (ent->v->health <= 0)
850 if ((int)ent->v->flags & FL_NOTARGET)
853 // anything that is a client, or has a client as an enemy
857 // get the PVS for the entity
858 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
859 leaf = Mod_PointInLeaf (org, sv.worldmodel);
860 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
861 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
870 Returns a client (or object that has a client enemy) that would be a
873 If there is more than one valid option, they are cycled each frame
875 If (self.origin + self.viewofs) is not in the PVS of the current target,
876 it is not returned at all.
881 int c_invis, c_notvis;
882 void PF_checkclient (void)
889 // find a new check if on a new frame
890 if (sv.time - sv.lastchecktime >= 0.1)
892 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
893 sv.lastchecktime = sv.time;
896 // return check if it might be visible
897 ent = EDICT_NUM(sv.lastcheck);
898 if (ent->free || ent->v->health <= 0)
900 RETURN_EDICT(sv.edicts);
904 // if current entity can't possibly see the check entity, return 0
905 self = PROG_TO_EDICT(pr_global_struct->self);
906 VectorAdd (self->v->origin, self->v->view_ofs, view);
907 leaf = Mod_PointInLeaf (view, sv.worldmodel);
910 l = (leaf - sv.worldmodel->leafs) - 1;
911 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
914 RETURN_EDICT(sv.edicts);
919 // might be able to see it
924 //============================================================================
931 Sends text over to the client's execution buffer
933 stuffcmd (clientent, value)
936 void PF_stuffcmd (void)
942 entnum = G_EDICTNUM(OFS_PARM0);
943 if (entnum < 1 || entnum > svs.maxclients)
944 Host_Error ("Parm 0 not a client");
945 str = G_STRING(OFS_PARM1);
948 host_client = &svs.clients[entnum-1];
949 Host_ClientCommands ("%s", str);
957 Sends text over to the client's execution buffer
962 void PF_localcmd (void)
966 str = G_STRING(OFS_PARM0);
981 str = G_STRING(OFS_PARM0);
983 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
993 void PF_cvar_set (void)
997 var = G_STRING(OFS_PARM0);
998 val = G_STRING(OFS_PARM1);
1000 Cvar_Set (var, val);
1007 Returns a chain of entities that have origins within a spherical area
1009 findradius (origin, radius)
1012 void PF_findradius (void)
1014 edict_t *ent, *chain;
1021 chain = (edict_t *)sv.edicts;
1023 org = G_VECTOR(OFS_PARM0);
1024 radius = G_FLOAT(OFS_PARM1);
1025 radius2 = radius * radius;
1027 ent = NEXT_EDICT(sv.edicts);
1028 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1030 pr_xfunction->builtinsprofile++;
1033 if (ent->v->solid == SOLID_NOT)
1036 // LordHavoc: compare against bounding box rather than center,
1037 // and use DotProduct instead of Length, major speedup
1038 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1039 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1040 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1041 if (DotProduct(eorg, eorg) > radius2)
1044 ent->v->chain = EDICT_TO_PROG(chain);
1048 RETURN_EDICT(chain);
1057 void PF_dprint (void)
1059 Con_DPrintf ("%s",PF_VarString(0));
1062 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1063 #define STRINGTEMP_BUFFERS 16
1064 #define STRINGTEMP_LENGTH 128
1065 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1066 static int pr_string_tempindex = 0;
1068 static char *PR_GetTempString(void)
1071 s = pr_string_temp[pr_string_tempindex];
1072 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1080 v = G_FLOAT(OFS_PARM0);
1082 s = PR_GetTempString();
1083 // LordHavoc: ftos improvement
1084 sprintf (s, "%g", v);
1085 G_INT(OFS_RETURN) = PR_SetString(s);
1091 v = G_FLOAT(OFS_PARM0);
1092 G_FLOAT(OFS_RETURN) = fabs(v);
1098 s = PR_GetTempString();
1099 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1100 G_INT(OFS_RETURN) = PR_SetString(s);
1106 s = PR_GetTempString();
1107 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1108 G_INT(OFS_RETURN) = PR_SetString(s);
1111 void PF_Spawn (void)
1114 pr_xfunction->builtinsprofile += 20;
1119 void PF_Remove (void)
1122 pr_xfunction->builtinsprofile += 20;
1124 ed = G_EDICT(OFS_PARM0);
1125 if (ed == sv.edicts)
1126 Host_Error("remove: tried to remove world\n");
1127 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1128 Host_Error("remove: tried to remove a client\n");
1133 // entity (entity start, .string field, string match) find = #5;
1141 e = G_EDICTNUM(OFS_PARM0);
1142 f = G_INT(OFS_PARM1);
1143 s = G_STRING(OFS_PARM2);
1146 RETURN_EDICT(sv.edicts);
1150 for (e++ ; e < sv.num_edicts ; e++)
1152 pr_xfunction->builtinsprofile++;
1166 RETURN_EDICT(sv.edicts);
1169 // LordHavoc: added this for searching float, int, and entity reference fields
1170 void PF_FindFloat (void)
1177 e = G_EDICTNUM(OFS_PARM0);
1178 f = G_INT(OFS_PARM1);
1179 s = G_FLOAT(OFS_PARM2);
1181 for (e++ ; e < sv.num_edicts ; e++)
1183 pr_xfunction->builtinsprofile++;
1187 if (E_FLOAT(ed,f) == s)
1194 RETURN_EDICT(sv.edicts);
1197 // chained search for strings in entity fields
1198 // entity(.string field, string match) findchain = #402;
1199 void PF_findchain (void)
1204 edict_t *ent, *chain;
1206 chain = (edict_t *)sv.edicts;
1208 f = G_INT(OFS_PARM0);
1209 s = G_STRING(OFS_PARM1);
1212 RETURN_EDICT(sv.edicts);
1216 ent = NEXT_EDICT(sv.edicts);
1217 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1219 pr_xfunction->builtinsprofile++;
1222 t = E_STRING(ent,f);
1228 ent->v->chain = EDICT_TO_PROG(chain);
1232 RETURN_EDICT(chain);
1235 // LordHavoc: chained search for float, int, and entity reference fields
1236 // entity(.string field, float match) findchainfloat = #403;
1237 void PF_findchainfloat (void)
1242 edict_t *ent, *chain;
1244 chain = (edict_t *)sv.edicts;
1246 f = G_INT(OFS_PARM0);
1247 s = G_FLOAT(OFS_PARM1);
1249 ent = NEXT_EDICT(sv.edicts);
1250 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1252 pr_xfunction->builtinsprofile++;
1255 if (E_FLOAT(ent,f) != s)
1258 ent->v->chain = EDICT_TO_PROG(chain);
1262 RETURN_EDICT(chain);
1265 void PR_CheckEmptyString (char *s)
1268 Host_Error ("Bad string");
1271 void PF_precache_file (void)
1272 { // precache_file is only used to copy files with qcc, it does nothing
1273 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1276 void PF_precache_sound (void)
1281 if (sv.state != ss_loading)
1282 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1284 s = G_STRING(OFS_PARM0);
1285 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1286 PR_CheckEmptyString (s);
1288 for (i=0 ; i<MAX_SOUNDS ; i++)
1290 if (!sv.sound_precache[i])
1292 sv.sound_precache[i] = s;
1295 if (!strcmp(sv.sound_precache[i], s))
1298 Host_Error ("PF_precache_sound: overflow");
1301 void PF_precache_model (void)
1306 if (sv.state != ss_loading)
1307 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1309 s = G_STRING(OFS_PARM0);
1310 if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1312 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1313 PR_CheckEmptyString (s);
1315 for (i=0 ; i<MAX_MODELS ; i++)
1317 if (!sv.model_precache[i])
1319 sv.model_precache[i] = s;
1320 sv.models[i] = Mod_ForName (s, true, false, false);
1323 if (!strcmp(sv.model_precache[i], s))
1326 Host_Error ("PF_precache_model: overflow");
1330 void PF_coredump (void)
1335 void PF_traceon (void)
1340 void PF_traceoff (void)
1345 void PF_eprint (void)
1347 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1354 float(float yaw, float dist) walkmove
1357 void PF_walkmove (void)
1365 ent = PROG_TO_EDICT(pr_global_struct->self);
1366 yaw = G_FLOAT(OFS_PARM0);
1367 dist = G_FLOAT(OFS_PARM1);
1369 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1371 G_FLOAT(OFS_RETURN) = 0;
1375 yaw = yaw*M_PI*2 / 360;
1377 move[0] = cos(yaw)*dist;
1378 move[1] = sin(yaw)*dist;
1381 // save program state, because SV_movestep may call other progs
1382 oldf = pr_xfunction;
1383 oldself = pr_global_struct->self;
1385 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1388 // restore program state
1389 pr_xfunction = oldf;
1390 pr_global_struct->self = oldself;
1400 void PF_droptofloor (void)
1406 ent = PROG_TO_EDICT(pr_global_struct->self);
1408 VectorCopy (ent->v->origin, end);
1411 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1413 if (trace.fraction == 1)
1414 G_FLOAT(OFS_RETURN) = 0;
1417 VectorCopy (trace.endpos, ent->v->origin);
1418 SV_LinkEdict (ent, false);
1419 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1420 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1421 G_FLOAT(OFS_RETURN) = 1;
1422 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1423 ent->suspendedinairflag = true;
1431 void(float style, string value) lightstyle
1434 void PF_lightstyle (void)
1441 style = G_FLOAT(OFS_PARM0);
1442 val = G_STRING(OFS_PARM1);
1444 // change the string in sv
1445 sv.lightstyles[style] = val;
1447 // send message to all clients on this server
1448 if (sv.state != ss_active)
1451 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1452 if (client->active || client->spawned)
1454 MSG_WriteChar (&client->message, svc_lightstyle);
1455 MSG_WriteChar (&client->message,style);
1456 MSG_WriteString (&client->message, val);
1463 f = G_FLOAT(OFS_PARM0);
1465 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1467 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1469 void PF_floor (void)
1471 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1475 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1484 void PF_checkbottom (void)
1486 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1494 void PF_pointcontents (void)
1496 G_FLOAT(OFS_RETURN) = Mod_PointContents(G_VECTOR(OFS_PARM0), sv.worldmodel);
1503 entity nextent(entity)
1506 void PF_nextent (void)
1511 i = G_EDICTNUM(OFS_PARM0);
1514 pr_xfunction->builtinsprofile++;
1516 if (i == sv.num_edicts)
1518 RETURN_EDICT(sv.edicts);
1534 Pick a vector for the player to shoot along
1535 vector aim(entity, missilespeed)
1540 edict_t *ent, *check, *bestent;
1541 vec3_t start, dir, end, bestdir;
1544 float dist, bestdist;
1547 ent = G_EDICT(OFS_PARM0);
1548 speed = G_FLOAT(OFS_PARM1);
1550 VectorCopy (ent->v->origin, start);
1553 // try sending a trace straight
1554 VectorCopy (pr_global_struct->v_forward, dir);
1555 VectorMA (start, 2048, dir, end);
1556 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1557 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1558 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1560 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1565 // try all possible entities
1566 VectorCopy (dir, bestdir);
1567 bestdist = sv_aim.value;
1570 check = NEXT_EDICT(sv.edicts);
1571 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1573 pr_xfunction->builtinsprofile++;
1574 if (check->v->takedamage != DAMAGE_AIM)
1578 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1579 continue; // don't aim at teammate
1580 for (j=0 ; j<3 ; j++)
1581 end[j] = check->v->origin[j]
1582 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1583 VectorSubtract (end, start, dir);
1584 VectorNormalize (dir);
1585 dist = DotProduct (dir, pr_global_struct->v_forward);
1586 if (dist < bestdist)
1587 continue; // to far to turn
1588 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1589 if (tr.ent == check)
1590 { // can shoot at this one
1598 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1599 dist = DotProduct (dir, pr_global_struct->v_forward);
1600 VectorScale (pr_global_struct->v_forward, dist, end);
1602 VectorNormalize (end);
1603 VectorCopy (end, G_VECTOR(OFS_RETURN));
1607 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1615 This was a major timewaster in progs, so it was converted to C
1618 void PF_changeyaw (void)
1621 float ideal, current, move, speed;
1623 ent = PROG_TO_EDICT(pr_global_struct->self);
1624 current = ANGLEMOD(ent->v->angles[1]);
1625 ideal = ent->v->ideal_yaw;
1626 speed = ent->v->yaw_speed;
1628 if (current == ideal)
1630 move = ideal - current;
1631 if (ideal > current)
1652 ent->v->angles[1] = ANGLEMOD (current + move);
1660 void PF_changepitch (void)
1663 float ideal, current, move, speed;
1666 ent = G_EDICT(OFS_PARM0);
1667 current = ANGLEMOD( ent->v->angles[0] );
1668 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1669 ideal = val->_float;
1672 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1675 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1676 speed = val->_float;
1679 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1683 if (current == ideal)
1685 move = ideal - current;
1686 if (ideal > current)
1707 ent->v->angles[0] = ANGLEMOD (current + move);
1711 ===============================================================================
1715 ===============================================================================
1718 #define MSG_BROADCAST 0 // unreliable to all
1719 #define MSG_ONE 1 // reliable to one (msg_entity)
1720 #define MSG_ALL 2 // reliable to all
1721 #define MSG_INIT 3 // write to the init string
1723 sizebuf_t *WriteDest (void)
1729 dest = G_FLOAT(OFS_PARM0);
1733 return &sv.datagram;
1736 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1737 entnum = NUM_FOR_EDICT(ent);
1738 if (entnum < 1 || entnum > svs.maxclients)
1739 Host_Error ("WriteDest: not a client");
1740 return &svs.clients[entnum-1].message;
1743 return &sv.reliable_datagram;
1749 Host_Error ("WriteDest: bad destination");
1756 void PF_WriteByte (void)
1758 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1761 void PF_WriteChar (void)
1763 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1766 void PF_WriteShort (void)
1768 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1771 void PF_WriteLong (void)
1773 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1776 void PF_WriteAngle (void)
1778 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1781 void PF_WriteCoord (void)
1783 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1786 void PF_WriteString (void)
1788 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1792 void PF_WriteEntity (void)
1794 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1797 //=============================================================================
1799 void PF_makestatic (void)
1804 ent = G_EDICT(OFS_PARM0);
1807 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1812 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1813 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1814 MSG_WriteShort (&sv.signon, ent->v->frame);
1818 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1819 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1820 MSG_WriteByte (&sv.signon, ent->v->frame);
1823 MSG_WriteByte (&sv.signon, ent->v->colormap);
1824 MSG_WriteByte (&sv.signon, ent->v->skin);
1825 for (i=0 ; i<3 ; i++)
1827 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1828 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1831 // throw the entity away now
1835 //=============================================================================
1842 void PF_setspawnparms (void)
1848 ent = G_EDICT(OFS_PARM0);
1849 i = NUM_FOR_EDICT(ent);
1850 if (i < 1 || i > svs.maxclients)
1851 Host_Error ("Entity is not a client");
1853 // copy spawn parms out of the client_t
1854 client = svs.clients + (i-1);
1856 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1857 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1865 void PF_changelevel (void)
1869 // make sure we don't issue two changelevels
1870 if (svs.changelevel_issued)
1872 svs.changelevel_issued = true;
1874 s = G_STRING(OFS_PARM0);
1875 Cbuf_AddText (va("changelevel %s\n",s));
1880 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1885 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1890 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1897 Returns a vector of length < 1
1902 void PF_randomvec (void)
1907 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1908 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1909 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1911 while (DotProduct(temp, temp) >= 1);
1912 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1915 void SV_LightPoint (vec3_t color, vec3_t p);
1920 Returns a color vector indicating the lighting at the requested point.
1922 (Internal Operation note: actually measures the light beneath the point, just like
1923 the model lighting on the client)
1928 void PF_GetLight (void)
1932 p = G_VECTOR(OFS_PARM0);
1933 SV_LightPoint (color, p);
1934 VectorCopy (color, G_VECTOR(OFS_RETURN));
1937 #define MAX_QC_CVARS 128
1938 cvar_t qc_cvar[MAX_QC_CVARS];
1941 void PF_registercvar (void)
1945 name = G_STRING(OFS_PARM0);
1946 value = G_STRING(OFS_PARM1);
1947 G_FLOAT(OFS_RETURN) = 0;
1948 // first check to see if it has already been defined
1949 if (Cvar_FindVar (name))
1952 // check for overlap with a command
1953 if (Cmd_Exists (name))
1955 Con_Printf ("PF_registercvar: %s is a command\n", name);
1959 if (currentqc_cvar >= MAX_QC_CVARS)
1960 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1962 // copy the name and value
1963 variable = &qc_cvar[currentqc_cvar++];
1964 variable->name = Z_Malloc (strlen(name)+1);
1965 strcpy (variable->name, name);
1966 variable->string = Z_Malloc (strlen(value)+1);
1967 strcpy (variable->string, value);
1968 variable->value = atof (value);
1970 Cvar_RegisterVariable(variable);
1971 G_FLOAT(OFS_RETURN) = 1; // success
1978 returns the minimum of two supplied floats
1985 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1987 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1988 else if (pr_argc >= 3)
1991 float f = G_FLOAT(OFS_PARM0);
1992 for (i = 1;i < pr_argc;i++)
1993 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1994 f = G_FLOAT((OFS_PARM0+i*3));
1995 G_FLOAT(OFS_RETURN) = f;
1998 Host_Error("min: must supply at least 2 floats\n");
2005 returns the maximum of two supplied floats
2012 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2014 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2015 else if (pr_argc >= 3)
2018 float f = G_FLOAT(OFS_PARM0);
2019 for (i = 1;i < pr_argc;i++)
2020 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2021 f = G_FLOAT((OFS_PARM0+i*3));
2022 G_FLOAT(OFS_RETURN) = f;
2025 Host_Error("max: must supply at least 2 floats\n");
2032 returns number bounded by supplied range
2034 min(min, value, max)
2037 void PF_bound (void)
2039 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2046 returns a raised to power b
2053 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2060 copies data from one entity to another
2062 copyentity(src, dst)
2065 void PF_copyentity (void)
2068 in = G_EDICT(OFS_PARM0);
2069 out = G_EDICT(OFS_PARM1);
2070 memcpy(out->v, in->v, progs->entityfields * 4);
2077 sets the color of a client and broadcasts the update to all connected clients
2079 setcolor(clientent, value)
2082 void PF_setcolor (void)
2087 entnum = G_EDICTNUM(OFS_PARM0);
2088 i = G_FLOAT(OFS_PARM1);
2090 if (entnum < 1 || entnum > svs.maxclients)
2092 Con_Printf ("tried to setcolor a non-client\n");
2096 client = &svs.clients[entnum-1];
2098 client->edict->v->team = (i & 15) + 1;
2100 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2101 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2102 MSG_WriteByte (&sv.reliable_datagram, i);
2109 effect(origin, modelname, startframe, framecount, framerate)
2112 void PF_effect (void)
2115 s = G_STRING(OFS_PARM1);
2117 Host_Error("effect: no model specified\n");
2119 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2122 void PF_te_blood (void)
2124 if (G_FLOAT(OFS_PARM2) < 1)
2126 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2127 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2129 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2130 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2131 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2133 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2134 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2135 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2137 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2140 void PF_te_bloodshower (void)
2142 if (G_FLOAT(OFS_PARM3) < 1)
2144 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2145 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2147 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2148 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2149 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2151 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2152 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2153 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2155 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2157 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2160 void PF_te_explosionrgb (void)
2162 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2163 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2165 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2166 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2167 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2169 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2170 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2171 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2174 void PF_te_particlecube (void)
2176 if (G_FLOAT(OFS_PARM3) < 1)
2178 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2179 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2181 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2182 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2183 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2185 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2186 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2187 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2189 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2190 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2191 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2193 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2195 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2196 // gravity true/false
2197 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2199 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2202 void PF_te_particlerain (void)
2204 if (G_FLOAT(OFS_PARM3) < 1)
2206 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2207 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2209 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2210 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2211 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2213 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2214 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2215 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2217 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2218 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2219 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2221 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2223 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2226 void PF_te_particlesnow (void)
2228 if (G_FLOAT(OFS_PARM3) < 1)
2230 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2231 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2233 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2237 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2238 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2239 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2241 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2242 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2243 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2245 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2247 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2250 void PF_te_spark (void)
2252 if (G_FLOAT(OFS_PARM2) < 1)
2254 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2255 MSG_WriteByte(&sv.datagram, TE_SPARK);
2257 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2258 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2259 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2261 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2262 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2263 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2265 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2268 void PF_te_gunshotquad (void)
2270 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2271 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2273 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2274 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2275 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2278 void PF_te_spikequad (void)
2280 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2281 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2283 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2284 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2285 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2288 void PF_te_superspikequad (void)
2290 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2291 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2293 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2294 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2295 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2298 void PF_te_explosionquad (void)
2300 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2301 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2303 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2304 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2305 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2308 void PF_te_smallflash (void)
2310 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2311 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2313 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2314 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2315 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2318 void PF_te_customflash (void)
2320 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2322 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2323 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2325 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2326 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2327 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2329 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2331 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2333 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2334 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2335 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2338 void PF_te_gunshot (void)
2340 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2341 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2343 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2344 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2345 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2348 void PF_te_spike (void)
2350 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2351 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2353 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2354 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2355 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2358 void PF_te_superspike (void)
2360 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2361 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2363 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2364 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2365 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2368 void PF_te_explosion (void)
2370 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2371 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2373 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2374 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2375 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2378 void PF_te_tarexplosion (void)
2380 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2381 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2383 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2384 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2385 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2388 void PF_te_wizspike (void)
2390 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2391 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2393 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2394 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2395 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2398 void PF_te_knightspike (void)
2400 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2401 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2403 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2404 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2405 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2408 void PF_te_lavasplash (void)
2410 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2411 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2413 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2414 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2415 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2418 void PF_te_teleport (void)
2420 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2421 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2423 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2424 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2425 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2428 void PF_te_explosion2 (void)
2430 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2431 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2433 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2434 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2435 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2437 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2440 void PF_te_lightning1 (void)
2442 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2443 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2445 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2447 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2448 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2449 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2451 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2452 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2453 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2456 void PF_te_lightning2 (void)
2458 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2459 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2461 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2463 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2464 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2465 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2467 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2468 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2469 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2472 void PF_te_lightning3 (void)
2474 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2475 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2477 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2479 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2480 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2481 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2483 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2484 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2485 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2488 void PF_te_beam (void)
2490 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2491 MSG_WriteByte(&sv.datagram, TE_BEAM);
2493 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2495 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2496 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2497 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2499 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2500 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2501 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2504 void PF_te_plasmaburn (void)
2506 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2507 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2508 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2509 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2510 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2513 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2516 vec3_t v1, clipplanenormal, normal;
2517 vec_t clipplanedist, clipdist;
2519 if (surf->flags & SURF_PLANEBACK)
2520 VectorNegate(surf->plane->normal, normal);
2522 VectorCopy(surf->plane->normal, normal);
2523 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2525 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2526 VectorNormalizeFast(v1);
2527 CrossProduct(v1, normal, clipplanenormal);
2528 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2529 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2532 clipdist = -clipdist;
2533 VectorMA(out, clipdist, clipplanenormal, out);
2538 static msurface_t *getsurface(edict_t *ed, int surfnum)
2542 if (!ed || ed->free)
2544 modelindex = ed->v->modelindex;
2545 if (modelindex < 1 || modelindex >= MAX_MODELS)
2547 model = sv.models[modelindex];
2548 if (model->type != mod_brush)
2550 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2552 return model->surfaces + surfnum + model->firstmodelsurface;
2556 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2557 void PF_getsurfacenumpoints(void)
2560 // return 0 if no such surface
2561 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2563 G_FLOAT(OFS_RETURN) = 0;
2567 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2569 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2570 void PF_getsurfacepoint(void)
2575 VectorClear(G_VECTOR(OFS_RETURN));
2576 ed = G_EDICT(OFS_PARM0);
2577 if (!ed || ed->free)
2579 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2581 pointnum = G_FLOAT(OFS_PARM2);
2582 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2584 // FIXME: implement rotation/scaling
2585 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2587 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2588 void PF_getsurfacenormal(void)
2591 VectorClear(G_VECTOR(OFS_RETURN));
2592 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2594 // FIXME: implement rotation/scaling
2595 if (surf->flags & SURF_PLANEBACK)
2596 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2598 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2600 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2601 void PF_getsurfacetexture(void)
2604 G_INT(OFS_RETURN) = 0;
2605 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2607 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2609 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2610 void PF_getsurfacenearpoint(void)
2612 int surfnum, best, modelindex;
2614 vec_t dist, bestdist;
2619 G_FLOAT(OFS_RETURN) = -1;
2620 ed = G_EDICT(OFS_PARM0);
2621 point = G_VECTOR(OFS_PARM1);
2623 if (!ed || ed->free)
2625 modelindex = ed->v->modelindex;
2626 if (modelindex < 1 || modelindex >= MAX_MODELS)
2628 model = sv.models[modelindex];
2629 if (model->type != mod_brush)
2632 // FIXME: implement rotation/scaling
2633 VectorSubtract(point, ed->v->origin, p);
2635 bestdist = 1000000000;
2636 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2638 surf = model->surfaces + surfnum + model->firstmodelsurface;
2639 dist = PlaneDiff(p, surf->plane);
2641 if (dist < bestdist)
2643 clippointtosurface(surf, p, clipped);
2644 VectorSubtract(clipped, p, clipped);
2645 dist += DotProduct(clipped, clipped);
2646 if (dist < bestdist)
2653 G_FLOAT(OFS_RETURN) = best;
2655 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2656 void PF_getsurfaceclippedpoint(void)
2661 VectorClear(G_VECTOR(OFS_RETURN));
2662 ed = G_EDICT(OFS_PARM0);
2663 if (!ed || ed->free)
2665 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2667 // FIXME: implement rotation/scaling
2668 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2669 clippointtosurface(surf, p, out);
2670 // FIXME: implement rotation/scaling
2671 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2674 #define MAX_PRFILES 256
2676 qfile_t *pr_files[MAX_PRFILES];
2678 void PR_Files_Init(void)
2680 memset(pr_files, 0, sizeof(pr_files));
2683 void PR_Files_CloseAll(void)
2686 for (i = 0;i < MAX_PRFILES;i++)
2689 FS_Close(pr_files[i]);
2694 //float(string s) stof = #81; // get numerical value from a string
2697 char *s = PF_VarString(0);
2698 G_FLOAT(OFS_RETURN) = atof(s);
2701 //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
2705 char *modestring, *filename;
2706 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2707 if (pr_files[filenum] == NULL)
2709 if (filenum >= MAX_PRFILES)
2711 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2712 G_FLOAT(OFS_RETURN) = -2;
2715 mode = G_FLOAT(OFS_PARM1);
2718 case 0: // FILE_READ
2721 case 1: // FILE_APPEND
2724 case 2: // FILE_WRITE
2728 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2729 G_FLOAT(OFS_RETURN) = -3;
2732 filename = G_STRING(OFS_PARM0);
2733 // .. is parent directory on many platforms
2734 // / is parent directory on Amiga
2735 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2736 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2737 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2739 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2740 G_FLOAT(OFS_RETURN) = -4;
2743 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2744 if (pr_files[filenum] == NULL)
2745 G_FLOAT(OFS_RETURN) = -1;
2747 G_FLOAT(OFS_RETURN) = filenum;
2750 //void(float fhandle) fclose = #111; // closes a file
2751 void PF_fclose(void)
2753 int filenum = G_FLOAT(OFS_PARM0);
2754 if (filenum < 0 || filenum >= MAX_PRFILES)
2756 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2759 if (pr_files[filenum] == NULL)
2761 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2764 FS_Close(pr_files[filenum]);
2765 pr_files[filenum] = NULL;
2768 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2772 static char string[MAX_VARSTRING];
2773 int filenum = G_FLOAT(OFS_PARM0);
2774 if (filenum < 0 || filenum >= MAX_PRFILES)
2776 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2779 if (pr_files[filenum] == NULL)
2781 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2787 c = FS_Getc(pr_files[filenum]);
2788 if (c == '\r' || c == '\n' || c < 0)
2790 if (end < MAX_VARSTRING - 1)
2794 // remove \n following \r
2796 c = FS_Getc(pr_files[filenum]);
2797 if (developer.integer)
2798 Con_Printf("fgets: %s\n", string);
2800 G_INT(OFS_RETURN) = PR_SetString(string);
2802 G_INT(OFS_RETURN) = 0;
2805 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2809 char *s = PF_VarString(1);
2810 int filenum = G_FLOAT(OFS_PARM0);
2811 if (filenum < 0 || filenum >= MAX_PRFILES)
2813 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2816 if (pr_files[filenum] == NULL)
2818 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2821 if ((stringlength = strlen(s)))
2822 FS_Write(pr_files[filenum], s, stringlength);
2823 if (developer.integer)
2824 Con_Printf("fputs: %s\n", s);
2827 //float(string s) strlen = #114; // returns how many characters are in a string
2828 void PF_strlen(void)
2831 s = G_STRING(OFS_PARM0);
2833 G_FLOAT(OFS_RETURN) = strlen(s);
2835 G_FLOAT(OFS_RETURN) = 0;
2838 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2839 void PF_strcat(void)
2841 char *s = PF_VarString(0);
2842 G_INT(OFS_RETURN) = PR_SetString(s);
2845 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2846 void PF_substring(void)
2848 int end, start, length, slen;
2850 char string[MAX_VARSTRING];
2851 s = G_STRING(OFS_PARM0);
2852 start = G_FLOAT(OFS_PARM1);
2853 length = G_FLOAT(OFS_PARM2);
2860 if (length > slen - start)
2861 length = slen - start;
2862 if (length > MAX_VARSTRING - 1)
2863 length = MAX_VARSTRING - 1;
2867 memcpy(string, s + start, length);
2871 G_INT(OFS_RETURN) = PR_SetString(string);
2874 //vector(string s) stov = #117; // returns vector value from a string
2877 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2880 //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)
2881 void PF_strzone(void)
2884 in = G_STRING(OFS_PARM0);
2885 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2887 G_INT(OFS_RETURN) = PR_SetString(out);
2890 //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!!!)
2891 void PF_strunzone(void)
2893 Mem_Free(G_STRING(OFS_PARM0));
2896 builtin_t pr_builtin[] =
2899 PF_makevectors, // #1 void(entity e) makevectors
2900 PF_setorigin, // #2 void(entity e, vector o) setorigin
2901 PF_setmodel, // #3 void(entity e, string m) setmodel
2902 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2903 NULL, // #5 void(entity e, vector min, vector max) setabssize
2904 PF_break, // #6 void() break
2905 PF_random, // #7 float() random
2906 PF_sound, // #8 void(entity e, float chan, string samp) sound
2907 PF_normalize, // #9 vector(vector v) normalize
2908 PF_error, // #10 void(string e) error
2909 PF_objerror, // #11 void(string e) objerror
2910 PF_vlen, // #12 float(vector v) vlen
2911 PF_vectoyaw, // #13 float(vector v) vectoyaw
2912 PF_Spawn, // #14 entity() spawn
2913 PF_Remove, // #15 void(entity e) remove
2914 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
2915 PF_checkclient, // #17 entity() clientlist
2916 PF_Find, // #18 entity(entity start, .string fld, string match) find
2917 PF_precache_sound, // #19 void(string s) precache_sound
2918 PF_precache_model, // #20 void(string s) precache_model
2919 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
2920 PF_findradius, // #22 entity(vector org, float rad) findradius
2921 PF_bprint, // #23 void(string s) bprint
2922 PF_sprint, // #24 void(entity client, string s) sprint
2923 PF_dprint, // #25 void(string s) dprint
2924 PF_ftos, // #26 void(string s) ftos
2925 PF_vtos, // #27 void(string s) vtos
2926 PF_coredump, // #28 void() coredump
2927 PF_traceon, // #29 void() traceon
2928 PF_traceoff, // #30 void() traceoff
2929 PF_eprint, // #31 void(entity e) eprint
2930 PF_walkmove, // #32 float(float yaw, float dist) walkmove
2932 PF_droptofloor, // #34 float() droptofloor
2933 PF_lightstyle, // #35 void(float style, string value) lightstyle
2934 PF_rint, // #36 float(float v) rint
2935 PF_floor, // #37 float(float v) floor
2936 PF_ceil, // #38 float(float v) ceil
2938 PF_checkbottom, // #40 float(entity e) checkbottom
2939 PF_pointcontents , // #41 float(vector v) pointcontents
2941 PF_fabs, // #43 float(float f) fabs
2942 PF_aim, // #44 vector(entity e, float speed) aim
2943 PF_cvar, // #45 float(string s) cvar
2944 PF_localcmd, // #46 void(string s) localcmd
2945 PF_nextent, // #47 entity(entity e) nextent
2946 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
2947 PF_changeyaw, // #49 void() ChangeYaw
2949 PF_vectoangles, // #51 vector(vector v) vectoangles
2950 PF_WriteByte, // #52 void(float to, float f) WriteByte
2951 PF_WriteChar, // #53 void(float to, float f) WriteChar
2952 PF_WriteShort, // #54 void(float to, float f) WriteShort
2953 PF_WriteLong, // #55 void(float to, float f) WriteLong
2954 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
2955 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
2956 PF_WriteString, // #58 void(float to, string s) WriteString
2957 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
2958 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2959 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2960 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2961 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2962 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2963 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2965 SV_MoveToGoal, // #67 void(float step) movetogoal
2966 PF_precache_file, // #68 string(string s) precache_file
2967 PF_makestatic, // #69 void(entity e) makestatic
2968 PF_changelevel, // #70 void(string s) changelevel
2970 PF_cvar_set, // #72 void(string var, string val) cvar_set
2971 PF_centerprint, // #73 void(entity client, strings) centerprint
2972 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
2973 PF_precache_model, // #75 string(string s) precache_model2
2974 PF_precache_sound, // #76 string(string s) precache_sound2
2975 PF_precache_file, // #77 string(string s) precache_file2
2976 PF_setspawnparms, // #78 void(entity e) setspawnparms
2979 PF_stof, // #81 float(string s) stof (FRIK_FILE)
2988 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2989 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2990 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2991 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2992 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2993 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2994 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2995 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2996 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2997 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3008 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3009 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3010 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3011 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3012 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3013 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3014 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3015 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3016 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3017 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3018 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3019 a a a a a a a a // #120-199
3020 a a a a a a a a a a // #200-299
3021 a a a a a a a a a a // #300-399
3022 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3023 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3024 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3025 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3026 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3027 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3028 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3029 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3030 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3031 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3032 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3033 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3034 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3035 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3036 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3037 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3038 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3039 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3040 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3041 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3042 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3043 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3044 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3045 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3046 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3047 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3048 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3049 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3050 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3051 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3052 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3053 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3054 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3055 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3056 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3057 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3058 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3059 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3060 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3061 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3062 a a a a a a // #440-499 (LordHavoc)
3065 builtin_t *pr_builtins = pr_builtin;
3066 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3068 void PR_Cmd_Init(void)
3070 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3074 void PR_Cmd_Reset(void)
3076 Mem_EmptyPool(pr_strings_mempool);
3077 PR_Files_CloseAll();