1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20
21#include "quakedef.h"
22
23#define	RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
24
25/*
26===============================================================================
27
28						BUILT-IN FUNCTIONS
29
30===============================================================================
31*/
32
33char *PF_VarString (int	first)
34{
35	int		i;
36	static char out[256];
37
38	out[0] = 0;
39	for (i=first ; i<pr_argc ; i++)
40	{
41		strcat (out, G_STRING((OFS_PARM0+i*3)));
42	}
43	return out;
44}
45
46
47/*
48=================
49PF_errror
50
51This is a TERMINAL error, which will kill off the entire server.
52Dumps self.
53
54error(value)
55=================
56*/
57void PF_error (void)
58{
59	char	*s;
60	edict_t	*ed;
61
62	s = PF_VarString(0);
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);
66	ED_Print (ed);
67
68	Host_Error ("Program error");
69}
70
71/*
72=================
73PF_objerror
74
75Dumps out self, then an error message.  The program is aborted and self is
76removed, but the level can continue.
77
78objerror(value)
79=================
80*/
81void PF_objerror (void)
82{
83	char	*s;
84	edict_t	*ed;
85
86	s = PF_VarString(0);
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);
90	ED_Print (ed);
91	ED_Free (ed);
92
93	Host_Error ("Program error");
94}
95
96
97
98/*
99==============
100PF_makevectors
101
102Writes new values for v_forward, v_up, and v_right based on angles
103makevectors(vector)
104==============
105*/
106void PF_makevectors (void)
107{
108	AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
109}
110
111/*
112=================
113PF_setorigin
114
115This 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.
116
117setorigin (entity, origin)
118=================
119*/
120void PF_setorigin (void)
121{
122	edict_t	*e;
123	float	*org;
124
125	e = G_EDICT(OFS_PARM0);
126	org = G_VECTOR(OFS_PARM1);
127	VectorCopy (org, e->u.v.origin);
128	SV_LinkEdict (e, false);
129}
130
131
132void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
133{
134	float	*angles;
135	vec3_t	rmin, rmax;
136	float	bounds[2][3];
137	float	xvector[2], yvector[2];
138	float	a;
139	vec3_t	base, transformed;
140	int		i, j, k, l;
141
142	for (i=0 ; i<3 ; i++)
143		if (min[i] > max[i])
144			PR_RunError ("backwards mins/maxs");
145
146	rotate = false;		// FIXME: implement rotation properly again
147
148	if (!rotate)
149	{
150		VectorCopy (min, rmin);
151		VectorCopy (max, rmax);
152	}
153	else
154	{
155	// find min / max for rotations
156		angles = e->u.v.angles;
157
158		a = angles[1]/180 * M_PI;
159
160		xvector[0] = cos(a);
161		xvector[1] = sin(a);
162		yvector[0] = -sin(a);
163		yvector[1] = cos(a);
164
165		VectorCopy (min, bounds[0]);
166		VectorCopy (max, bounds[1]);
167
168		rmin[0] = rmin[1] = rmin[2] = 9999;
169		rmax[0] = rmax[1] = rmax[2] = -9999;
170
171		for (i=0 ; i<= 1 ; i++)
172		{
173			base[0] = bounds[i][0];
174			for (j=0 ; j<= 1 ; j++)
175			{
176				base[1] = bounds[j][1];
177				for (k=0 ; k<= 1 ; k++)
178				{
179					base[2] = bounds[k][2];
180
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];
185
186					for (l=0 ; l<3 ; l++)
187					{
188						if (transformed[l] < rmin[l])
189							rmin[l] = transformed[l];
190						if (transformed[l] > rmax[l])
191							rmax[l] = transformed[l];
192					}
193				}
194			}
195		}
196	}
197
198// set derived values
199	VectorCopy (rmin, e->u.v.mins);
200	VectorCopy (rmax, e->u.v.maxs);
201	VectorSubtract (max, min, e->u.v.size);
202
203	SV_LinkEdict (e, false);
204}
205
206/*
207=================
208PF_setsize
209
210the size box is rotated by the current angle
211
212setsize (entity, minvector, maxvector)
213=================
214*/
215void PF_setsize (void)
216{
217	edict_t	*e;
218	float	*min, *max;
219
220	e = G_EDICT(OFS_PARM0);
221	min = G_VECTOR(OFS_PARM1);
222	max = G_VECTOR(OFS_PARM2);
223	SetMinMaxSize (e, min, max, false);
224}
225
226
227/*
228=================
229PF_setmodel
230
231setmodel(entity, model)
232=================
233*/
234void PF_setmodel (void)
235{
236	edict_t	*e;
237	char	*m, **check;
238	model_t	*mod;
239	int		i;
240
241	e = G_EDICT(OFS_PARM0);
242	m = G_STRING(OFS_PARM1);
243
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))
247			break;
248
249	if (!*check)
250		PR_RunError ("no precache: %s\n", m);
251
252
253	e->u.v.model = m - pr_strings;
254	e->u.v.modelindex = i; //SV_ModelIndex (m);
255
256	mod = sv.models[ (int)e->u.v.modelindex];  // Mod_ForName (m, true);
257
258	if (mod)
259		SetMinMaxSize (e, mod->mins, mod->maxs, true);
260	else
261		SetMinMaxSize (e, vec3_origin, vec3_origin, true);
262}
263
264/*
265=================
266PF_bprint
267
268broadcast print to everyone on server
269
270bprint(value)
271=================
272*/
273void PF_bprint (void)
274{
275	char		*s;
276
277	s = PF_VarString(0);
278	SV_BroadcastPrintf ("%s", s);
279}
280
281/*
282=================
283PF_sprint
284
285single print to a specific client
286
287sprint(clientent, value)
288=================
289*/
290void PF_sprint (void)
291{
292	char		*s;
293	client_t	*client;
294	int			entnum;
295
296	entnum = G_EDICTNUM(OFS_PARM0);
297	s = PF_VarString(1);
298
299	if (entnum < 1 || entnum > svs.maxclients)
300	{
301		Con_Printf ("tried to sprint to a non-client\n");
302		return;
303	}
304
305	client = &svs.clients[entnum-1];
306
307	MSG_WriteChar (&client->message,svc_print);
308	MSG_WriteString (&client->message, s );
309}
310
311
312/*
313=================
314PF_centerprint
315
316single print to a specific client
317
318centerprint(clientent, value)
319=================
320*/
321void PF_centerprint (void)
322{
323	char		*s;
324	client_t	*client;
325	int			entnum;
326
327	entnum = G_EDICTNUM(OFS_PARM0);
328	s = PF_VarString(1);
329
330	if (entnum < 1 || entnum > svs.maxclients)
331	{
332		Con_Printf ("tried to sprint to a non-client\n");
333		return;
334	}
335
336	client = &svs.clients[entnum-1];
337
338	MSG_WriteChar (&client->message,svc_centerprint);
339	MSG_WriteString (&client->message, s );
340}
341
342
343/*
344=================
345PF_normalize
346
347vector normalize(vector)
348=================
349*/
350void PF_normalize (void)
351{
352	float	*value1;
353	vec3_t	newvalue;
354	float	temp;
355
356	value1 = G_VECTOR(OFS_PARM0);
357
358	temp = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
359	temp = sqrt(temp);
360
361	if (temp == 0)
362		newvalue[0] = newvalue[1] = newvalue[2] = 0;
363	else
364	{
365		temp = 1/temp;
366		newvalue[0] = value1[0] * temp;
367		newvalue[1] = value1[1] * temp;
368		newvalue[2] = value1[2] * temp;
369	}
370
371	VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
372}
373
374/*
375=================
376PF_vlen
377
378scalar vlen(vector)
379=================
380*/
381void PF_vlen (void)
382{
383	float	*value1;
384	float	temp;
385
386	value1 = G_VECTOR(OFS_PARM0);
387
388	temp = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
389	temp = sqrt(temp);
390
391	G_FLOAT(OFS_RETURN) = temp;
392}
393
394/*
395=================
396PF_vectoyaw
397
398float vectoyaw(vector)
399=================
400*/
401void PF_vectoyaw (void)
402{
403	float	*value1;
404	float	yaw;
405
406	value1 = G_VECTOR(OFS_PARM0);
407
408	if (value1[1] == 0 && value1[0] == 0)
409		yaw = 0;
410	else
411	{
412		yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
413		if (yaw < 0)
414			yaw += 360;
415	}
416
417	G_FLOAT(OFS_RETURN) = yaw;
418}
419
420
421/*
422=================
423PF_vectoangles
424
425vector vectoangles(vector)
426=================
427*/
428void PF_vectoangles (void)
429{
430	float	*value1;
431	float	forward;
432	float	yaw, pitch;
433
434	value1 = G_VECTOR(OFS_PARM0);
435
436	if (value1[1] == 0 && value1[0] == 0)
437	{
438		yaw = 0;
439		if (value1[2] > 0)
440			pitch = 90;
441		else
442			pitch = 270;
443	}
444	else
445	{
446		yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
447		if (yaw < 0)
448			yaw += 360;
449
450		forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
451		pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
452		if (pitch < 0)
453			pitch += 360;
454	}
455
456	G_FLOAT(OFS_RETURN+0) = pitch;
457	G_FLOAT(OFS_RETURN+1) = yaw;
458	G_FLOAT(OFS_RETURN+2) = 0;
459}
460
461/*
462=================
463PF_Random
464
465Returns a number from 0<= num < 1
466
467random()
468=================
469*/
470void PF_random (void)
471{
472	float		num;
473
474	num = (rand ()&0x7fff) / ((float)0x7fff);
475
476	G_FLOAT(OFS_RETURN) = num;
477}
478
479/*
480=================
481PF_particle
482
483particle(origin, color, count)
484=================
485*/
486void PF_particle (void)
487{
488	float		*org, *dir;
489	float		color;
490	float		count;
491
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, (int) color, (int) count);
497}
498
499
500/*
501=================
502PF_ambientsound
503
504=================
505*/
506void PF_ambientsound (void)
507{
508	char		**check;
509	char		*samp;
510	float		*pos;
511	float 		vol, attenuation;
512	int			i, soundnum;
513
514	pos = G_VECTOR (OFS_PARM0);
515	samp = G_STRING(OFS_PARM1);
516	vol = G_FLOAT(OFS_PARM2);
517	attenuation = G_FLOAT(OFS_PARM3);
518
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))
522			break;
523
524	if (!*check)
525	{
526		Con_Printf ("no precache: %s\n", samp);
527		return;
528	}
529
530// add an svc_spawnambient command to the level signon packet
531
532	MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
533	for (i=0 ; i<3 ; i++)
534		MSG_WriteCoord(&sv.signon, pos[i]);
535
536	MSG_WriteByte (&sv.signon, soundnum);
537
538	MSG_WriteByte (&sv.signon, (int) (vol*255));
539	MSG_WriteByte (&sv.signon, (int) (attenuation*64));
540
541}
542
543/*
544=================
545PF_sound
546
547Each entity can have eight independant sound sources, like voice,
548weapon, feet, etc.
549
550Channel 0 is an auto-allocate channel, the others override anything
551allready running on that entity/channel pair.
552
553An attenuation of 0 will play full volume everywhere in the level.
554Larger attenuations will drop off.
555
556=================
557*/
558void PF_sound (void)
559{
560	char		*sample;
561	int			channel;
562	edict_t		*entity;
563	int 		volume;
564	float attenuation;
565
566	entity = G_EDICT(OFS_PARM0);
567	channel = (int) G_FLOAT(OFS_PARM1);
568	sample = G_STRING(OFS_PARM2);
569	volume = (int)(G_FLOAT(OFS_PARM3) * 255);
570	attenuation = G_FLOAT(OFS_PARM4);
571
572	if (volume < 0 || volume > 255)
573		Sys_Error ("SV_StartSound: volume = %i", volume);
574
575	if (attenuation < 0 || attenuation > 4)
576		Sys_Error ("SV_StartSound: attenuation = %f", attenuation);
577
578	if (channel < 0 || channel > 7)
579		Sys_Error ("SV_StartSound: channel = %i", channel);
580
581	SV_StartSound (entity, channel, sample, volume, attenuation);
582}
583
584/*
585=================
586PF_break
587
588break()
589=================
590*/
591void PF_break (void)
592{
593Con_Printf ("break statement\n");
594*(int *)-4 = 0;	// dump to debugger
595//	PR_RunError ("break statement");
596}
597
598/*
599=================
600PF_traceline
601
602Used for use tracing and shot targeting
603Traces are blocked by bbox and exact bsp entityes, and also slide box entities
604if the tryents flag is set.
605
606traceline (vector1, vector2, tryents)
607=================
608*/
609void PF_traceline (void)
610{
611	float	*v1, *v2;
612	trace_t	trace;
613	int		nomonsters;
614	edict_t	*ent;
615
616	v1 = G_VECTOR(OFS_PARM0);
617	v2 = G_VECTOR(OFS_PARM1);
618	nomonsters = (int) G_FLOAT(OFS_PARM2);
619	ent = G_EDICT(OFS_PARM3);
620
621	trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
622
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;
631	if (trace.ent)
632		pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
633	else
634		pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
635}
636
637
638#ifdef QUAKE2
639extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
640
641void PF_TraceToss (void)
642{
643	trace_t	trace;
644	edict_t	*ent;
645	edict_t	*ignore;
646
647	ent = G_EDICT(OFS_PARM0);
648	ignore = G_EDICT(OFS_PARM1);
649
650	trace = SV_Trace_Toss (ent, ignore);
651
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;
660	if (trace.ent)
661		pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
662	else
663		pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
664}
665#endif
666
667
668/*
669=================
670PF_checkpos
671
672Returns true if the given entity can move to the given position from it's
673current position by walking or rolling.
674FIXME: make work...
675scalar checkpos (entity, vector)
676=================
677*/
678void PF_checkpos (void)
679{
680}
681
682//============================================================================
683
684byte	checkpvs[MAX_MAP_LEAFS/8];
685
686int PF_newcheckclient (int check)
687{
688	int		i;
689	byte	*pvs;
690	edict_t	*ent;
691	mleaf_t	*leaf;
692	vec3_t	org;
693
694// cycle to the next one
695
696	if (check < 1)
697		check = 1;
698	if (check > svs.maxclients)
699		check = svs.maxclients;
700
701	if (check == svs.maxclients)
702		i = 1;
703	else
704		i = check + 1;
705
706	for ( ;  ; i++)
707	{
708		if (i == svs.maxclients+1)
709			i = 1;
710
711		ent = EDICT_NUM(i);
712
713		if (i == check)
714			break;	// didn't find anything else
715
716		if (ent->free)
717			continue;
718		if (ent->u.v.health <= 0)
719			continue;
720		if ((int)ent->u.v.flags & FL_NOTARGET)
721			continue;
722
723	// anything that is a client, or has a client as an enemy
724		break;
725	}
726
727// get the PVS for the entity
728	VectorAdd (ent->u.v.origin, ent->u.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 );
732
733	return i;
734}
735
736/*
737=================
738PF_checkclient
739
740Returns a client (or object that has a client enemy) that would be a
741valid target.
742
743If there are more than one valid options, they are cycled each frame
744
745If (self.origin + self.viewofs) is not in the PVS of the current target,
746it is not returned at all.
747
748name checkclient ()
749=================
750*/
751#define	MAX_CHECK	16
752int c_invis, c_notvis;
753void PF_checkclient (void)
754{
755	edict_t	*ent, *self;
756	mleaf_t	*leaf;
757	int		l;
758	vec3_t	view;
759
760// find a new check if on a new frame
761	if (sv.time - sv.lastchecktime >= 0.1)
762	{
763		sv.lastcheck = PF_newcheckclient (sv.lastcheck);
764		sv.lastchecktime = sv.time;
765	}
766
767// return check if it might be visible
768	ent = EDICT_NUM(sv.lastcheck);
769	if (ent->free || ent->u.v.health <= 0)
770	{
771		RETURN_EDICT(sv.edicts);
772		return;
773	}
774
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->u.v.origin, self->u.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)) ) )
781	{
782c_notvis++;
783		RETURN_EDICT(sv.edicts);
784		return;
785	}
786
787// might be able to see it
788c_invis++;
789	RETURN_EDICT(ent);
790}
791
792//============================================================================
793
794
795/*
796=================
797PF_stuffcmd
798
799Sends text over to the client's execution buffer
800
801stuffcmd (clientent, value)
802=================
803*/
804void PF_stuffcmd (void)
805{
806	int		entnum;
807	char	*str;
808	client_t	*old;
809
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);
814
815	old = host_client;
816	host_client = &svs.clients[entnum-1];
817	Host_ClientCommands ("%s", str);
818	host_client = old;
819}
820
821/*
822=================
823PF_localcmd
824
825Sends text over to the client's execution buffer
826
827localcmd (string)
828=================
829*/
830void PF_localcmd (void)
831{
832	char	*str;
833
834	str = G_STRING(OFS_PARM0);
835	Cbuf_AddText (str);
836}
837
838/*
839=================
840PF_cvar
841
842float cvar (string)
843=================
844*/
845void PF_cvar (void)
846{
847	char	*str;
848
849	str = G_STRING(OFS_PARM0);
850
851	G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
852}
853
854/*
855=================
856PF_cvar_set
857
858float cvar (string)
859=================
860*/
861void PF_cvar_set (void)
862{
863	char	*var, *val;
864
865	var = G_STRING(OFS_PARM0);
866	val = G_STRING(OFS_PARM1);
867
868	Cvar_Set (var, val);
869}
870
871/*
872=================
873PF_findradius
874
875Returns a chain of entities that have origins within a spherical area
876
877findradius (origin, radius)
878=================
879*/
880void PF_findradius (void)
881{
882	edict_t	*ent, *chain;
883	float	rad;
884	float	*org;
885	vec3_t	eorg;
886	int		i, j;
887
888	chain = (edict_t *)sv.edicts;
889
890	org = G_VECTOR(OFS_PARM0);
891	rad = G_FLOAT(OFS_PARM1);
892
893	ent = NEXT_EDICT(sv.edicts);
894	for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
895	{
896		if (ent->free)
897			continue;
898		if (ent->u.v.solid == SOLID_NOT)
899			continue;
900		for (j=0 ; j<3 ; j++)
901			eorg[j] = org[j] - (ent->u.v.origin[j] + (ent->u.v.mins[j] + ent->u.v.maxs[j])*0.5);
902		if (Length(eorg) > rad)
903			continue;
904
905		ent->u.v.chain = EDICT_TO_PROG(chain);
906		chain = ent;
907	}
908
909	RETURN_EDICT(chain);
910}
911
912
913/*
914=========
915PF_dprint
916=========
917*/
918void PF_dprint (void)
919{
920	Con_DPrintf ("%s",PF_VarString(0));
921}
922
923char	pr_string_temp[128];
924
925void PF_ftos (void)
926{
927	float	v;
928	v = G_FLOAT(OFS_PARM0);
929
930	if (v == (int)v)
931		sprintf (pr_string_temp, "%d",(int)v);
932	else
933		sprintf (pr_string_temp, "%5.1f",v);
934	G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
935}
936
937void PF_fabs (void)
938{
939	float	v;
940	v = G_FLOAT(OFS_PARM0);
941	G_FLOAT(OFS_RETURN) = fabs(v);
942}
943
944void PF_vtos (void)
945{
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;
948}
949
950#ifdef QUAKE2
951void PF_etos (void)
952{
953	sprintf (pr_string_temp, "entity %i", G_EDICTNUM(OFS_PARM0));
954	G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
955}
956#endif
957
958void PF_Spawn (void)
959{
960	edict_t	*ed;
961	ed = ED_Alloc();
962	RETURN_EDICT(ed);
963}
964
965void PF_Remove (void)
966{
967	edict_t	*ed;
968
969	ed = G_EDICT(OFS_PARM0);
970	ED_Free (ed);
971}
972
973
974// entity (entity start, .string field, string match) find = #5;
975void PF_Find (void)
976#ifdef QUAKE2
977{
978	int		e;
979	int		f;
980	char	*s, *t;
981	edict_t	*ed;
982	edict_t	*first;
983	edict_t	*second;
984	edict_t	*last;
985
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);
990	if (!s)
991		PR_RunError ("PF_Find: bad search string");
992
993	for (e++ ; e < sv.num_edicts ; e++)
994	{
995		ed = EDICT_NUM(e);
996		if (ed->free)
997			continue;
998		t = E_STRING(ed,f);
999		if (!t)
1000			continue;
1001		if (!strcmp(t,s))
1002		{
1003			if (first == (edict_t *)sv.edicts)
1004				first = ed;
1005			else if (second == (edict_t *)sv.edicts)
1006				second = ed;
1007			ed->u.v.chain = EDICT_TO_PROG(last);
1008			last = ed;
1009		}
1010	}
1011
1012	if (first != last)
1013	{
1014		if (last != second)
1015			first->u.v.chain = last->u.v.chain;
1016		else
1017			first->u.v.chain = EDICT_TO_PROG(last);
1018		last->u.v.chain = EDICT_TO_PROG((edict_t *)sv.edicts);
1019		if (second && second != last)
1020			second->u.v.chain = EDICT_TO_PROG(last);
1021	}
1022	RETURN_EDICT(first);
1023}
1024#else
1025{
1026	int		e;
1027	int		f;
1028	char	*s, *t;
1029	edict_t	*ed;
1030
1031	e = G_EDICTNUM(OFS_PARM0);
1032	f = G_INT(OFS_PARM1);
1033	s = G_STRING(OFS_PARM2);
1034	if (!s)
1035		PR_RunError ("PF_Find: bad search string");
1036
1037	for (e++ ; e < sv.num_edicts ; e++)
1038	{
1039		ed = EDICT_NUM(e);
1040		if (ed->free)
1041			continue;
1042		t = E_STRING(ed,f);
1043		if (!t)
1044			continue;
1045		if (!strcmp(t,s))
1046		{
1047			RETURN_EDICT(ed);
1048			return;
1049		}
1050	}
1051
1052	RETURN_EDICT(sv.edicts);
1053}
1054#endif
1055
1056void PR_CheckEmptyString (char *s)
1057{
1058	if (s[0] <= ' ')
1059		PR_RunError ("Bad string");
1060}
1061
1062void 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);
1065}
1066
1067void PF_precache_sound (void)
1068{
1069	char	*s;
1070	int		i;
1071
1072	if (sv.state != ss_loading)
1073		PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1074
1075	s = G_STRING(OFS_PARM0);
1076	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1077	PR_CheckEmptyString (s);
1078
1079	for (i=0 ; i<MAX_SOUNDS ; i++)
1080	{
1081		if (!sv.sound_precache[i])
1082		{
1083			sv.sound_precache[i] = s;
1084			return;
1085		}
1086		if (!strcmp(sv.sound_precache[i], s))
1087			return;
1088	}
1089	PR_RunError ("PF_precache_sound: overflow");
1090}
1091
1092void PF_precache_model (void)
1093{
1094	char	*s;
1095	int		i;
1096
1097	if (sv.state != ss_loading)
1098		PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1099
1100	s = G_STRING(OFS_PARM0);
1101	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1102	PR_CheckEmptyString (s);
1103
1104	for (i=0 ; i<MAX_MODELS ; i++)
1105	{
1106		if (!sv.model_precache[i])
1107		{
1108			sv.model_precache[i] = s;
1109			sv.models[i] = Mod_ForName (s, true);
1110			return;
1111		}
1112		if (!strcmp(sv.model_precache[i], s))
1113			return;
1114	}
1115	PR_RunError ("PF_precache_model: overflow");
1116}
1117
1118
1119void PF_coredump (void)
1120{
1121	ED_PrintEdicts ();
1122}
1123
1124void PF_traceon (void)
1125{
1126	pr_trace = true;
1127}
1128
1129void PF_traceoff (void)
1130{
1131	pr_trace = false;
1132}
1133
1134void PF_eprint (void)
1135{
1136	ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1137}
1138
1139/*
1140===============
1141PF_walkmove
1142
1143float(float yaw, float dist) walkmove
1144===============
1145*/
1146void PF_walkmove (void)
1147{
1148	edict_t	*ent;
1149	float	yaw, dist;
1150	vec3_t	move;
1151	dfunction_t	*oldf;
1152	int 	oldself;
1153
1154	ent = PROG_TO_EDICT(pr_global_struct->self);
1155	yaw = G_FLOAT(OFS_PARM0);
1156	dist = G_FLOAT(OFS_PARM1);
1157
1158	if ( !( (int)ent->u.v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1159	{
1160		G_FLOAT(OFS_RETURN) = 0;
1161		return;
1162	}
1163
1164	yaw = yaw*M_PI*2 / 360;
1165
1166	move[0] = cos(yaw)*dist;
1167	move[1] = sin(yaw)*dist;
1168	move[2] = 0;
1169
1170// save program state, because SV_movestep may call other progs
1171	oldf = pr_xfunction;
1172	oldself = pr_global_struct->self;
1173
1174	G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1175
1176
1177// restore program state
1178	pr_xfunction = oldf;
1179	pr_global_struct->self = oldself;
1180}
1181
1182/*
1183===============
1184PF_droptofloor
1185
1186void() droptofloor
1187===============
1188*/
1189void PF_droptofloor (void)
1190{
1191	edict_t		*ent;
1192	vec3_t		end;
1193	trace_t		trace;
1194
1195	ent = PROG_TO_EDICT(pr_global_struct->self);
1196
1197	VectorCopy (ent->u.v.origin, end);
1198	end[2] -= 256;
1199
1200	trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, end, false, ent);
1201
1202	if (trace.fraction == 1 || trace.allsolid)
1203		G_FLOAT(OFS_RETURN) = 0;
1204	else
1205	{
1206		VectorCopy (trace.endpos, ent->u.v.origin);
1207		SV_LinkEdict (ent, false);
1208		ent->u.v.flags = (int)ent->u.v.flags | FL_ONGROUND;
1209		ent->u.v.groundentity = EDICT_TO_PROG(trace.ent);
1210		G_FLOAT(OFS_RETURN) = 1;
1211	}
1212}
1213
1214/*
1215===============
1216PF_lightstyle
1217
1218void(float style, string value) lightstyle
1219===============
1220*/
1221void PF_lightstyle (void)
1222{
1223	int		style;
1224	char	*val;
1225	client_t	*client;
1226	int			j;
1227
1228	style = (int) G_FLOAT(OFS_PARM0);
1229	val = G_STRING(OFS_PARM1);
1230
1231// change the string in sv
1232	sv.lightstyles[style] = val;
1233
1234// send message to all clients on this server
1235	if (sv.state != ss_active)
1236		return;
1237
1238	for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1239		if (client->active || client->spawned)
1240		{
1241			MSG_WriteChar (&client->message, svc_lightstyle);
1242			MSG_WriteChar (&client->message,style);
1243			MSG_WriteString (&client->message, val);
1244		}
1245}
1246
1247void PF_rint (void)
1248{
1249	float	f;
1250	f = G_FLOAT(OFS_PARM0);
1251	if (f > 0)
1252		G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1253	else
1254		G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1255}
1256void PF_floor (void)
1257{
1258	G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1259}
1260void PF_ceil (void)
1261{
1262	G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1263}
1264
1265
1266/*
1267=============
1268PF_checkbottom
1269=============
1270*/
1271void PF_checkbottom (void)
1272{
1273	edict_t	*ent;
1274
1275	ent = G_EDICT(OFS_PARM0);
1276
1277	G_FLOAT(OFS_RETURN) = SV_CheckBottom (ent);
1278}
1279
1280/*
1281=============
1282PF_pointcontents
1283=============
1284*/
1285void PF_pointcontents (void)
1286{
1287	float	*v;
1288
1289	v = G_VECTOR(OFS_PARM0);
1290
1291	G_FLOAT(OFS_RETURN) = SV_PointContents (v);
1292}
1293
1294/*
1295=============
1296PF_nextent
1297
1298entity nextent(entity)
1299=============
1300*/
1301void PF_nextent (void)
1302{
1303	int		i;
1304	edict_t	*ent;
1305
1306	i = G_EDICTNUM(OFS_PARM0);
1307	while (1)
1308	{
1309		i++;
1310		if (i == sv.num_edicts)
1311		{
1312			RETURN_EDICT(sv.edicts);
1313			return;
1314		}
1315		ent = EDICT_NUM(i);
1316		if (!ent->free)
1317		{
1318			RETURN_EDICT(ent);
1319			return;
1320		}
1321	}
1322}
1323
1324/*
1325=============
1326PF_aim
1327
1328Pick a vector for the player to shoot along
1329vector aim(entity, missilespeed)
1330=============
1331*/
1332cvar_t	sv_aim = CVAR2("sv_aim", "0.93");
1333void PF_aim (void)
1334{
1335	edict_t	*ent, *check, *bestent;
1336	vec3_t	start, dir, end, bestdir;
1337	int		i, j;
1338	trace_t	tr;
1339	float	dist, bestdist;
1340	float	speed;
1341
1342	ent = G_EDICT(OFS_PARM0);
1343	speed = G_FLOAT(OFS_PARM1);
1344
1345	VectorCopy (ent->u.v.origin, start);
1346	start[2] += 20;
1347
1348// try sending a trace straight
1349	VectorCopy (pr_global_struct->v_forward, dir);
1350	VectorMA (start, 2048, dir, end);
1351	tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1352	if (tr.ent && tr.ent->u.v.takedamage == DAMAGE_AIM
1353	&& (!teamplay.value || ent->u.v.team <=0 || ent->u.v.team != tr.ent->u.v.team) )
1354	{
1355		VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1356		return;
1357	}
1358
1359
1360// try all possible entities
1361	VectorCopy (dir, bestdir);
1362	bestdist = sv_aim.value;
1363	bestent = NULL;
1364
1365	check = NEXT_EDICT(sv.edicts);
1366	for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1367	{
1368		if (check->u.v.takedamage != DAMAGE_AIM)
1369			continue;
1370		if (check == ent)
1371			continue;
1372		if (teamplay.value && ent->u.v.team > 0 && ent->u.v.team == check->u.v.team)
1373			continue;	// don't aim at teammate
1374		for (j=0 ; j<3 ; j++)
1375			end[j] = check->u.v.origin[j]
1376			+ 0.5*(check->u.v.mins[j] + check->u.v.maxs[j]);
1377		VectorSubtract (end, start, dir);
1378		VectorNormalize (dir);
1379		dist = DotProduct (dir, pr_global_struct->v_forward);
1380		if (dist < bestdist)
1381			continue;	// to far to turn
1382		tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1383		if (tr.ent == check)
1384		{	// can shoot at this one
1385			bestdist = dist;
1386			bestent = check;
1387		}
1388	}
1389
1390	if (bestent)
1391	{
1392		VectorSubtract (bestent->u.v.origin, ent->u.v.origin, dir);
1393		dist = DotProduct (dir, pr_global_struct->v_forward);
1394		VectorScale (pr_global_struct->v_forward, dist, end);
1395		end[2] = dir[2];
1396		VectorNormalize (end);
1397		VectorCopy (end, G_VECTOR(OFS_RETURN));
1398	}
1399	else
1400	{
1401		VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1402	}
1403}
1404
1405/*
1406==============
1407PF_changeyaw
1408
1409This was a major timewaster in progs, so it was converted to C
1410==============
1411*/
1412void PF_changeyaw (void)
1413{
1414	edict_t		*ent;
1415	float		ideal, current, move, speed;
1416
1417	ent = PROG_TO_EDICT(pr_global_struct->self);
1418	current = anglemod( ent->u.v.angles[1] );
1419	ideal = ent->u.v.ideal_yaw;
1420	speed = ent->u.v.yaw_speed;
1421
1422	if (current == ideal)
1423		return;
1424	move = ideal - current;
1425	if (ideal > current)
1426	{
1427		if (move >= 180)
1428			move = move - 360;
1429	}
1430	else
1431	{
1432		if (move <= -180)
1433			move = move + 360;
1434	}
1435	if (move > 0)
1436	{
1437		if (move > speed)
1438			move = speed;
1439	}
1440	else
1441	{
1442		if (move < -speed)
1443			move = -speed;
1444	}
1445
1446	ent->u.v.angles[1] = anglemod (current + move);
1447}
1448
1449#ifdef QUAKE2
1450/*
1451==============
1452PF_changepitch
1453==============
1454*/
1455void PF_changepitch (void)
1456{
1457	edict_t		*ent;
1458	float		ideal, current, move, speed;
1459
1460	ent = G_EDICT(OFS_PARM0);
1461	current = anglemod( ent->u.v.angles[0] );
1462	ideal = ent->u.v.idealpitch;
1463	speed = ent->u.v.pitch_speed;
1464
1465	if (current == ideal)
1466		return;
1467	move = ideal - current;
1468	if (ideal > current)
1469	{
1470		if (move >= 180)
1471			move = move - 360;
1472	}
1473	else
1474	{
1475		if (move <= -180)
1476			move = move + 360;
1477	}
1478	if (move > 0)
1479	{
1480		if (move > speed)
1481			move = speed;
1482	}
1483	else
1484	{
1485		if (move < -speed)
1486			move = -speed;
1487	}
1488
1489	ent->u.v.angles[0] = anglemod (current + move);
1490}
1491#endif
1492
1493/*
1494===============================================================================
1495
1496MESSAGE WRITING
1497
1498===============================================================================
1499*/
1500
1501#define	MSG_BROADCAST	0		// unreliable to all
1502#define	MSG_ONE			1		// reliable to one (msg_entity)
1503#define	MSG_ALL			2		// reliable to all
1504#define	MSG_INIT		3		// write to the init string
1505
1506sizebuf_t *WriteDest (void)
1507{
1508	int		entnum;
1509	int		dest;
1510	edict_t	*ent;
1511
1512	dest = (int) G_FLOAT(OFS_PARM0);
1513	switch (dest)
1514	{
1515	case MSG_BROADCAST:
1516		return &sv.datagram;
1517
1518	case MSG_ONE:
1519		ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1520		entnum = NUM_FOR_EDICT(ent);
1521		if (entnum < 1 || entnum > svs.maxclients)
1522			PR_RunError ("WriteDest: not a client");
1523		return &svs.clients[entnum-1].message;
1524
1525	case MSG_ALL:
1526		return &sv.reliable_datagram;
1527
1528	case MSG_INIT:
1529		return &sv.signon;
1530
1531	default:
1532		PR_RunError ("WriteDest: bad destination");
1533		break;
1534	}
1535
1536	return NULL;
1537}
1538
1539void PF_WriteByte (void)
1540{
1541	MSG_WriteByte (WriteDest(), (int) G_FLOAT(OFS_PARM1));
1542}
1543
1544void PF_WriteChar (void)
1545{
1546	MSG_WriteChar (WriteDest(), (int) G_FLOAT(OFS_PARM1));
1547}
1548
1549void PF_WriteShort (void)
1550{
1551	MSG_WriteShort (WriteDest(), (int) G_FLOAT(OFS_PARM1));
1552}
1553
1554void PF_WriteLong (void)
1555{
1556	MSG_WriteLong (WriteDest(), (int) G_FLOAT(OFS_PARM1));
1557}
1558
1559void PF_WriteAngle (void)
1560{
1561	MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1562}
1563
1564void PF_WriteCoord (void)
1565{
1566	MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1567}
1568
1569void PF_WriteString (void)
1570{
1571	MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1572}
1573
1574
1575void PF_WriteEntity (void)
1576{
1577	MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1578}
1579
1580//=============================================================================
1581
1582int SV_ModelIndex (const char *name);
1583
1584void PF_makestatic (void)
1585{
1586	edict_t	*ent;
1587	int		i;
1588
1589	ent = G_EDICT(OFS_PARM0);
1590
1591	MSG_WriteByte (&sv.signon,svc_spawnstatic);
1592
1593	MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->u.v.model));
1594
1595	MSG_WriteByte (&sv.signon, (int) ent->u.v.frame);
1596	MSG_WriteByte (&sv.signon, (int) ent->u.v.colormap);
1597	MSG_WriteByte (&sv.signon, (int) ent->u.v.skin);
1598	for (i=0 ; i<3 ; i++)
1599	{
1600		MSG_WriteCoord(&sv.signon, ent->u.v.origin[i]);
1601		MSG_WriteAngle(&sv.signon, ent->u.v.angles[i]);
1602	}
1603
1604// throw the entity away now
1605	ED_Free (ent);
1606}
1607
1608//=============================================================================
1609
1610/*
1611==============
1612PF_setspawnparms
1613==============
1614*/
1615void PF_setspawnparms (void)
1616{
1617	edict_t	*ent;
1618	int		i;
1619	client_t	*client;
1620
1621	ent = G_EDICT(OFS_PARM0);
1622	i = NUM_FOR_EDICT(ent);
1623	if (i < 1 || i > svs.maxclients)
1624		PR_RunError ("Entity is not a client");
1625
1626	// copy spawn parms out of the client_t
1627	client = svs.clients + (i-1);
1628
1629	for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1630		(&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1631}
1632
1633/*
1634==============
1635PF_changelevel
1636==============
1637*/
1638void PF_changelevel (void)
1639{
1640#ifdef QUAKE2
1641	char	*s1, *s2;
1642
1643	if (svs.changelevel_issued)
1644		return;
1645	svs.changelevel_issued = true;
1646
1647	s1 = G_STRING(OFS_PARM0);
1648	s2 = G_STRING(OFS_PARM1);
1649
1650	if ((int)pr_global_struct->serverflags & (SFL_NEW_UNIT | SFL_NEW_EPISODE))
1651		Cbuf_AddText (va("changelevel %s %s\n",s1, s2));
1652	else
1653		Cbuf_AddText (va("changelevel2 %s %s\n",s1, s2));
1654#else
1655	char	*s;
1656
1657// make sure we don't issue two changelevels
1658	if (svs.changelevel_issued)
1659		return;
1660	svs.changelevel_issued = true;
1661
1662	s = G_STRING(OFS_PARM0);
1663	Cbuf_AddText (va("changelevel %s\n",s));
1664#endif
1665}
1666
1667
1668#ifdef QUAKE2
1669
1670#define	CONTENT_WATER	-3
1671#define CONTENT_SLIME	-4
1672#define CONTENT_LAVA	-5
1673
1674#define FL_IMMUNE_WATER	131072
1675#define	FL_IMMUNE_SLIME	262144
1676#define FL_IMMUNE_LAVA	524288
1677
1678#define	CHAN_VOICE	2
1679#define	CHAN_BODY	4
1680
1681#define	ATTN_NORM	1
1682
1683void PF_WaterMove (void)
1684{
1685	edict_t		*self;
1686	int			flags;
1687	int			waterlevel;
1688	int			watertype;
1689	float		drownlevel;
1690	float		damage = 0.0;
1691
1692	self = PROG_TO_EDICT(pr_global_struct->self);
1693
1694	if (self->u.v.movetype == MOVETYPE_NOCLIP)
1695	{
1696		self->u.v.air_finished = sv.time + 12;
1697		G_FLOAT(OFS_RETURN) = damage;
1698		return;
1699	}
1700
1701	if (self->u.v.health < 0)
1702	{
1703		G_FLOAT(OFS_RETURN) = damage;
1704		return;
1705	}
1706
1707	if (self->u.v.deadflag == DEAD_NO)
1708		drownlevel = 3;
1709	else
1710		drownlevel = 1;
1711
1712	flags = (int)self->u.v.flags;
1713	waterlevel = (int)self->u.v.waterlevel;
1714	watertype = (int)self->u.v.watertype;
1715
1716	if (!(flags & (FL_IMMUNE_WATER + FL_GODMODE)))
1717		if (((flags & FL_SWIM) && (waterlevel < drownlevel)) || (waterlevel >= drownlevel))
1718		{
1719			if (self->u.v.air_finished < sv.time)
1720				if (self->u.v.pain_finished < sv.time)
1721				{
1722					self->u.v.dmg = self->u.v.dmg + 2;
1723					if (self->u.v.dmg > 15)
1724						self->u.v.dmg = 10;
1725//					T_Damage (self, world, world, self.dmg, 0, FALSE);
1726					damage = self->u.v.dmg;
1727					self->u.v.pain_finished = sv.time + 1.0;
1728				}
1729		}
1730		else
1731		{
1732			if (self->u.v.air_finished < sv.time)
1733//				sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
1734				SV_StartSound (self, CHAN_VOICE, "player/gasp2.wav", 255, ATTN_NORM);
1735			else if (self->u.v.air_finished < sv.time + 9)
1736//				sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
1737				SV_StartSound (self, CHAN_VOICE, "player/gasp1.wav", 255, ATTN_NORM);
1738			self->u.v.air_finished = sv.time + 12.0;
1739			self->u.v.dmg = 2;
1740		}
1741
1742	if (!waterlevel)
1743	{
1744		if (flags & FL_INWATER)
1745		{
1746			// play leave water sound
1747//			sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
1748			SV_StartSound (self, CHAN_BODY, "misc/outwater.wav", 255, ATTN_NORM);
1749			self->u.v.flags = (float)(flags &~FL_INWATER);
1750		}
1751		self->u.v.air_finished = sv.time + 12.0;
1752		G_FLOAT(OFS_RETURN) = damage;
1753		return;
1754	}
1755
1756	if (watertype == CONTENT_LAVA)
1757	{	// do damage
1758		if (!(flags & (FL_IMMUNE_LAVA + FL_GODMODE)))
1759			if (self->u.v.dmgtime < sv.time)
1760			{
1761				if (self->u.v.radsuit_finished < sv.time)
1762					self->u.v.dmgtime = sv.time + 0.2;
1763				else
1764					self->u.v.dmgtime = sv.time + 1.0;
1765//				T_Damage (self, world, world, 10*self.waterlevel, 0, TRUE);
1766				damage = (float)(10*waterlevel);
1767			}
1768	}
1769	else if (watertype == CONTENT_SLIME)
1770	{	// do damage
1771		if (!(flags & (FL_IMMUNE_SLIME + FL_GODMODE)))
1772			if (self->u.v.dmgtime < sv.time && self->u.v.radsuit_finished < sv.time)
1773			{
1774				self->u.v.dmgtime = sv.time + 1.0;
1775//				T_Damage (self, world, world, 4*self.waterlevel, 0, TRUE);
1776				damage = (float)(4*waterlevel);
1777			}
1778	}
1779
1780	if ( !(flags & FL_INWATER) )
1781	{
1782
1783// player enter water sound
1784		if (watertype == CONTENT_LAVA)
1785//			sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
1786			SV_StartSound (self, CHAN_BODY, "player/inlava.wav", 255, ATTN_NORM);
1787		if (watertype == CONTENT_WATER)
1788//			sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
1789			SV_StartSound (self, CHAN_BODY, "player/inh2o.wav", 255, ATTN_NORM);
1790		if (watertype == CONTENT_SLIME)
1791//			sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
1792			SV_StartSound (self, CHAN_BODY, "player/slimbrn2.wav", 255, ATTN_NORM);
1793
1794		self->u.v.flags = (float)(flags | FL_INWATER);
1795		self->u.v.dmgtime = 0;
1796	}
1797
1798	if (! (flags & FL_WATERJUMP) )
1799	{
1800//		self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity;
1801		VectorMA (self->u.v.velocity, -0.8 * self->u.v.waterlevel * host_frametime, self->u.v.velocity, self->u.v.velocity);
1802	}
1803
1804	G_FLOAT(OFS_RETURN) = damage;
1805}
1806
1807
1808void PF_sin (void)
1809{
1810	G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1811}
1812
1813void PF_cos (void)
1814{
1815	G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1816}
1817
1818void PF_sqrt (void)
1819{
1820	G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1821}
1822#endif
1823
1824void PF_Fixme (void)
1825{
1826	PR_RunError ("unimplemented bulitin");
1827}
1828
1829
1830
1831builtin_t pr_builtin[] =
1832{
1833PF_Fixme,
1834PF_makevectors,	// void(entity e)	makevectors 		= #1;
1835PF_setorigin,	// void(entity e, vector o) setorigin	= #2;
1836PF_setmodel,	// void(entity e, string m) setmodel	= #3;
1837PF_setsize,	// void(entity e, vector min, vector max) setsize = #4;
1838PF_Fixme,	// void(entity e, vector min, vector max) setabssize = #5;
1839PF_break,	// void() break						= #6;
1840PF_random,	// float() random						= #7;
1841PF_sound,	// void(entity e, float chan, string samp) sound = #8;
1842PF_normalize,	// vector(vector v) normalize			= #9;
1843PF_error,	// void(string e) error				= #10;
1844PF_objerror,	// void(string e) objerror				= #11;
1845PF_vlen,	// float(vector v) vlen				= #12;
1846PF_vectoyaw,	// float(vector v) vectoyaw		= #13;
1847PF_Spawn,	// entity() spawn						= #14;
1848PF_Remove,	// void(entity e) remove				= #15;
1849PF_traceline,	// float(vector v1, vector v2, float tryents) traceline = #16;
1850PF_checkclient,	// entity() clientlist					= #17;
1851PF_Find,	// entity(entity start, .string fld, string match) find = #18;
1852PF_precache_sound,	// void(string s) precache_sound		= #19;
1853PF_precache_model,	// void(string s) precache_model		= #20;
1854PF_stuffcmd,	// void(entity client, string s)stuffcmd = #21;
1855PF_findradius,	// entity(vector org, float rad) findradius = #22;
1856PF_bprint,	// void(string s) bprint				= #23;
1857PF_sprint,	// void(entity client, string s) sprint = #24;
1858PF_dprint,	// void(string s) dprint				= #25;
1859PF_ftos,	// void(string s) ftos				= #26;
1860PF_vtos,	// void(string s) vtos				= #27;
1861PF_coredump,
1862PF_traceon,
1863PF_traceoff,
1864PF_eprint,	// void(entity e) debug print an entire entity
1865PF_walkmove, // float(float yaw, float dist) walkmove
1866PF_Fixme, // float(float yaw, float dist) walkmove
1867PF_droptofloor,
1868PF_lightstyle,
1869PF_rint,
1870PF_floor,
1871PF_ceil,
1872PF_Fixme,
1873PF_checkbottom,
1874PF_pointcontents,
1875PF_Fixme,
1876PF_fabs,
1877PF_aim,
1878PF_cvar,
1879PF_localcmd,
1880PF_nextent,
1881PF_particle,
1882PF_changeyaw,
1883PF_Fixme,
1884PF_vectoangles,
1885
1886PF_WriteByte,
1887PF_WriteChar,
1888PF_WriteShort,
1889PF_WriteLong,
1890PF_WriteCoord,
1891PF_WriteAngle,
1892PF_WriteString,
1893PF_WriteEntity,
1894
1895#ifdef QUAKE2
1896PF_sin,
1897PF_cos,
1898PF_sqrt,
1899PF_changepitch,
1900PF_TraceToss,
1901PF_etos,
1902PF_WaterMove,
1903#else
1904PF_Fixme,
1905PF_Fixme,
1906PF_Fixme,
1907PF_Fixme,
1908PF_Fixme,
1909PF_Fixme,
1910PF_Fixme,
1911#endif
1912
1913SV_MoveToGoal,
1914PF_precache_file,
1915PF_makestatic,
1916
1917PF_changelevel,
1918PF_Fixme,
1919
1920PF_cvar_set,
1921PF_centerprint,
1922
1923PF_ambientsound,
1924
1925PF_precache_model,
1926PF_precache_sound,		// precache_sound2 is different only for qcc
1927PF_precache_file,
1928
1929PF_setspawnparms
1930};
1931
1932builtin_t *pr_builtins = pr_builtin;
1933int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
1934
1935