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 =
69 "DP_ENT_CUSTOMCOLORMAP "
70 "DP_ENT_EXTERIORMODELTOCLIENT "
71 "DP_ENT_LOWPRECISION "
84 "DP_QC_FINDCHAINFLOAT "
89 "DP_QC_SINCOSSQRTPOW "
92 "DP_QC_VECTORVECTORS "
97 "DP_SV_DRAWONLYTOCLIENT "
99 "DP_SV_EXTERIORMODELTOCLIENT "
100 "DP_SV_NODRAWTOCLIENT "
101 "DP_SV_PLAYERPHYSICS "
106 "DP_TE_EXPLOSIONRGB "
107 "DP_TE_PARTICLECUBE "
108 "DP_TE_PARTICLERAIN "
109 "DP_TE_PARTICLESNOW "
117 qboolean checkextension(char *name)
122 for (e = ENGINE_EXTENSIONS;*e;e++)
129 while (*e && *e != ' ')
131 if (e - start == len)
132 if (!strncasecmp(start, name, len))
142 returns true if the extension is supported by the server
144 checkextension(extensionname)
147 void PF_checkextension (void)
149 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
156 This is a TERMINAL error, which will kill off the entire server.
168 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
169 ed = PROG_TO_EDICT(pr_global_struct->self);
172 Host_Error ("Program error");
179 Dumps out self, then an error message. The program is aborted and self is
180 removed, but the level can continue.
185 void PF_objerror (void)
191 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
192 ed = PROG_TO_EDICT(pr_global_struct->self);
202 Writes new values for v_forward, v_up, and v_right based on angles
206 void PF_makevectors (void)
208 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
215 Writes new values for v_forward, v_up, and v_right based on the given forward vector
216 vectorvectors(vector, vector)
219 void PF_vectorvectors (void)
221 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
222 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
229 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.
231 setorigin (entity, origin)
234 void PF_setorigin (void)
239 e = G_EDICT(OFS_PARM0);
240 org = G_VECTOR(OFS_PARM1);
241 VectorCopy (org, e->v->origin);
242 SV_LinkEdict (e, false);
246 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
250 for (i=0 ; i<3 ; i++)
252 Host_Error ("backwards mins/maxs");
254 // set derived values
255 VectorCopy (min, e->v->mins);
256 VectorCopy (max, e->v->maxs);
257 VectorSubtract (max, min, e->v->size);
259 SV_LinkEdict (e, false);
266 the size box is rotated by the current angle
267 LordHavoc: no it isn't...
269 setsize (entity, minvector, maxvector)
272 void PF_setsize (void)
277 e = G_EDICT(OFS_PARM0);
278 min = G_VECTOR(OFS_PARM1);
279 max = G_VECTOR(OFS_PARM2);
280 SetMinMaxSize (e, min, max, false);
288 setmodel(entity, model)
291 void PF_setmodel (void)
298 e = G_EDICT(OFS_PARM0);
299 m = G_STRING(OFS_PARM1);
301 // check to see if model was properly precached
302 for (i=0, check = sv.model_precache ; *check ; i++, check++)
303 if (!strcmp(*check, m))
307 Host_Error ("no precache: %s\n", m);
310 e->v->model = PR_SetString(*check);
311 e->v->modelindex = i;
313 mod = sv.models[ (int)e->v->modelindex];
316 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
318 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
325 broadcast print to everyone on server
330 void PF_bprint (void)
335 SV_BroadcastPrintf ("%s", s);
342 single print to a specific client
344 sprint(clientent, value)
347 void PF_sprint (void)
353 entnum = G_EDICTNUM(OFS_PARM0);
356 if (entnum < 1 || entnum > svs.maxclients)
358 Con_Printf ("tried to sprint to a non-client\n");
362 client = &svs.clients[entnum-1];
364 MSG_WriteChar (&client->message,svc_print);
365 MSG_WriteString (&client->message, s );
373 single print to a specific client
375 centerprint(clientent, value)
378 void PF_centerprint (void)
384 entnum = G_EDICTNUM(OFS_PARM0);
387 if (entnum < 1 || entnum > svs.maxclients)
389 Con_Printf ("tried to sprint to a non-client\n");
393 client = &svs.clients[entnum-1];
395 MSG_WriteChar (&client->message,svc_centerprint);
396 MSG_WriteString (&client->message, s );
404 vector normalize(vector)
407 void PF_normalize (void)
413 value1 = G_VECTOR(OFS_PARM0);
415 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
419 newvalue[0] = newvalue[1] = newvalue[2] = 0;
423 newvalue[0] = value1[0] * new;
424 newvalue[1] = value1[1] * new;
425 newvalue[2] = value1[2] * new;
428 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
443 value1 = G_VECTOR(OFS_PARM0);
445 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
448 G_FLOAT(OFS_RETURN) = new;
455 float vectoyaw(vector)
458 void PF_vectoyaw (void)
463 value1 = G_VECTOR(OFS_PARM0);
465 if (value1[1] == 0 && value1[0] == 0)
469 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
474 G_FLOAT(OFS_RETURN) = yaw;
482 vector vectoangles(vector)
485 void PF_vectoangles (void)
491 value1 = G_VECTOR(OFS_PARM0);
493 if (value1[1] == 0 && value1[0] == 0)
503 // LordHavoc: optimized a bit
506 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
510 else if (value1[1] > 0)
515 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
516 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
521 G_FLOAT(OFS_RETURN+0) = pitch;
522 G_FLOAT(OFS_RETURN+1) = yaw;
523 G_FLOAT(OFS_RETURN+2) = 0;
530 Returns a number from 0<= num < 1
535 void PF_random (void)
539 num = (rand ()&0x7fff) / ((float)0x7fff);
541 G_FLOAT(OFS_RETURN) = num;
548 particle(origin, color, count)
551 void PF_particle (void)
557 org = G_VECTOR(OFS_PARM0);
558 dir = G_VECTOR(OFS_PARM1);
559 color = G_FLOAT(OFS_PARM2);
560 count = G_FLOAT(OFS_PARM3);
561 SV_StartParticle (org, dir, color, count);
571 void PF_ambientsound (void)
576 float vol, attenuation;
577 int i, soundnum, large;
579 pos = G_VECTOR (OFS_PARM0);
580 samp = G_STRING(OFS_PARM1);
581 vol = G_FLOAT(OFS_PARM2);
582 attenuation = G_FLOAT(OFS_PARM3);
584 // check to see if samp was properly precached
585 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
586 if (!strcmp(*check,samp))
591 Con_Printf ("no precache: %s\n", samp);
599 // add an svc_spawnambient command to the level signon packet
602 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
604 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
606 for (i=0 ; i<3 ; i++)
607 MSG_WriteDPCoord(&sv.signon, pos[i]);
610 MSG_WriteShort (&sv.signon, soundnum);
612 MSG_WriteByte (&sv.signon, soundnum);
614 MSG_WriteByte (&sv.signon, vol*255);
615 MSG_WriteByte (&sv.signon, attenuation*64);
623 Each entity can have eight independant sound sources, like voice,
626 Channel 0 is an auto-allocate channel, the others override anything
627 already running on that entity/channel pair.
629 An attenuation of 0 will play full volume everywhere in the level.
630 Larger attenuations will drop off.
642 entity = G_EDICT(OFS_PARM0);
643 channel = G_FLOAT(OFS_PARM1);
644 sample = G_STRING(OFS_PARM2);
645 volume = G_FLOAT(OFS_PARM3) * 255;
646 attenuation = G_FLOAT(OFS_PARM4);
648 if (volume < 0 || volume > 255)
649 Host_Error ("SV_StartSound: volume = %i", volume);
651 if (attenuation < 0 || attenuation > 4)
652 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
654 if (channel < 0 || channel > 7)
655 Host_Error ("SV_StartSound: channel = %i", channel);
657 SV_StartSound (entity, channel, sample, volume, attenuation);
669 Host_Error ("break statement");
676 Used for use tracing and shot targeting
677 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
678 if the tryents flag is set.
680 traceline (vector1, vector2, tryents)
683 void PF_traceline (void)
690 pr_xfunction->builtinsprofile += 30;
692 v1 = G_VECTOR(OFS_PARM0);
693 v2 = G_VECTOR(OFS_PARM1);
694 nomonsters = G_FLOAT(OFS_PARM2);
695 ent = G_EDICT(OFS_PARM3);
697 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
699 pr_global_struct->trace_allsolid = trace.allsolid;
700 pr_global_struct->trace_startsolid = trace.startsolid;
701 pr_global_struct->trace_fraction = trace.fraction;
702 pr_global_struct->trace_inwater = trace.inwater;
703 pr_global_struct->trace_inopen = trace.inopen;
704 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
705 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
706 pr_global_struct->trace_plane_dist = trace.plane.dist;
708 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
710 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
711 // FIXME: add trace_endcontents
719 Used for use tracing and shot targeting
720 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
721 if the tryents flag is set.
723 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
726 // LordHavoc: added this for my own use, VERY useful, similar to traceline
727 void PF_tracebox (void)
729 float *v1, *v2, *m1, *m2;
734 pr_xfunction->builtinsprofile += 30;
736 v1 = G_VECTOR(OFS_PARM0);
737 m1 = G_VECTOR(OFS_PARM1);
738 m2 = G_VECTOR(OFS_PARM2);
739 v2 = G_VECTOR(OFS_PARM3);
740 nomonsters = G_FLOAT(OFS_PARM4);
741 ent = G_EDICT(OFS_PARM5);
743 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
745 pr_global_struct->trace_allsolid = trace.allsolid;
746 pr_global_struct->trace_startsolid = trace.startsolid;
747 pr_global_struct->trace_fraction = trace.fraction;
748 pr_global_struct->trace_inwater = trace.inwater;
749 pr_global_struct->trace_inopen = trace.inopen;
750 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
751 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
752 pr_global_struct->trace_plane_dist = trace.plane.dist;
754 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
756 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
759 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
760 void PF_TraceToss (void)
766 pr_xfunction->builtinsprofile += 600;
768 ent = G_EDICT(OFS_PARM0);
769 ignore = G_EDICT(OFS_PARM1);
771 trace = SV_Trace_Toss (ent, ignore);
773 pr_global_struct->trace_allsolid = trace.allsolid;
774 pr_global_struct->trace_startsolid = trace.startsolid;
775 pr_global_struct->trace_fraction = trace.fraction;
776 pr_global_struct->trace_inwater = trace.inwater;
777 pr_global_struct->trace_inopen = trace.inopen;
778 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
779 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
780 pr_global_struct->trace_plane_dist = trace.plane.dist;
782 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
784 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
792 Returns true if the given entity can move to the given position from it's
793 current position by walking or rolling.
795 scalar checkpos (entity, vector)
798 void PF_checkpos (void)
802 //============================================================================
804 qbyte checkpvs[MAX_MAP_LEAFS/8];
806 int PF_newcheckclient (int check)
814 // cycle to the next one
818 if (check > svs.maxclients)
819 check = svs.maxclients;
821 if (check == svs.maxclients)
828 pr_xfunction->builtinsprofile++;
829 if (i == svs.maxclients+1)
835 break; // didn't find anything else
839 if (ent->v->health <= 0)
841 if ((int)ent->v->flags & FL_NOTARGET)
844 // anything that is a client, or has a client as an enemy
848 // get the PVS for the entity
849 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
850 leaf = Mod_PointInLeaf (org, sv.worldmodel);
851 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
852 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
861 Returns a client (or object that has a client enemy) that would be a
864 If there is more than one valid option, they are cycled each frame
866 If (self.origin + self.viewofs) is not in the PVS of the current target,
867 it is not returned at all.
872 int c_invis, c_notvis;
873 void PF_checkclient (void)
880 // find a new check if on a new frame
881 if (sv.time - sv.lastchecktime >= 0.1)
883 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
884 sv.lastchecktime = sv.time;
887 // return check if it might be visible
888 ent = EDICT_NUM(sv.lastcheck);
889 if (ent->free || ent->v->health <= 0)
891 RETURN_EDICT(sv.edicts);
895 // if current entity can't possibly see the check entity, return 0
896 self = PROG_TO_EDICT(pr_global_struct->self);
897 VectorAdd (self->v->origin, self->v->view_ofs, view);
898 leaf = Mod_PointInLeaf (view, sv.worldmodel);
901 l = (leaf - sv.worldmodel->leafs) - 1;
902 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
905 RETURN_EDICT(sv.edicts);
910 // might be able to see it
915 //============================================================================
922 Sends text over to the client's execution buffer
924 stuffcmd (clientent, value)
927 void PF_stuffcmd (void)
933 entnum = G_EDICTNUM(OFS_PARM0);
934 if (entnum < 1 || entnum > svs.maxclients)
935 Host_Error ("Parm 0 not a client");
936 str = G_STRING(OFS_PARM1);
939 host_client = &svs.clients[entnum-1];
940 Host_ClientCommands ("%s", str);
948 Sends text over to the client's execution buffer
953 void PF_localcmd (void)
957 str = G_STRING(OFS_PARM0);
972 str = G_STRING(OFS_PARM0);
974 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
984 void PF_cvar_set (void)
988 var = G_STRING(OFS_PARM0);
989 val = G_STRING(OFS_PARM1);
998 Returns a chain of entities that have origins within a spherical area
1000 findradius (origin, radius)
1003 void PF_findradius (void)
1005 edict_t *ent, *chain;
1012 chain = (edict_t *)sv.edicts;
1014 org = G_VECTOR(OFS_PARM0);
1015 radius = G_FLOAT(OFS_PARM1);
1016 radius2 = radius * radius;
1018 ent = NEXT_EDICT(sv.edicts);
1019 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1021 pr_xfunction->builtinsprofile++;
1024 if (ent->v->solid == SOLID_NOT)
1027 // LordHavoc: compare against bounding box rather than center,
1028 // and use DotProduct instead of Length, major speedup
1029 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1030 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1031 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1032 if (DotProduct(eorg, eorg) > radius2)
1035 ent->v->chain = EDICT_TO_PROG(chain);
1039 RETURN_EDICT(chain);
1048 void PF_dprint (void)
1050 Con_DPrintf ("%s",PF_VarString(0));
1053 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1054 #define STRINGTEMP_BUFFERS 16
1055 #define STRINGTEMP_LENGTH 128
1056 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1057 static int pr_string_tempindex = 0;
1059 static char *PR_GetTempString(void)
1062 s = pr_string_temp[pr_string_tempindex];
1063 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1071 v = G_FLOAT(OFS_PARM0);
1073 s = PR_GetTempString();
1074 // LordHavoc: ftos improvement
1075 sprintf (s, "%g", v);
1076 G_INT(OFS_RETURN) = PR_SetString(s);
1082 v = G_FLOAT(OFS_PARM0);
1083 G_FLOAT(OFS_RETURN) = fabs(v);
1089 s = PR_GetTempString();
1090 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1091 G_INT(OFS_RETURN) = PR_SetString(s);
1097 s = PR_GetTempString();
1098 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1099 G_INT(OFS_RETURN) = PR_SetString(s);
1102 void PF_Spawn (void)
1105 pr_xfunction->builtinsprofile += 20;
1110 void PF_Remove (void)
1113 pr_xfunction->builtinsprofile += 20;
1115 ed = G_EDICT(OFS_PARM0);
1116 if (ed == sv.edicts)
1117 Host_Error("remove: tried to remove world\n");
1118 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1119 Host_Error("remove: tried to remove a client\n");
1124 // entity (entity start, .string field, string match) find = #5;
1132 e = G_EDICTNUM(OFS_PARM0);
1133 f = G_INT(OFS_PARM1);
1134 s = G_STRING(OFS_PARM2);
1137 RETURN_EDICT(sv.edicts);
1141 for (e++ ; e < sv.num_edicts ; e++)
1143 pr_xfunction->builtinsprofile++;
1157 RETURN_EDICT(sv.edicts);
1160 // LordHavoc: added this for searching float, int, and entity reference fields
1161 void PF_FindFloat (void)
1168 e = G_EDICTNUM(OFS_PARM0);
1169 f = G_INT(OFS_PARM1);
1170 s = G_FLOAT(OFS_PARM2);
1172 for (e++ ; e < sv.num_edicts ; e++)
1174 pr_xfunction->builtinsprofile++;
1178 if (E_FLOAT(ed,f) == s)
1185 RETURN_EDICT(sv.edicts);
1188 // chained search for strings in entity fields
1189 // entity(.string field, string match) findchain = #402;
1190 void PF_findchain (void)
1195 edict_t *ent, *chain;
1197 chain = (edict_t *)sv.edicts;
1199 f = G_INT(OFS_PARM0);
1200 s = G_STRING(OFS_PARM1);
1203 RETURN_EDICT(sv.edicts);
1207 ent = NEXT_EDICT(sv.edicts);
1208 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1210 pr_xfunction->builtinsprofile++;
1213 t = E_STRING(ent,f);
1219 ent->v->chain = EDICT_TO_PROG(chain);
1223 RETURN_EDICT(chain);
1226 // LordHavoc: chained search for float, int, and entity reference fields
1227 // entity(.string field, float match) findchainfloat = #403;
1228 void PF_findchainfloat (void)
1233 edict_t *ent, *chain;
1235 chain = (edict_t *)sv.edicts;
1237 f = G_INT(OFS_PARM0);
1238 s = G_FLOAT(OFS_PARM1);
1240 ent = NEXT_EDICT(sv.edicts);
1241 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1243 pr_xfunction->builtinsprofile++;
1246 if (E_FLOAT(ent,f) != s)
1249 ent->v->chain = EDICT_TO_PROG(chain);
1253 RETURN_EDICT(chain);
1256 void PR_CheckEmptyString (char *s)
1259 Host_Error ("Bad string");
1262 void PF_precache_file (void)
1263 { // precache_file is only used to copy files with qcc, it does nothing
1264 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1267 void PF_precache_sound (void)
1272 if (sv.state != ss_loading)
1273 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1275 s = G_STRING(OFS_PARM0);
1276 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1277 PR_CheckEmptyString (s);
1279 for (i=0 ; i<MAX_SOUNDS ; i++)
1281 if (!sv.sound_precache[i])
1283 sv.sound_precache[i] = s;
1286 if (!strcmp(sv.sound_precache[i], s))
1289 Host_Error ("PF_precache_sound: overflow");
1292 void PF_precache_model (void)
1297 if (sv.state != ss_loading)
1298 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1300 s = G_STRING(OFS_PARM0);
1301 if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1303 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1304 PR_CheckEmptyString (s);
1306 for (i=0 ; i<MAX_MODELS ; i++)
1308 if (!sv.model_precache[i])
1310 sv.model_precache[i] = s;
1311 sv.models[i] = Mod_ForName (s, true, false, false);
1314 if (!strcmp(sv.model_precache[i], s))
1317 Host_Error ("PF_precache_model: overflow");
1321 void PF_coredump (void)
1326 void PF_traceon (void)
1331 void PF_traceoff (void)
1336 void PF_eprint (void)
1338 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1345 float(float yaw, float dist) walkmove
1348 void PF_walkmove (void)
1356 ent = PROG_TO_EDICT(pr_global_struct->self);
1357 yaw = G_FLOAT(OFS_PARM0);
1358 dist = G_FLOAT(OFS_PARM1);
1360 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1362 G_FLOAT(OFS_RETURN) = 0;
1366 yaw = yaw*M_PI*2 / 360;
1368 move[0] = cos(yaw)*dist;
1369 move[1] = sin(yaw)*dist;
1372 // save program state, because SV_movestep may call other progs
1373 oldf = pr_xfunction;
1374 oldself = pr_global_struct->self;
1376 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1379 // restore program state
1380 pr_xfunction = oldf;
1381 pr_global_struct->self = oldself;
1391 void PF_droptofloor (void)
1397 ent = PROG_TO_EDICT(pr_global_struct->self);
1399 VectorCopy (ent->v->origin, end);
1402 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1404 if (trace.fraction == 1)
1405 G_FLOAT(OFS_RETURN) = 0;
1408 VectorCopy (trace.endpos, ent->v->origin);
1409 SV_LinkEdict (ent, false);
1410 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1411 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1412 G_FLOAT(OFS_RETURN) = 1;
1413 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1414 ent->suspendedinairflag = true;
1422 void(float style, string value) lightstyle
1425 void PF_lightstyle (void)
1432 style = G_FLOAT(OFS_PARM0);
1433 val = G_STRING(OFS_PARM1);
1435 // change the string in sv
1436 sv.lightstyles[style] = val;
1438 // send message to all clients on this server
1439 if (sv.state != ss_active)
1442 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1443 if (client->active || client->spawned)
1445 MSG_WriteChar (&client->message, svc_lightstyle);
1446 MSG_WriteChar (&client->message,style);
1447 MSG_WriteString (&client->message, val);
1454 f = G_FLOAT(OFS_PARM0);
1456 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1458 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1460 void PF_floor (void)
1462 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1466 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1475 void PF_checkbottom (void)
1477 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1485 void PF_pointcontents (void)
1487 G_FLOAT(OFS_RETURN) = Mod_PointContents(G_VECTOR(OFS_PARM0), sv.worldmodel);
1494 entity nextent(entity)
1497 void PF_nextent (void)
1502 i = G_EDICTNUM(OFS_PARM0);
1505 pr_xfunction->builtinsprofile++;
1507 if (i == sv.num_edicts)
1509 RETURN_EDICT(sv.edicts);
1525 Pick a vector for the player to shoot along
1526 vector aim(entity, missilespeed)
1531 edict_t *ent, *check, *bestent;
1532 vec3_t start, dir, end, bestdir;
1535 float dist, bestdist;
1538 ent = G_EDICT(OFS_PARM0);
1539 speed = G_FLOAT(OFS_PARM1);
1541 VectorCopy (ent->v->origin, start);
1544 // try sending a trace straight
1545 VectorCopy (pr_global_struct->v_forward, dir);
1546 VectorMA (start, 2048, dir, end);
1547 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1548 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1549 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1551 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1556 // try all possible entities
1557 VectorCopy (dir, bestdir);
1558 bestdist = sv_aim.value;
1561 check = NEXT_EDICT(sv.edicts);
1562 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1564 pr_xfunction->builtinsprofile++;
1565 if (check->v->takedamage != DAMAGE_AIM)
1569 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1570 continue; // don't aim at teammate
1571 for (j=0 ; j<3 ; j++)
1572 end[j] = check->v->origin[j]
1573 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1574 VectorSubtract (end, start, dir);
1575 VectorNormalize (dir);
1576 dist = DotProduct (dir, pr_global_struct->v_forward);
1577 if (dist < bestdist)
1578 continue; // to far to turn
1579 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1580 if (tr.ent == check)
1581 { // can shoot at this one
1589 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1590 dist = DotProduct (dir, pr_global_struct->v_forward);
1591 VectorScale (pr_global_struct->v_forward, dist, end);
1593 VectorNormalize (end);
1594 VectorCopy (end, G_VECTOR(OFS_RETURN));
1598 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1606 This was a major timewaster in progs, so it was converted to C
1609 void PF_changeyaw (void)
1612 float ideal, current, move, speed;
1614 ent = PROG_TO_EDICT(pr_global_struct->self);
1615 current = ANGLEMOD(ent->v->angles[1]);
1616 ideal = ent->v->ideal_yaw;
1617 speed = ent->v->yaw_speed;
1619 if (current == ideal)
1621 move = ideal - current;
1622 if (ideal > current)
1643 ent->v->angles[1] = ANGLEMOD (current + move);
1651 void PF_changepitch (void)
1654 float ideal, current, move, speed;
1657 ent = G_EDICT(OFS_PARM0);
1658 current = ANGLEMOD( ent->v->angles[0] );
1659 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1660 ideal = val->_float;
1663 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1666 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1667 speed = val->_float;
1670 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1674 if (current == ideal)
1676 move = ideal - current;
1677 if (ideal > current)
1698 ent->v->angles[0] = ANGLEMOD (current + move);
1702 ===============================================================================
1706 ===============================================================================
1709 #define MSG_BROADCAST 0 // unreliable to all
1710 #define MSG_ONE 1 // reliable to one (msg_entity)
1711 #define MSG_ALL 2 // reliable to all
1712 #define MSG_INIT 3 // write to the init string
1714 sizebuf_t *WriteDest (void)
1720 dest = G_FLOAT(OFS_PARM0);
1724 return &sv.datagram;
1727 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1728 entnum = NUM_FOR_EDICT(ent);
1729 if (entnum < 1 || entnum > svs.maxclients)
1730 Host_Error ("WriteDest: not a client");
1731 return &svs.clients[entnum-1].message;
1734 return &sv.reliable_datagram;
1740 Host_Error ("WriteDest: bad destination");
1747 void PF_WriteByte (void)
1749 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1752 void PF_WriteChar (void)
1754 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1757 void PF_WriteShort (void)
1759 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1762 void PF_WriteLong (void)
1764 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1767 void PF_WriteAngle (void)
1769 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1772 void PF_WriteCoord (void)
1774 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1777 void PF_WriteString (void)
1779 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1783 void PF_WriteEntity (void)
1785 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1788 //=============================================================================
1790 void PF_makestatic (void)
1795 ent = G_EDICT(OFS_PARM0);
1798 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1803 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1804 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1805 MSG_WriteShort (&sv.signon, ent->v->frame);
1809 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1810 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1811 MSG_WriteByte (&sv.signon, ent->v->frame);
1814 MSG_WriteByte (&sv.signon, ent->v->colormap);
1815 MSG_WriteByte (&sv.signon, ent->v->skin);
1816 for (i=0 ; i<3 ; i++)
1818 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1819 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1822 // throw the entity away now
1826 //=============================================================================
1833 void PF_setspawnparms (void)
1839 ent = G_EDICT(OFS_PARM0);
1840 i = NUM_FOR_EDICT(ent);
1841 if (i < 1 || i > svs.maxclients)
1842 Host_Error ("Entity is not a client");
1844 // copy spawn parms out of the client_t
1845 client = svs.clients + (i-1);
1847 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1848 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1856 void PF_changelevel (void)
1860 // make sure we don't issue two changelevels
1861 if (svs.changelevel_issued)
1863 svs.changelevel_issued = true;
1865 s = G_STRING(OFS_PARM0);
1866 Cbuf_AddText (va("changelevel %s\n",s));
1871 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1876 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1881 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1888 Returns a vector of length < 1
1893 void PF_randomvec (void)
1898 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1899 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1900 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1902 while (DotProduct(temp, temp) >= 1);
1903 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1906 void SV_LightPoint (vec3_t color, vec3_t p);
1911 Returns a color vector indicating the lighting at the requested point.
1913 (Internal Operation note: actually measures the light beneath the point, just like
1914 the model lighting on the client)
1919 void PF_GetLight (void)
1923 p = G_VECTOR(OFS_PARM0);
1924 SV_LightPoint (color, p);
1925 VectorCopy (color, G_VECTOR(OFS_RETURN));
1928 #define MAX_QC_CVARS 128
1929 cvar_t qc_cvar[MAX_QC_CVARS];
1932 void PF_registercvar (void)
1936 name = G_STRING(OFS_PARM0);
1937 value = G_STRING(OFS_PARM1);
1938 G_FLOAT(OFS_RETURN) = 0;
1939 // first check to see if it has already been defined
1940 if (Cvar_FindVar (name))
1943 // check for overlap with a command
1944 if (Cmd_Exists (name))
1946 Con_Printf ("PF_registercvar: %s is a command\n", name);
1950 if (currentqc_cvar >= MAX_QC_CVARS)
1951 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1953 // copy the name and value
1954 variable = &qc_cvar[currentqc_cvar++];
1955 variable->name = Z_Malloc (strlen(name)+1);
1956 strcpy (variable->name, name);
1957 variable->string = Z_Malloc (strlen(value)+1);
1958 strcpy (variable->string, value);
1959 variable->value = atof (value);
1961 Cvar_RegisterVariable(variable);
1962 G_FLOAT(OFS_RETURN) = 1; // success
1969 returns the minimum of two supplied floats
1976 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1978 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1979 else if (pr_argc >= 3)
1982 float f = G_FLOAT(OFS_PARM0);
1983 for (i = 1;i < pr_argc;i++)
1984 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1985 f = G_FLOAT((OFS_PARM0+i*3));
1986 G_FLOAT(OFS_RETURN) = f;
1989 Host_Error("min: must supply at least 2 floats\n");
1996 returns the maximum of two supplied floats
2003 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2005 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2006 else if (pr_argc >= 3)
2009 float f = G_FLOAT(OFS_PARM0);
2010 for (i = 1;i < pr_argc;i++)
2011 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2012 f = G_FLOAT((OFS_PARM0+i*3));
2013 G_FLOAT(OFS_RETURN) = f;
2016 Host_Error("max: must supply at least 2 floats\n");
2023 returns number bounded by supplied range
2025 min(min, value, max)
2028 void PF_bound (void)
2030 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2037 returns a raised to power b
2044 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2051 copies data from one entity to another
2053 copyentity(src, dst)
2056 void PF_copyentity (void)
2059 in = G_EDICT(OFS_PARM0);
2060 out = G_EDICT(OFS_PARM1);
2061 memcpy(out->v, in->v, progs->entityfields * 4);
2068 sets the color of a client and broadcasts the update to all connected clients
2070 setcolors(clientent, value)
2073 void PF_setcolors (void)
2078 entnum = G_EDICTNUM(OFS_PARM0);
2079 i = G_FLOAT(OFS_PARM1);
2081 if (entnum < 1 || entnum > svs.maxclients)
2083 Con_Printf ("tried to setcolor a non-client\n");
2087 client = &svs.clients[entnum-1];
2089 client->edict->v->team = (i & 15) + 1;
2091 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2092 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2093 MSG_WriteByte (&sv.reliable_datagram, i);
2100 effect(origin, modelname, startframe, framecount, framerate)
2103 void PF_effect (void)
2106 s = G_STRING(OFS_PARM1);
2108 Host_Error("effect: no model specified\n");
2110 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2113 void PF_te_blood (void)
2115 if (G_FLOAT(OFS_PARM2) < 1)
2117 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2118 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2120 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2121 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2122 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2124 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2125 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2126 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2128 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2131 void PF_te_bloodshower (void)
2133 if (G_FLOAT(OFS_PARM3) < 1)
2135 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2136 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2138 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2139 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2140 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2142 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2143 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2144 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2146 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2148 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2151 void PF_te_explosionrgb (void)
2153 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2154 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2156 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2157 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2158 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2160 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2161 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2162 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2165 void PF_te_particlecube (void)
2167 if (G_FLOAT(OFS_PARM3) < 1)
2169 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2170 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2172 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2173 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2174 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2176 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2177 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2178 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2180 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2181 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2182 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2184 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2186 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2187 // gravity true/false
2188 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2190 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2193 void PF_te_particlerain (void)
2195 if (G_FLOAT(OFS_PARM3) < 1)
2197 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2198 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2200 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2201 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2202 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2204 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2205 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2206 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2208 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2209 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2210 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2212 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2214 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2217 void PF_te_particlesnow (void)
2219 if (G_FLOAT(OFS_PARM3) < 1)
2221 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2222 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2224 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2225 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2226 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2228 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2229 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2230 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2232 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2233 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2236 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2238 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2241 void PF_te_spark (void)
2243 if (G_FLOAT(OFS_PARM2) < 1)
2245 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2246 MSG_WriteByte(&sv.datagram, TE_SPARK);
2248 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2249 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2250 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2252 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2253 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2254 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2256 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2259 void PF_te_gunshotquad (void)
2261 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2262 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2264 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2265 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2266 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2269 void PF_te_spikequad (void)
2271 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2272 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2274 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2275 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2276 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2279 void PF_te_superspikequad (void)
2281 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2282 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2284 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2285 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2286 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2289 void PF_te_explosionquad (void)
2291 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2292 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2294 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2295 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2296 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2299 void PF_te_smallflash (void)
2301 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2302 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2304 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2305 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2306 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2309 void PF_te_customflash (void)
2311 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2313 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2314 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2316 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2317 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2318 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2320 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2322 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2324 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2325 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2326 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2329 void PF_te_gunshot (void)
2331 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2332 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2334 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2335 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2336 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2339 void PF_te_spike (void)
2341 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2342 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2344 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2345 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2346 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2349 void PF_te_superspike (void)
2351 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2352 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2354 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2355 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2356 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2359 void PF_te_explosion (void)
2361 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2362 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2364 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2365 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2366 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2369 void PF_te_tarexplosion (void)
2371 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2372 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2374 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2375 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2376 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2379 void PF_te_wizspike (void)
2381 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2382 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2384 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2385 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2386 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2389 void PF_te_knightspike (void)
2391 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2392 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2394 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2395 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2396 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2399 void PF_te_lavasplash (void)
2401 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2402 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2404 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2405 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2406 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2409 void PF_te_teleport (void)
2411 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2412 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2414 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2415 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2416 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2419 void PF_te_explosion2 (void)
2421 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2422 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2424 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2425 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2426 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2428 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2431 void PF_te_lightning1 (void)
2433 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2434 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2436 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2438 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2439 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2440 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2442 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2443 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2444 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2447 void PF_te_lightning2 (void)
2449 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2450 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2452 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2454 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2455 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2456 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2458 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2459 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2460 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2463 void PF_te_lightning3 (void)
2465 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2466 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2468 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2470 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2471 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2472 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2474 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2475 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2476 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2479 void PF_te_beam (void)
2481 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2482 MSG_WriteByte(&sv.datagram, TE_BEAM);
2484 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2486 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2487 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2488 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2490 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2491 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2492 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2495 void PF_te_plasmaburn (void)
2497 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2498 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2499 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2500 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2501 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2504 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2507 vec3_t v1, clipplanenormal, normal;
2508 vec_t clipplanedist, clipdist;
2510 if (surf->flags & SURF_PLANEBACK)
2511 VectorNegate(surf->plane->normal, normal);
2513 VectorCopy(surf->plane->normal, normal);
2514 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2516 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2517 VectorNormalizeFast(v1);
2518 CrossProduct(v1, normal, clipplanenormal);
2519 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2520 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2523 clipdist = -clipdist;
2524 VectorMA(out, clipdist, clipplanenormal, out);
2529 static msurface_t *getsurface(edict_t *ed, int surfnum)
2533 if (!ed || ed->free)
2535 modelindex = ed->v->modelindex;
2536 if (modelindex < 1 || modelindex >= MAX_MODELS)
2538 model = sv.models[modelindex];
2539 if (model->type != mod_brush)
2541 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2543 return model->surfaces + surfnum + model->firstmodelsurface;
2547 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2548 void PF_getsurfacenumpoints(void)
2551 // return 0 if no such surface
2552 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2554 G_FLOAT(OFS_RETURN) = 0;
2558 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2560 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2561 void PF_getsurfacepoint(void)
2566 VectorClear(G_VECTOR(OFS_RETURN));
2567 ed = G_EDICT(OFS_PARM0);
2568 if (!ed || ed->free)
2570 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2572 pointnum = G_FLOAT(OFS_PARM2);
2573 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2575 // FIXME: implement rotation/scaling
2576 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2578 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2579 void PF_getsurfacenormal(void)
2582 VectorClear(G_VECTOR(OFS_RETURN));
2583 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2585 // FIXME: implement rotation/scaling
2586 if (surf->flags & SURF_PLANEBACK)
2587 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2589 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2591 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2592 void PF_getsurfacetexture(void)
2595 G_INT(OFS_RETURN) = 0;
2596 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2598 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2600 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2601 void PF_getsurfacenearpoint(void)
2603 int surfnum, best, modelindex;
2605 vec_t dist, bestdist;
2610 G_FLOAT(OFS_RETURN) = -1;
2611 ed = G_EDICT(OFS_PARM0);
2612 point = G_VECTOR(OFS_PARM1);
2614 if (!ed || ed->free)
2616 modelindex = ed->v->modelindex;
2617 if (modelindex < 1 || modelindex >= MAX_MODELS)
2619 model = sv.models[modelindex];
2620 if (model->type != mod_brush)
2623 // FIXME: implement rotation/scaling
2624 VectorSubtract(point, ed->v->origin, p);
2626 bestdist = 1000000000;
2627 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2629 surf = model->surfaces + surfnum + model->firstmodelsurface;
2630 dist = PlaneDiff(p, surf->plane);
2632 if (dist < bestdist)
2634 clippointtosurface(surf, p, clipped);
2635 VectorSubtract(clipped, p, clipped);
2636 dist += DotProduct(clipped, clipped);
2637 if (dist < bestdist)
2644 G_FLOAT(OFS_RETURN) = best;
2646 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2647 void PF_getsurfaceclippedpoint(void)
2652 VectorClear(G_VECTOR(OFS_RETURN));
2653 ed = G_EDICT(OFS_PARM0);
2654 if (!ed || ed->free)
2656 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2658 // FIXME: implement rotation/scaling
2659 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2660 clippointtosurface(surf, p, out);
2661 // FIXME: implement rotation/scaling
2662 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2665 void PF_Fixme (void)
2667 Host_Error ("unimplemented QC builtin"); // LordHavoc: was misspelled (bulitin)
2670 #define MAX_PRFILES 256
2672 qfile_t *pr_files[MAX_PRFILES];
2674 void PR_Files_Init(void)
2676 memset(pr_files, 0, sizeof(pr_files));
2679 void PR_Files_CloseAll(void)
2682 for (i = 0;i < MAX_PRFILES;i++)
2685 FS_Close(pr_files[i]);
2690 //float(string s) stof = #81; // get numerical value from a string
2693 char *s = PF_VarString(0);
2694 G_FLOAT(OFS_RETURN) = atof(s);
2697 //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
2701 char *modestring, *filename;
2702 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2703 if (pr_files[filenum] == NULL)
2705 if (filenum >= MAX_PRFILES)
2707 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2708 G_FLOAT(OFS_RETURN) = -2;
2711 mode = G_FLOAT(OFS_PARM1);
2714 case 0: // FILE_READ
2717 case 1: // FILE_APPEND
2720 case 2: // FILE_WRITE
2724 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2725 G_FLOAT(OFS_RETURN) = -3;
2728 filename = G_STRING(OFS_PARM0);
2729 // .. is parent directory on many platforms
2730 // / is parent directory on Amiga
2731 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2732 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2733 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2735 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2736 G_FLOAT(OFS_RETURN) = -4;
2739 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2740 if (pr_files[filenum] == NULL)
2741 G_FLOAT(OFS_RETURN) = -1;
2743 G_FLOAT(OFS_RETURN) = filenum;
2746 //void(float fhandle) fclose = #111; // closes a file
2747 void PF_fclose(void)
2749 int filenum = G_FLOAT(OFS_PARM0);
2750 if (filenum < 0 || filenum >= MAX_PRFILES)
2752 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2755 if (pr_files[filenum] == NULL)
2757 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2760 FS_Close(pr_files[filenum]);
2761 pr_files[filenum] = NULL;
2764 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2768 static char string[MAX_VARSTRING];
2769 int filenum = G_FLOAT(OFS_PARM0);
2770 if (filenum < 0 || filenum >= MAX_PRFILES)
2772 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2775 if (pr_files[filenum] == NULL)
2777 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2783 c = FS_Getc(pr_files[filenum]);
2784 if (c == '\r' || c == '\n' || c < 0)
2786 if (end < MAX_VARSTRING - 1)
2790 // remove \n following \r
2792 c = FS_Getc(pr_files[filenum]);
2793 if (developer.integer)
2794 Con_Printf("fgets: %s\n", string);
2796 G_INT(OFS_RETURN) = PR_SetString(string);
2798 G_INT(OFS_RETURN) = 0;
2801 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2805 char *s = PF_VarString(1);
2806 int filenum = G_FLOAT(OFS_PARM0);
2807 if (filenum < 0 || filenum >= MAX_PRFILES)
2809 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2812 if (pr_files[filenum] == NULL)
2814 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2817 if ((stringlength = strlen(s)))
2818 FS_Write(pr_files[filenum], s, stringlength);
2819 if (developer.integer)
2820 Con_Printf("fputs: %s\n", s);
2823 //float(string s) strlen = #114; // returns how many characters are in a string
2824 void PF_strlen(void)
2827 s = G_STRING(OFS_PARM0);
2829 G_FLOAT(OFS_RETURN) = strlen(s);
2831 G_FLOAT(OFS_RETURN) = 0;
2834 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2835 void PF_strcat(void)
2837 char *s = PF_VarString(0);
2838 G_INT(OFS_RETURN) = PR_SetString(s);
2841 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2842 void PF_substring(void)
2844 int end, start, length, slen;
2846 char string[MAX_VARSTRING];
2847 s = G_STRING(OFS_PARM0);
2848 start = G_FLOAT(OFS_PARM1);
2849 length = G_FLOAT(OFS_PARM2);
2856 if (length > slen - start)
2857 length = slen - start;
2858 if (length > MAX_VARSTRING - 1)
2859 length = MAX_VARSTRING - 1;
2863 memcpy(string, s + start, length);
2867 G_INT(OFS_RETURN) = PR_SetString(string);
2870 //vector(string s) stov = #117; // returns vector value from a string
2873 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2876 //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)
2877 void PF_strzone(void)
2880 in = G_STRING(OFS_PARM0);
2881 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2883 G_INT(OFS_RETURN) = PR_SetString(out);
2886 //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!!!)
2887 void PF_strunzone(void)
2889 Mem_Free(G_STRING(OFS_PARM0));
2892 builtin_t pr_builtin[] =
2895 PF_makevectors, // void(entity e) makevectors = #1;
2896 PF_setorigin, // void(entity e, vector o) setorigin = #2;
2897 PF_setmodel, // void(entity e, string m) setmodel = #3;
2898 PF_setsize, // void(entity e, vector min, vector max) setsize = #4;
2899 PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5;
2900 PF_break, // void() break = #6;
2901 PF_random, // float() random = #7;
2902 PF_sound, // void(entity e, float chan, string samp) sound = #8;
2903 PF_normalize, // vector(vector v) normalize = #9;
2904 PF_error, // void(string e) error = #10;
2905 PF_objerror, // void(string e) objerror = #11;
2906 PF_vlen, // float(vector v) vlen = #12;
2907 PF_vectoyaw, // float(vector v) vectoyaw = #13;
2908 PF_Spawn, // entity() spawn = #14;
2909 PF_Remove, // void(entity e) remove = #15;
2910 PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16;
2911 PF_checkclient, // entity() clientlist = #17;
2912 PF_Find, // entity(entity start, .string fld, string match) find = #18;
2913 PF_precache_sound, // void(string s) precache_sound = #19;
2914 PF_precache_model, // void(string s) precache_model = #20;
2915 PF_stuffcmd, // void(entity client, string s)stuffcmd = #21;
2916 PF_findradius, // entity(vector org, float rad) findradius = #22;
2917 PF_bprint, // void(string s) bprint = #23;
2918 PF_sprint, // void(entity client, string s) sprint = #24;
2919 PF_dprint, // void(string s) dprint = #25;
2920 PF_ftos, // void(string s) ftos = #26;
2921 PF_vtos, // void(string s) vtos = #27;
2925 PF_eprint, // void(entity e) debug print an entire entity
2926 PF_walkmove, // float(float yaw, float dist) walkmove
2927 PF_Fixme, // float(float yaw, float dist) walkmove
2977 PF_precache_sound, // precache_sound2 is different only for qcc
2982 PF_Fixme, // #79 LordHavoc: dunno who owns 79-89, so these are just padding
2984 PF_stof, // #81 float(string s) stof = #81;
2994 PF_tracebox, // #90 LordHavoc builtin range (9x)
2995 PF_randomvec, // #91
2997 PF_registercvar, // #93
3002 PF_FindFloat, // #98
3003 PF_checkextension, // #99
3004 #define a PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme,
3006 PF_fopen, // #110 float(string filename, float mode) fopen = #110;
3007 PF_fclose, // #111 void(float fhandle) fclose = #111;
3008 PF_fgets, // #112 string(float fhandle) fgets = #112;
3009 PF_fputs, // #113 void(float fhandle, string s) fputs = #113;
3010 PF_strlen, // #114 float(string s) strlen = #114;
3011 PF_strcat, // #115 string(string s1, string s2) strcat = #115;
3012 PF_substring, // #116 string(string s, float start, float length) substring = #116;
3013 PF_stov, // #117 vector(string) stov = #117;
3014 PF_strzone, // #118 string(string s) strzone = #118;
3015 PF_strunzone, // #119 void(string s) strunzone = #119;
3024 a a a a a a a a a a // #200-299
3025 a a a a a a a a a a // #300-399
3026 PF_copyentity, // #400 LordHavoc: builtin range (4xx)
3027 PF_setcolors, // #401
3028 PF_findchain, // #402
3029 PF_findchainfloat, // #403
3031 PF_te_blood, // #405
3032 PF_te_bloodshower, // #406
3033 PF_te_explosionrgb, // #407
3034 PF_te_particlecube, // #408
3035 PF_te_particlerain, // #409
3036 PF_te_particlesnow, // #410
3037 PF_te_spark, // #411
3038 PF_te_gunshotquad, // #412
3039 PF_te_spikequad, // #413
3040 PF_te_superspikequad, // #414
3041 PF_te_explosionquad, // #415
3042 PF_te_smallflash, // #416
3043 PF_te_customflash, // #417
3044 PF_te_gunshot, // #418
3045 PF_te_spike, // #419
3046 PF_te_superspike, // #420
3047 PF_te_explosion, // #421
3048 PF_te_tarexplosion, // #422
3049 PF_te_wizspike, // #423
3050 PF_te_knightspike, // #424
3051 PF_te_lavasplash, // #425
3052 PF_te_teleport, // #426
3053 PF_te_explosion2, // #427
3054 PF_te_lightning1, // #428
3055 PF_te_lightning2, // #429
3056 PF_te_lightning3, // #430
3058 PF_vectorvectors, // #432
3059 PF_te_plasmaburn, // #433
3060 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
3061 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
3062 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
3063 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
3064 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
3065 PF_getsurfaceclippedpoint,// #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
3068 builtin_t *pr_builtins = pr_builtin;
3069 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3071 void PR_Cmd_Init(void)
3073 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3077 void PR_Cmd_Reset(void)
3079 Mem_EmptyPool(pr_strings_mempool);
3080 PR_Files_CloseAll();