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 #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
26 ===============================================================================
30 ===============================================================================
33 char *PF_VarString (int first
)
39 for (i
=first
; i
<pr_argc
; i
++)
41 strcat (out
, G_STRING((OFS_PARM0
+i
*3)));
51 This is a TERMINAL error, which will kill off the entire server.
63 Con_Printf ("======SERVER ERROR in %s:\n%s\n"
64 ,pr_strings
+ pr_xfunction
->s_name
,s
);
65 ed
= PROG_TO_EDICT(pr_global_struct
->self
);
68 Host_Error ("Program error");
75 Dumps out self, then an error message. The program is aborted and self is
76 removed, but the level can continue.
81 void PF_objerror (void)
87 Con_Printf ("======OBJECT ERROR in %s:\n%s\n"
88 ,pr_strings
+ pr_xfunction
->s_name
,s
);
89 ed
= PROG_TO_EDICT(pr_global_struct
->self
);
93 Host_Error ("Program error");
102 Writes new values for v_forward, v_up, and v_right based on angles
106 void PF_makevectors (void)
108 AngleVectors (G_VECTOR(OFS_PARM0
), pr_global_struct
->v_forward
, pr_global_struct
->v_right
, pr_global_struct
->v_up
);
115 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.
117 setorigin (entity, origin)
120 void PF_setorigin (void)
125 e
= G_EDICT(OFS_PARM0
);
126 org
= G_VECTOR(OFS_PARM1
);
127 VectorCopy (org
, e
->v
.origin
);
128 SV_LinkEdict (e
, false);
132 void SetMinMaxSize (edict_t
*e
, float *min
, float *max
, qboolean rotate
)
137 float xvector
[2], yvector
[2];
139 vec3_t base
, transformed
;
142 for (i
=0 ; i
<3 ; i
++)
144 PR_RunError ("backwards mins/maxs");
146 rotate
= false; // FIXME: implement rotation properly again
150 VectorCopy (min
, rmin
);
151 VectorCopy (max
, rmax
);
155 // find min / max for rotations
156 angles
= e
->v
.angles
;
158 a
= angles
[1]/180 * M_PI
;
162 yvector
[0] = -sin(a
);
165 VectorCopy (min
, bounds
[0]);
166 VectorCopy (max
, bounds
[1]);
168 rmin
[0] = rmin
[1] = rmin
[2] = 9999;
169 rmax
[0] = rmax
[1] = rmax
[2] = -9999;
171 for (i
=0 ; i
<= 1 ; i
++)
173 base
[0] = bounds
[i
][0];
174 for (j
=0 ; j
<= 1 ; j
++)
176 base
[1] = bounds
[j
][1];
177 for (k
=0 ; k
<= 1 ; k
++)
179 base
[2] = bounds
[k
][2];
181 // transform the point
182 transformed
[0] = xvector
[0]*base
[0] + yvector
[0]*base
[1];
183 transformed
[1] = xvector
[1]*base
[0] + yvector
[1]*base
[1];
184 transformed
[2] = base
[2];
186 for (l
=0 ; l
<3 ; l
++)
188 if (transformed
[l
] < rmin
[l
])
189 rmin
[l
] = transformed
[l
];
190 if (transformed
[l
] > rmax
[l
])
191 rmax
[l
] = transformed
[l
];
198 // set derived values
199 VectorCopy (rmin
, e
->v
.mins
);
200 VectorCopy (rmax
, e
->v
.maxs
);
201 VectorSubtract (max
, min
, e
->v
.size
);
203 SV_LinkEdict (e
, false);
210 the size box is rotated by the current angle
212 setsize (entity, minvector, maxvector)
215 void PF_setsize (void)
220 e
= G_EDICT(OFS_PARM0
);
221 min
= G_VECTOR(OFS_PARM1
);
222 max
= G_VECTOR(OFS_PARM2
);
223 SetMinMaxSize (e
, min
, max
, false);
231 setmodel(entity, model)
234 void PF_setmodel (void)
241 e
= G_EDICT(OFS_PARM0
);
242 m
= G_STRING(OFS_PARM1
);
244 // check to see if model was properly precached
245 for (i
=0, check
= sv
.model_precache
; *check
; i
++, check
++)
246 if (!strcmp(*check
, m
))
250 PR_RunError ("no precache: %s\n", m
);
253 e
->v
.model
= m
- pr_strings
;
254 e
->v
.modelindex
= i
; //SV_ModelIndex (m);
256 mod
= sv
.models
[ (int)e
->v
.modelindex
]; // Mod_ForName (m, true);
259 SetMinMaxSize (e
, mod
->mins
, mod
->maxs
, true);
261 SetMinMaxSize (e
, vec3_origin
, vec3_origin
, true);
268 broadcast print to everyone on server
273 void PF_bprint (void)
278 SV_BroadcastPrintf ("%s", s
);
285 single print to a specific client
287 sprint(clientent, value)
290 void PF_sprint (void)
296 entnum
= G_EDICTNUM(OFS_PARM0
);
299 if (entnum
< 1 || entnum
> svs
.maxclients
)
301 Con_Printf ("tried to sprint to a non-client\n");
305 client
= &svs
.clients
[entnum
-1];
307 MSG_WriteChar (&client
->message
,svc_print
);
308 MSG_WriteString (&client
->message
, s
);
316 single print to a specific client
318 centerprint(clientent, value)
321 void PF_centerprint (void)
327 entnum
= G_EDICTNUM(OFS_PARM0
);
330 if (entnum
< 1 || entnum
> svs
.maxclients
)
332 Con_Printf ("tried to sprint to a non-client\n");
336 client
= &svs
.clients
[entnum
-1];
338 MSG_WriteChar (&client
->message
,svc_centerprint
);
339 MSG_WriteString (&client
->message
, s
);
347 vector normalize(vector)
350 void PF_normalize (void)
356 value1
= G_VECTOR(OFS_PARM0
);
358 new = value1
[0] * value1
[0] + value1
[1] * value1
[1] + value1
[2]*value1
[2];
362 newvalue
[0] = newvalue
[1] = newvalue
[2] = 0;
366 newvalue
[0] = value1
[0] * new;
367 newvalue
[1] = value1
[1] * new;
368 newvalue
[2] = value1
[2] * new;
371 VectorCopy (newvalue
, G_VECTOR(OFS_RETURN
));
386 value1
= G_VECTOR(OFS_PARM0
);
388 new = value1
[0] * value1
[0] + value1
[1] * value1
[1] + value1
[2]*value1
[2];
391 G_FLOAT(OFS_RETURN
) = new;
398 float vectoyaw(vector)
401 void PF_vectoyaw (void)
406 value1
= G_VECTOR(OFS_PARM0
);
408 if (value1
[1] == 0 && value1
[0] == 0)
412 yaw
= (int) (atan2(value1
[1], value1
[0]) * 180 / M_PI
);
417 G_FLOAT(OFS_RETURN
) = yaw
;
425 vector vectoangles(vector)
428 void PF_vectoangles (void)
434 value1
= G_VECTOR(OFS_PARM0
);
436 if (value1
[1] == 0 && value1
[0] == 0)
446 yaw
= (int) (atan2(value1
[1], value1
[0]) * 180 / M_PI
);
450 forward
= sqrt (value1
[0]*value1
[0] + value1
[1]*value1
[1]);
451 pitch
= (int) (atan2(value1
[2], forward
) * 180 / M_PI
);
456 G_FLOAT(OFS_RETURN
+0) = pitch
;
457 G_FLOAT(OFS_RETURN
+1) = yaw
;
458 G_FLOAT(OFS_RETURN
+2) = 0;
465 Returns a number from 0<= num < 1
470 void PF_random (void)
474 num
= (rand ()&0x7fff) / ((float)0x7fff);
476 G_FLOAT(OFS_RETURN
) = num
;
483 particle(origin, color, count)
486 void PF_particle (void)
492 org
= G_VECTOR(OFS_PARM0
);
493 dir
= G_VECTOR(OFS_PARM1
);
494 color
= G_FLOAT(OFS_PARM2
);
495 count
= G_FLOAT(OFS_PARM3
);
496 SV_StartParticle (org
, dir
, color
, count
);
506 void PF_ambientsound (void)
511 float vol
, attenuation
;
514 pos
= G_VECTOR (OFS_PARM0
);
515 samp
= G_STRING(OFS_PARM1
);
516 vol
= G_FLOAT(OFS_PARM2
);
517 attenuation
= G_FLOAT(OFS_PARM3
);
519 // check to see if samp was properly precached
520 for (soundnum
=0, check
= sv
.sound_precache
; *check
; check
++, soundnum
++)
521 if (!strcmp(*check
,samp
))
526 Con_Printf ("no precache: %s\n", samp
);
530 // add an svc_spawnambient command to the level signon packet
532 MSG_WriteByte (&sv
.signon
,svc_spawnstaticsound
);
533 for (i
=0 ; i
<3 ; i
++)
534 MSG_WriteCoord(&sv
.signon
, pos
[i
]);
536 MSG_WriteByte (&sv
.signon
, soundnum
);
538 MSG_WriteByte (&sv
.signon
, vol
*255);
539 MSG_WriteByte (&sv
.signon
, attenuation
*64);
547 Each entity can have eight independant sound sources, like voice,
550 Channel 0 is an auto-allocate channel, the others override anything
551 allready running on that entity/channel pair.
553 An attenuation of 0 will play full volume everywhere in the level.
554 Larger attenuations will drop off.
566 entity
= G_EDICT(OFS_PARM0
);
567 channel
= G_FLOAT(OFS_PARM1
);
568 sample
= G_STRING(OFS_PARM2
);
569 volume
= G_FLOAT(OFS_PARM3
) * 255;
570 attenuation
= G_FLOAT(OFS_PARM4
);
572 if (volume
< 0 || volume
> 255)
573 Sys_Error ("SV_StartSound: volume = %i", volume
);
575 if (attenuation
< 0 || attenuation
> 4)
576 Sys_Error ("SV_StartSound: attenuation = %f", attenuation
);
578 if (channel
< 0 || channel
> 7)
579 Sys_Error ("SV_StartSound: channel = %i", channel
);
581 SV_StartSound (entity
, channel
, sample
, volume
, attenuation
);
593 Con_Printf ("break statement\n");
594 *(int *)-4 = 0; // dump to debugger
595 // PR_RunError ("break statement");
602 Used for use tracing and shot targeting
603 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
604 if the tryents flag is set.
606 traceline (vector1, vector2, tryents)
609 void PF_traceline (void)
616 v1
= G_VECTOR(OFS_PARM0
);
617 v2
= G_VECTOR(OFS_PARM1
);
618 nomonsters
= G_FLOAT(OFS_PARM2
);
619 ent
= G_EDICT(OFS_PARM3
);
621 trace
= SV_Move (v1
, vec3_origin
, vec3_origin
, v2
, nomonsters
, ent
);
623 pr_global_struct
->trace_allsolid
= trace
.allsolid
;
624 pr_global_struct
->trace_startsolid
= trace
.startsolid
;
625 pr_global_struct
->trace_fraction
= trace
.fraction
;
626 pr_global_struct
->trace_inwater
= trace
.inwater
;
627 pr_global_struct
->trace_inopen
= trace
.inopen
;
628 VectorCopy (trace
.endpos
, pr_global_struct
->trace_endpos
);
629 VectorCopy (trace
.plane
.normal
, pr_global_struct
->trace_plane_normal
);
630 pr_global_struct
->trace_plane_dist
= trace
.plane
.dist
;
632 pr_global_struct
->trace_ent
= EDICT_TO_PROG(trace
.ent
);
634 pr_global_struct
->trace_ent
= EDICT_TO_PROG(sv
.edicts
);
639 extern trace_t
SV_Trace_Toss (edict_t
*ent
, edict_t
*ignore
);
641 void PF_TraceToss (void)
647 ent
= G_EDICT(OFS_PARM0
);
648 ignore
= G_EDICT(OFS_PARM1
);
650 trace
= SV_Trace_Toss (ent
, ignore
);
652 pr_global_struct
->trace_allsolid
= trace
.allsolid
;
653 pr_global_struct
->trace_startsolid
= trace
.startsolid
;
654 pr_global_struct
->trace_fraction
= trace
.fraction
;
655 pr_global_struct
->trace_inwater
= trace
.inwater
;
656 pr_global_struct
->trace_inopen
= trace
.inopen
;
657 VectorCopy (trace
.endpos
, pr_global_struct
->trace_endpos
);
658 VectorCopy (trace
.plane
.normal
, pr_global_struct
->trace_plane_normal
);
659 pr_global_struct
->trace_plane_dist
= trace
.plane
.dist
;
661 pr_global_struct
->trace_ent
= EDICT_TO_PROG(trace
.ent
);
663 pr_global_struct
->trace_ent
= EDICT_TO_PROG(sv
.edicts
);
672 Returns true if the given entity can move to the given position from it's
673 current position by walking or rolling.
675 scalar checkpos (entity, vector)
678 void PF_checkpos (void)
682 //============================================================================
684 byte checkpvs
[MAX_MAP_LEAFS
/8];
686 int PF_newcheckclient (int check
)
694 // cycle to the next one
698 if (check
> svs
.maxclients
)
699 check
= svs
.maxclients
;
701 if (check
== svs
.maxclients
)
708 if (i
== svs
.maxclients
+1)
714 break; // didn't find anything else
718 if (ent
->v
.health
<= 0)
720 if ((int)ent
->v
.flags
& FL_NOTARGET
)
723 // anything that is a client, or has a client as an enemy
727 // get the PVS for the entity
728 VectorAdd (ent
->v
.origin
, ent
->v
.view_ofs
, org
);
729 leaf
= Mod_PointInLeaf (org
, sv
.worldmodel
);
730 pvs
= Mod_LeafPVS (leaf
, sv
.worldmodel
);
731 memcpy (checkpvs
, pvs
, (sv
.worldmodel
->numleafs
+7)>>3 );
740 Returns a client (or object that has a client enemy) that would be a
743 If there are more than one valid options, they are cycled each frame
745 If (self.origin + self.viewofs) is not in the PVS of the current target,
746 it is not returned at all.
752 int c_invis
, c_notvis
;
753 void PF_checkclient (void)
760 // find a new check if on a new frame
761 if (sv
.time
- sv
.lastchecktime
>= 0.1)
763 sv
.lastcheck
= PF_newcheckclient (sv
.lastcheck
);
764 sv
.lastchecktime
= sv
.time
;
767 // return check if it might be visible
768 ent
= EDICT_NUM(sv
.lastcheck
);
769 if (ent
->free
|| ent
->v
.health
<= 0)
771 RETURN_EDICT(sv
.edicts
);
775 // if current entity can't possibly see the check entity, return 0
776 self
= PROG_TO_EDICT(pr_global_struct
->self
);
777 VectorAdd (self
->v
.origin
, self
->v
.view_ofs
, view
);
778 leaf
= Mod_PointInLeaf (view
, sv
.worldmodel
);
779 l
= (leaf
- sv
.worldmodel
->leafs
) - 1;
780 if ( (l
<0) || !(checkpvs
[l
>>3] & (1<<(l
&7)) ) )
783 RETURN_EDICT(sv
.edicts
);
787 // might be able to see it
792 //============================================================================
799 Sends text over to the client's execution buffer
801 stuffcmd (clientent, value)
804 void PF_stuffcmd (void)
810 entnum
= G_EDICTNUM(OFS_PARM0
);
811 if (entnum
< 1 || entnum
> svs
.maxclients
)
812 PR_RunError ("Parm 0 not a client");
813 str
= G_STRING(OFS_PARM1
);
816 host_client
= &svs
.clients
[entnum
-1];
817 Host_ClientCommands ("%s", str
);
825 Sends text over to the client's execution buffer
830 void PF_localcmd (void)
834 str
= G_STRING(OFS_PARM0
);
849 str
= G_STRING(OFS_PARM0
);
851 G_FLOAT(OFS_RETURN
) = Cvar_VariableValue (str
);
861 void PF_cvar_set (void)
865 var
= G_STRING(OFS_PARM0
);
866 val
= G_STRING(OFS_PARM1
);
875 Returns a chain of entities that have origins within a spherical area
877 findradius (origin, radius)
880 void PF_findradius (void)
882 edict_t
*ent
, *chain
;
888 chain
= (edict_t
*)sv
.edicts
;
890 org
= G_VECTOR(OFS_PARM0
);
891 rad
= G_FLOAT(OFS_PARM1
);
893 ent
= NEXT_EDICT(sv
.edicts
);
894 for (i
=1 ; i
<sv
.num_edicts
; i
++, ent
= NEXT_EDICT(ent
))
898 if (ent
->v
.solid
== SOLID_NOT
)
900 for (j
=0 ; j
<3 ; j
++)
901 eorg
[j
] = org
[j
] - (ent
->v
.origin
[j
] + (ent
->v
.mins
[j
] + ent
->v
.maxs
[j
])*0.5);
902 if (Length(eorg
) > rad
)
905 ent
->v
.chain
= EDICT_TO_PROG(chain
);
918 void PF_dprint (void)
920 Con_DPrintf ("%s",PF_VarString(0));
923 char pr_string_temp
[128];
928 v
= G_FLOAT(OFS_PARM0
);
931 sprintf (pr_string_temp
, "%d",(int)v
);
933 sprintf (pr_string_temp
, "%5.1f",v
);
934 G_INT(OFS_RETURN
) = pr_string_temp
- pr_strings
;
940 v
= G_FLOAT(OFS_PARM0
);
941 G_FLOAT(OFS_RETURN
) = fabs(v
);
946 sprintf (pr_string_temp
, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0
)[0], G_VECTOR(OFS_PARM0
)[1], G_VECTOR(OFS_PARM0
)[2]);
947 G_INT(OFS_RETURN
) = pr_string_temp
- pr_strings
;
953 sprintf (pr_string_temp
, "entity %i", G_EDICTNUM(OFS_PARM0
));
954 G_INT(OFS_RETURN
) = pr_string_temp
- pr_strings
;
965 void PF_Remove (void)
969 ed
= G_EDICT(OFS_PARM0
);
974 // entity (entity start, .string field, string match) find = #5;
986 first
= second
= last
= (edict_t
*)sv
.edicts
;
987 e
= G_EDICTNUM(OFS_PARM0
);
988 f
= G_INT(OFS_PARM1
);
989 s
= G_STRING(OFS_PARM2
);
991 PR_RunError ("PF_Find: bad search string");
993 for (e
++ ; e
< sv
.num_edicts
; e
++)
1003 if (first
== (edict_t
*)sv
.edicts
)
1005 else if (second
== (edict_t
*)sv
.edicts
)
1007 ed
->v
.chain
= EDICT_TO_PROG(last
);
1015 first
->v
.chain
= last
->v
.chain
;
1017 first
->v
.chain
= EDICT_TO_PROG(last
);
1018 last
->v
.chain
= EDICT_TO_PROG((edict_t
*)sv
.edicts
);
1019 if (second
&& second
!= last
)
1020 second
->v
.chain
= EDICT_TO_PROG(last
);
1022 RETURN_EDICT(first
);
1031 e
= G_EDICTNUM(OFS_PARM0
);
1032 f
= G_INT(OFS_PARM1
);
1033 s
= G_STRING(OFS_PARM2
);
1035 PR_RunError ("PF_Find: bad search string");
1037 for (e
++ ; e
< sv
.num_edicts
; e
++)
1052 RETURN_EDICT(sv
.edicts
);
1056 void PR_CheckEmptyString (char *s
)
1059 PR_RunError ("Bad string");
1062 void PF_precache_file (void)
1063 { // precache_file is only used to copy files with qcc, it does nothing
1064 G_INT(OFS_RETURN
) = G_INT(OFS_PARM0
);
1067 void PF_precache_sound (void)
1072 if (sv
.state
!= ss_loading
)
1073 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1075 s
= G_STRING(OFS_PARM0
);
1076 G_INT(OFS_RETURN
) = G_INT(OFS_PARM0
);
1077 PR_CheckEmptyString (s
);
1079 for (i
=0 ; i
<MAX_SOUNDS
; i
++)
1081 if (!sv
.sound_precache
[i
])
1083 sv
.sound_precache
[i
] = s
;
1086 if (!strcmp(sv
.sound_precache
[i
], s
))
1089 PR_RunError ("PF_precache_sound: overflow");
1092 void PF_precache_model (void)
1097 if (sv
.state
!= ss_loading
)
1098 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1100 s
= G_STRING(OFS_PARM0
);
1101 G_INT(OFS_RETURN
) = G_INT(OFS_PARM0
);
1102 PR_CheckEmptyString (s
);
1104 for (i
=0 ; i
<MAX_MODELS
; i
++)
1106 if (!sv
.model_precache
[i
])
1108 sv
.model_precache
[i
] = s
;
1109 sv
.models
[i
] = Mod_ForName (s
, true);
1112 if (!strcmp(sv
.model_precache
[i
], s
))
1115 PR_RunError ("PF_precache_model: overflow");
1119 void PF_coredump (void)
1124 void PF_traceon (void)
1129 void PF_traceoff (void)
1134 void PF_eprint (void)
1136 ED_PrintNum (G_EDICTNUM(OFS_PARM0
));
1143 float(float yaw, float dist) walkmove
1146 void PF_walkmove (void)
1154 ent
= PROG_TO_EDICT(pr_global_struct
->self
);
1155 yaw
= G_FLOAT(OFS_PARM0
);
1156 dist
= G_FLOAT(OFS_PARM1
);
1158 if ( !( (int)ent
->v
.flags
& (FL_ONGROUND
|FL_FLY
|FL_SWIM
) ) )
1160 G_FLOAT(OFS_RETURN
) = 0;
1164 yaw
= yaw
*M_PI
*2 / 360;
1166 move
[0] = cos(yaw
)*dist
;
1167 move
[1] = sin(yaw
)*dist
;
1170 // save program state, because SV_movestep may call other progs
1171 oldf
= pr_xfunction
;
1172 oldself
= pr_global_struct
->self
;
1174 G_FLOAT(OFS_RETURN
) = SV_movestep(ent
, move
, true);
1177 // restore program state
1178 pr_xfunction
= oldf
;
1179 pr_global_struct
->self
= oldself
;
1189 void PF_droptofloor (void)
1195 ent
= PROG_TO_EDICT(pr_global_struct
->self
);
1197 VectorCopy (ent
->v
.origin
, end
);
1200 trace
= SV_Move (ent
->v
.origin
, ent
->v
.mins
, ent
->v
.maxs
, end
, false, ent
);
1202 if (trace
.fraction
== 1 || trace
.allsolid
)
1203 G_FLOAT(OFS_RETURN
) = 0;
1206 VectorCopy (trace
.endpos
, ent
->v
.origin
);
1207 SV_LinkEdict (ent
, false);
1208 ent
->v
.flags
= (int)ent
->v
.flags
| FL_ONGROUND
;
1209 ent
->v
.groundentity
= EDICT_TO_PROG(trace
.ent
);
1210 G_FLOAT(OFS_RETURN
) = 1;
1218 void(float style, string value) lightstyle
1221 void PF_lightstyle (void)
1228 style
= G_FLOAT(OFS_PARM0
);
1229 val
= G_STRING(OFS_PARM1
);
1231 // change the string in sv
1232 sv
.lightstyles
[style
] = val
;
1234 // send message to all clients on this server
1235 if (sv
.state
!= ss_active
)
1238 for (j
=0, client
= svs
.clients
; j
<svs
.maxclients
; j
++, client
++)
1239 if (client
->active
|| client
->spawned
)
1241 MSG_WriteChar (&client
->message
, svc_lightstyle
);
1242 MSG_WriteChar (&client
->message
,style
);
1243 MSG_WriteString (&client
->message
, val
);
1250 f
= G_FLOAT(OFS_PARM0
);
1252 G_FLOAT(OFS_RETURN
) = (int)(f
+ 0.5);
1254 G_FLOAT(OFS_RETURN
) = (int)(f
- 0.5);
1256 void PF_floor (void)
1258 G_FLOAT(OFS_RETURN
) = floor(G_FLOAT(OFS_PARM0
));
1262 G_FLOAT(OFS_RETURN
) = ceil(G_FLOAT(OFS_PARM0
));
1271 void PF_checkbottom (void)
1275 ent
= G_EDICT(OFS_PARM0
);
1277 G_FLOAT(OFS_RETURN
) = SV_CheckBottom (ent
);
1285 void PF_pointcontents (void)
1289 v
= G_VECTOR(OFS_PARM0
);
1291 G_FLOAT(OFS_RETURN
) = SV_PointContents (v
);
1298 entity nextent(entity)
1301 void PF_nextent (void)
1306 i
= G_EDICTNUM(OFS_PARM0
);
1310 if (i
== sv
.num_edicts
)
1312 RETURN_EDICT(sv
.edicts
);
1328 Pick a vector for the player to shoot along
1329 vector aim(entity, missilespeed)
1332 cvar_t sv_aim
= {"sv_aim", "0.93"};
1335 edict_t
*ent
, *check
, *bestent
;
1336 vec3_t start
, dir
, end
, bestdir
;
1339 float dist
, bestdist
;
1341 ent
= G_EDICT(OFS_PARM0
);
1343 VectorCopy (ent
->v
.origin
, start
);
1346 // try sending a trace straight
1347 VectorCopy (pr_global_struct
->v_forward
, dir
);
1348 VectorMA (start
, 2048, dir
, end
);
1349 tr
= SV_Move (start
, vec3_origin
, vec3_origin
, end
, false, ent
);
1350 if (tr
.ent
&& tr
.ent
->v
.takedamage
== DAMAGE_AIM
1351 && (!teamplay
.value
|| ent
->v
.team
<=0 || ent
->v
.team
!= tr
.ent
->v
.team
) )
1353 VectorCopy (pr_global_struct
->v_forward
, G_VECTOR(OFS_RETURN
));
1358 // try all possible entities
1359 VectorCopy (dir
, bestdir
);
1360 bestdist
= sv_aim
.value
;
1363 check
= NEXT_EDICT(sv
.edicts
);
1364 for (i
=1 ; i
<sv
.num_edicts
; i
++, check
= NEXT_EDICT(check
) )
1366 if (check
->v
.takedamage
!= DAMAGE_AIM
)
1370 if (teamplay
.value
&& ent
->v
.team
> 0 && ent
->v
.team
== check
->v
.team
)
1371 continue; // don't aim at teammate
1372 for (j
=0 ; j
<3 ; j
++)
1373 end
[j
] = check
->v
.origin
[j
]
1374 + 0.5*(check
->v
.mins
[j
] + check
->v
.maxs
[j
]);
1375 VectorSubtract (end
, start
, dir
);
1376 VectorNormalize (dir
);
1377 dist
= DotProduct (dir
, pr_global_struct
->v_forward
);
1378 if (dist
< bestdist
)
1379 continue; // to far to turn
1380 tr
= SV_Move (start
, vec3_origin
, vec3_origin
, end
, false, ent
);
1381 if (tr
.ent
== check
)
1382 { // can shoot at this one
1390 VectorSubtract (bestent
->v
.origin
, ent
->v
.origin
, dir
);
1391 dist
= DotProduct (dir
, pr_global_struct
->v_forward
);
1392 VectorScale (pr_global_struct
->v_forward
, dist
, end
);
1394 VectorNormalize (end
);
1395 VectorCopy (end
, G_VECTOR(OFS_RETURN
));
1399 VectorCopy (bestdir
, G_VECTOR(OFS_RETURN
));
1407 This was a major timewaster in progs, so it was converted to C
1410 void PF_changeyaw (void)
1413 float ideal
, current
, move
, speed
;
1415 ent
= PROG_TO_EDICT(pr_global_struct
->self
);
1416 current
= anglemod( ent
->v
.angles
[1] );
1417 ideal
= ent
->v
.ideal_yaw
;
1418 speed
= ent
->v
.yaw_speed
;
1420 if (current
== ideal
)
1422 move
= ideal
- current
;
1423 if (ideal
> current
)
1444 ent
->v
.angles
[1] = anglemod (current
+ move
);
1453 void PF_changepitch (void)
1456 float ideal
, current
, move
, speed
;
1458 ent
= G_EDICT(OFS_PARM0
);
1459 current
= anglemod( ent
->v
.angles
[0] );
1460 ideal
= ent
->v
.idealpitch
;
1461 speed
= ent
->v
.pitch_speed
;
1463 if (current
== ideal
)
1465 move
= ideal
- current
;
1466 if (ideal
> current
)
1487 ent
->v
.angles
[0] = anglemod (current
+ move
);
1492 ===============================================================================
1496 ===============================================================================
1499 #define MSG_BROADCAST 0 // unreliable to all
1500 #define MSG_ONE 1 // reliable to one (msg_entity)
1501 #define MSG_ALL 2 // reliable to all
1502 #define MSG_INIT 3 // write to the init string
1504 sizebuf_t
*WriteDest (void)
1510 dest
= G_FLOAT(OFS_PARM0
);
1514 return &sv
.datagram
;
1517 ent
= PROG_TO_EDICT(pr_global_struct
->msg_entity
);
1518 entnum
= NUM_FOR_EDICT(ent
);
1519 if (entnum
< 1 || entnum
> svs
.maxclients
)
1520 PR_RunError ("WriteDest: not a client");
1521 return &svs
.clients
[entnum
-1].message
;
1524 return &sv
.reliable_datagram
;
1530 PR_RunError ("WriteDest: bad destination");
1537 void PF_WriteByte (void)
1539 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1
));
1542 void PF_WriteChar (void)
1544 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1
));
1547 void PF_WriteShort (void)
1549 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1
));
1552 void PF_WriteLong (void)
1554 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1
));
1557 void PF_WriteAngle (void)
1559 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1
));
1562 void PF_WriteCoord (void)
1564 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1
));
1567 void PF_WriteString (void)
1569 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1
));
1573 void PF_WriteEntity (void)
1575 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1
));
1578 //=============================================================================
1580 int SV_ModelIndex (char *name
);
1582 void PF_makestatic (void)
1587 ent
= G_EDICT(OFS_PARM0
);
1589 MSG_WriteByte (&sv
.signon
,svc_spawnstatic
);
1591 MSG_WriteByte (&sv
.signon
, SV_ModelIndex(pr_strings
+ ent
->v
.model
));
1593 MSG_WriteByte (&sv
.signon
, ent
->v
.frame
);
1594 MSG_WriteByte (&sv
.signon
, ent
->v
.colormap
);
1595 MSG_WriteByte (&sv
.signon
, ent
->v
.skin
);
1596 for (i
=0 ; i
<3 ; i
++)
1598 MSG_WriteCoord(&sv
.signon
, ent
->v
.origin
[i
]);
1599 MSG_WriteAngle(&sv
.signon
, ent
->v
.angles
[i
]);
1602 // throw the entity away now
1606 //=============================================================================
1613 void PF_setspawnparms (void)
1619 ent
= G_EDICT(OFS_PARM0
);
1620 i
= NUM_FOR_EDICT(ent
);
1621 if (i
< 1 || i
> svs
.maxclients
)
1622 PR_RunError ("Entity is not a client");
1624 // copy spawn parms out of the client_t
1625 client
= svs
.clients
+ (i
-1);
1627 for (i
=0 ; i
< NUM_SPAWN_PARMS
; i
++)
1628 (&pr_global_struct
->parm1
)[i
] = client
->spawn_parms
[i
];
1636 void PF_changelevel (void)
1641 if (svs
.changelevel_issued
)
1643 svs
.changelevel_issued
= true;
1645 s1
= G_STRING(OFS_PARM0
);
1646 s2
= G_STRING(OFS_PARM1
);
1648 if ((int)pr_global_struct
->serverflags
& (SFL_NEW_UNIT
| SFL_NEW_EPISODE
))
1649 Cbuf_AddText (va("changelevel %s %s\n",s1
, s2
));
1651 Cbuf_AddText (va("changelevel2 %s %s\n",s1
, s2
));
1655 // make sure we don't issue two changelevels
1656 if (svs
.changelevel_issued
)
1658 svs
.changelevel_issued
= true;
1660 s
= G_STRING(OFS_PARM0
);
1661 Cbuf_AddText (va("changelevel %s\n",s
));
1668 #define CONTENT_WATER -3
1669 #define CONTENT_SLIME -4
1670 #define CONTENT_LAVA -5
1672 #define FL_IMMUNE_WATER 131072
1673 #define FL_IMMUNE_SLIME 262144
1674 #define FL_IMMUNE_LAVA 524288
1676 #define CHAN_VOICE 2
1681 void PF_WaterMove (void)
1690 self
= PROG_TO_EDICT(pr_global_struct
->self
);
1692 if (self
->v
.movetype
== MOVETYPE_NOCLIP
)
1694 self
->v
.air_finished
= sv
.time
+ 12;
1695 G_FLOAT(OFS_RETURN
) = damage
;
1699 if (self
->v
.health
< 0)
1701 G_FLOAT(OFS_RETURN
) = damage
;
1705 if (self
->v
.deadflag
== DEAD_NO
)
1710 flags
= (int)self
->v
.flags
;
1711 waterlevel
= (int)self
->v
.waterlevel
;
1712 watertype
= (int)self
->v
.watertype
;
1714 if (!(flags
& (FL_IMMUNE_WATER
+ FL_GODMODE
)))
1715 if (((flags
& FL_SWIM
) && (waterlevel
< drownlevel
)) || (waterlevel
>= drownlevel
))
1717 if (self
->v
.air_finished
< sv
.time
)
1718 if (self
->v
.pain_finished
< sv
.time
)
1720 self
->v
.dmg
= self
->v
.dmg
+ 2;
1721 if (self
->v
.dmg
> 15)
1723 // T_Damage (self, world, world, self.dmg, 0, FALSE);
1724 damage
= self
->v
.dmg
;
1725 self
->v
.pain_finished
= sv
.time
+ 1.0;
1730 if (self
->v
.air_finished
< sv
.time
)
1731 // sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
1732 SV_StartSound (self
, CHAN_VOICE
, "player/gasp2.wav", 255, ATTN_NORM
);
1733 else if (self
->v
.air_finished
< sv
.time
+ 9)
1734 // sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
1735 SV_StartSound (self
, CHAN_VOICE
, "player/gasp1.wav", 255, ATTN_NORM
);
1736 self
->v
.air_finished
= sv
.time
+ 12.0;
1742 if (flags
& FL_INWATER
)
1744 // play leave water sound
1745 // sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
1746 SV_StartSound (self
, CHAN_BODY
, "misc/outwater.wav", 255, ATTN_NORM
);
1747 self
->v
.flags
= (float)(flags
&~FL_INWATER
);
1749 self
->v
.air_finished
= sv
.time
+ 12.0;
1750 G_FLOAT(OFS_RETURN
) = damage
;
1754 if (watertype
== CONTENT_LAVA
)
1756 if (!(flags
& (FL_IMMUNE_LAVA
+ FL_GODMODE
)))
1757 if (self
->v
.dmgtime
< sv
.time
)
1759 if (self
->v
.radsuit_finished
< sv
.time
)
1760 self
->v
.dmgtime
= sv
.time
+ 0.2;
1762 self
->v
.dmgtime
= sv
.time
+ 1.0;
1763 // T_Damage (self, world, world, 10*self.waterlevel, 0, TRUE);
1764 damage
= (float)(10*waterlevel
);
1767 else if (watertype
== CONTENT_SLIME
)
1769 if (!(flags
& (FL_IMMUNE_SLIME
+ FL_GODMODE
)))
1770 if (self
->v
.dmgtime
< sv
.time
&& self
->v
.radsuit_finished
< sv
.time
)
1772 self
->v
.dmgtime
= sv
.time
+ 1.0;
1773 // T_Damage (self, world, world, 4*self.waterlevel, 0, TRUE);
1774 damage
= (float)(4*waterlevel
);
1778 if ( !(flags
& FL_INWATER
) )
1781 // player enter water sound
1782 if (watertype
== CONTENT_LAVA
)
1783 // sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
1784 SV_StartSound (self
, CHAN_BODY
, "player/inlava.wav", 255, ATTN_NORM
);
1785 if (watertype
== CONTENT_WATER
)
1786 // sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
1787 SV_StartSound (self
, CHAN_BODY
, "player/inh2o.wav", 255, ATTN_NORM
);
1788 if (watertype
== CONTENT_SLIME
)
1789 // sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
1790 SV_StartSound (self
, CHAN_BODY
, "player/slimbrn2.wav", 255, ATTN_NORM
);
1792 self
->v
.flags
= (float)(flags
| FL_INWATER
);
1793 self
->v
.dmgtime
= 0;
1796 if (! (flags
& FL_WATERJUMP
) )
1798 // self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity;
1799 VectorMA (self
->v
.velocity
, -0.8 * self
->v
.waterlevel
* host_frametime
, self
->v
.velocity
, self
->v
.velocity
);
1802 G_FLOAT(OFS_RETURN
) = damage
;
1808 G_FLOAT(OFS_RETURN
) = sin(G_FLOAT(OFS_PARM0
));
1813 G_FLOAT(OFS_RETURN
) = cos(G_FLOAT(OFS_PARM0
));
1818 G_FLOAT(OFS_RETURN
) = sqrt(G_FLOAT(OFS_PARM0
));
1822 void PF_Fixme (void)
1824 PR_RunError ("unimplemented bulitin");
1829 builtin_t pr_builtin
[] =
1832 PF_makevectors
, // void(entity e) makevectors = #1;
1833 PF_setorigin
, // void(entity e, vector o) setorigin = #2;
1834 PF_setmodel
, // void(entity e, string m) setmodel = #3;
1835 PF_setsize
, // void(entity e, vector min, vector max) setsize = #4;
1836 PF_Fixme
, // void(entity e, vector min, vector max) setabssize = #5;
1837 PF_break
, // void() break = #6;
1838 PF_random
, // float() random = #7;
1839 PF_sound
, // void(entity e, float chan, string samp) sound = #8;
1840 PF_normalize
, // vector(vector v) normalize = #9;
1841 PF_error
, // void(string e) error = #10;
1842 PF_objerror
, // void(string e) objerror = #11;
1843 PF_vlen
, // float(vector v) vlen = #12;
1844 PF_vectoyaw
, // float(vector v) vectoyaw = #13;
1845 PF_Spawn
, // entity() spawn = #14;
1846 PF_Remove
, // void(entity e) remove = #15;
1847 PF_traceline
, // float(vector v1, vector v2, float tryents) traceline = #16;
1848 PF_checkclient
, // entity() clientlist = #17;
1849 PF_Find
, // entity(entity start, .string fld, string match) find = #18;
1850 PF_precache_sound
, // void(string s) precache_sound = #19;
1851 PF_precache_model
, // void(string s) precache_model = #20;
1852 PF_stuffcmd
, // void(entity client, string s)stuffcmd = #21;
1853 PF_findradius
, // entity(vector org, float rad) findradius = #22;
1854 PF_bprint
, // void(string s) bprint = #23;
1855 PF_sprint
, // void(entity client, string s) sprint = #24;
1856 PF_dprint
, // void(string s) dprint = #25;
1857 PF_ftos
, // void(string s) ftos = #26;
1858 PF_vtos
, // void(string s) vtos = #27;
1862 PF_eprint
, // void(entity e) debug print an entire entity
1863 PF_walkmove
, // float(float yaw, float dist) walkmove
1864 PF_Fixme
, // float(float yaw, float dist) walkmove
1924 PF_precache_sound
, // precache_sound2 is different only for qcc
1930 builtin_t
*pr_builtins
= pr_builtin
;
1931 int pr_numbuiltins
= sizeof(pr_builtin
)/sizeof(pr_builtin
[0]);