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