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