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
;
160 xvector
[0] = cosf(a
);
161 xvector
[1] = sinf(a
);
162 yvector
[0] = -sinf(a
);
163 yvector
[1] = cosf(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) (atan2f(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) (atan2f(value1
[1], value1
[0]) * 180 / M_PI
);
450 forward
= sqrtf (value1
[0]*value1
[0] + value1
[1]*value1
[1]);
451 pitch
= (int) (atan2f(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 sprintf (pr_string_temp
, "%1f",v
);
935 G_INT(OFS_RETURN
) = pr_string_temp
- pr_strings
;
941 v
= G_FLOAT(OFS_PARM0
);
942 G_FLOAT(OFS_RETURN
) = fabsf(v
);
947 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]);
948 G_INT(OFS_RETURN
) = pr_string_temp
- pr_strings
;
954 sprintf (pr_string_temp
, "entity %i", G_EDICTNUM(OFS_PARM0
));
955 G_INT(OFS_RETURN
) = pr_string_temp
- pr_strings
;
966 void PF_Remove (void)
970 ed
= G_EDICT(OFS_PARM0
);
975 // entity (entity start, .string field, string match) find = #5;
987 first
= second
= last
= (edict_t
*)sv
.edicts
;
988 e
= G_EDICTNUM(OFS_PARM0
);
989 f
= G_INT(OFS_PARM1
);
990 s
= G_STRING(OFS_PARM2
);
992 PR_RunError ("PF_Find: bad search string");
994 for (e
++ ; e
< sv
.num_edicts
; e
++)
1004 if (first
== (edict_t
*)sv
.edicts
)
1006 else if (second
== (edict_t
*)sv
.edicts
)
1008 ed
->v
.chain
= EDICT_TO_PROG(last
);
1016 first
->v
.chain
= last
->v
.chain
;
1018 first
->v
.chain
= EDICT_TO_PROG(last
);
1019 last
->v
.chain
= EDICT_TO_PROG((edict_t
*)sv
.edicts
);
1020 if (second
&& second
!= last
)
1021 second
->v
.chain
= EDICT_TO_PROG(last
);
1023 RETURN_EDICT(first
);
1032 e
= G_EDICTNUM(OFS_PARM0
);
1033 f
= G_INT(OFS_PARM1
);
1034 s
= G_STRING(OFS_PARM2
);
1036 PR_RunError ("PF_Find: bad search string");
1038 for (e
++ ; e
< sv
.num_edicts
; e
++)
1053 RETURN_EDICT(sv
.edicts
);
1057 void PR_CheckEmptyString (char *s
)
1060 PR_RunError ("Bad string");
1063 void PF_precache_file (void)
1064 { // precache_file is only used to copy files with qcc, it does nothing
1065 G_INT(OFS_RETURN
) = G_INT(OFS_PARM0
);
1068 void PF_precache_sound (void)
1073 if (sv
.state
!= ss_loading
)
1074 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1076 s
= G_STRING(OFS_PARM0
);
1077 G_INT(OFS_RETURN
) = G_INT(OFS_PARM0
);
1078 PR_CheckEmptyString (s
);
1080 for (i
=0 ; i
<MAX_SOUNDS
; i
++)
1082 if (!sv
.sound_precache
[i
])
1084 sv
.sound_precache
[i
] = s
;
1087 if (!strcmp(sv
.sound_precache
[i
], s
))
1090 PR_RunError ("PF_precache_sound: overflow");
1093 void PF_precache_model (void)
1098 if (sv
.state
!= ss_loading
)
1099 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1101 s
= G_STRING(OFS_PARM0
);
1102 G_INT(OFS_RETURN
) = G_INT(OFS_PARM0
);
1103 PR_CheckEmptyString (s
);
1105 for (i
=0 ; i
<MAX_MODELS
; i
++)
1107 if (!sv
.model_precache
[i
])
1109 sv
.model_precache
[i
] = s
;
1110 sv
.models
[i
] = Mod_ForName (s
, true);
1113 if (!strcmp(sv
.model_precache
[i
], s
))
1116 PR_RunError ("PF_precache_model: overflow");
1120 void PF_coredump (void)
1125 void PF_traceon (void)
1130 void PF_traceoff (void)
1135 void PF_eprint (void)
1137 ED_PrintNum (G_EDICTNUM(OFS_PARM0
));
1144 float(float yaw, float dist) walkmove
1147 void PF_walkmove (void)
1155 ent
= PROG_TO_EDICT(pr_global_struct
->self
);
1156 yaw
= G_FLOAT(OFS_PARM0
);
1157 dist
= G_FLOAT(OFS_PARM1
);
1159 if ( !( (int)ent
->v
.flags
& (FL_ONGROUND
|FL_FLY
|FL_SWIM
) ) )
1161 G_FLOAT(OFS_RETURN
) = 0;
1165 yaw
= yaw
*M_PI
*2 / 360;
1167 move
[0] = cosf(yaw
)*dist
;
1168 move
[1] = sinf(yaw
)*dist
;
1171 // save program state, because SV_movestep may call other progs
1172 oldf
= pr_xfunction
;
1173 oldself
= pr_global_struct
->self
;
1175 G_FLOAT(OFS_RETURN
) = SV_movestep(ent
, move
, true);
1178 // restore program state
1179 pr_xfunction
= oldf
;
1180 pr_global_struct
->self
= oldself
;
1190 void PF_droptofloor (void)
1196 ent
= PROG_TO_EDICT(pr_global_struct
->self
);
1198 VectorCopy (ent
->v
.origin
, end
);
1201 trace
= SV_Move (ent
->v
.origin
, ent
->v
.mins
, ent
->v
.maxs
, end
, false, ent
);
1203 if (trace
.fraction
== 1 || trace
.allsolid
)
1204 G_FLOAT(OFS_RETURN
) = 0;
1207 VectorCopy (trace
.endpos
, ent
->v
.origin
);
1208 SV_LinkEdict (ent
, false);
1209 ent
->v
.flags
= (int)ent
->v
.flags
| FL_ONGROUND
;
1210 ent
->v
.groundentity
= EDICT_TO_PROG(trace
.ent
);
1211 G_FLOAT(OFS_RETURN
) = 1;
1219 void(float style, string value) lightstyle
1222 void PF_lightstyle (void)
1229 style
= G_FLOAT(OFS_PARM0
);
1230 val
= G_STRING(OFS_PARM1
);
1232 // change the string in sv
1233 sv
.lightstyles
[style
] = val
;
1235 // send message to all clients on this server
1236 if (sv
.state
!= ss_active
)
1239 for (j
=0, client
= svs
.clients
; j
<svs
.maxclients
; j
++, client
++)
1240 if (client
->active
|| client
->spawned
)
1242 MSG_WriteChar (&client
->message
, svc_lightstyle
);
1243 MSG_WriteChar (&client
->message
,style
);
1244 MSG_WriteString (&client
->message
, val
);
1251 f
= G_FLOAT(OFS_PARM0
);
1253 G_FLOAT(OFS_RETURN
) = (int)(f
+ 0.5);
1255 G_FLOAT(OFS_RETURN
) = (int)(f
- 0.5);
1257 void PF_floor (void)
1259 G_FLOAT(OFS_RETURN
) = floorf(G_FLOAT(OFS_PARM0
));
1263 G_FLOAT(OFS_RETURN
) = ceilf(G_FLOAT(OFS_PARM0
));
1272 void PF_checkbottom (void)
1276 ent
= G_EDICT(OFS_PARM0
);
1278 G_FLOAT(OFS_RETURN
) = SV_CheckBottom (ent
);
1286 void PF_pointcontents (void)
1290 v
= G_VECTOR(OFS_PARM0
);
1292 G_FLOAT(OFS_RETURN
) = SV_PointContents (v
);
1299 entity nextent(entity)
1302 void PF_nextent (void)
1307 i
= G_EDICTNUM(OFS_PARM0
);
1311 if (i
== sv
.num_edicts
)
1313 RETURN_EDICT(sv
.edicts
);
1329 Pick a vector for the player to shoot along
1330 vector aim(entity, missilespeed)
1333 cvar_t sv_aim
= {"sv_aim", "0.99"};
1336 edict_t
*ent
, *check
, *bestent
;
1337 vec3_t start
, dir
, end
, bestdir
;
1340 float dist
, bestdist
;
1343 ent
= G_EDICT(OFS_PARM0
);
1344 speed
= G_FLOAT(OFS_PARM1
);
1346 VectorCopy (ent
->v
.origin
, start
);
1349 // try sending a trace straight
1350 VectorCopy (pr_global_struct
->v_forward
, dir
);
1351 VectorMA (start
, 2048, dir
, end
);
1352 tr
= SV_Move (start
, vec3_origin
, vec3_origin
, end
, false, ent
);
1353 if (tr
.ent
&& tr
.ent
->v
.takedamage
== DAMAGE_AIM
1354 && (!teamplay
.value
|| ent
->v
.team
<=0 || ent
->v
.team
!= tr
.ent
->v
.team
) )
1356 VectorCopy (pr_global_struct
->v_forward
, G_VECTOR(OFS_RETURN
));
1361 // try all possible entities
1362 VectorCopy (dir
, bestdir
);
1363 if (cl_autoaim
.value
)
1364 bestdist
= sv_aim
.value
;
1369 check
= NEXT_EDICT(sv
.edicts
);
1370 for (i
=1 ; i
<sv
.num_edicts
; i
++, check
= NEXT_EDICT(check
) )
1372 if (check
->v
.takedamage
!= DAMAGE_AIM
)
1376 if (teamplay
.value
&& ent
->v
.team
> 0 && ent
->v
.team
== check
->v
.team
)
1377 continue; // don't aim at teammate
1378 for (j
=0 ; j
<3 ; j
++)
1379 end
[j
] = check
->v
.origin
[j
]
1380 + 0.5*(check
->v
.mins
[j
] + check
->v
.maxs
[j
]);
1381 VectorSubtract (end
, start
, dir
);
1382 VectorNormalize (dir
);
1383 dist
= DotProduct (dir
, pr_global_struct
->v_forward
);
1384 if (dist
< bestdist
)
1385 continue; // to far to turn
1386 tr
= SV_Move (start
, vec3_origin
, vec3_origin
, end
, false, ent
);
1387 if (tr
.ent
== check
)
1388 { // can shoot at this one
1396 VectorSubtract (bestent
->v
.origin
, ent
->v
.origin
, dir
);
1397 // dist = DotProduct (dir, pr_global_struct->v_forward);
1398 // VectorScale (pr_global_struct->v_forward, dist, end);
1402 VectorNormalize (end
);
1403 VectorCopy (end
, G_VECTOR(OFS_RETURN
));
1407 VectorCopy (bestdir
, G_VECTOR(OFS_RETURN
));
1415 This was a major timewaster in progs, so it was converted to C
1418 void PF_changeyaw (void)
1421 float ideal
, current
, move
, speed
;
1423 ent
= PROG_TO_EDICT(pr_global_struct
->self
);
1424 current
= anglemod( ent
->v
.angles
[1] );
1425 ideal
= ent
->v
.ideal_yaw
;
1426 speed
= ent
->v
.yaw_speed
;
1428 if (current
== ideal
)
1430 move
= ideal
- current
;
1431 if (ideal
> current
)
1452 ent
->v
.angles
[1] = anglemod (current
+ move
);
1461 void PF_changepitch (void)
1464 float ideal
, current
, move
, speed
;
1466 ent
= G_EDICT(OFS_PARM0
);
1467 current
= anglemod( ent
->v
.angles
[0] );
1468 ideal
= ent
->v
.idealpitch
;
1469 speed
= ent
->v
.pitch_speed
;
1471 if (current
== ideal
)
1473 move
= ideal
- current
;
1474 if (ideal
> current
)
1495 ent
->v
.angles
[0] = anglemod (current
+ move
);
1500 ===============================================================================
1504 ===============================================================================
1507 #define MSG_BROADCAST 0 // unreliable to all
1508 #define MSG_ONE 1 // reliable to one (msg_entity)
1509 #define MSG_ALL 2 // reliable to all
1510 #define MSG_INIT 3 // write to the init string
1512 sizebuf_t
*WriteDest (void)
1518 dest
= G_FLOAT(OFS_PARM0
);
1522 return &sv
.datagram
;
1525 ent
= PROG_TO_EDICT(pr_global_struct
->msg_entity
);
1526 entnum
= NUM_FOR_EDICT(ent
);
1527 if (entnum
< 1 || entnum
> svs
.maxclients
)
1528 PR_RunError ("WriteDest: not a client");
1529 return &svs
.clients
[entnum
-1].message
;
1532 return &sv
.reliable_datagram
;
1538 PR_RunError ("WriteDest: bad destination");
1545 void PF_WriteByte (void)
1547 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1
));
1550 void PF_WriteChar (void)
1552 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1
));
1555 void PF_WriteShort (void)
1557 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1
));
1560 void PF_WriteLong (void)
1562 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1
));
1565 void PF_WriteAngle (void)
1567 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1
));
1570 void PF_WriteCoord (void)
1572 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1
));
1575 void PF_WriteString (void)
1577 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1
));
1581 void PF_WriteEntity (void)
1583 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1
));
1586 //=============================================================================
1588 int SV_ModelIndex (char *name
);
1590 void PF_makestatic (void)
1595 ent
= G_EDICT(OFS_PARM0
);
1597 MSG_WriteByte (&sv
.signon
,svc_spawnstatic
);
1599 MSG_WriteByte (&sv
.signon
, SV_ModelIndex(pr_strings
+ ent
->v
.model
));
1601 MSG_WriteByte (&sv
.signon
, ent
->v
.frame
);
1602 MSG_WriteByte (&sv
.signon
, ent
->v
.colormap
);
1603 MSG_WriteByte (&sv
.signon
, ent
->v
.skin
);
1604 for (i
=0 ; i
<3 ; i
++)
1606 MSG_WriteCoord(&sv
.signon
, ent
->v
.origin
[i
]);
1607 MSG_WriteAngle(&sv
.signon
, ent
->v
.angles
[i
]);
1610 // throw the entity away now
1614 //=============================================================================
1621 void PF_setspawnparms (void)
1627 ent
= G_EDICT(OFS_PARM0
);
1628 i
= NUM_FOR_EDICT(ent
);
1629 if (i
< 1 || i
> svs
.maxclients
)
1630 PR_RunError ("Entity is not a client");
1632 // copy spawn parms out of the client_t
1633 client
= svs
.clients
+ (i
-1);
1635 for (i
=0 ; i
< NUM_SPAWN_PARMS
; i
++)
1636 (&pr_global_struct
->parm1
)[i
] = client
->spawn_parms
[i
];
1644 void PF_changelevel (void)
1649 if (svs
.changelevel_issued
)
1651 svs
.changelevel_issued
= true;
1653 s1
= G_STRING(OFS_PARM0
);
1654 s2
= G_STRING(OFS_PARM1
);
1656 if ((int)pr_global_struct
->serverflags
& (SFL_NEW_UNIT
| SFL_NEW_EPISODE
))
1657 Cbuf_AddText (va("changelevel %s %s\n",s1
, s2
));
1659 Cbuf_AddText (va("changelevel2 %s %s\n",s1
, s2
));
1663 // make sure we don't issue two changelevels
1664 if (svs
.changelevel_issued
)
1666 svs
.changelevel_issued
= true;
1668 s
= G_STRING(OFS_PARM0
);
1669 Cbuf_AddText (va("changelevel %s\n",s
));
1676 #define CONTENT_WATER -3
1677 #define CONTENT_SLIME -4
1678 #define CONTENT_LAVA -5
1680 #define FL_IMMUNE_WATER 131072
1681 #define FL_IMMUNE_SLIME 262144
1682 #define FL_IMMUNE_LAVA 524288
1684 #define CHAN_VOICE 2
1689 void PF_WaterMove (void)
1698 self
= PROG_TO_EDICT(pr_global_struct
->self
);
1700 if (self
->v
.movetype
== MOVETYPE_NOCLIP
)
1702 self
->v
.air_finished
= sv
.time
+ 12;
1703 G_FLOAT(OFS_RETURN
) = damage
;
1707 if (self
->v
.health
< 0)
1709 G_FLOAT(OFS_RETURN
) = damage
;
1713 if (self
->v
.deadflag
== DEAD_NO
)
1718 flags
= (int)self
->v
.flags
;
1719 waterlevel
= (int)self
->v
.waterlevel
;
1720 watertype
= (int)self
->v
.watertype
;
1722 if (!(flags
& (FL_IMMUNE_WATER
+ FL_GODMODE
)))
1723 if (((flags
& FL_SWIM
) && (waterlevel
< drownlevel
)) || (waterlevel
>= drownlevel
))
1725 if (self
->v
.air_finished
< sv
.time
)
1726 if (self
->v
.pain_finished
< sv
.time
)
1728 self
->v
.dmg
= self
->v
.dmg
+ 2;
1729 if (self
->v
.dmg
> 15)
1731 // T_Damage (self, world, world, self.dmg, 0, FALSE);
1732 damage
= self
->v
.dmg
;
1733 self
->v
.pain_finished
= sv
.time
+ 1.0;
1738 if (self
->v
.air_finished
< sv
.time
)
1739 // sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
1740 SV_StartSound (self
, CHAN_VOICE
, "player/gasp2.wav", 255, ATTN_NORM
);
1741 else if (self
->v
.air_finished
< sv
.time
+ 9)
1742 // sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
1743 SV_StartSound (self
, CHAN_VOICE
, "player/gasp1.wav", 255, ATTN_NORM
);
1744 self
->v
.air_finished
= sv
.time
+ 12.0;
1750 if (flags
& FL_INWATER
)
1752 // play leave water sound
1753 // sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
1754 SV_StartSound (self
, CHAN_BODY
, "misc/outwater.wav", 255, ATTN_NORM
);
1755 self
->v
.flags
= (float)(flags
&~FL_INWATER
);
1757 self
->v
.air_finished
= sv
.time
+ 12.0;
1758 G_FLOAT(OFS_RETURN
) = damage
;
1762 if (watertype
== CONTENT_LAVA
)
1764 if (!(flags
& (FL_IMMUNE_LAVA
+ FL_GODMODE
)))
1765 if (self
->v
.dmgtime
< sv
.time
)
1767 if (self
->v
.radsuit_finished
< sv
.time
)
1768 self
->v
.dmgtime
= sv
.time
+ 0.2;
1770 self
->v
.dmgtime
= sv
.time
+ 1.0;
1771 // T_Damage (self, world, world, 10*self.waterlevel, 0, TRUE);
1772 damage
= (float)(10*waterlevel
);
1775 else if (watertype
== CONTENT_SLIME
)
1777 if (!(flags
& (FL_IMMUNE_SLIME
+ FL_GODMODE
)))
1778 if (self
->v
.dmgtime
< sv
.time
&& self
->v
.radsuit_finished
< sv
.time
)
1780 self
->v
.dmgtime
= sv
.time
+ 1.0;
1781 // T_Damage (self, world, world, 4*self.waterlevel, 0, TRUE);
1782 damage
= (float)(4*waterlevel
);
1786 if ( !(flags
& FL_INWATER
) )
1789 // player enter water sound
1790 if (watertype
== CONTENT_LAVA
)
1791 // sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
1792 SV_StartSound (self
, CHAN_BODY
, "player/inlava.wav", 255, ATTN_NORM
);
1793 if (watertype
== CONTENT_WATER
)
1794 // sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
1795 SV_StartSound (self
, CHAN_BODY
, "player/inh2o.wav", 255, ATTN_NORM
);
1796 if (watertype
== CONTENT_SLIME
)
1797 // sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
1798 SV_StartSound (self
, CHAN_BODY
, "player/slimbrn2.wav", 255, ATTN_NORM
);
1800 self
->v
.flags
= (float)(flags
| FL_INWATER
);
1801 self
->v
.dmgtime
= 0;
1804 if (! (flags
& FL_WATERJUMP
) )
1806 // self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity;
1807 VectorMA (self
->v
.velocity
, -0.8 * self
->v
.waterlevel
* host_frametime
, self
->v
.velocity
, self
->v
.velocity
);
1810 G_FLOAT(OFS_RETURN
) = damage
;
1816 G_FLOAT(OFS_RETURN
) = sinf(G_FLOAT(OFS_PARM0
));
1821 G_FLOAT(OFS_RETURN
) = cosf(G_FLOAT(OFS_PARM0
));
1826 G_FLOAT(OFS_RETURN
) = sqrtf(G_FLOAT(OFS_PARM0
));
1830 void PF_Fixme (void)
1832 PR_RunError ("unimplemented bulitin");
1837 builtin_t pr_builtin
[] =
1840 PF_makevectors
, // void(entity e) makevectors = #1;
1841 PF_setorigin
, // void(entity e, vector o) setorigin = #2;
1842 PF_setmodel
, // void(entity e, string m) setmodel = #3;
1843 PF_setsize
, // void(entity e, vector min, vector max) setsize = #4;
1844 PF_Fixme
, // void(entity e, vector min, vector max) setabssize = #5;
1845 PF_break
, // void() break = #6;
1846 PF_random
, // float() random = #7;
1847 PF_sound
, // void(entity e, float chan, string samp) sound = #8;
1848 PF_normalize
, // vector(vector v) normalize = #9;
1849 PF_error
, // void(string e) error = #10;
1850 PF_objerror
, // void(string e) objerror = #11;
1851 PF_vlen
, // float(vector v) vlen = #12;
1852 PF_vectoyaw
, // float(vector v) vectoyaw = #13;
1853 PF_Spawn
, // entity() spawn = #14;
1854 PF_Remove
, // void(entity e) remove = #15;
1855 PF_traceline
, // float(vector v1, vector v2, float tryents) traceline = #16;
1856 PF_checkclient
, // entity() clientlist = #17;
1857 PF_Find
, // entity(entity start, .string fld, string match) find = #18;
1858 PF_precache_sound
, // void(string s) precache_sound = #19;
1859 PF_precache_model
, // void(string s) precache_model = #20;
1860 PF_stuffcmd
, // void(entity client, string s)stuffcmd = #21;
1861 PF_findradius
, // entity(vector org, float rad) findradius = #22;
1862 PF_bprint
, // void(string s) bprint = #23;
1863 PF_sprint
, // void(entity client, string s) sprint = #24;
1864 PF_dprint
, // void(string s) dprint = #25;
1865 PF_ftos
, // void(string s) ftos = #26;
1866 PF_vtos
, // void(string s) vtos = #27;
1870 PF_eprint
, // void(entity e) debug print an entire entity
1871 PF_walkmove
, // float(float yaw, float dist) walkmove
1872 PF_Fixme
, // float(float yaw, float dist) walkmove
1932 PF_precache_sound
, // precache_sound2 is different only for qcc
1938 builtin_t
*pr_builtins
= pr_builtin
;
1939 int pr_numbuiltins
= sizeof(pr_builtin
)/sizeof(pr_builtin
[0]);