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 "
118 qboolean checkextension(char *name)
123 for (e = ENGINE_EXTENSIONS;*e;e++)
130 while (*e && *e != ' ')
132 if (e - start == len)
133 if (!strncasecmp(start, name, len))
143 returns true if the extension is supported by the server
145 checkextension(extensionname)
148 void PF_checkextension (void)
150 G_FLOAT(OFS_RETURN) = checkextension(G_STRING(OFS_PARM0));
157 This is a TERMINAL error, which will kill off the entire server.
169 Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
170 ed = PROG_TO_EDICT(pr_global_struct->self);
173 Host_Error ("Program error");
180 Dumps out self, then an error message. The program is aborted and self is
181 removed, but the level can continue.
186 void PF_objerror (void)
192 Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s);
193 ed = PROG_TO_EDICT(pr_global_struct->self);
203 Writes new values for v_forward, v_up, and v_right based on angles
207 void PF_makevectors (void)
209 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
216 Writes new values for v_forward, v_up, and v_right based on the given forward vector
217 vectorvectors(vector, vector)
220 void PF_vectorvectors (void)
222 VectorNormalize2(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward);
223 VectorVectors(pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
230 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.
232 setorigin (entity, origin)
235 void PF_setorigin (void)
240 e = G_EDICT(OFS_PARM0);
241 org = G_VECTOR(OFS_PARM1);
242 VectorCopy (org, e->v->origin);
243 SV_LinkEdict (e, false);
247 void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
251 for (i=0 ; i<3 ; i++)
253 Host_Error ("backwards mins/maxs");
255 // set derived values
256 VectorCopy (min, e->v->mins);
257 VectorCopy (max, e->v->maxs);
258 VectorSubtract (max, min, e->v->size);
260 SV_LinkEdict (e, false);
267 the size box is rotated by the current angle
268 LordHavoc: no it isn't...
270 setsize (entity, minvector, maxvector)
273 void PF_setsize (void)
278 e = G_EDICT(OFS_PARM0);
279 min = G_VECTOR(OFS_PARM1);
280 max = G_VECTOR(OFS_PARM2);
281 SetMinMaxSize (e, min, max, false);
289 setmodel(entity, model)
292 void PF_setmodel (void)
299 e = G_EDICT(OFS_PARM0);
300 m = G_STRING(OFS_PARM1);
302 // check to see if model was properly precached
303 for (i=0, check = sv.model_precache ; *check ; i++, check++)
304 if (!strcmp(*check, m))
308 Host_Error ("no precache: %s\n", m);
311 e->v->model = PR_SetString(*check);
312 e->v->modelindex = i;
314 mod = sv.models[ (int)e->v->modelindex];
317 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
319 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
326 broadcast print to everyone on server
331 void PF_bprint (void)
336 SV_BroadcastPrintf ("%s", s);
343 single print to a specific client
345 sprint(clientent, value)
348 void PF_sprint (void)
354 entnum = G_EDICTNUM(OFS_PARM0);
357 if (entnum < 1 || entnum > svs.maxclients)
359 Con_Printf ("tried to sprint to a non-client\n");
363 client = &svs.clients[entnum-1];
365 MSG_WriteChar (&client->message,svc_print);
366 MSG_WriteString (&client->message, s );
374 single print to a specific client
376 centerprint(clientent, value)
379 void PF_centerprint (void)
385 entnum = G_EDICTNUM(OFS_PARM0);
388 if (entnum < 1 || entnum > svs.maxclients)
390 Con_Printf ("tried to sprint to a non-client\n");
394 client = &svs.clients[entnum-1];
396 MSG_WriteChar (&client->message,svc_centerprint);
397 MSG_WriteString (&client->message, s );
405 vector normalize(vector)
408 void PF_normalize (void)
414 value1 = G_VECTOR(OFS_PARM0);
416 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
420 newvalue[0] = newvalue[1] = newvalue[2] = 0;
424 newvalue[0] = value1[0] * new;
425 newvalue[1] = value1[1] * new;
426 newvalue[2] = value1[2] * new;
429 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
444 value1 = G_VECTOR(OFS_PARM0);
446 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
449 G_FLOAT(OFS_RETURN) = new;
456 float vectoyaw(vector)
459 void PF_vectoyaw (void)
464 value1 = G_VECTOR(OFS_PARM0);
466 if (value1[1] == 0 && value1[0] == 0)
470 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
475 G_FLOAT(OFS_RETURN) = yaw;
483 vector vectoangles(vector)
486 void PF_vectoangles (void)
492 value1 = G_VECTOR(OFS_PARM0);
494 if (value1[1] == 0 && value1[0] == 0)
504 // LordHavoc: optimized a bit
507 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
511 else if (value1[1] > 0)
516 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
517 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
522 G_FLOAT(OFS_RETURN+0) = pitch;
523 G_FLOAT(OFS_RETURN+1) = yaw;
524 G_FLOAT(OFS_RETURN+2) = 0;
531 Returns a number from 0<= num < 1
536 void PF_random (void)
540 num = (rand ()&0x7fff) / ((float)0x7fff);
542 G_FLOAT(OFS_RETURN) = num;
549 particle(origin, color, count)
552 void PF_particle (void)
558 org = G_VECTOR(OFS_PARM0);
559 dir = G_VECTOR(OFS_PARM1);
560 color = G_FLOAT(OFS_PARM2);
561 count = G_FLOAT(OFS_PARM3);
562 SV_StartParticle (org, dir, color, count);
572 void PF_ambientsound (void)
577 float vol, attenuation;
578 int i, soundnum, large;
580 pos = G_VECTOR (OFS_PARM0);
581 samp = G_STRING(OFS_PARM1);
582 vol = G_FLOAT(OFS_PARM2);
583 attenuation = G_FLOAT(OFS_PARM3);
585 // check to see if samp was properly precached
586 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
587 if (!strcmp(*check,samp))
592 Con_Printf ("no precache: %s\n", samp);
600 // add an svc_spawnambient command to the level signon packet
603 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
605 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
607 for (i=0 ; i<3 ; i++)
608 MSG_WriteDPCoord(&sv.signon, pos[i]);
611 MSG_WriteShort (&sv.signon, soundnum);
613 MSG_WriteByte (&sv.signon, soundnum);
615 MSG_WriteByte (&sv.signon, vol*255);
616 MSG_WriteByte (&sv.signon, attenuation*64);
624 Each entity can have eight independant sound sources, like voice,
627 Channel 0 is an auto-allocate channel, the others override anything
628 already running on that entity/channel pair.
630 An attenuation of 0 will play full volume everywhere in the level.
631 Larger attenuations will drop off.
643 entity = G_EDICT(OFS_PARM0);
644 channel = G_FLOAT(OFS_PARM1);
645 sample = G_STRING(OFS_PARM2);
646 volume = G_FLOAT(OFS_PARM3) * 255;
647 attenuation = G_FLOAT(OFS_PARM4);
649 if (volume < 0 || volume > 255)
650 Host_Error ("SV_StartSound: volume = %i", volume);
652 if (attenuation < 0 || attenuation > 4)
653 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
655 if (channel < 0 || channel > 7)
656 Host_Error ("SV_StartSound: channel = %i", channel);
658 SV_StartSound (entity, channel, sample, volume, attenuation);
670 Host_Error ("break statement");
677 Used for use tracing and shot targeting
678 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
679 if the tryents flag is set.
681 traceline (vector1, vector2, tryents)
684 void PF_traceline (void)
691 pr_xfunction->builtinsprofile += 30;
693 v1 = G_VECTOR(OFS_PARM0);
694 v2 = G_VECTOR(OFS_PARM1);
695 nomonsters = G_FLOAT(OFS_PARM2);
696 ent = G_EDICT(OFS_PARM3);
698 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
700 pr_global_struct->trace_allsolid = trace.allsolid;
701 pr_global_struct->trace_startsolid = trace.startsolid;
702 pr_global_struct->trace_fraction = trace.fraction;
703 pr_global_struct->trace_inwater = trace.inwater;
704 pr_global_struct->trace_inopen = trace.inopen;
705 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
706 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
707 pr_global_struct->trace_plane_dist = trace.plane.dist;
709 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
711 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
712 // FIXME: add trace_endcontents
720 Used for use tracing and shot targeting
721 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
722 if the tryents flag is set.
724 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
727 // LordHavoc: added this for my own use, VERY useful, similar to traceline
728 void PF_tracebox (void)
730 float *v1, *v2, *m1, *m2;
735 pr_xfunction->builtinsprofile += 30;
737 v1 = G_VECTOR(OFS_PARM0);
738 m1 = G_VECTOR(OFS_PARM1);
739 m2 = G_VECTOR(OFS_PARM2);
740 v2 = G_VECTOR(OFS_PARM3);
741 nomonsters = G_FLOAT(OFS_PARM4);
742 ent = G_EDICT(OFS_PARM5);
744 trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
746 pr_global_struct->trace_allsolid = trace.allsolid;
747 pr_global_struct->trace_startsolid = trace.startsolid;
748 pr_global_struct->trace_fraction = trace.fraction;
749 pr_global_struct->trace_inwater = trace.inwater;
750 pr_global_struct->trace_inopen = trace.inopen;
751 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
752 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
753 pr_global_struct->trace_plane_dist = trace.plane.dist;
755 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
757 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
760 extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
761 void PF_TraceToss (void)
767 pr_xfunction->builtinsprofile += 600;
769 ent = G_EDICT(OFS_PARM0);
770 ignore = G_EDICT(OFS_PARM1);
772 trace = SV_Trace_Toss (ent, ignore);
774 pr_global_struct->trace_allsolid = trace.allsolid;
775 pr_global_struct->trace_startsolid = trace.startsolid;
776 pr_global_struct->trace_fraction = trace.fraction;
777 pr_global_struct->trace_inwater = trace.inwater;
778 pr_global_struct->trace_inopen = trace.inopen;
779 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
780 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
781 pr_global_struct->trace_plane_dist = trace.plane.dist;
783 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
785 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
793 Returns true if the given entity can move to the given position from it's
794 current position by walking or rolling.
796 scalar checkpos (entity, vector)
799 void PF_checkpos (void)
803 //============================================================================
805 qbyte checkpvs[MAX_MAP_LEAFS/8];
807 int PF_newcheckclient (int check)
815 // cycle to the next one
819 if (check > svs.maxclients)
820 check = svs.maxclients;
822 if (check == svs.maxclients)
829 pr_xfunction->builtinsprofile++;
830 if (i == svs.maxclients+1)
836 break; // didn't find anything else
840 if (ent->v->health <= 0)
842 if ((int)ent->v->flags & FL_NOTARGET)
845 // anything that is a client, or has a client as an enemy
849 // get the PVS for the entity
850 VectorAdd (ent->v->origin, ent->v->view_ofs, org);
851 leaf = Mod_PointInLeaf (org, sv.worldmodel);
852 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
853 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
862 Returns a client (or object that has a client enemy) that would be a
865 If there is more than one valid option, they are cycled each frame
867 If (self.origin + self.viewofs) is not in the PVS of the current target,
868 it is not returned at all.
873 int c_invis, c_notvis;
874 void PF_checkclient (void)
881 // find a new check if on a new frame
882 if (sv.time - sv.lastchecktime >= 0.1)
884 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
885 sv.lastchecktime = sv.time;
888 // return check if it might be visible
889 ent = EDICT_NUM(sv.lastcheck);
890 if (ent->free || ent->v->health <= 0)
892 RETURN_EDICT(sv.edicts);
896 // if current entity can't possibly see the check entity, return 0
897 self = PROG_TO_EDICT(pr_global_struct->self);
898 VectorAdd (self->v->origin, self->v->view_ofs, view);
899 leaf = Mod_PointInLeaf (view, sv.worldmodel);
902 l = (leaf - sv.worldmodel->leafs) - 1;
903 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
906 RETURN_EDICT(sv.edicts);
911 // might be able to see it
916 //============================================================================
923 Sends text over to the client's execution buffer
925 stuffcmd (clientent, value)
928 void PF_stuffcmd (void)
934 entnum = G_EDICTNUM(OFS_PARM0);
935 if (entnum < 1 || entnum > svs.maxclients)
936 Host_Error ("Parm 0 not a client");
937 str = G_STRING(OFS_PARM1);
940 host_client = &svs.clients[entnum-1];
941 Host_ClientCommands ("%s", str);
949 Sends text over to the client's execution buffer
954 void PF_localcmd (void)
958 str = G_STRING(OFS_PARM0);
973 str = G_STRING(OFS_PARM0);
975 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
985 void PF_cvar_set (void)
989 var = G_STRING(OFS_PARM0);
990 val = G_STRING(OFS_PARM1);
999 Returns a chain of entities that have origins within a spherical area
1001 findradius (origin, radius)
1004 void PF_findradius (void)
1006 edict_t *ent, *chain;
1013 chain = (edict_t *)sv.edicts;
1015 org = G_VECTOR(OFS_PARM0);
1016 radius = G_FLOAT(OFS_PARM1);
1017 radius2 = radius * radius;
1019 ent = NEXT_EDICT(sv.edicts);
1020 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1022 pr_xfunction->builtinsprofile++;
1025 if (ent->v->solid == SOLID_NOT)
1028 // LordHavoc: compare against bounding box rather than center,
1029 // and use DotProduct instead of Length, major speedup
1030 eorg[0] = (org[0] - ent->v->origin[0]) - bound(ent->v->mins[0], (org[0] - ent->v->origin[0]), ent->v->maxs[0]);
1031 eorg[1] = (org[1] - ent->v->origin[1]) - bound(ent->v->mins[1], (org[1] - ent->v->origin[1]), ent->v->maxs[1]);
1032 eorg[2] = (org[2] - ent->v->origin[2]) - bound(ent->v->mins[2], (org[2] - ent->v->origin[2]), ent->v->maxs[2]);
1033 if (DotProduct(eorg, eorg) > radius2)
1036 ent->v->chain = EDICT_TO_PROG(chain);
1040 RETURN_EDICT(chain);
1049 void PF_dprint (void)
1051 Con_DPrintf ("%s",PF_VarString(0));
1054 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
1055 #define STRINGTEMP_BUFFERS 16
1056 #define STRINGTEMP_LENGTH 128
1057 static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
1058 static int pr_string_tempindex = 0;
1060 static char *PR_GetTempString(void)
1063 s = pr_string_temp[pr_string_tempindex];
1064 pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS;
1072 v = G_FLOAT(OFS_PARM0);
1074 s = PR_GetTempString();
1075 // LordHavoc: ftos improvement
1076 sprintf (s, "%g", v);
1077 G_INT(OFS_RETURN) = PR_SetString(s);
1083 v = G_FLOAT(OFS_PARM0);
1084 G_FLOAT(OFS_RETURN) = fabs(v);
1090 s = PR_GetTempString();
1091 sprintf (s, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
1092 G_INT(OFS_RETURN) = PR_SetString(s);
1098 s = PR_GetTempString();
1099 sprintf (s, "entity %i", G_EDICTNUM(OFS_PARM0));
1100 G_INT(OFS_RETURN) = PR_SetString(s);
1103 void PF_Spawn (void)
1106 pr_xfunction->builtinsprofile += 20;
1111 void PF_Remove (void)
1114 pr_xfunction->builtinsprofile += 20;
1116 ed = G_EDICT(OFS_PARM0);
1117 if (ed == sv.edicts)
1118 Host_Error("remove: tried to remove world\n");
1119 if (NUM_FOR_EDICT(ed) <= svs.maxclients)
1120 Host_Error("remove: tried to remove a client\n");
1125 // entity (entity start, .string field, string match) find = #5;
1133 e = G_EDICTNUM(OFS_PARM0);
1134 f = G_INT(OFS_PARM1);
1135 s = G_STRING(OFS_PARM2);
1138 RETURN_EDICT(sv.edicts);
1142 for (e++ ; e < sv.num_edicts ; e++)
1144 pr_xfunction->builtinsprofile++;
1158 RETURN_EDICT(sv.edicts);
1161 // LordHavoc: added this for searching float, int, and entity reference fields
1162 void PF_FindFloat (void)
1169 e = G_EDICTNUM(OFS_PARM0);
1170 f = G_INT(OFS_PARM1);
1171 s = G_FLOAT(OFS_PARM2);
1173 for (e++ ; e < sv.num_edicts ; e++)
1175 pr_xfunction->builtinsprofile++;
1179 if (E_FLOAT(ed,f) == s)
1186 RETURN_EDICT(sv.edicts);
1189 // chained search for strings in entity fields
1190 // entity(.string field, string match) findchain = #402;
1191 void PF_findchain (void)
1196 edict_t *ent, *chain;
1198 chain = (edict_t *)sv.edicts;
1200 f = G_INT(OFS_PARM0);
1201 s = G_STRING(OFS_PARM1);
1204 RETURN_EDICT(sv.edicts);
1208 ent = NEXT_EDICT(sv.edicts);
1209 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1211 pr_xfunction->builtinsprofile++;
1214 t = E_STRING(ent,f);
1220 ent->v->chain = EDICT_TO_PROG(chain);
1224 RETURN_EDICT(chain);
1227 // LordHavoc: chained search for float, int, and entity reference fields
1228 // entity(.string field, float match) findchainfloat = #403;
1229 void PF_findchainfloat (void)
1234 edict_t *ent, *chain;
1236 chain = (edict_t *)sv.edicts;
1238 f = G_INT(OFS_PARM0);
1239 s = G_FLOAT(OFS_PARM1);
1241 ent = NEXT_EDICT(sv.edicts);
1242 for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1244 pr_xfunction->builtinsprofile++;
1247 if (E_FLOAT(ent,f) != s)
1250 ent->v->chain = EDICT_TO_PROG(chain);
1254 RETURN_EDICT(chain);
1257 void PR_CheckEmptyString (char *s)
1260 Host_Error ("Bad string");
1263 void PF_precache_file (void)
1264 { // precache_file is only used to copy files with qcc, it does nothing
1265 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1268 void PF_precache_sound (void)
1273 if (sv.state != ss_loading)
1274 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1276 s = G_STRING(OFS_PARM0);
1277 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1278 PR_CheckEmptyString (s);
1280 for (i=0 ; i<MAX_SOUNDS ; i++)
1282 if (!sv.sound_precache[i])
1284 sv.sound_precache[i] = s;
1287 if (!strcmp(sv.sound_precache[i], s))
1290 Host_Error ("PF_precache_sound: overflow");
1293 void PF_precache_model (void)
1298 if (sv.state != ss_loading)
1299 Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
1301 s = G_STRING(OFS_PARM0);
1302 if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
1304 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1305 PR_CheckEmptyString (s);
1307 for (i=0 ; i<MAX_MODELS ; i++)
1309 if (!sv.model_precache[i])
1311 sv.model_precache[i] = s;
1312 sv.models[i] = Mod_ForName (s, true, false, false);
1315 if (!strcmp(sv.model_precache[i], s))
1318 Host_Error ("PF_precache_model: overflow");
1322 void PF_coredump (void)
1327 void PF_traceon (void)
1332 void PF_traceoff (void)
1337 void PF_eprint (void)
1339 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1346 float(float yaw, float dist) walkmove
1349 void PF_walkmove (void)
1357 ent = PROG_TO_EDICT(pr_global_struct->self);
1358 yaw = G_FLOAT(OFS_PARM0);
1359 dist = G_FLOAT(OFS_PARM1);
1361 if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1363 G_FLOAT(OFS_RETURN) = 0;
1367 yaw = yaw*M_PI*2 / 360;
1369 move[0] = cos(yaw)*dist;
1370 move[1] = sin(yaw)*dist;
1373 // save program state, because SV_movestep may call other progs
1374 oldf = pr_xfunction;
1375 oldself = pr_global_struct->self;
1377 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1380 // restore program state
1381 pr_xfunction = oldf;
1382 pr_global_struct->self = oldself;
1392 void PF_droptofloor (void)
1398 ent = PROG_TO_EDICT(pr_global_struct->self);
1400 VectorCopy (ent->v->origin, end);
1403 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
1405 if (trace.fraction == 1)
1406 G_FLOAT(OFS_RETURN) = 0;
1409 VectorCopy (trace.endpos, ent->v->origin);
1410 SV_LinkEdict (ent, false);
1411 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1412 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1413 G_FLOAT(OFS_RETURN) = 1;
1414 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
1415 ent->suspendedinairflag = true;
1423 void(float style, string value) lightstyle
1426 void PF_lightstyle (void)
1433 style = G_FLOAT(OFS_PARM0);
1434 val = G_STRING(OFS_PARM1);
1436 // change the string in sv
1437 sv.lightstyles[style] = val;
1439 // send message to all clients on this server
1440 if (sv.state != ss_active)
1443 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1444 if (client->active || client->spawned)
1446 MSG_WriteChar (&client->message, svc_lightstyle);
1447 MSG_WriteChar (&client->message,style);
1448 MSG_WriteString (&client->message, val);
1455 f = G_FLOAT(OFS_PARM0);
1457 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1459 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1461 void PF_floor (void)
1463 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1467 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1476 void PF_checkbottom (void)
1478 G_FLOAT(OFS_RETURN) = SV_CheckBottom (G_EDICT(OFS_PARM0));
1486 void PF_pointcontents (void)
1488 G_FLOAT(OFS_RETURN) = Mod_PointContents(G_VECTOR(OFS_PARM0), sv.worldmodel);
1495 entity nextent(entity)
1498 void PF_nextent (void)
1503 i = G_EDICTNUM(OFS_PARM0);
1506 pr_xfunction->builtinsprofile++;
1508 if (i == sv.num_edicts)
1510 RETURN_EDICT(sv.edicts);
1526 Pick a vector for the player to shoot along
1527 vector aim(entity, missilespeed)
1532 edict_t *ent, *check, *bestent;
1533 vec3_t start, dir, end, bestdir;
1536 float dist, bestdist;
1539 ent = G_EDICT(OFS_PARM0);
1540 speed = G_FLOAT(OFS_PARM1);
1542 VectorCopy (ent->v->origin, start);
1545 // try sending a trace straight
1546 VectorCopy (pr_global_struct->v_forward, dir);
1547 VectorMA (start, 2048, dir, end);
1548 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1549 if (tr.ent && ((edict_t *)tr.ent)->v->takedamage == DAMAGE_AIM
1550 && (!teamplay.integer || ent->v->team <=0 || ent->v->team != ((edict_t *)tr.ent)->v->team) )
1552 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1557 // try all possible entities
1558 VectorCopy (dir, bestdir);
1559 bestdist = sv_aim.value;
1562 check = NEXT_EDICT(sv.edicts);
1563 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1565 pr_xfunction->builtinsprofile++;
1566 if (check->v->takedamage != DAMAGE_AIM)
1570 if (teamplay.integer && ent->v->team > 0 && ent->v->team == check->v->team)
1571 continue; // don't aim at teammate
1572 for (j=0 ; j<3 ; j++)
1573 end[j] = check->v->origin[j]
1574 + 0.5*(check->v->mins[j] + check->v->maxs[j]);
1575 VectorSubtract (end, start, dir);
1576 VectorNormalize (dir);
1577 dist = DotProduct (dir, pr_global_struct->v_forward);
1578 if (dist < bestdist)
1579 continue; // to far to turn
1580 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1581 if (tr.ent == check)
1582 { // can shoot at this one
1590 VectorSubtract (bestent->v->origin, ent->v->origin, dir);
1591 dist = DotProduct (dir, pr_global_struct->v_forward);
1592 VectorScale (pr_global_struct->v_forward, dist, end);
1594 VectorNormalize (end);
1595 VectorCopy (end, G_VECTOR(OFS_RETURN));
1599 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1607 This was a major timewaster in progs, so it was converted to C
1610 void PF_changeyaw (void)
1613 float ideal, current, move, speed;
1615 ent = PROG_TO_EDICT(pr_global_struct->self);
1616 current = ANGLEMOD(ent->v->angles[1]);
1617 ideal = ent->v->ideal_yaw;
1618 speed = ent->v->yaw_speed;
1620 if (current == ideal)
1622 move = ideal - current;
1623 if (ideal > current)
1644 ent->v->angles[1] = ANGLEMOD (current + move);
1652 void PF_changepitch (void)
1655 float ideal, current, move, speed;
1658 ent = G_EDICT(OFS_PARM0);
1659 current = ANGLEMOD( ent->v->angles[0] );
1660 if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1661 ideal = val->_float;
1664 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1667 if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1668 speed = val->_float;
1671 Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
1675 if (current == ideal)
1677 move = ideal - current;
1678 if (ideal > current)
1699 ent->v->angles[0] = ANGLEMOD (current + move);
1703 ===============================================================================
1707 ===============================================================================
1710 #define MSG_BROADCAST 0 // unreliable to all
1711 #define MSG_ONE 1 // reliable to one (msg_entity)
1712 #define MSG_ALL 2 // reliable to all
1713 #define MSG_INIT 3 // write to the init string
1715 sizebuf_t *WriteDest (void)
1721 dest = G_FLOAT(OFS_PARM0);
1725 return &sv.datagram;
1728 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1729 entnum = NUM_FOR_EDICT(ent);
1730 if (entnum < 1 || entnum > svs.maxclients)
1731 Host_Error ("WriteDest: not a client");
1732 return &svs.clients[entnum-1].message;
1735 return &sv.reliable_datagram;
1741 Host_Error ("WriteDest: bad destination");
1748 void PF_WriteByte (void)
1750 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1753 void PF_WriteChar (void)
1755 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1758 void PF_WriteShort (void)
1760 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1763 void PF_WriteLong (void)
1765 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1768 void PF_WriteAngle (void)
1770 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1773 void PF_WriteCoord (void)
1775 MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1778 void PF_WriteString (void)
1780 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1784 void PF_WriteEntity (void)
1786 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1789 //=============================================================================
1791 void PF_makestatic (void)
1796 ent = G_EDICT(OFS_PARM0);
1799 if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
1804 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1805 MSG_WriteShort (&sv.signon, ent->v->modelindex);
1806 MSG_WriteShort (&sv.signon, ent->v->frame);
1810 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1811 MSG_WriteByte (&sv.signon, ent->v->modelindex);
1812 MSG_WriteByte (&sv.signon, ent->v->frame);
1815 MSG_WriteByte (&sv.signon, ent->v->colormap);
1816 MSG_WriteByte (&sv.signon, ent->v->skin);
1817 for (i=0 ; i<3 ; i++)
1819 MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
1820 MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
1823 // throw the entity away now
1827 //=============================================================================
1834 void PF_setspawnparms (void)
1840 ent = G_EDICT(OFS_PARM0);
1841 i = NUM_FOR_EDICT(ent);
1842 if (i < 1 || i > svs.maxclients)
1843 Host_Error ("Entity is not a client");
1845 // copy spawn parms out of the client_t
1846 client = svs.clients + (i-1);
1848 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1849 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1857 void PF_changelevel (void)
1861 // make sure we don't issue two changelevels
1862 if (svs.changelevel_issued)
1864 svs.changelevel_issued = true;
1866 s = G_STRING(OFS_PARM0);
1867 Cbuf_AddText (va("changelevel %s\n",s));
1872 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1877 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1882 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1889 Returns a vector of length < 1
1894 void PF_randomvec (void)
1899 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1900 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1901 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1903 while (DotProduct(temp, temp) >= 1);
1904 VectorCopy (temp, G_VECTOR(OFS_RETURN));
1907 void SV_LightPoint (vec3_t color, vec3_t p);
1912 Returns a color vector indicating the lighting at the requested point.
1914 (Internal Operation note: actually measures the light beneath the point, just like
1915 the model lighting on the client)
1920 void PF_GetLight (void)
1924 p = G_VECTOR(OFS_PARM0);
1925 SV_LightPoint (color, p);
1926 VectorCopy (color, G_VECTOR(OFS_RETURN));
1929 #define MAX_QC_CVARS 128
1930 cvar_t qc_cvar[MAX_QC_CVARS];
1933 void PF_registercvar (void)
1937 name = G_STRING(OFS_PARM0);
1938 value = G_STRING(OFS_PARM1);
1939 G_FLOAT(OFS_RETURN) = 0;
1940 // first check to see if it has already been defined
1941 if (Cvar_FindVar (name))
1944 // check for overlap with a command
1945 if (Cmd_Exists (name))
1947 Con_Printf ("PF_registercvar: %s is a command\n", name);
1951 if (currentqc_cvar >= MAX_QC_CVARS)
1952 Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1954 // copy the name and value
1955 variable = &qc_cvar[currentqc_cvar++];
1956 variable->name = Z_Malloc (strlen(name)+1);
1957 strcpy (variable->name, name);
1958 variable->string = Z_Malloc (strlen(value)+1);
1959 strcpy (variable->string, value);
1960 variable->value = atof (value);
1962 Cvar_RegisterVariable(variable);
1963 G_FLOAT(OFS_RETURN) = 1; // success
1970 returns the minimum of two supplied floats
1977 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1979 G_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
1980 else if (pr_argc >= 3)
1983 float f = G_FLOAT(OFS_PARM0);
1984 for (i = 1;i < pr_argc;i++)
1985 if (G_FLOAT((OFS_PARM0+i*3)) < f)
1986 f = G_FLOAT((OFS_PARM0+i*3));
1987 G_FLOAT(OFS_RETURN) = f;
1990 Host_Error("min: must supply at least 2 floats\n");
1997 returns the maximum of two supplied floats
2004 // LordHavoc: 3+ argument enhancement suggested by FrikaC
2006 G_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2007 else if (pr_argc >= 3)
2010 float f = G_FLOAT(OFS_PARM0);
2011 for (i = 1;i < pr_argc;i++)
2012 if (G_FLOAT((OFS_PARM0+i*3)) > f)
2013 f = G_FLOAT((OFS_PARM0+i*3));
2014 G_FLOAT(OFS_RETURN) = f;
2017 Host_Error("max: must supply at least 2 floats\n");
2024 returns number bounded by supplied range
2026 min(min, value, max)
2029 void PF_bound (void)
2031 G_FLOAT(OFS_RETURN) = bound(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
2038 returns a raised to power b
2045 G_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));
2052 copies data from one entity to another
2054 copyentity(src, dst)
2057 void PF_copyentity (void)
2060 in = G_EDICT(OFS_PARM0);
2061 out = G_EDICT(OFS_PARM1);
2062 memcpy(out->v, in->v, progs->entityfields * 4);
2069 sets the color of a client and broadcasts the update to all connected clients
2071 setcolors(clientent, value)
2074 void PF_setcolors (void)
2079 entnum = G_EDICTNUM(OFS_PARM0);
2080 i = G_FLOAT(OFS_PARM1);
2082 if (entnum < 1 || entnum > svs.maxclients)
2084 Con_Printf ("tried to setcolor a non-client\n");
2088 client = &svs.clients[entnum-1];
2090 client->edict->v->team = (i & 15) + 1;
2092 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
2093 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
2094 MSG_WriteByte (&sv.reliable_datagram, i);
2101 effect(origin, modelname, startframe, framecount, framerate)
2104 void PF_effect (void)
2107 s = G_STRING(OFS_PARM1);
2109 Host_Error("effect: no model specified\n");
2111 SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
2114 void PF_te_blood (void)
2116 if (G_FLOAT(OFS_PARM2) < 1)
2118 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2119 MSG_WriteByte(&sv.datagram, TE_BLOOD);
2121 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2122 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2123 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2125 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2126 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2127 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2129 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2132 void PF_te_bloodshower (void)
2134 if (G_FLOAT(OFS_PARM3) < 1)
2136 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2137 MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
2139 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2140 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2141 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2143 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2144 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2145 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2147 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
2149 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2152 void PF_te_explosionrgb (void)
2154 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2155 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
2157 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2158 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2159 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2161 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
2162 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
2163 MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
2166 void PF_te_particlecube (void)
2168 if (G_FLOAT(OFS_PARM3) < 1)
2170 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2171 MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
2173 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2174 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2175 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2177 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2178 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2179 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2181 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2182 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2183 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2185 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2187 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2188 // gravity true/false
2189 MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
2191 MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
2194 void PF_te_particlerain (void)
2196 if (G_FLOAT(OFS_PARM3) < 1)
2198 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2199 MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
2201 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2202 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2203 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2205 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2206 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2207 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2209 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2210 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2211 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2213 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2215 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2218 void PF_te_particlesnow (void)
2220 if (G_FLOAT(OFS_PARM3) < 1)
2222 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2223 MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
2225 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2226 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2227 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2229 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2230 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2231 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2233 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2234 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2235 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2237 MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
2239 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
2242 void PF_te_spark (void)
2244 if (G_FLOAT(OFS_PARM2) < 1)
2246 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2247 MSG_WriteByte(&sv.datagram, TE_SPARK);
2249 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2250 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2251 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2253 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
2254 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
2255 MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
2257 MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
2260 void PF_te_gunshotquad (void)
2262 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2263 MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
2265 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2266 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2267 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2270 void PF_te_spikequad (void)
2272 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2273 MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
2275 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2276 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2277 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2280 void PF_te_superspikequad (void)
2282 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2283 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
2285 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2286 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2287 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2290 void PF_te_explosionquad (void)
2292 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2293 MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
2295 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2296 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2297 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2300 void PF_te_smallflash (void)
2302 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2303 MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
2305 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2306 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2307 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2310 void PF_te_customflash (void)
2312 if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
2314 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2315 MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
2317 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2318 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2319 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2321 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
2323 MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
2325 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
2326 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
2327 MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
2330 void PF_te_gunshot (void)
2332 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2333 MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
2335 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2336 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2337 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2340 void PF_te_spike (void)
2342 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2343 MSG_WriteByte(&sv.datagram, TE_SPIKE);
2345 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2346 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2347 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2350 void PF_te_superspike (void)
2352 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2353 MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
2355 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2356 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2357 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2360 void PF_te_explosion (void)
2362 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2363 MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
2365 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2366 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2367 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2370 void PF_te_tarexplosion (void)
2372 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2373 MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
2375 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2376 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2377 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2380 void PF_te_wizspike (void)
2382 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2383 MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
2385 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2386 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2387 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2390 void PF_te_knightspike (void)
2392 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2393 MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2395 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2396 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2397 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2400 void PF_te_lavasplash (void)
2402 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2403 MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2405 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2406 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2407 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2410 void PF_te_teleport (void)
2412 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2413 MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2415 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2416 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2417 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2420 void PF_te_explosion2 (void)
2422 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2423 MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2425 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2426 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2427 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2429 MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
2432 void PF_te_lightning1 (void)
2434 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2435 MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2437 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2439 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2440 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2441 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2443 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2444 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2445 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2448 void PF_te_lightning2 (void)
2450 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2451 MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2453 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2455 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2456 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2457 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2459 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2460 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2461 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2464 void PF_te_lightning3 (void)
2466 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2467 MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2469 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2471 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2472 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2473 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2475 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2476 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2477 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2480 void PF_te_beam (void)
2482 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2483 MSG_WriteByte(&sv.datagram, TE_BEAM);
2485 MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
2487 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
2488 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
2489 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
2491 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
2492 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
2493 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
2496 void PF_te_plasmaburn (void)
2498 MSG_WriteByte(&sv.datagram, svc_temp_entity);
2499 MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2500 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
2501 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
2502 MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
2505 static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
2508 vec3_t v1, clipplanenormal, normal;
2509 vec_t clipplanedist, clipdist;
2511 if (surf->flags & SURF_PLANEBACK)
2512 VectorNegate(surf->plane->normal, normal);
2514 VectorCopy(surf->plane->normal, normal);
2515 for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
2517 VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
2518 VectorNormalizeFast(v1);
2519 CrossProduct(v1, normal, clipplanenormal);
2520 clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
2521 clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
2524 clipdist = -clipdist;
2525 VectorMA(out, clipdist, clipplanenormal, out);
2530 static msurface_t *getsurface(edict_t *ed, int surfnum)
2534 if (!ed || ed->free)
2536 modelindex = ed->v->modelindex;
2537 if (modelindex < 1 || modelindex >= MAX_MODELS)
2539 model = sv.models[modelindex];
2540 if (model->type != mod_brush)
2542 if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
2544 return model->surfaces + surfnum + model->firstmodelsurface;
2548 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2549 void PF_getsurfacenumpoints(void)
2552 // return 0 if no such surface
2553 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2555 G_FLOAT(OFS_RETURN) = 0;
2559 G_FLOAT(OFS_RETURN) = surf->poly_numverts;
2561 //PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2562 void PF_getsurfacepoint(void)
2567 VectorClear(G_VECTOR(OFS_RETURN));
2568 ed = G_EDICT(OFS_PARM0);
2569 if (!ed || ed->free)
2571 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2573 pointnum = G_FLOAT(OFS_PARM2);
2574 if (pointnum < 0 || pointnum >= surf->poly_numverts)
2576 // FIXME: implement rotation/scaling
2577 VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
2579 //PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
2580 void PF_getsurfacenormal(void)
2583 VectorClear(G_VECTOR(OFS_RETURN));
2584 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2586 // FIXME: implement rotation/scaling
2587 if (surf->flags & SURF_PLANEBACK)
2588 VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
2590 VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
2592 //PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
2593 void PF_getsurfacetexture(void)
2596 G_INT(OFS_RETURN) = 0;
2597 if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
2599 G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
2601 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2602 void PF_getsurfacenearpoint(void)
2604 int surfnum, best, modelindex;
2606 vec_t dist, bestdist;
2611 G_FLOAT(OFS_RETURN) = -1;
2612 ed = G_EDICT(OFS_PARM0);
2613 point = G_VECTOR(OFS_PARM1);
2615 if (!ed || ed->free)
2617 modelindex = ed->v->modelindex;
2618 if (modelindex < 1 || modelindex >= MAX_MODELS)
2620 model = sv.models[modelindex];
2621 if (model->type != mod_brush)
2624 // FIXME: implement rotation/scaling
2625 VectorSubtract(point, ed->v->origin, p);
2627 bestdist = 1000000000;
2628 for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
2630 surf = model->surfaces + surfnum + model->firstmodelsurface;
2631 dist = PlaneDiff(p, surf->plane);
2633 if (dist < bestdist)
2635 clippointtosurface(surf, p, clipped);
2636 VectorSubtract(clipped, p, clipped);
2637 dist += DotProduct(clipped, clipped);
2638 if (dist < bestdist)
2645 G_FLOAT(OFS_RETURN) = best;
2647 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2648 void PF_getsurfaceclippedpoint(void)
2653 VectorClear(G_VECTOR(OFS_RETURN));
2654 ed = G_EDICT(OFS_PARM0);
2655 if (!ed || ed->free)
2657 if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
2659 // FIXME: implement rotation/scaling
2660 VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
2661 clippointtosurface(surf, p, out);
2662 // FIXME: implement rotation/scaling
2663 VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
2666 void PF_Fixme (void)
2668 Host_Error ("unimplemented QC builtin"); // LordHavoc: was misspelled (bulitin)
2671 #define MAX_PRFILES 256
2673 qfile_t *pr_files[MAX_PRFILES];
2675 void PR_Files_Init(void)
2677 memset(pr_files, 0, sizeof(pr_files));
2680 void PR_Files_CloseAll(void)
2683 for (i = 0;i < MAX_PRFILES;i++)
2686 FS_Close(pr_files[i]);
2691 //float(string s) stof = #81; // get numerical value from a string
2694 char *s = PF_VarString(0);
2695 G_FLOAT(OFS_RETURN) = atof(s);
2698 //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
2702 char *modestring, *filename;
2703 for (filenum = 0;filenum < MAX_PRFILES;filenum++)
2704 if (pr_files[filenum] == NULL)
2706 if (filenum >= MAX_PRFILES)
2708 Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
2709 G_FLOAT(OFS_RETURN) = -2;
2712 mode = G_FLOAT(OFS_PARM1);
2715 case 0: // FILE_READ
2718 case 1: // FILE_APPEND
2721 case 2: // FILE_WRITE
2725 Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
2726 G_FLOAT(OFS_RETURN) = -3;
2729 filename = G_STRING(OFS_PARM0);
2730 // .. is parent directory on many platforms
2731 // / is parent directory on Amiga
2732 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2733 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2734 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2736 Con_Printf("PF_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
2737 G_FLOAT(OFS_RETURN) = -4;
2740 pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
2741 if (pr_files[filenum] == NULL)
2742 G_FLOAT(OFS_RETURN) = -1;
2744 G_FLOAT(OFS_RETURN) = filenum;
2747 //void(float fhandle) fclose = #111; // closes a file
2748 void PF_fclose(void)
2750 int filenum = G_FLOAT(OFS_PARM0);
2751 if (filenum < 0 || filenum >= MAX_PRFILES)
2753 Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
2756 if (pr_files[filenum] == NULL)
2758 Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
2761 FS_Close(pr_files[filenum]);
2762 pr_files[filenum] = NULL;
2765 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
2769 static char string[MAX_VARSTRING];
2770 int filenum = G_FLOAT(OFS_PARM0);
2771 if (filenum < 0 || filenum >= MAX_PRFILES)
2773 Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
2776 if (pr_files[filenum] == NULL)
2778 Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
2784 c = FS_Getc(pr_files[filenum]);
2785 if (c == '\r' || c == '\n' || c < 0)
2787 if (end < MAX_VARSTRING - 1)
2791 // remove \n following \r
2793 c = FS_Getc(pr_files[filenum]);
2794 if (developer.integer)
2795 Con_Printf("fgets: %s\n", string);
2797 G_INT(OFS_RETURN) = PR_SetString(string);
2799 G_INT(OFS_RETURN) = 0;
2802 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2806 char *s = PF_VarString(1);
2807 int filenum = G_FLOAT(OFS_PARM0);
2808 if (filenum < 0 || filenum >= MAX_PRFILES)
2810 Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
2813 if (pr_files[filenum] == NULL)
2815 Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
2818 if ((stringlength = strlen(s)))
2819 FS_Write(pr_files[filenum], s, stringlength);
2820 if (developer.integer)
2821 Con_Printf("fputs: %s\n", s);
2824 //float(string s) strlen = #114; // returns how many characters are in a string
2825 void PF_strlen(void)
2828 s = G_STRING(OFS_PARM0);
2830 G_FLOAT(OFS_RETURN) = strlen(s);
2832 G_FLOAT(OFS_RETURN) = 0;
2835 //string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
2836 void PF_strcat(void)
2838 char *s = PF_VarString(0);
2839 G_INT(OFS_RETURN) = PR_SetString(s);
2842 //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring
2843 void PF_substring(void)
2845 int end, start, length, slen;
2847 char string[MAX_VARSTRING];
2848 s = G_STRING(OFS_PARM0);
2849 start = G_FLOAT(OFS_PARM1);
2850 length = G_FLOAT(OFS_PARM2);
2857 if (length > slen - start)
2858 length = slen - start;
2859 if (length > MAX_VARSTRING - 1)
2860 length = MAX_VARSTRING - 1;
2864 memcpy(string, s + start, length);
2868 G_INT(OFS_RETURN) = PR_SetString(string);
2871 //vector(string s) stov = #117; // returns vector value from a string
2874 Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN));
2877 //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)
2878 void PF_strzone(void)
2881 in = G_STRING(OFS_PARM0);
2882 out = Mem_Alloc(pr_strings_mempool, strlen(in) + 1);
2884 G_INT(OFS_RETURN) = PR_SetString(out);
2887 //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!!!)
2888 void PF_strunzone(void)
2890 Mem_Free(G_STRING(OFS_PARM0));
2893 builtin_t pr_builtin[] =
2896 PF_makevectors, // void(entity e) makevectors = #1;
2897 PF_setorigin, // void(entity e, vector o) setorigin = #2;
2898 PF_setmodel, // void(entity e, string m) setmodel = #3;
2899 PF_setsize, // void(entity e, vector min, vector max) setsize = #4;
2900 PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5;
2901 PF_break, // void() break = #6;
2902 PF_random, // float() random = #7;
2903 PF_sound, // void(entity e, float chan, string samp) sound = #8;
2904 PF_normalize, // vector(vector v) normalize = #9;
2905 PF_error, // void(string e) error = #10;
2906 PF_objerror, // void(string e) objerror = #11;
2907 PF_vlen, // float(vector v) vlen = #12;
2908 PF_vectoyaw, // float(vector v) vectoyaw = #13;
2909 PF_Spawn, // entity() spawn = #14;
2910 PF_Remove, // void(entity e) remove = #15;
2911 PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16;
2912 PF_checkclient, // entity() clientlist = #17;
2913 PF_Find, // entity(entity start, .string fld, string match) find = #18;
2914 PF_precache_sound, // void(string s) precache_sound = #19;
2915 PF_precache_model, // void(string s) precache_model = #20;
2916 PF_stuffcmd, // void(entity client, string s)stuffcmd = #21;
2917 PF_findradius, // entity(vector org, float rad) findradius = #22;
2918 PF_bprint, // void(string s) bprint = #23;
2919 PF_sprint, // void(entity client, string s) sprint = #24;
2920 PF_dprint, // void(string s) dprint = #25;
2921 PF_ftos, // void(string s) ftos = #26;
2922 PF_vtos, // void(string s) vtos = #27;
2926 PF_eprint, // void(entity e) debug print an entire entity
2927 PF_walkmove, // float(float yaw, float dist) walkmove
2928 PF_Fixme, // float(float yaw, float dist) walkmove
2978 PF_precache_sound, // precache_sound2 is different only for qcc
2983 PF_Fixme, // #79 LordHavoc: dunno who owns 79-89, so these are just padding
2985 PF_stof, // #81 float(string s) stof = #81;
2995 PF_tracebox, // #90 LordHavoc builtin range (9x)
2996 PF_randomvec, // #91
2998 PF_registercvar, // #93
3003 PF_FindFloat, // #98
3004 PF_checkextension, // #99
3005 #define a PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme,
3007 PF_fopen, // #110 float(string filename, float mode) fopen = #110;
3008 PF_fclose, // #111 void(float fhandle) fclose = #111;
3009 PF_fgets, // #112 string(float fhandle) fgets = #112;
3010 PF_fputs, // #113 void(float fhandle, string s) fputs = #113;
3011 PF_strlen, // #114 float(string s) strlen = #114;
3012 PF_strcat, // #115 string(string s1, string s2) strcat = #115;
3013 PF_substring, // #116 string(string s, float start, float length) substring = #116;
3014 PF_stov, // #117 vector(string) stov = #117;
3015 PF_strzone, // #118 string(string s) strzone = #118;
3016 PF_strunzone, // #119 void(string s) strunzone = #119;
3025 a a a a a a a a a a // #200-299
3026 a a a a a a a a a a // #300-399
3027 PF_copyentity, // #400 LordHavoc: builtin range (4xx)
3028 PF_setcolors, // #401
3029 PF_findchain, // #402
3030 PF_findchainfloat, // #403
3032 PF_te_blood, // #405
3033 PF_te_bloodshower, // #406
3034 PF_te_explosionrgb, // #407
3035 PF_te_particlecube, // #408
3036 PF_te_particlerain, // #409
3037 PF_te_particlesnow, // #410
3038 PF_te_spark, // #411
3039 PF_te_gunshotquad, // #412
3040 PF_te_spikequad, // #413
3041 PF_te_superspikequad, // #414
3042 PF_te_explosionquad, // #415
3043 PF_te_smallflash, // #416
3044 PF_te_customflash, // #417
3045 PF_te_gunshot, // #418
3046 PF_te_spike, // #419
3047 PF_te_superspike, // #420
3048 PF_te_explosion, // #421
3049 PF_te_tarexplosion, // #422
3050 PF_te_wizspike, // #423
3051 PF_te_knightspike, // #424
3052 PF_te_lavasplash, // #425
3053 PF_te_teleport, // #426
3054 PF_te_explosion2, // #427
3055 PF_te_lightning1, // #428
3056 PF_te_lightning2, // #429
3057 PF_te_lightning3, // #430
3059 PF_vectorvectors, // #432
3060 PF_te_plasmaburn, // #433
3061 PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
3062 PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
3063 PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
3064 PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
3065 PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
3066 PF_getsurfaceclippedpoint,// #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
3069 builtin_t *pr_builtins = pr_builtin;
3070 int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
3072 void PR_Cmd_Init(void)
3074 pr_strings_mempool = Mem_AllocPool("pr_stringszone");
3078 void PR_Cmd_Reset(void)
3080 Mem_EmptyPool(pr_strings_mempool);
3081 PR_Files_CloseAll();