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 "
106 "DP_SV_DRAWONLYTOCLIENT "
108 "DP_SV_EXTERIORMODELTOCLIENT "
109 "DP_SV_NODRAWTOCLIENT "
110 "DP_SV_PLAYERPHYSICS "
115 "DP_TE_EXPLOSIONRGB "
117 "DP_TE_PARTICLECUBE "
118 "DP_TE_PARTICLERAIN "
119 "DP_TE_PARTICLESNOW "
127 qboolean checkextension(char *name)
132 for (e = ENGINE_EXTENSIONS;*e;e++)
139 while (*e && *e != ' ')
141 if (e - start == len)
142 if (!strncasecmp(start, name, len))
152 returns true if the extension is supported by the server
154 checkextension(extensionname)
157 void PF_checkextension (void)
159 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
166 This is a TERMINAL error, which will kill off the entire server.
178 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
179 ed = PROG_TO_EDICT(pr_global_struct->self);
182 Host_Error ("Program error");
189 Dumps out self, then an error message. The program is aborted and self is
190 removed, but the level can continue.
195 void PF_objerror (void)
201 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
202 ed = PROG_TO_EDICT(pr_global_struct->self);
212 Writes new values for v_forward, v_up, and v_right based on angles
216 void PF_makevectors (void)
218 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
225 Writes new values for v_forward, v_up, and v_right based on the given forward vector
226 vectorvectors(vector, vector)
229 void PF_vectorvectors (void)
231 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
232 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
239 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.
241 setorigin (entity, origin)
244 void PF_setorigin (void)
249 e = G_EDICT(OFS_PARM0);
250 org = G_VECTOR(OFS_PARM1);
251 VectorCopy (org, e->v->origin);
252 SV_LinkEdict (e, false);
256 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
260 for (i=0 ; i<3 ; i++)
262 Host_Error ("backwards mins/maxs");
264 // set derived values
265 VectorCopy (min, e->v->mins);
266 VectorCopy (max, e->v->maxs);
267 VectorSubtract (max, min, e->v->size);
269 SV_LinkEdict (e, false);
276 the size box is rotated by the current angle
277 LordHavoc: no it isn't...
279 setsize (entity, minvector, maxvector)
282 void PF_setsize (void)
287 e = G_EDICT(OFS_PARM0);
288 min = G_VECTOR(OFS_PARM1);
289 max = G_VECTOR(OFS_PARM2);
290 SetMinMaxSize (e, min, max, false);
298 setmodel(entity, model)
301 void PF_setmodel (void)
308 e = G_EDICT(OFS_PARM0);
309 m = G_STRING(OFS_PARM1);
311 // check to see if model was properly precached
312 for (i=0, check = sv.model_precache ; *check ; i++, check++)
313 if (!strcmp(*check, m))
317 Host_Error ("no precache: %s\n", m);
320 e->v->model = PR_SetString(*check);
321 e->v->modelindex = i;
323 mod = sv.models[ (int)e->v->modelindex];
326 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
328 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
335 broadcast print to everyone on server
340 void PF_bprint (void)
345 SV_BroadcastPrintf ("%s", s);
352 single print to a specific client
354 sprint(clientent, value)
357 void PF_sprint (void)
363 entnum = G_EDICTNUM(OFS_PARM0);
366 if (entnum < 1 || entnum > svs.maxclients)
368 Con_Printf ("tried to sprint to a non-client\n");
372 client = &svs.clients[entnum-1];
374 MSG_WriteChar (&client->message,svc_print);
375 MSG_WriteString (&client->message, s );
383 single print to a specific client
385 centerprint(clientent, value)
388 void PF_centerprint (void)
394 entnum = G_EDICTNUM(OFS_PARM0);
397 if (entnum < 1 || entnum > svs.maxclients)
399 Con_Printf ("tried to sprint to a non-client\n");
403 client = &svs.clients[entnum-1];
405 MSG_WriteChar (&client->message,svc_centerprint);
406 MSG_WriteString (&client->message, s );
414 vector normalize(vector)
417 void PF_normalize (void)
423 value1 = G_VECTOR(OFS_PARM0);
425 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
429 newvalue[0] = newvalue[1] = newvalue[2] = 0;
433 newvalue[0] = value1[0] * new;
434 newvalue[1] = value1[1] * new;
435 newvalue[2] = value1[2] * new;
438 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
453 value1 = G_VECTOR(OFS_PARM0);
455 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
458 G_FLOAT(OFS_RETURN) = new;
465 float vectoyaw(vector)
468 void PF_vectoyaw (void)
473 value1 = G_VECTOR(OFS_PARM0);
475 if (value1[1] == 0 && value1[0] == 0)
479 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
484 G_FLOAT(OFS_RETURN) = yaw;
492 vector vectoangles(vector)
495 void PF_vectoangles (void)
501 value1 = G_VECTOR(OFS_PARM0);
503 if (value1[1] == 0 && value1[0] == 0)
513 // LordHavoc: optimized a bit
516 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
520 else if (value1[1] > 0)
525 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
526 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
531 G_FLOAT(OFS_RETURN+0) = pitch;
532 G_FLOAT(OFS_RETURN+1) = yaw;
533 G_FLOAT(OFS_RETURN+2) = 0;
540 Returns a number from 0<= num < 1
545 void PF_random (void)
549 num = (rand ()&0x7fff) / ((float)0x7fff);
551 G_FLOAT(OFS_RETURN) = num;
558 particle(origin, color, count)
561 void PF_particle (void)
567 org = G_VECTOR(OFS_PARM0);
568 dir = G_VECTOR(OFS_PARM1);
569 color = G_FLOAT(OFS_PARM2);
570 count = G_FLOAT(OFS_PARM3);
571 SV_StartParticle (org, dir, color, count);
581 void PF_ambientsound (void)
586 float vol, attenuation;
587 int i, soundnum, large;
589 pos = G_VECTOR (OFS_PARM0);
590 samp = G_STRING(OFS_PARM1);
591 vol = G_FLOAT(OFS_PARM2);
592 attenuation = G_FLOAT(OFS_PARM3);
594 // check to see if samp was properly precached
595 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
596 if (!strcmp(*check,samp))
601 Con_Printf ("no precache: %s\n", samp);
609 // add an svc_spawnambient command to the level signon packet
612 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
614 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
616 for (i=0 ; i<3 ; i++)
617 MSG_WriteDPCoord(&sv.signon, pos[i]);
620 MSG_WriteShort (&sv.signon, soundnum);
622 MSG_WriteByte (&sv.signon, soundnum);
624 MSG_WriteByte (&sv.signon, vol*255);
625 MSG_WriteByte (&sv.signon, attenuation*64);
633 Each entity can have eight independant sound sources, like voice,
636 Channel 0 is an auto-allocate channel, the others override anything
637 already running on that entity/channel pair.
639 An attenuation of 0 will play full volume everywhere in the level.
640 Larger attenuations will drop off.
652 entity = G_EDICT(OFS_PARM0);
653 channel = G_FLOAT(OFS_PARM1);
654 sample = G_STRING(OFS_PARM2);
655 volume = G_FLOAT(OFS_PARM3) * 255;
656 attenuation = G_FLOAT(OFS_PARM4);
658 if (volume < 0 || volume > 255)
659 Host_Error ("SV_StartSound: volume = %i", volume);
661 if (attenuation < 0 || attenuation > 4)
662 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
664 if (channel < 0 || channel > 7)
665 Host_Error ("SV_StartSound: channel = %i", channel);
667 SV_StartSound (entity, channel, sample, volume, attenuation);
679 Host_Error ("break statement");
686 Used for use tracing and shot targeting
687 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
688 if the tryents flag is set.
690 traceline (vector1, vector2, tryents)
693 void PF_traceline (void)
700 pr_xfunction->builtinsprofile += 30;
702 v1 = G_VECTOR(OFS_PARM0);
703 v2 = G_VECTOR(OFS_PARM1);
704 nomonsters = G_FLOAT(OFS_PARM2);
705 ent = G_EDICT(OFS_PARM3);
707 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
709 pr_global_struct->trace_allsolid = trace.allsolid;
710 pr_global_struct->trace_startsolid = trace.startsolid;
711 pr_global_struct->trace_fraction = trace.fraction;
712 pr_global_struct->trace_inwater = trace.inwater;
713 pr_global_struct->trace_inopen = trace.inopen;
714 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
715 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
716 pr_global_struct->trace_plane_dist = trace.plane.dist;
718 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
720 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
721 // FIXME: add trace_endcontents
729 Used for use tracing and shot targeting
730 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
731 if the tryents flag is set.
733 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
736 // LordHavoc: added this for my own use, VERY useful, similar to traceline
737 void PF_tracebox (void)
739 float *v1, *v2, *m1, *m2;
744 pr_xfunction->builtinsprofile += 30;
746 v1 = G_VECTOR(OFS_PARM0);
747 m1 = G_VECTOR(OFS_PARM1);
748 m2 = G_VECTOR(OFS_PARM2);
749 v2 = G_VECTOR(OFS_PARM3);
750 nomonsters = G_FLOAT(OFS_PARM4);
751 ent = G_EDICT(OFS_PARM5);
753 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
755 pr_global_struct->trace_allsolid = trace.allsolid;
756 pr_global_struct->trace_startsolid = trace.startsolid;
757 pr_global_struct->trace_fraction = trace.fraction;
758 pr_global_struct->trace_inwater = trace.inwater;
759 pr_global_struct->trace_inopen = trace.inopen;
760 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
761 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
762 pr_global_struct->trace_plane_dist = trace.plane.dist;
764 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
766 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
769 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
770 void PF_TraceToss (void)
776 pr_xfunction->builtinsprofile += 600;
778 ent = G_EDICT(OFS_PARM0);
779 ignore = G_EDICT(OFS_PARM1);
781 trace = SV_Trace_Toss (ent, ignore);
783 pr_global_struct->trace_allsolid = trace.allsolid;
784 pr_global_struct->trace_startsolid = trace.startsolid;
785 pr_global_struct->trace_fraction = trace.fraction;
786 pr_global_struct->trace_inwater = trace.inwater;
787 pr_global_struct->trace_inopen = trace.inopen;
788 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
789 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
790 pr_global_struct->trace_plane_dist = trace.plane.dist;
792 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
794 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
802 Returns true if the given entity can move to the given position from it's
803 current position by walking or rolling.
805 scalar checkpos (entity, vector)
808 void PF_checkpos (void)
812 //============================================================================
814 qbyte checkpvs[MAX_MAP_LEAFS/8];
816 int PF_newcheckclient (int check)
824 // cycle to the next one
828 if (check > svs.maxclients)
829 check = svs.maxclients;
831 if (check == svs.maxclients)
838 pr_xfunction->builtinsprofile++;
839 if (i == svs.maxclients+1)
845 break; // didn't find anything else
849 if (ent->v->health <= 0)
851 if ((int)ent->v->flags & FL_NOTARGET)
854 // anything that is a client, or has a client as an enemy
858 // get the PVS for the entity
859 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
860 leaf = Mod_PointInLeaf (org, sv.worldmodel);
861 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
862 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
871 Returns a client (or object that has a client enemy) that would be a
874 If there is more than one valid option, they are cycled each frame
876 If (self.origin + self.viewofs) is not in the PVS of the current target,
877 it is not returned at all.
882 int c_invis, c_notvis;
883 void PF_checkclient (void)
890 // find a new check if on a new frame
891 if (sv.time - sv.lastchecktime >= 0.1)
893 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
894 sv.lastchecktime = sv.time;
897 // return check if it might be visible
898 ent = EDICT_NUM(sv.lastcheck);
899 if (ent->free || ent->v->health <= 0)
901 RETURN_EDICT(sv.edicts);
905 // if current entity can't possibly see the check entity, return 0
906 self = PROG_TO_EDICT(pr_global_struct->self);
907 VectorAdd (self->v->origin, self->v->view_ofs, view);
908 leaf = Mod_PointInLeaf (view, sv.worldmodel);
911 l = (leaf - sv.worldmodel->leafs) - 1;
912 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
915 RETURN_EDICT(sv.edicts);
920 // might be able to see it
925 //============================================================================
932 Sends text over to the client's execution buffer
934 stuffcmd (clientent, value)
937 void PF_stuffcmd (void)
943 entnum = G_EDICTNUM(OFS_PARM0);
944 if (entnum < 1 || entnum > svs.maxclients)
945 Host_Error ("Parm 0 not a client");
946 str = G_STRING(OFS_PARM1);
949 host_client = &svs.clients[entnum-1];
950 Host_ClientCommands ("%s", str);
958 Sends text over to the client's execution buffer
963 void PF_localcmd (void)
967 str = G_STRING(OFS_PARM0);
982 str = G_STRING(OFS_PARM0);
984 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
994 void PF_cvar_set (void)
998 var = G_STRING(OFS_PARM0);
999 val = G_STRING(OFS_PARM1);
1001 Cvar_Set (var, val);
1008 Returns a chain of entities that have origins within a spherical area
1010 findradius (origin, radius)
1013 void PF_findradius (void)
1015 edict_t *ent, *chain;
1022 chain = (edict_t *)sv.edicts;
1024 org = G_VECTOR(OFS_PARM0);
1025 radius = G_FLOAT(OFS_PARM1);
1026 radius2 = radius * radius;
1028 ent = NEXT_EDICT(sv.edicts);
1029 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1031 pr_xfunction->builtinsprofile++;
1034 if (ent->v->solid == SOLID_NOT)
1037 // LordHavoc: compare against bounding box rather than center,
1038 // and use DotProduct instead of Length, major speedup
1039 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1040 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1041 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1042 if (DotProduct(eorg, eorg) > radius2)
1045 ent->v->chain = EDICT_TO_PROG(chain);
1049 RETURN_EDICT(chain);
1058 void PF_dprint (void)
1060 Con_DPrintf ("%s",PF_VarString(0));
1063 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1064 #define STRINGTEMP_BUFFERS 16
1065 #define STRINGTEMP_LENGTH 128
1066 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1067 static int pr_string_tempindex = 0;
1069 static char *PR_GetTempString(void)
1072 s = pr_string_temp[pr_string_tempindex];
1073 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1081 v = G_FLOAT(OFS_PARM0);
1083 s = PR_GetTempString();
1084 // LordHavoc: ftos improvement
1085 sprintf (s, "%g", v);
1086 G_INT(OFS_RETURN) = PR_SetString(s);
1092 v = G_FLOAT(OFS_PARM0);
1093 G_FLOAT(OFS_RETURN) = fabs(v);
1099 s = PR_GetTempString();
1100 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1101 G_INT(OFS_RETURN) = PR_SetString(s);
1107 s = PR_GetTempString();
1108 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1109 G_INT(OFS_RETURN) = PR_SetString(s);
1112 void PF_Spawn (void)
1115 pr_xfunction->builtinsprofile += 20;
1120 void PF_Remove (void)
1123 pr_xfunction->builtinsprofile += 20;
1125 ed = G_EDICT(OFS_PARM0);
1126 if (ed == sv.edicts)
1127 Host_Error("remove: tried to remove world\n");
1128 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1129 Host_Error("remove: tried to remove a client\n");
1134 // entity (entity start, .string field, string match) find = #5;
1142 e = G_EDICTNUM(OFS_PARM0);
1143 f = G_INT(OFS_PARM1);
1144 s = G_STRING(OFS_PARM2);
1147 RETURN_EDICT(sv.edicts);
1151 for (e++ ; e < sv.num_edicts ; e++)
1153 pr_xfunction->builtinsprofile++;
1167 RETURN_EDICT(sv.edicts);
1170 // LordHavoc: added this for searching float, int, and entity reference fields
1171 void PF_FindFloat (void)
1178 e = G_EDICTNUM(OFS_PARM0);
1179 f = G_INT(OFS_PARM1);
1180 s = G_FLOAT(OFS_PARM2);
1182 for (e++ ; e < sv.num_edicts ; e++)
1184 pr_xfunction->builtinsprofile++;
1188 if (E_FLOAT(ed,f) == s)
1195 RETURN_EDICT(sv.edicts);
1198 // chained search for strings in entity fields
1199 // entity(.string field, string match) findchain = #402;
1200 void PF_findchain (void)
1205 edict_t *ent, *chain;
1207 chain = (edict_t *)sv.edicts;
1209 f = G_INT(OFS_PARM0);
1210 s = G_STRING(OFS_PARM1);
1213 RETURN_EDICT(sv.edicts);
1217 ent = NEXT_EDICT(sv.edicts);
1218 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1220 pr_xfunction->builtinsprofile++;
1223 t = E_STRING(ent,f);
1229 ent->v->chain = EDICT_TO_PROG(chain);
1233 RETURN_EDICT(chain);
1236 // LordHavoc: chained search for float, int, and entity reference fields
1237 // entity(.string field, float match) findchainfloat = #403;
1238 void PF_findchainfloat (void)
1243 edict_t *ent, *chain;
1245 chain = (edict_t *)sv.edicts;
1247 f = G_INT(OFS_PARM0);
1248 s = G_FLOAT(OFS_PARM1);
1250 ent = NEXT_EDICT(sv.edicts);
1251 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1253 pr_xfunction->builtinsprofile++;
1256 if (E_FLOAT(ent,f) != s)
1259 ent->v->chain = EDICT_TO_PROG(chain);
1263 RETURN_EDICT(chain);
1266 void PR_CheckEmptyString (char *s)
1269 Host_Error ("Bad string");
1272 void PF_precache_file (void)
1273 { // precache_file is only used to copy files with qcc, it does nothing
1274 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1277 void PF_precache_sound (void)
1282 if (sv.state != ss_loading)
1283 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1285 s = G_STRING(OFS_PARM0);
1286 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1287 PR_CheckEmptyString (s);
1289 for (i=0 ; i<MAX_SOUNDS ; i++)
1291 if (!sv.sound_precache[i])
1293 sv.sound_precache[i] = s;
1296 if (!strcmp(sv.sound_precache[i], s))
1299 Host_Error ("PF_precache_sound: overflow");
1302 void PF_precache_model (void)
1307 if (sv.state != ss_loading)
1308 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1310 s = G_STRING(OFS_PARM0);
1311 if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1313 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1314 PR_CheckEmptyString (s);
1316 for (i=0 ; i<MAX_MODELS ; i++)
1318 if (!sv.model_precache[i])
1320 sv.model_precache[i] = s;
1321 sv.models[i] = Mod_ForName (s, true, false, false);
1324 if (!strcmp(sv.model_precache[i], s))
1327 Host_Error ("PF_precache_model: overflow");
1331 void PF_coredump (void)
1336 void PF_traceon (void)
1341 void PF_traceoff (void)
1346 void PF_eprint (void)
1348 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1355 float(float yaw, float dist) walkmove
1358 void PF_walkmove (void)
1366 ent = PROG_TO_EDICT(pr_global_struct->self);
1367 yaw = G_FLOAT(OFS_PARM0);
1368 dist = G_FLOAT(OFS_PARM1);
1370 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1372 G_FLOAT(OFS_RETURN) = 0;
1376 yaw = yaw*M_PI*2 / 360;
1378 move[0] = cos(yaw)*dist;
1379 move[1] = sin(yaw)*dist;
1382 // save program state, because SV_movestep may call other progs
1383 oldf = pr_xfunction;
1384 oldself = pr_global_struct->self;
1386 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1389 // restore program state
1390 pr_xfunction = oldf;
1391 pr_global_struct->self = oldself;
1401 void PF_droptofloor (void)
1407 ent = PROG_TO_EDICT(pr_global_struct->self);
1409 VectorCopy (ent->v->origin, end);
1412 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1414 if (trace.fraction == 1)
1415 G_FLOAT(OFS_RETURN) = 0;
1418 VectorCopy (trace.endpos, ent->v->origin);
1419 SV_LinkEdict (ent, false);
1420 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1421 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1422 G_FLOAT(OFS_RETURN) = 1;
1423 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1424 ent->suspendedinairflag = true;
1432 void(float style, string value) lightstyle
1435 void PF_lightstyle (void)
1442 style = G_FLOAT(OFS_PARM0);
1443 val = G_STRING(OFS_PARM1);
1445 // change the string in sv
1446 sv.lightstyles[style] = val;
1448 // send message to all clients on this server
1449 if (sv.state != ss_active)
1452 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1453 if (client->active || client->spawned)
1455 MSG_WriteChar (&client->message, svc_lightstyle);
1456 MSG_WriteChar (&client->message,style);
1457 MSG_WriteString (&client->message, val);
1464 f = G_FLOAT(OFS_PARM0);
1466 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1468 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1470 void PF_floor (void)
1472 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1476 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1485 void PF_checkbottom (void)
1487 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1495 void PF_pointcontents (void)
1497 G_FLOAT(OFS_RETURN) = Mod_PointContents(G_VECTOR(OFS_PARM0), sv.worldmodel);
1504 entity nextent(entity)
1507 void PF_nextent (void)
1512 i = G_EDICTNUM(OFS_PARM0);
1515 pr_xfunction->builtinsprofile++;
1517 if (i == sv.num_edicts)
1519 RETURN_EDICT(sv.edicts);
1535 Pick a vector for the player to shoot along
1536 vector aim(entity, missilespeed)
1541 edict_t *ent, *check, *bestent;
1542 vec3_t start, dir, end, bestdir;
1545 float dist, bestdist;
1548 ent = G_EDICT(OFS_PARM0);
1549 speed = G_FLOAT(OFS_PARM1);
1551 VectorCopy (ent->v->origin, start);
1554 // try sending a trace straight
1555 VectorCopy (pr_global_struct->v_forward, dir);
1556 VectorMA (start, 2048, dir, end);
1557 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1558 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1559 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1561 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1566 // try all possible entities
1567 VectorCopy (dir, bestdir);
1568 bestdist = sv_aim.value;
1571 check = NEXT_EDICT(sv.edicts);
1572 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1574 pr_xfunction->builtinsprofile++;
1575 if (check->v->takedamage != DAMAGE_AIM)
1579 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1580 continue; // don't aim at teammate
1581 for (j=0 ; j<3 ; j++)
1582 end[j] = check->v->origin[j]
1583 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1584 VectorSubtract (end, start, dir);
1585 VectorNormalize (dir);
1586 dist = DotProduct (dir, pr_global_struct->v_forward);
1587 if (dist < bestdist)
1588 continue; // to far to turn
1589 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1590 if (tr.ent == check)
1591 { // can shoot at this one
1599 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1600 dist = DotProduct (dir, pr_global_struct->v_forward);
1601 VectorScale (pr_global_struct->v_forward, dist, end);
1603 VectorNormalize (end);
1604 VectorCopy (end, G_VECTOR(OFS_RETURN));
1608 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1616 This was a major timewaster in progs, so it was converted to C
1619 void PF_changeyaw (void)
1622 float ideal, current, move, speed;
1624 ent = PROG_TO_EDICT(pr_global_struct->self);
1625 current = ANGLEMOD(ent->v->angles[1]);
1626 ideal = ent->v->ideal_yaw;
1627 speed = ent->v->yaw_speed;
1629 if (current == ideal)
1631 move = ideal - current;
1632 if (ideal > current)
1653 ent->v->angles[1] = ANGLEMOD (current + move);
1661 void PF_changepitch (void)
1664 float ideal, current, move, speed;
1667 ent = G_EDICT(OFS_PARM0);
1668 current = ANGLEMOD( ent->v->angles[0] );
1669 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1670 ideal = val->_float;
1673 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1676 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1677 speed = val->_float;
1680 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1684 if (current == ideal)
1686 move = ideal - current;
1687 if (ideal > current)
1708 ent->v->angles[0] = ANGLEMOD (current + move);
1712 ===============================================================================
1716 ===============================================================================
1719 #define MSG_BROADCAST 0 // unreliable to all
1720 #define MSG_ONE 1 // reliable to one (msg_entity)
1721 #define MSG_ALL 2 // reliable to all
1722 #define MSG_INIT 3 // write to the init string
1724 sizebuf_t *WriteDest (void)
1730 dest = G_FLOAT(OFS_PARM0);
1734 return &sv.datagram;
1737 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1738 entnum = NUM_FOR_EDICT(ent);
1739 if (entnum < 1 || entnum > svs.maxclients)
1740 Host_Error ("WriteDest: not a client");
1741 return &svs.clients[entnum-1].message;
1744 return &sv.reliable_datagram;
1750 Host_Error ("WriteDest: bad destination");
1757 void PF_WriteByte (void)
1759 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1762 void PF_WriteChar (void)
1764 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1767 void PF_WriteShort (void)
1769 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1772 void PF_WriteLong (void)
1774 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1777 void PF_WriteAngle (void)
1779 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1782 void PF_WriteCoord (void)
1784 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1787 void PF_WriteString (void)
1789 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1793 void PF_WriteEntity (void)
1795 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1798 //=============================================================================
1800 void PF_makestatic (void)
1805 ent = G_EDICT(OFS_PARM0);
1808 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1813 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1814 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1815 MSG_WriteShort (&sv.signon, ent->v->frame);
1819 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1820 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1821 MSG_WriteByte (&sv.signon, ent->v->frame);
1824 MSG_WriteByte (&sv.signon, ent->v->colormap);
1825 MSG_WriteByte (&sv.signon, ent->v->skin);
1826 for (i=0 ; i<3 ; i++)
1828 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1829 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1832 // throw the entity away now
1836 //=============================================================================
1843 void PF_setspawnparms (void)
1849 ent = G_EDICT(OFS_PARM0);
1850 i = NUM_FOR_EDICT(ent);
1851 if (i < 1 || i > svs.maxclients)
1852 Host_Error ("Entity is not a client");
1854 // copy spawn parms out of the client_t
1855 client = svs.clients + (i-1);
1857 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1858 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1866 void PF_changelevel (void)
1870 // make sure we don't issue two changelevels
1871 if (svs.changelevel_issued)
1873 svs.changelevel_issued = true;
1875 s = G_STRING(OFS_PARM0);
1876 Cbuf_AddText (va("changelevel %s\n",s));
1881 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1886 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1891 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1898 Returns a vector of length < 1
1903 void PF_randomvec (void)
1908 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1909 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1910 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1912 while (DotProduct(temp, temp) >= 1);
1913 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1916 void SV_LightPoint (vec3_t color, vec3_t p);
1921 Returns a color vector indicating the lighting at the requested point.
1923 (Internal Operation note: actually measures the light beneath the point, just like
1924 the model lighting on the client)
1929 void PF_GetLight (void)
1933 p = G_VECTOR(OFS_PARM0);
1934 SV_LightPoint (color, p);
1935 VectorCopy (color, G_VECTOR(OFS_RETURN));
1938 #define MAX_QC_CVARS 128
1939 cvar_t qc_cvar[MAX_QC_CVARS];
1942 void PF_registercvar (void)
1946 name = G_STRING(OFS_PARM0);
1947 value = G_STRING(OFS_PARM1);
1948 G_FLOAT(OFS_RETURN) = 0;
1949 // first check to see if it has already been defined
1950 if (Cvar_FindVar (name))
1953 // check for overlap with a command
1954 if (Cmd_Exists (name))
1956 Con_Printf ("PF_registercvar: %s is a command\n", name);
1960 if (currentqc_cvar >= MAX_QC_CVARS)
1961 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1963 // copy the name and value
1964 variable = &qc_cvar[currentqc_cvar++];
1965 variable->name = Z_Malloc (strlen(name)+1);
1966 strcpy (variable->name, name);
1967 variable->string = Z_Malloc (strlen(value)+1);
1968 strcpy (variable->string, value);
1969 variable->value = atof (value);
1971 Cvar_RegisterVariable(variable);
1972 G_FLOAT(OFS_RETURN) = 1; // success
1979 returns the minimum of two supplied floats
1986 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1988 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1989 else if (pr_argc >= 3)
1992 float f = G_FLOAT(OFS_PARM0);
1993 for (i = 1;i < pr_argc;i++)
1994 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1995 f = G_FLOAT((OFS_PARM0+i*3));
1996 G_FLOAT(OFS_RETURN) = f;
1999 Host_Error("min: must supply at least 2 floats\n");
2006 returns the maximum of two supplied floats
2013 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2015 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2016 else if (pr_argc >= 3)
2019 float f = G_FLOAT(OFS_PARM0);
2020 for (i = 1;i < pr_argc;i++)
2021 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2022 f = G_FLOAT((OFS_PARM0+i*3));
2023 G_FLOAT(OFS_RETURN) = f;
2026 Host_Error("max: must supply at least 2 floats\n");
2033 returns number bounded by supplied range
2035 min(min, value, max)
2038 void PF_bound (void)
2040 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2047 returns a raised to power b
2054 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2061 copies data from one entity to another
2063 copyentity(src, dst)
2066 void PF_copyentity (void)
2069 in = G_EDICT(OFS_PARM0);
2070 out = G_EDICT(OFS_PARM1);
2071 memcpy(out->v, in->v, progs->entityfields * 4);
2078 sets the color of a client and broadcasts the update to all connected clients
2080 setcolor(clientent, value)
2083 void PF_setcolor (void)
2088 entnum = G_EDICTNUM(OFS_PARM0);
2089 i = G_FLOAT(OFS_PARM1);
2091 if (entnum < 1 || entnum > svs.maxclients)
2093 Con_Printf ("tried to setcolor a non-client\n");
2097 client = &svs.clients[entnum-1];
2099 client->edict->v->team = (i & 15) + 1;
2101 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2102 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2103 MSG_WriteByte (&sv.reliable_datagram, i);
2110 effect(origin, modelname, startframe, framecount, framerate)
2113 void PF_effect (void)
2116 s = G_STRING(OFS_PARM1);
2118 Host_Error("effect: no model specified\n");
2120 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2123 void PF_te_blood (void)
2125 if (G_FLOAT(OFS_PARM2) < 1)
2127 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2128 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2130 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2131 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2132 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2134 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2135 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2136 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2138 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2141 void PF_te_bloodshower (void)
2143 if (G_FLOAT(OFS_PARM3) < 1)
2145 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2146 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2148 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2149 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2150 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2152 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2153 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2154 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2156 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2158 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2161 void PF_te_explosionrgb (void)
2163 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2164 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2166 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2167 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2168 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2170 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2171 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2172 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2175 void PF_te_particlecube (void)
2177 if (G_FLOAT(OFS_PARM3) < 1)
2179 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2180 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2182 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2183 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2184 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2186 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2187 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2188 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2190 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2191 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2192 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2194 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2196 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2197 // gravity true/false
2198 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2200 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2203 void PF_te_particlerain (void)
2205 if (G_FLOAT(OFS_PARM3) < 1)
2207 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2208 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2210 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2211 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2212 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2214 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2215 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2216 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2218 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2219 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2220 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2222 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2224 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2227 void PF_te_particlesnow (void)
2229 if (G_FLOAT(OFS_PARM3) < 1)
2231 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2232 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2236 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2238 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2239 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2240 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2242 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2243 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2244 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2246 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2248 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2251 void PF_te_spark (void)
2253 if (G_FLOAT(OFS_PARM2) < 1)
2255 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2256 MSG_WriteByte(&sv.datagram, TE_SPARK);
2258 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2259 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2260 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2262 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2263 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2264 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2266 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2269 void PF_te_gunshotquad (void)
2271 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2272 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
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_spikequad (void)
2281 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2282 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
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_superspikequad (void)
2291 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2292 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
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_explosionquad (void)
2301 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2302 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
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_smallflash (void)
2311 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2312 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2314 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2315 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2316 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2319 void PF_te_customflash (void)
2321 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2323 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2324 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2326 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2327 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2328 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2330 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2332 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2334 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2335 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2336 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2339 void PF_te_gunshot (void)
2341 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2342 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
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_spike (void)
2351 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2352 MSG_WriteByte(&sv.datagram, TE_SPIKE);
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_superspike (void)
2361 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2362 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
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_explosion (void)
2371 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2372 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
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_tarexplosion (void)
2381 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2382 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
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_wizspike (void)
2391 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2392 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
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_knightspike (void)
2401 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2402 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
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_lavasplash (void)
2411 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2412 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
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_teleport (void)
2421 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2422 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
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]);
2429 void PF_te_explosion2 (void)
2431 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2432 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2434 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2435 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2436 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2438 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2441 void PF_te_lightning1 (void)
2443 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2444 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2446 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2448 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2449 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2450 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2452 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2453 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2454 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2457 void PF_te_lightning2 (void)
2459 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2460 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2462 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2464 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2465 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2466 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2468 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2469 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2470 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2473 void PF_te_lightning3 (void)
2475 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2476 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2478 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2480 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2481 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2482 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2484 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2485 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2486 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2489 void PF_te_beam (void)
2491 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2492 MSG_WriteByte(&sv.datagram, TE_BEAM);
2494 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2496 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2497 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2498 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2500 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2501 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2502 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2505 void PF_te_plasmaburn (void)
2507 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2508 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2509 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2510 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2511 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2514 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2517 vec3_t v1, clipplanenormal, normal;
2518 vec_t clipplanedist, clipdist;
2520 if (surf->flags & SURF_PLANEBACK)
2521 VectorNegate(surf->plane->normal, normal);
2523 VectorCopy(surf->plane->normal, normal);
2524 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2526 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2527 VectorNormalizeFast(v1);
2528 CrossProduct(v1, normal, clipplanenormal);
2529 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2530 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2533 clipdist = -clipdist;
2534 VectorMA(out, clipdist, clipplanenormal, out);
2539 static msurface_t *getsurface(edict_t *ed, int surfnum)
2543 if (!ed || ed->free)
2545 modelindex = ed->v->modelindex;
2546 if (modelindex < 1 || modelindex >= MAX_MODELS)
2548 model = sv.models[modelindex];
2549 if (model->type != mod_brush)
2551 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2553 return model->surfaces + surfnum + model->firstmodelsurface;
2557 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2558 void PF_getsurfacenumpoints(void)
2561 // return 0 if no such surface
2562 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2564 G_FLOAT(OFS_RETURN) = 0;
2568 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2570 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2571 void PF_getsurfacepoint(void)
2576 VectorClear(G_VECTOR(OFS_RETURN));
2577 ed = G_EDICT(OFS_PARM0);
2578 if (!ed || ed->free)
2580 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2582 pointnum = G_FLOAT(OFS_PARM2);
2583 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2585 // FIXME: implement rotation/scaling
2586 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2588 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2589 void PF_getsurfacenormal(void)
2592 VectorClear(G_VECTOR(OFS_RETURN));
2593 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2595 // FIXME: implement rotation/scaling
2596 if (surf->flags & SURF_PLANEBACK)
2597 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2599 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2601 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2602 void PF_getsurfacetexture(void)
2605 G_INT(OFS_RETURN) = 0;
2606 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2608 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2610 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2611 void PF_getsurfacenearpoint(void)
2613 int surfnum, best, modelindex;
2615 vec_t dist, bestdist;
2620 G_FLOAT(OFS_RETURN) = -1;
2621 ed = G_EDICT(OFS_PARM0);
2622 point = G_VECTOR(OFS_PARM1);
2624 if (!ed || ed->free)
2626 modelindex = ed->v->modelindex;
2627 if (modelindex < 1 || modelindex >= MAX_MODELS)
2629 model = sv.models[modelindex];
2630 if (model->type != mod_brush)
2633 // FIXME: implement rotation/scaling
2634 VectorSubtract(point, ed->v->origin, p);
2636 bestdist = 1000000000;
2637 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2639 surf = model->surfaces + surfnum + model->firstmodelsurface;
2640 dist = PlaneDiff(p, surf->plane);
2642 if (dist < bestdist)
2644 clippointtosurface(surf, p, clipped);
2645 VectorSubtract(clipped, p, clipped);
2646 dist += DotProduct(clipped, clipped);
2647 if (dist < bestdist)
2654 G_FLOAT(OFS_RETURN) = best;
2656 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2657 void PF_getsurfaceclippedpoint(void)
2662 VectorClear(G_VECTOR(OFS_RETURN));
2663 ed = G_EDICT(OFS_PARM0);
2664 if (!ed || ed->free)
2666 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2668 // FIXME: implement rotation/scaling
2669 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2670 clippointtosurface(surf, p, out);
2671 // FIXME: implement rotation/scaling
2672 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2675 #define MAX_PRFILES 256
2677 qfile_t *pr_files[MAX_PRFILES];
2679 void PR_Files_Init(void)
2681 memset(pr_files, 0, sizeof(pr_files));
2684 void PR_Files_CloseAll(void)
2687 for (i = 0;i < MAX_PRFILES;i++)
2690 FS_Close(pr_files[i]);
2695 //float(string s) stof = #81; // get numerical value from a string
2698 char *s = PF_VarString(0);
2699 G_FLOAT(OFS_RETURN) = atof(s);
2702 //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
2706 char *modestring, *filename;
2707 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2708 if (pr_files[filenum] == NULL)
2710 if (filenum >= MAX_PRFILES)
2712 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2713 G_FLOAT(OFS_RETURN) = -2;
2716 mode = G_FLOAT(OFS_PARM1);
2719 case 0: // FILE_READ
2722 case 1: // FILE_APPEND
2725 case 2: // FILE_WRITE
2729 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2730 G_FLOAT(OFS_RETURN) = -3;
2733 filename = G_STRING(OFS_PARM0);
2734 // .. is parent directory on many platforms
2735 // / is parent directory on Amiga
2736 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2737 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2738 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2740 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2741 G_FLOAT(OFS_RETURN) = -4;
2744 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2745 if (pr_files[filenum] == NULL)
2746 G_FLOAT(OFS_RETURN) = -1;
2748 G_FLOAT(OFS_RETURN) = filenum;
2751 //void(float fhandle) fclose = #111; // closes a file
2752 void PF_fclose(void)
2754 int filenum = G_FLOAT(OFS_PARM0);
2755 if (filenum < 0 || filenum >= MAX_PRFILES)
2757 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2760 if (pr_files[filenum] == NULL)
2762 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2765 FS_Close(pr_files[filenum]);
2766 pr_files[filenum] = NULL;
2769 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2773 static char string[MAX_VARSTRING];
2774 int filenum = G_FLOAT(OFS_PARM0);
2775 if (filenum < 0 || filenum >= MAX_PRFILES)
2777 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2780 if (pr_files[filenum] == NULL)
2782 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2788 c = FS_Getc(pr_files[filenum]);
2789 if (c == '\r' || c == '\n' || c < 0)
2791 if (end < MAX_VARSTRING - 1)
2795 // remove \n following \r
2797 c = FS_Getc(pr_files[filenum]);
2798 if (developer.integer)
2799 Con_Printf("fgets: %s\n", string);
2801 G_INT(OFS_RETURN) = PR_SetString(string);
2803 G_INT(OFS_RETURN) = 0;
2806 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2810 char *s = PF_VarString(1);
2811 int filenum = G_FLOAT(OFS_PARM0);
2812 if (filenum < 0 || filenum >= MAX_PRFILES)
2814 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2817 if (pr_files[filenum] == NULL)
2819 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2822 if ((stringlength = strlen(s)))
2823 FS_Write(pr_files[filenum], s, stringlength);
2824 if (developer.integer)
2825 Con_Printf("fputs: %s\n", s);
2828 //float(string s) strlen = #114; // returns how many characters are in a string
2829 void PF_strlen(void)
2832 s = G_STRING(OFS_PARM0);
2834 G_FLOAT(OFS_RETURN) = strlen(s);
2836 G_FLOAT(OFS_RETURN) = 0;
2839 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2840 void PF_strcat(void)
2842 char *s = PF_VarString(0);
2843 G_INT(OFS_RETURN) = PR_SetString(s);
2846 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2847 void PF_substring(void)
2849 int end, start, length, slen;
2851 char string[MAX_VARSTRING];
2852 s = G_STRING(OFS_PARM0);
2853 start = G_FLOAT(OFS_PARM1);
2854 length = G_FLOAT(OFS_PARM2);
2861 if (length > slen - start)
2862 length = slen - start;
2863 if (length > MAX_VARSTRING - 1)
2864 length = MAX_VARSTRING - 1;
2868 memcpy(string, s + start, length);
2872 G_INT(OFS_RETURN) = PR_SetString(string);
2875 //vector(string s) stov = #117; // returns vector value from a string
2878 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2881 //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)
2882 void PF_strzone(void)
2885 in = G_STRING(OFS_PARM0);
2886 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2888 G_INT(OFS_RETURN) = PR_SetString(out);
2891 //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!!!)
2892 void PF_strunzone(void)
2894 Mem_Free(G_STRING(OFS_PARM0));
2897 builtin_t pr_builtin[] =
2900 PF_makevectors, // #1 void(entity e) makevectors
2901 PF_setorigin, // #2 void(entity e, vector o) setorigin
2902 PF_setmodel, // #3 void(entity e, string m) setmodel
2903 PF_setsize, // #4 void(entity e, vector min, vector max) setsize
2904 NULL, // #5 void(entity e, vector min, vector max) setabssize
2905 PF_break, // #6 void() break
2906 PF_random, // #7 float() random
2907 PF_sound, // #8 void(entity e, float chan, string samp) sound
2908 PF_normalize, // #9 vector(vector v) normalize
2909 PF_error, // #10 void(string e) error
2910 PF_objerror, // #11 void(string e) objerror
2911 PF_vlen, // #12 float(vector v) vlen
2912 PF_vectoyaw, // #13 float(vector v) vectoyaw
2913 PF_Spawn, // #14 entity() spawn
2914 PF_Remove, // #15 void(entity e) remove
2915 PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline
2916 PF_checkclient, // #17 entity() clientlist
2917 PF_Find, // #18 entity(entity start, .string fld, string match) find
2918 PF_precache_sound, // #19 void(string s) precache_sound
2919 PF_precache_model, // #20 void(string s) precache_model
2920 PF_stuffcmd, // #21 void(entity client, string s)stuffcmd
2921 PF_findradius, // #22 entity(vector org, float rad) findradius
2922 PF_bprint, // #23 void(string s) bprint
2923 PF_sprint, // #24 void(entity client, string s) sprint
2924 PF_dprint, // #25 void(string s) dprint
2925 PF_ftos, // #26 void(string s) ftos
2926 PF_vtos, // #27 void(string s) vtos
2927 PF_coredump, // #28 void() coredump
2928 PF_traceon, // #29 void() traceon
2929 PF_traceoff, // #30 void() traceoff
2930 PF_eprint, // #31 void(entity e) eprint
2931 PF_walkmove, // #32 float(float yaw, float dist) walkmove
2933 PF_droptofloor, // #34 float() droptofloor
2934 PF_lightstyle, // #35 void(float style, string value) lightstyle
2935 PF_rint, // #36 float(float v) rint
2936 PF_floor, // #37 float(float v) floor
2937 PF_ceil, // #38 float(float v) ceil
2939 PF_checkbottom, // #40 float(entity e) checkbottom
2940 PF_pointcontents , // #41 float(vector v) pointcontents
2942 PF_fabs, // #43 float(float f) fabs
2943 PF_aim, // #44 vector(entity e, float speed) aim
2944 PF_cvar, // #45 float(string s) cvar
2945 PF_localcmd, // #46 void(string s) localcmd
2946 PF_nextent, // #47 entity(entity e) nextent
2947 PF_particle, // #48 void(vector o, vector d, float color, float count) particle
2948 PF_changeyaw, // #49 void() ChangeYaw
2950 PF_vectoangles, // #51 vector(vector v) vectoangles
2951 PF_WriteByte, // #52 void(float to, float f) WriteByte
2952 PF_WriteChar, // #53 void(float to, float f) WriteChar
2953 PF_WriteShort, // #54 void(float to, float f) WriteShort
2954 PF_WriteLong, // #55 void(float to, float f) WriteLong
2955 PF_WriteCoord, // #56 void(float to, float f) WriteCoord
2956 PF_WriteAngle, // #57 void(float to, float f) WriteAngle
2957 PF_WriteString, // #58 void(float to, string s) WriteString
2958 PF_WriteEntity, // #59 void(float to, entity e) WriteEntity
2959 PF_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2960 PF_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2961 PF_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2962 PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2963 PF_TraceToss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2964 PF_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2966 SV_MoveToGoal, // #67 void(float step) movetogoal
2967 PF_precache_file, // #68 string(string s) precache_file
2968 PF_makestatic, // #69 void(entity e) makestatic
2969 PF_changelevel, // #70 void(string s) changelevel
2971 PF_cvar_set, // #72 void(string var, string val) cvar_set
2972 PF_centerprint, // #73 void(entity client, strings) centerprint
2973 PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound
2974 PF_precache_model, // #75 string(string s) precache_model2
2975 PF_precache_sound, // #76 string(string s) precache_sound2
2976 PF_precache_file, // #77 string(string s) precache_file2
2977 PF_setspawnparms, // #78 void(entity e) setspawnparms
2980 PF_stof, // #81 float(string s) stof (FRIK_FILE)
2989 PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2990 PF_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2991 PF_GetLight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2992 PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2993 PF_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2994 PF_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2995 PF_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2996 PF_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2997 PF_FindFloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2998 PF_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
3009 PF_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
3010 PF_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
3011 PF_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
3012 PF_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
3013 PF_strlen, // #114 float(string s) strlen (FRIK_FILE)
3014 PF_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE)
3015 PF_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
3016 PF_stov, // #117 vector(string) stov (FRIK_FILE)
3017 PF_strzone, // #118 string(string s) strzone (FRIK_FILE)
3018 PF_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3019 #define a NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3020 a a a a a a a a // #120-199
3021 a a a a a a a a a a // #200-299
3022 a a a a a a a a a a // #300-399
3023 PF_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3024 PF_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3025 PF_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3026 PF_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3027 PF_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3028 PF_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3029 PF_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3030 PF_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3031 PF_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
3032 PF_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3033 PF_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3034 PF_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3035 PF_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3036 PF_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3037 PF_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3038 PF_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3039 PF_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3040 PF_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3041 PF_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3042 PF_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3043 PF_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3044 PF_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3045 PF_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3046 PF_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3047 PF_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3048 PF_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3049 PF_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3050 PF_te_explosion2, // #427 void(vector org, float color) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3051 PF_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3052 PF_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3053 PF_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3054 PF_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3055 PF_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3056 PF_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3057 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3058 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3059 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3060 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3061 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3062 PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3063 a a a a a a // #440-499 (LordHavoc)
3066 builtin_t *pr_builtins = pr_builtin;
3067 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3069 void PR_Cmd_Init(void)
3071 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3075 void PR_Cmd_Reset(void)
3077 Mem_EmptyPool(pr_strings_mempool);
3078 PR_Files_CloseAll();