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 "qwsvdef.h"
22
23#define	RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
24#define	RETURN_STRING(s) (((int *)pr_globals)[OFS_RETURN] = PR_SetString(s))
25
26/*
27===============================================================================
28
29						BUILT-IN FUNCTIONS
30
31===============================================================================
32*/
33
34char *PF_VarString (int	first)
35{
36	int		i;
37	static char out[256];
38
39	out[0] = 0;
40	for (i=first ; i<pr_argc ; i++)
41	{
42		strcat (out, G_STRING((OFS_PARM0+i*3)));
43	}
44	return out;
45}
46
47
48/*
49=================
50PF_errror
51
52This is a TERMINAL error, which will kill off the entire server.
53Dumps self.
54
55error(value)
56=================
57*/
58void PF_error (void)
59{
60	char	*s;
61	edict_t	*ed;
62
63	s = PF_VarString(0);
64	Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name) ,s);
65	ed = PROG_TO_EDICT(pr_global_struct->self);
66	ED_Print (ed);
67
68	SV_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", PR_GetString(pr_xfunction->s_name),s);
88	ed = PROG_TO_EDICT(pr_global_struct->self);
89	ED_Print (ed);
90	ED_Free (ed);
91
92	SV_Error ("Program error");
93}
94
95
96
97/*
98==============
99PF_makevectors
100
101Writes new values for v_forward, v_up, and v_right based on angles
102makevectors(vector)
103==============
104*/
105void PF_makevectors (void)
106{
107	AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
108}
109
110/*
111=================
112PF_setorigin
113
114This 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.
115
116setorigin (entity, origin)
117=================
118*/
119void PF_setorigin (void)
120{
121	edict_t	*e;
122	float	*org;
123
124	e = G_EDICT(OFS_PARM0);
125	org = G_VECTOR(OFS_PARM1);
126	VectorCopy (org, e->v.origin);
127	SV_LinkEdict (e, false);
128}
129
130
131/*
132=================
133PF_setsize
134
135the size box is rotated by the current angle
136
137setsize (entity, minvector, maxvector)
138=================
139*/
140void PF_setsize (void)
141{
142	edict_t	*e;
143	float	*min, *max;
144
145	e = G_EDICT(OFS_PARM0);
146	min = G_VECTOR(OFS_PARM1);
147	max = G_VECTOR(OFS_PARM2);
148	VectorCopy (min, e->v.mins);
149	VectorCopy (max, e->v.maxs);
150	VectorSubtract (max, min, e->v.size);
151	SV_LinkEdict (e, false);
152}
153
154
155/*
156=================
157PF_setmodel
158
159setmodel(entity, model)
160Also sets size, mins, and maxs for inline bmodels
161=================
162*/
163void PF_setmodel (void)
164{
165	edict_t	*e;
166	char	*m, **check;
167	int		i;
168	model_t	*mod;
169
170	e = G_EDICT(OFS_PARM0);
171	m = G_STRING(OFS_PARM1);
172
173// check to see if model was properly precached
174	for (i=0, check = sv.model_precache ; *check ; i++, check++)
175		if (!strcmp(*check, m))
176			break;
177
178	if (!*check)
179		PR_RunError ("no precache: %s\n", m);
180
181	e->v.model = PR_SetString(m);
182	e->v.modelindex = i;
183
184// if it is an inline model, get the size information for it
185	if (m[0] == '*')
186	{
187		mod = Mod_ForName (m, true);
188		VectorCopy (mod->mins, e->v.mins);
189		VectorCopy (mod->maxs, e->v.maxs);
190		VectorSubtract (mod->maxs, mod->mins, e->v.size);
191		SV_LinkEdict (e, false);
192	}
193
194}
195
196/*
197=================
198PF_bprint
199
200broadcast print to everyone on server
201
202bprint(value)
203=================
204*/
205void PF_bprint (void)
206{
207	char		*s;
208	int			level;
209
210	level = G_FLOAT(OFS_PARM0);
211
212	s = PF_VarString(1);
213	SV_BroadcastPrintf (level, "%s", s);
214}
215
216/*
217=================
218PF_sprint
219
220single print to a specific client
221
222sprint(clientent, value)
223=================
224*/
225void PF_sprint (void)
226{
227	char		*s;
228	client_t	*client;
229	int			entnum;
230	int			level;
231
232	entnum = G_EDICTNUM(OFS_PARM0);
233	level = G_FLOAT(OFS_PARM1);
234
235	s = PF_VarString(2);
236
237	if (entnum < 1 || entnum > MAX_CLIENTS)
238	{
239		Con_Printf ("tried to sprint to a non-client\n");
240		return;
241	}
242
243	client = &svs.clients[entnum-1];
244
245	SV_ClientPrintf (client, level, "%s", s);
246}
247
248
249/*
250=================
251PF_centerprint
252
253single print to a specific client
254
255centerprint(clientent, value)
256=================
257*/
258void PF_centerprint (void)
259{
260	char		*s;
261	int			entnum;
262	client_t	*cl;
263
264	entnum = G_EDICTNUM(OFS_PARM0);
265	s = PF_VarString(1);
266
267	if (entnum < 1 || entnum > MAX_CLIENTS)
268	{
269		Con_Printf ("tried to sprint to a non-client\n");
270		return;
271	}
272
273	cl = &svs.clients[entnum-1];
274
275	ClientReliableWrite_Begin (cl, svc_centerprint, 2 + strlen(s));
276	ClientReliableWrite_String (cl, s);
277}
278
279
280/*
281=================
282PF_normalize
283
284vector normalize(vector)
285=================
286*/
287void PF_normalize (void)
288{
289	float	*value1;
290	vec3_t	newvalue;
291	float	new;
292
293	value1 = G_VECTOR(OFS_PARM0);
294
295	new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
296	new = sqrt(new);
297
298	if (new == 0)
299		newvalue[0] = newvalue[1] = newvalue[2] = 0;
300	else
301	{
302		new = 1/new;
303		newvalue[0] = value1[0] * new;
304		newvalue[1] = value1[1] * new;
305		newvalue[2] = value1[2] * new;
306	}
307
308	VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
309}
310
311/*
312=================
313PF_vlen
314
315scalar vlen(vector)
316=================
317*/
318void PF_vlen (void)
319{
320	float	*value1;
321	float	new;
322
323	value1 = G_VECTOR(OFS_PARM0);
324
325	new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
326	new = sqrt(new);
327
328	G_FLOAT(OFS_RETURN) = new;
329}
330
331/*
332=================
333PF_vectoyaw
334
335float vectoyaw(vector)
336=================
337*/
338void PF_vectoyaw (void)
339{
340	float	*value1;
341	float	yaw;
342
343	value1 = G_VECTOR(OFS_PARM0);
344
345	if (value1[1] == 0 && value1[0] == 0)
346		yaw = 0;
347	else
348	{
349		yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
350		if (yaw < 0)
351			yaw += 360;
352	}
353
354	G_FLOAT(OFS_RETURN) = yaw;
355}
356
357
358/*
359=================
360PF_vectoangles
361
362vector vectoangles(vector)
363=================
364*/
365void PF_vectoangles (void)
366{
367	float	*value1;
368	float	forward;
369	float	yaw, pitch;
370
371	value1 = G_VECTOR(OFS_PARM0);
372
373	if (value1[1] == 0 && value1[0] == 0)
374	{
375		yaw = 0;
376		if (value1[2] > 0)
377			pitch = 90;
378		else
379			pitch = 270;
380	}
381	else
382	{
383		yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
384		if (yaw < 0)
385			yaw += 360;
386
387		forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
388		pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
389		if (pitch < 0)
390			pitch += 360;
391	}
392
393	G_FLOAT(OFS_RETURN+0) = pitch;
394	G_FLOAT(OFS_RETURN+1) = yaw;
395	G_FLOAT(OFS_RETURN+2) = 0;
396}
397
398/*
399=================
400PF_Random
401
402Returns a number from 0<= num < 1
403
404random()
405=================
406*/
407void PF_random (void)
408{
409	float		num;
410
411	num = (rand ()&0x7fff) / ((float)0x7fff);
412
413	G_FLOAT(OFS_RETURN) = num;
414}
415
416
417/*
418=================
419PF_ambientsound
420
421=================
422*/
423void PF_ambientsound (void)
424{
425	char		**check;
426	char		*samp;
427	float		*pos;
428	float 		vol, attenuation;
429	int			i, soundnum;
430
431	pos = G_VECTOR (OFS_PARM0);
432	samp = G_STRING(OFS_PARM1);
433	vol = G_FLOAT(OFS_PARM2);
434	attenuation = G_FLOAT(OFS_PARM3);
435
436// check to see if samp was properly precached
437	for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
438		if (!strcmp(*check,samp))
439			break;
440
441	if (!*check)
442	{
443		Con_Printf ("no precache: %s\n", samp);
444		return;
445	}
446
447// add an svc_spawnambient command to the level signon packet
448
449	MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
450	for (i=0 ; i<3 ; i++)
451		MSG_WriteCoord(&sv.signon, pos[i]);
452
453	MSG_WriteByte (&sv.signon, soundnum);
454
455	MSG_WriteByte (&sv.signon, vol*255);
456	MSG_WriteByte (&sv.signon, attenuation*64);
457
458}
459
460/*
461=================
462PF_sound
463
464Each entity can have eight independant sound sources, like voice,
465weapon, feet, etc.
466
467Channel 0 is an auto-allocate channel, the others override anything
468allready running on that entity/channel pair.
469
470An attenuation of 0 will play full volume everywhere in the level.
471Larger attenuations will drop off.
472
473=================
474*/
475void PF_sound (void)
476{
477	char		*sample;
478	int			channel;
479	edict_t		*entity;
480	int 		volume;
481	float attenuation;
482
483	entity = G_EDICT(OFS_PARM0);
484	channel = G_FLOAT(OFS_PARM1);
485	sample = G_STRING(OFS_PARM2);
486	volume = G_FLOAT(OFS_PARM3) * 255;
487	attenuation = G_FLOAT(OFS_PARM4);
488
489	SV_StartSound (entity, channel, sample, volume, attenuation);
490}
491
492/*
493=================
494PF_break
495
496break()
497=================
498*/
499void PF_break (void)
500{
501Con_Printf ("break statement\n");
502*(int *)-4 = 0;	// dump to debugger
503//	PR_RunError ("break statement");
504}
505
506/*
507=================
508PF_traceline
509
510Used for use tracing and shot targeting
511Traces are blocked by bbox and exact bsp entityes, and also slide box entities
512if the tryents flag is set.
513
514traceline (vector1, vector2, tryents)
515=================
516*/
517void PF_traceline (void)
518{
519	float	*v1, *v2;
520	trace_t	trace;
521	int		nomonsters;
522	edict_t	*ent;
523
524	v1 = G_VECTOR(OFS_PARM0);
525	v2 = G_VECTOR(OFS_PARM1);
526	nomonsters = G_FLOAT(OFS_PARM2);
527	ent = G_EDICT(OFS_PARM3);
528
529	trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
530
531	pr_global_struct->trace_allsolid = trace.allsolid;
532	pr_global_struct->trace_startsolid = trace.startsolid;
533	pr_global_struct->trace_fraction = trace.fraction;
534	pr_global_struct->trace_inwater = trace.inwater;
535	pr_global_struct->trace_inopen = trace.inopen;
536	VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
537	VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
538	pr_global_struct->trace_plane_dist =  trace.plane.dist;
539	if (trace.ent)
540		pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
541	else
542		pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
543}
544
545/*
546=================
547PF_checkpos
548
549Returns true if the given entity can move to the given position from it's
550current position by walking or rolling.
551FIXME: make work...
552scalar checkpos (entity, vector)
553=================
554*/
555void PF_checkpos (void)
556{
557}
558
559//============================================================================
560
561byte	checkpvs[MAX_MAP_LEAFS/8];
562
563int PF_newcheckclient (int check)
564{
565	int		i;
566	byte	*pvs;
567	edict_t	*ent;
568	mleaf_t	*leaf;
569	vec3_t	org;
570
571// cycle to the next one
572
573	if (check < 1)
574		check = 1;
575	if (check > MAX_CLIENTS)
576		check = MAX_CLIENTS;
577
578	if (check == MAX_CLIENTS)
579		i = 1;
580	else
581		i = check + 1;
582
583	for ( ;  ; i++)
584	{
585		if (i == MAX_CLIENTS+1)
586			i = 1;
587
588		ent = EDICT_NUM(i);
589
590		if (i == check)
591			break;	// didn't find anything else
592
593		if (ent->free)
594			continue;
595		if (ent->v.health <= 0)
596			continue;
597		if ((int)ent->v.flags & FL_NOTARGET)
598			continue;
599
600	// anything that is a client, or has a client as an enemy
601		break;
602	}
603
604// get the PVS for the entity
605	VectorAdd (ent->v.origin, ent->v.view_ofs, org);
606	leaf = Mod_PointInLeaf (org, sv.worldmodel);
607	pvs = Mod_LeafPVS (leaf, sv.worldmodel);
608	memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
609
610	return i;
611}
612
613/*
614=================
615PF_checkclient
616
617Returns a client (or object that has a client enemy) that would be a
618valid target.
619
620If there are more than one valid options, they are cycled each frame
621
622If (self.origin + self.viewofs) is not in the PVS of the current target,
623it is not returned at all.
624
625name checkclient ()
626=================
627*/
628#define	MAX_CHECK	16
629int c_invis, c_notvis;
630void PF_checkclient (void)
631{
632	edict_t	*ent, *self;
633	mleaf_t	*leaf;
634	int		l;
635	vec3_t	view;
636
637// find a new check if on a new frame
638	if (sv.time - sv.lastchecktime >= 0.1)
639	{
640		sv.lastcheck = PF_newcheckclient (sv.lastcheck);
641		sv.lastchecktime = sv.time;
642	}
643
644// return check if it might be visible
645	ent = EDICT_NUM(sv.lastcheck);
646	if (ent->free || ent->v.health <= 0)
647	{
648		RETURN_EDICT(sv.edicts);
649		return;
650	}
651
652// if current entity can't possibly see the check entity, return 0
653	self = PROG_TO_EDICT(pr_global_struct->self);
654	VectorAdd (self->v.origin, self->v.view_ofs, view);
655	leaf = Mod_PointInLeaf (view, sv.worldmodel);
656	l = (leaf - sv.worldmodel->leafs) - 1;
657	if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
658	{
659c_notvis++;
660		RETURN_EDICT(sv.edicts);
661		return;
662	}
663
664// might be able to see it
665c_invis++;
666	RETURN_EDICT(ent);
667}
668
669//============================================================================
670
671
672/*
673=================
674PF_stuffcmd
675
676Sends text over to the client's execution buffer
677
678stuffcmd (clientent, value)
679=================
680*/
681void PF_stuffcmd (void)
682{
683	int		entnum;
684	char	*str;
685	client_t	*cl;
686
687	entnum = G_EDICTNUM(OFS_PARM0);
688	if (entnum < 1 || entnum > MAX_CLIENTS)
689		PR_RunError ("Parm 0 not a client");
690	str = G_STRING(OFS_PARM1);
691
692	cl = &svs.clients[entnum-1];
693
694	if (strcmp(str, "disconnect\n") == 0) {
695		// so long and thanks for all the fish
696		cl->drop = true;
697		return;
698	}
699
700	ClientReliableWrite_Begin (cl, svc_stufftext, 2+strlen(str));
701	ClientReliableWrite_String (cl, str);
702}
703
704/*
705=================
706PF_localcmd
707
708Sends text over to the client's execution buffer
709
710localcmd (string)
711=================
712*/
713void PF_localcmd (void)
714{
715	char	*str;
716
717	str = G_STRING(OFS_PARM0);
718	Cbuf_AddText (str);
719}
720
721/*
722=================
723PF_cvar
724
725float cvar (string)
726=================
727*/
728void PF_cvar (void)
729{
730	char	*str;
731
732	str = G_STRING(OFS_PARM0);
733
734	G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
735}
736
737/*
738=================
739PF_cvar_set
740
741float cvar (string)
742=================
743*/
744void PF_cvar_set (void)
745{
746	char	*var, *val;
747
748	var = G_STRING(OFS_PARM0);
749	val = G_STRING(OFS_PARM1);
750
751	Cvar_Set (var, val);
752}
753
754/*
755=================
756PF_findradius
757
758Returns a chain of entities that have origins within a spherical area
759
760findradius (origin, radius)
761=================
762*/
763void PF_findradius (void)
764{
765	edict_t	*ent, *chain;
766	float	rad;
767	float	*org;
768	vec3_t	eorg;
769	int		i, j;
770
771	chain = (edict_t *)sv.edicts;
772
773	org = G_VECTOR(OFS_PARM0);
774	rad = G_FLOAT(OFS_PARM1);
775
776	ent = NEXT_EDICT(sv.edicts);
777	for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
778	{
779		if (ent->free)
780			continue;
781		if (ent->v.solid == SOLID_NOT)
782			continue;
783		for (j=0 ; j<3 ; j++)
784			eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5);
785		if (Length(eorg) > rad)
786			continue;
787
788		ent->v.chain = EDICT_TO_PROG(chain);
789		chain = ent;
790	}
791
792	RETURN_EDICT(chain);
793}
794
795
796/*
797=========
798PF_dprint
799=========
800*/
801void PF_dprint (void)
802{
803	Con_Printf ("%s",PF_VarString(0));
804}
805
806char	pr_string_temp[128];
807
808void PF_ftos (void)
809{
810	float	v;
811	v = G_FLOAT(OFS_PARM0);
812
813	if (v == (int)v)
814		sprintf (pr_string_temp, "%d",(int)v);
815	else
816		sprintf (pr_string_temp, "%5.1f",v);
817	G_INT(OFS_RETURN) = PR_SetString(pr_string_temp);
818}
819
820void PF_fabs (void)
821{
822	float	v;
823	v = G_FLOAT(OFS_PARM0);
824	G_FLOAT(OFS_RETURN) = fabs(v);
825}
826
827void PF_vtos (void)
828{
829	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]);
830	G_INT(OFS_RETURN) = PR_SetString(pr_string_temp);
831}
832
833void PF_Spawn (void)
834{
835	edict_t	*ed;
836	ed = ED_Alloc();
837	RETURN_EDICT(ed);
838}
839
840void PF_Remove (void)
841{
842	edict_t	*ed;
843
844	ed = G_EDICT(OFS_PARM0);
845	ED_Free (ed);
846}
847
848
849// entity (entity start, .string field, string match) find = #5;
850void PF_Find (void)
851{
852	int		e;
853	int		f;
854	char	*s, *t;
855	edict_t	*ed;
856
857	e = G_EDICTNUM(OFS_PARM0);
858	f = G_INT(OFS_PARM1);
859	s = G_STRING(OFS_PARM2);
860	if (!s)
861		PR_RunError ("PF_Find: bad search string");
862
863	for (e++ ; e < sv.num_edicts ; e++)
864	{
865		ed = EDICT_NUM(e);
866		if (ed->free)
867			continue;
868		t = E_STRING(ed,f);
869		if (!t)
870			continue;
871		if (!strcmp(t,s))
872		{
873			RETURN_EDICT(ed);
874			return;
875		}
876	}
877
878	RETURN_EDICT(sv.edicts);
879}
880
881void PR_CheckEmptyString (char *s)
882{
883	if (s[0] <= ' ')
884		PR_RunError ("Bad string");
885}
886
887void PF_precache_file (void)
888{	// precache_file is only used to copy files with qcc, it does nothing
889	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
890}
891
892void PF_precache_sound (void)
893{
894	char	*s;
895	int		i;
896
897	if (sv.state != ss_loading)
898		PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
899
900	s = G_STRING(OFS_PARM0);
901	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
902	PR_CheckEmptyString (s);
903
904	for (i=0 ; i<MAX_SOUNDS ; i++)
905	{
906		if (!sv.sound_precache[i])
907		{
908			sv.sound_precache[i] = s;
909			return;
910		}
911		if (!strcmp(sv.sound_precache[i], s))
912			return;
913	}
914	PR_RunError ("PF_precache_sound: overflow");
915}
916
917void PF_precache_model (void)
918{
919	char	*s;
920	int		i;
921
922	if (sv.state != ss_loading)
923		PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
924
925	s = G_STRING(OFS_PARM0);
926	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
927	PR_CheckEmptyString (s);
928
929	for (i=0 ; i<MAX_MODELS ; i++)
930	{
931		if (!sv.model_precache[i])
932		{
933			sv.model_precache[i] = s;
934			return;
935		}
936		if (!strcmp(sv.model_precache[i], s))
937			return;
938	}
939	PR_RunError ("PF_precache_model: overflow");
940}
941
942
943void PF_coredump (void)
944{
945	ED_PrintEdicts ();
946}
947
948void PF_traceon (void)
949{
950	pr_trace = true;
951}
952
953void PF_traceoff (void)
954{
955	pr_trace = false;
956}
957
958void PF_eprint (void)
959{
960	ED_PrintNum (G_EDICTNUM(OFS_PARM0));
961}
962
963/*
964===============
965PF_walkmove
966
967float(float yaw, float dist) walkmove
968===============
969*/
970void PF_walkmove (void)
971{
972	edict_t	*ent;
973	float	yaw, dist;
974	vec3_t	move;
975	dfunction_t	*oldf;
976	int 	oldself;
977
978	ent = PROG_TO_EDICT(pr_global_struct->self);
979	yaw = G_FLOAT(OFS_PARM0);
980	dist = G_FLOAT(OFS_PARM1);
981
982	if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
983	{
984		G_FLOAT(OFS_RETURN) = 0;
985		return;
986	}
987
988	yaw = yaw*M_PI*2 / 360;
989
990	move[0] = cos(yaw)*dist;
991	move[1] = sin(yaw)*dist;
992	move[2] = 0;
993
994// save program state, because SV_movestep may call other progs
995	oldf = pr_xfunction;
996	oldself = pr_global_struct->self;
997
998	G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
999
1000
1001// restore program state
1002	pr_xfunction = oldf;
1003	pr_global_struct->self = oldself;
1004}
1005
1006/*
1007===============
1008PF_droptofloor
1009
1010void() droptofloor
1011===============
1012*/
1013void PF_droptofloor (void)
1014{
1015	edict_t		*ent;
1016	vec3_t		end;
1017	trace_t		trace;
1018
1019	ent = PROG_TO_EDICT(pr_global_struct->self);
1020
1021	VectorCopy (ent->v.origin, end);
1022	end[2] -= 256;
1023
1024	trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
1025
1026	if (trace.fraction == 1 || trace.allsolid)
1027		G_FLOAT(OFS_RETURN) = 0;
1028	else
1029	{
1030		VectorCopy (trace.endpos, ent->v.origin);
1031		SV_LinkEdict (ent, false);
1032		ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1033		ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1034		G_FLOAT(OFS_RETURN) = 1;
1035	}
1036}
1037
1038/*
1039===============
1040PF_lightstyle
1041
1042void(float style, string value) lightstyle
1043===============
1044*/
1045void PF_lightstyle (void)
1046{
1047	int		style;
1048	char	*val;
1049	client_t	*client;
1050	int			j;
1051
1052	style = G_FLOAT(OFS_PARM0);
1053	val = G_STRING(OFS_PARM1);
1054
1055// change the string in sv
1056	sv.lightstyles[style] = val;
1057
1058// send message to all clients on this server
1059	if (sv.state != ss_active)
1060		return;
1061
1062	for (j=0, client = svs.clients ; j<MAX_CLIENTS ; j++, client++)
1063		if ( client->state == cs_spawned )
1064		{
1065			ClientReliableWrite_Begin (client, svc_lightstyle, strlen(val)+3);
1066			ClientReliableWrite_Char (client, style);
1067			ClientReliableWrite_String (client, val);
1068		}
1069}
1070
1071void PF_rint (void)
1072{
1073	float	f;
1074	f = G_FLOAT(OFS_PARM0);
1075	if (f > 0)
1076		G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1077	else
1078		G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1079}
1080void PF_floor (void)
1081{
1082	G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1083}
1084void PF_ceil (void)
1085{
1086	G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1087}
1088
1089
1090/*
1091=============
1092PF_checkbottom
1093=============
1094*/
1095void PF_checkbottom (void)
1096{
1097	edict_t	*ent;
1098
1099	ent = G_EDICT(OFS_PARM0);
1100
1101	G_FLOAT(OFS_RETURN) = SV_CheckBottom (ent);
1102}
1103
1104/*
1105=============
1106PF_pointcontents
1107=============
1108*/
1109void PF_pointcontents (void)
1110{
1111	float	*v;
1112
1113	v = G_VECTOR(OFS_PARM0);
1114
1115	G_FLOAT(OFS_RETURN) = SV_PointContents (v);
1116}
1117
1118/*
1119=============
1120PF_nextent
1121
1122entity nextent(entity)
1123=============
1124*/
1125void PF_nextent (void)
1126{
1127	int		i;
1128	edict_t	*ent;
1129
1130	i = G_EDICTNUM(OFS_PARM0);
1131	while (1)
1132	{
1133		i++;
1134		if (i == sv.num_edicts)
1135		{
1136			RETURN_EDICT(sv.edicts);
1137			return;
1138		}
1139		ent = EDICT_NUM(i);
1140		if (!ent->free)
1141		{
1142			RETURN_EDICT(ent);
1143			return;
1144		}
1145	}
1146}
1147
1148/*
1149=============
1150PF_aim
1151
1152Pick a vector for the player to shoot along
1153vector aim(entity, missilespeed)
1154=============
1155*/
1156//cvar_t	sv_aim = {"sv_aim", "0.93"};
1157cvar_t	sv_aim = {"sv_aim", "2"};
1158void PF_aim (void)
1159{
1160	edict_t	*ent, *check, *bestent;
1161	vec3_t	start, dir, end, bestdir;
1162	int		i, j;
1163	trace_t	tr;
1164	float	dist, bestdist;
1165	float	speed;
1166	char	*noaim;
1167
1168	ent = G_EDICT(OFS_PARM0);
1169	speed = G_FLOAT(OFS_PARM1);
1170
1171	VectorCopy (ent->v.origin, start);
1172	start[2] += 20;
1173
1174// noaim option
1175	i = NUM_FOR_EDICT(ent);
1176	if (i>0 && i<MAX_CLIENTS)
1177	{
1178		noaim = Info_ValueForKey (svs.clients[i-1].userinfo, "noaim");
1179		if (atoi(noaim) > 0)
1180		{
1181			VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1182			return;
1183		}
1184	}
1185
1186// try sending a trace straight
1187	VectorCopy (pr_global_struct->v_forward, dir);
1188	VectorMA (start, 2048, dir, end);
1189	tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1190	if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM
1191	&& (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) )
1192	{
1193		VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1194		return;
1195	}
1196
1197
1198// try all possible entities
1199	VectorCopy (dir, bestdir);
1200	bestdist = sv_aim.value;
1201	bestent = NULL;
1202
1203	check = NEXT_EDICT(sv.edicts);
1204	for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1205	{
1206		if (check->v.takedamage != DAMAGE_AIM)
1207			continue;
1208		if (check == ent)
1209			continue;
1210		if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team)
1211			continue;	// don't aim at teammate
1212		for (j=0 ; j<3 ; j++)
1213			end[j] = check->v.origin[j]
1214			+ 0.5*(check->v.mins[j] + check->v.maxs[j]);
1215		VectorSubtract (end, start, dir);
1216		VectorNormalize (dir);
1217		dist = DotProduct (dir, pr_global_struct->v_forward);
1218		if (dist < bestdist)
1219			continue;	// to far to turn
1220		tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1221		if (tr.ent == check)
1222		{	// can shoot at this one
1223			bestdist = dist;
1224			bestent = check;
1225		}
1226	}
1227
1228	if (bestent)
1229	{
1230		VectorSubtract (bestent->v.origin, ent->v.origin, dir);
1231		dist = DotProduct (dir, pr_global_struct->v_forward);
1232		VectorScale (pr_global_struct->v_forward, dist, end);
1233		end[2] = dir[2];
1234		VectorNormalize (end);
1235		VectorCopy (end, G_VECTOR(OFS_RETURN));
1236	}
1237	else
1238	{
1239		VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1240	}
1241}
1242
1243/*
1244==============
1245PF_changeyaw
1246
1247This was a major timewaster in progs, so it was converted to C
1248==============
1249*/
1250void PF_changeyaw (void)
1251{
1252	edict_t		*ent;
1253	float		ideal, current, move, speed;
1254
1255	ent = PROG_TO_EDICT(pr_global_struct->self);
1256	current = anglemod( ent->v.angles[1] );
1257	ideal = ent->v.ideal_yaw;
1258	speed = ent->v.yaw_speed;
1259
1260	if (current == ideal)
1261		return;
1262	move = ideal - current;
1263	if (ideal > current)
1264	{
1265		if (move >= 180)
1266			move = move - 360;
1267	}
1268	else
1269	{
1270		if (move <= -180)
1271			move = move + 360;
1272	}
1273	if (move > 0)
1274	{
1275		if (move > speed)
1276			move = speed;
1277	}
1278	else
1279	{
1280		if (move < -speed)
1281			move = -speed;
1282	}
1283
1284	ent->v.angles[1] = anglemod (current + move);
1285}
1286
1287/*
1288===============================================================================
1289
1290MESSAGE WRITING
1291
1292===============================================================================
1293*/
1294
1295#define	MSG_BROADCAST	0		// unreliable to all
1296#define	MSG_ONE			1		// reliable to one (msg_entity)
1297#define	MSG_ALL			2		// reliable to all
1298#define	MSG_INIT		3		// write to the init string
1299#define	MSG_MULTICAST	4		// for multicast()
1300
1301sizebuf_t *WriteDest (void)
1302{
1303	int		entnum;
1304	int		dest;
1305	edict_t	*ent;
1306
1307	dest = G_FLOAT(OFS_PARM0);
1308	switch (dest)
1309	{
1310	case MSG_BROADCAST:
1311		return &sv.datagram;
1312
1313	case MSG_ONE:
1314		SV_Error("Shouldn't be at MSG_ONE");
1315#if 0
1316		ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1317		entnum = NUM_FOR_EDICT(ent);
1318		if (entnum < 1 || entnum > MAX_CLIENTS)
1319			PR_RunError ("WriteDest: not a client");
1320		return &svs.clients[entnum-1].netchan.message;
1321#endif
1322
1323	case MSG_ALL:
1324		return &sv.reliable_datagram;
1325
1326	case MSG_INIT:
1327		if (sv.state != ss_loading)
1328			PR_RunError ("PF_Write_*: MSG_INIT can only be written in spawn functions");
1329		return &sv.signon;
1330
1331	case MSG_MULTICAST:
1332		return &sv.multicast;
1333
1334	default:
1335		PR_RunError ("WriteDest: bad destination");
1336		break;
1337	}
1338
1339	return NULL;
1340}
1341
1342static client_t *Write_GetClient(void)
1343{
1344	int		entnum;
1345	edict_t	*ent;
1346
1347	ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1348	entnum = NUM_FOR_EDICT(ent);
1349	if (entnum < 1 || entnum > MAX_CLIENTS)
1350		PR_RunError ("WriteDest: not a client");
1351	return &svs.clients[entnum-1];
1352}
1353
1354
1355void PF_WriteByte (void)
1356{
1357	if (G_FLOAT(OFS_PARM0) == MSG_ONE) {
1358		client_t *cl = Write_GetClient();
1359		ClientReliableCheckBlock(cl, 1);
1360		ClientReliableWrite_Byte(cl, G_FLOAT(OFS_PARM1));
1361	} else
1362		MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1363}
1364
1365void PF_WriteChar (void)
1366{
1367	if (G_FLOAT(OFS_PARM0) == MSG_ONE) {
1368		client_t *cl = Write_GetClient();
1369		ClientReliableCheckBlock(cl, 1);
1370		ClientReliableWrite_Char(cl, G_FLOAT(OFS_PARM1));
1371	} else
1372		MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1373}
1374
1375void PF_WriteShort (void)
1376{
1377	if (G_FLOAT(OFS_PARM0) == MSG_ONE) {
1378		client_t *cl = Write_GetClient();
1379		ClientReliableCheckBlock(cl, 2);
1380		ClientReliableWrite_Short(cl, G_FLOAT(OFS_PARM1));
1381	} else
1382		MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1383}
1384
1385void PF_WriteLong (void)
1386{
1387	if (G_FLOAT(OFS_PARM0) == MSG_ONE) {
1388		client_t *cl = Write_GetClient();
1389		ClientReliableCheckBlock(cl, 4);
1390		ClientReliableWrite_Long(cl, G_FLOAT(OFS_PARM1));
1391	} else
1392		MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1393}
1394
1395void PF_WriteAngle (void)
1396{
1397	if (G_FLOAT(OFS_PARM0) == MSG_ONE) {
1398		client_t *cl = Write_GetClient();
1399		ClientReliableCheckBlock(cl, 1);
1400		ClientReliableWrite_Angle(cl, G_FLOAT(OFS_PARM1));
1401	} else
1402		MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1403}
1404
1405void PF_WriteCoord (void)
1406{
1407	if (G_FLOAT(OFS_PARM0) == MSG_ONE) {
1408		client_t *cl = Write_GetClient();
1409		ClientReliableCheckBlock(cl, 2);
1410		ClientReliableWrite_Coord(cl, G_FLOAT(OFS_PARM1));
1411	} else
1412		MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1413}
1414
1415void PF_WriteString (void)
1416{
1417	if (G_FLOAT(OFS_PARM0) == MSG_ONE) {
1418		client_t *cl = Write_GetClient();
1419		ClientReliableCheckBlock(cl, 1+strlen(G_STRING(OFS_PARM1)));
1420		ClientReliableWrite_String(cl, G_STRING(OFS_PARM1));
1421	} else
1422		MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1423}
1424
1425
1426void PF_WriteEntity (void)
1427{
1428	if (G_FLOAT(OFS_PARM0) == MSG_ONE) {
1429		client_t *cl = Write_GetClient();
1430		ClientReliableCheckBlock(cl, 2);
1431		ClientReliableWrite_Short(cl, G_EDICTNUM(OFS_PARM1));
1432	} else
1433		MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1434}
1435
1436//=============================================================================
1437
1438int SV_ModelIndex (char *name);
1439
1440void PF_makestatic (void)
1441{
1442	edict_t	*ent;
1443	int		i;
1444
1445	ent = G_EDICT(OFS_PARM0);
1446
1447	MSG_WriteByte (&sv.signon,svc_spawnstatic);
1448
1449	MSG_WriteByte (&sv.signon, SV_ModelIndex(PR_GetString(ent->v.model)));
1450
1451	MSG_WriteByte (&sv.signon, ent->v.frame);
1452	MSG_WriteByte (&sv.signon, ent->v.colormap);
1453	MSG_WriteByte (&sv.signon, ent->v.skin);
1454	for (i=0 ; i<3 ; i++)
1455	{
1456		MSG_WriteCoord(&sv.signon, ent->v.origin[i]);
1457		MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
1458	}
1459
1460// throw the entity away now
1461	ED_Free (ent);
1462}
1463
1464//=============================================================================
1465
1466/*
1467==============
1468PF_setspawnparms
1469==============
1470*/
1471void PF_setspawnparms (void)
1472{
1473	edict_t	*ent;
1474	int		i;
1475	client_t	*client;
1476
1477	ent = G_EDICT(OFS_PARM0);
1478	i = NUM_FOR_EDICT(ent);
1479	if (i < 1 || i > MAX_CLIENTS)
1480		PR_RunError ("Entity is not a client");
1481
1482	// copy spawn parms out of the client_t
1483	client = svs.clients + (i-1);
1484
1485	for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1486		(&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1487}
1488
1489/*
1490==============
1491PF_changelevel
1492==============
1493*/
1494void PF_changelevel (void)
1495{
1496	char	*s;
1497	static	int	last_spawncount;
1498
1499// make sure we don't issue two changelevels
1500	if (svs.spawncount == last_spawncount)
1501		return;
1502	last_spawncount = svs.spawncount;
1503
1504	s = G_STRING(OFS_PARM0);
1505	Cbuf_AddText (va("map %s\n",s));
1506}
1507
1508
1509/*
1510==============
1511PF_logfrag
1512
1513logfrag (killer, killee)
1514==============
1515*/
1516void PF_logfrag (void)
1517{
1518	edict_t	*ent1, *ent2;
1519	int		e1, e2;
1520	char	*s;
1521
1522	ent1 = G_EDICT(OFS_PARM0);
1523	ent2 = G_EDICT(OFS_PARM1);
1524
1525	e1 = NUM_FOR_EDICT(ent1);
1526	e2 = NUM_FOR_EDICT(ent2);
1527
1528	if (e1 < 1 || e1 > MAX_CLIENTS
1529	|| e2 < 1 || e2 > MAX_CLIENTS)
1530		return;
1531
1532	s = va("\\%s\\%s\\\n",svs.clients[e1-1].name, svs.clients[e2-1].name);
1533
1534	SZ_Print (&svs.log[svs.logsequence&1], s);
1535	if (sv_fraglogfile) {
1536		fprintf (sv_fraglogfile, s);
1537		fflush (sv_fraglogfile);
1538	}
1539}
1540
1541
1542/*
1543==============
1544PF_infokey
1545
1546string(entity e, string key) infokey
1547==============
1548*/
1549void PF_infokey (void)
1550{
1551	edict_t	*e;
1552	int		e1;
1553	char	*value;
1554	char	*key;
1555	static	char ov[256];
1556
1557	e = G_EDICT(OFS_PARM0);
1558	e1 = NUM_FOR_EDICT(e);
1559	key = G_STRING(OFS_PARM1);
1560
1561	if (e1 == 0) {
1562		if ((value = Info_ValueForKey (svs.info, key)) == NULL ||
1563			!*value)
1564			value = Info_ValueForKey(localinfo, key);
1565	} else if (e1 <= MAX_CLIENTS) {
1566		if (!strcmp(key, "ip"))
1567			value = strcpy(ov, NET_BaseAdrToString (svs.clients[e1-1].netchan.remote_address));
1568		else if (!strcmp(key, "ping")) {
1569			int ping = SV_CalcPing (&svs.clients[e1-1]);
1570			sprintf(ov, "%d", ping);
1571			value = ov;
1572		} else
1573			value = Info_ValueForKey (svs.clients[e1-1].userinfo, key);
1574	} else
1575		value = "";
1576
1577	RETURN_STRING(value);
1578}
1579
1580/*
1581==============
1582PF_stof
1583
1584float(string s) stof
1585==============
1586*/
1587void PF_stof (void)
1588{
1589	char	*s;
1590
1591	s = G_STRING(OFS_PARM0);
1592
1593	G_FLOAT(OFS_RETURN) = atof(s);
1594}
1595
1596
1597/*
1598==============
1599PF_multicast
1600
1601void(vector where, float set) multicast
1602==============
1603*/
1604void PF_multicast (void)
1605{
1606	float	*o;
1607	int		to;
1608
1609	o = G_VECTOR(OFS_PARM0);
1610	to = G_FLOAT(OFS_PARM1);
1611
1612	SV_Multicast (o, to);
1613}
1614
1615
1616void PF_Fixme (void)
1617{
1618	PR_RunError ("unimplemented bulitin");
1619}
1620
1621
1622
1623builtin_t pr_builtin[] =
1624{
1625	PF_Fixme,
1626PF_makevectors,	// void(entity e)	makevectors 		= #1;
1627PF_setorigin,	// void(entity e, vector o) setorigin	= #2;
1628PF_setmodel,	// void(entity e, string m) setmodel	= #3;
1629PF_setsize,	// void(entity e, vector min, vector max) setsize = #4;
1630PF_Fixme,	// void(entity e, vector min, vector max) setabssize = #5;
1631PF_break,	// void() break						= #6;
1632PF_random,	// float() random						= #7;
1633PF_sound,	// void(entity e, float chan, string samp) sound = #8;
1634PF_normalize,	// vector(vector v) normalize			= #9;
1635PF_error,	// void(string e) error				= #10;
1636PF_objerror,	// void(string e) objerror				= #11;
1637PF_vlen,	// float(vector v) vlen				= #12;
1638PF_vectoyaw,	// float(vector v) vectoyaw		= #13;
1639PF_Spawn,	// entity() spawn						= #14;
1640PF_Remove,	// void(entity e) remove				= #15;
1641PF_traceline,	// float(vector v1, vector v2, float tryents) traceline = #16;
1642PF_checkclient,	// entity() clientlist					= #17;
1643PF_Find,	// entity(entity start, .string fld, string match) find = #18;
1644PF_precache_sound,	// void(string s) precache_sound		= #19;
1645PF_precache_model,	// void(string s) precache_model		= #20;
1646PF_stuffcmd,	// void(entity client, string s)stuffcmd = #21;
1647PF_findradius,	// entity(vector org, float rad) findradius = #22;
1648PF_bprint,	// void(string s) bprint				= #23;
1649PF_sprint,	// void(entity client, string s) sprint = #24;
1650PF_dprint,	// void(string s) dprint				= #25;
1651PF_ftos,	// void(string s) ftos				= #26;
1652PF_vtos,	// void(string s) vtos				= #27;
1653PF_coredump,
1654PF_traceon,
1655PF_traceoff,
1656PF_eprint,	// void(entity e) debug print an entire entity
1657PF_walkmove, // float(float yaw, float dist) walkmove
1658PF_Fixme, // float(float yaw, float dist) walkmove
1659PF_droptofloor,
1660PF_lightstyle,
1661PF_rint,
1662PF_floor,
1663PF_ceil,
1664PF_Fixme,
1665PF_checkbottom,
1666PF_pointcontents,
1667PF_Fixme,
1668PF_fabs,
1669PF_aim,
1670PF_cvar,
1671PF_localcmd,
1672PF_nextent,
1673PF_Fixme,
1674PF_changeyaw,
1675PF_Fixme,
1676PF_vectoangles,
1677
1678PF_WriteByte,
1679PF_WriteChar,
1680PF_WriteShort,
1681PF_WriteLong,
1682PF_WriteCoord,
1683PF_WriteAngle,
1684PF_WriteString,
1685PF_WriteEntity,
1686
1687PF_Fixme,
1688PF_Fixme,
1689PF_Fixme,
1690PF_Fixme,
1691PF_Fixme,
1692PF_Fixme,
1693PF_Fixme,
1694
1695SV_MoveToGoal,
1696PF_precache_file,
1697PF_makestatic,
1698
1699PF_changelevel,
1700PF_Fixme,
1701
1702PF_cvar_set,
1703PF_centerprint,
1704
1705PF_ambientsound,
1706
1707PF_precache_model,
1708PF_precache_sound,		// precache_sound2 is different only for qcc
1709PF_precache_file,
1710
1711PF_setspawnparms,
1712
1713PF_logfrag,
1714
1715PF_infokey,
1716PF_stof,
1717PF_multicast
1718};
1719
1720builtin_t *pr_builtins = pr_builtin;
1721int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
1722
1723