1 /*
2 	sv_pr_cmds.c
3 
4 	(description)
5 
6 	Copyright (C) 1996-1997  Id Software, Inc.
7 
8 	This program is free software; you can redistribute it and/or
9 	modify it under the terms of the GNU General Public License
10 	as published by the Free Software Foundation; either version 2
11 	of the License, or (at your option) any later version.
12 
13 	This program is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 	See the GNU General Public License for more details.
18 
19 	You should have received a copy of the GNU General Public License
20 	along with this program; if not, write to:
21 
22 		Free Software Foundation, Inc.
23 		59 Temple Place - Suite 330
24 		Boston, MA  02111-1307, USA
25 
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #endif
34 #ifdef HAVE_STRINGS_H
35 # include <strings.h>
36 #endif
37 #include <ctype.h>
38 
39 #include "QF/cbuf.h"
40 #include "QF/clip_hull.h"
41 #include "QF/cmd.h"
42 #include "QF/cvar.h"
43 #include "QF/msg.h"
44 #include "QF/ruamoko.h"
45 #include "QF/sys.h"
46 #include "QF/va.h"
47 
48 #include "compat.h"
49 #include "crudefile.h"
50 #include "server.h"
51 #include "sv_gib.h"
52 #include "sv_progs.h"
53 #include "sv_recorder.h"
54 #include "world.h"
55 
56 /* BUILT-IN FUNCTIONS */
57 
58 
59 /*
60 	PF_error
61 
62 	This is a TERMINAL error, which will kill off the entire server.
63 	Dumps self.
64 
65 	error (value)
66 	// void (string e) error
67 */
68 static void
PF_error(progs_t * pr)69 PF_error (progs_t *pr)
70 {
71 	const char *s;
72 	edict_t    *ed;
73 
74 	s = PF_VarString (pr, 0);
75 	Sys_Printf ("======SERVER ERROR in %s:\n%s\n",
76 				PR_GetString (pr, pr->pr_xfunction->descriptor->s_name), s);
77 	ed = PROG_TO_EDICT (pr, *sv_globals.self);
78 	ED_Print (pr, ed);
79 
80 	Sys_Error ("Program error");
81 }
82 
83 /*
84 	PF_objerror
85 
86 	Dumps out self, then an error message.  The program is aborted and self is
87 	removed, but the level can continue.
88 
89 	objerror (value)
90 	// void (string e) objerror
91 */
92 static void
PF_objerror(progs_t * pr)93 PF_objerror (progs_t *pr)
94 {
95 	const char *s;
96 	edict_t    *ed;
97 
98 	s = PF_VarString (pr, 0);
99 	Sys_Printf ("======OBJECT ERROR in %s:\n%s\n",
100 				PR_GetString (pr, pr->pr_xfunction->descriptor->s_name), s);
101 	ed = PROG_TO_EDICT (pr, *sv_globals.self);
102 	ED_Print (pr, ed);
103 	ED_Free (pr, ed);
104 
105 	PR_RunError (pr, "object error");
106 }
107 
108 /*
109 	PF_makevectors
110 
111 	Writes new values for v_forward, v_up, and v_right based on angles
112 	void (vector angles) makevectors
113 */
114 static void
PF_makevectors(progs_t * pr)115 PF_makevectors (progs_t *pr)
116 {
117 	AngleVectors (P_VECTOR (pr, 0), *sv_globals.v_forward,
118 				  *sv_globals.v_right, *sv_globals.v_up);
119 }
120 
121 /*
122 	PF_setorigin
123 
124 	This is the only valid way to move an object without using the physics of
125 	the world (setting velocity and waiting).  Directly changing origin will
126 	not set internal links correctly, so clipping would be messed up.  This
127 	should be called when an object is spawned, and then only if it is
128 	teleported.
129 
130 	setorigin (entity, origin)
131 	// void (entity e, vector o) setorigin
132 */
133 static void
PF_setorigin(progs_t * pr)134 PF_setorigin (progs_t *pr)
135 {
136 	edict_t    *e;
137 	float      *org;
138 
139 	e = P_EDICT (pr, 0);
140 	org = P_VECTOR (pr, 1);
141 	VectorCopy (org, SVvector (e, origin));
142 	SV_LinkEdict (e, false);
143 }
144 
145 /*
146 	PF_setsize
147 
148 	the size box is rotated by the current angle
149 
150 	setsize (entity, minvector, maxvector)
151 	// void (entity e, vector min, vector max) setsize
152 */
153 static void
PF_setsize(progs_t * pr)154 PF_setsize (progs_t *pr)
155 {
156 	edict_t    *e;
157 	float      *min, *max;
158 
159 	e = P_EDICT (pr, 0);
160 	min = P_VECTOR (pr, 1);
161 	max = P_VECTOR (pr, 2);
162 	VectorCopy (min, SVvector (e, mins));
163 	VectorCopy (max, SVvector (e, maxs));
164 	VectorSubtract (max, min, SVvector (e, size));
165 	SV_LinkEdict (e, false);
166 }
167 
168 /*
169 	PF_setmodel
170 
171 	setmodel (entity, model)
172 	// void (entity e, string m) setmodel
173 	Also sets size, mins, and maxs for inline bmodels
174 */
175 static void
PF_setmodel(progs_t * pr)176 PF_setmodel (progs_t *pr)
177 {
178 	edict_t    *e;
179 	const char *m, **check;
180 	int         i;
181 	model_t    *mod;
182 
183 	e = P_EDICT (pr, 0);
184 	m = P_GSTRING (pr, 1);
185 
186 	// check to see if model was properly precached
187 	for (i = 0, check = sv.model_precache; *check; i++, check++)
188 		if (!strcmp (*check, m))
189 			break;
190 
191 	if (!*check)
192 		PR_RunError (pr, "no precache: %s\n", m);
193 
194 	SVstring (e, model) = PR_SetString (pr, m);
195 	SVfloat (e, modelindex) = i;
196 
197 	// if it is an inline model, get the size information for it
198 	if (m[0] == '*') {
199 		mod = Mod_ForName (m, true);
200 		VectorCopy (mod->mins, SVvector (e, mins));
201 		VectorCopy (mod->maxs, SVvector (e, maxs));
202 		VectorSubtract (mod->maxs, mod->mins, SVvector (e, size));
203 		SV_LinkEdict (e, false);
204 	}
205 }
206 
207 /*
208 	PF_bprint
209 
210 	broadcast print to everyone on server
211 
212 	bprint (value)
213 	// void (string s) bprint
214 */
215 static void
PF_bprint(progs_t * pr)216 PF_bprint (progs_t *pr)
217 {
218 	const char *s;
219 	int         level;
220 
221 	level = P_FLOAT (pr, 0);
222 
223 	s = PF_VarString (pr, 1);
224 	SV_BroadcastPrintf (level, "%s", s);
225 }
226 
227 /*
228 	PF_sprint
229 
230 	single print to a specific client
231 
232 	sprint (clientent, value)
233 	// void (entity client, string s) sprint
234 */
235 static void
PF_sprint(progs_t * pr)236 PF_sprint (progs_t *pr)
237 {
238 	const char *s;
239 	client_t   *client;
240 	int         entnum, level;
241 
242 	entnum = P_EDICTNUM (pr, 0);
243 	level = P_FLOAT (pr, 1);
244 
245 	if (entnum < 1 || entnum > MAX_CLIENTS) {
246 		Sys_Printf ("tried to sprint to a non-client\n");
247 		return;
248 	}
249 
250 	client = &svs.clients[entnum - 1];
251 
252 	if (client->state == cs_server) //FIXME record to mvd?
253 		return;
254 
255 	s = PF_VarString (pr, 2);
256 
257 	SV_ClientPrintf (1, client, level, "%s", s);
258 }
259 
260 /*
261 	PF_centerprint
262 
263 	single print to a specific client
264 
265 	centerprint (clientent, value)
266 	// void (...) centerprint
267 */
268 static void
PF_centerprint(progs_t * pr)269 PF_centerprint (progs_t *pr)
270 {
271 	const char *s;
272 	client_t   *cl;
273 	int         entnum;
274 
275 	entnum = P_EDICTNUM (pr, 0);
276 
277 	if (entnum < 1 || entnum > MAX_CLIENTS) {
278 		Sys_Printf ("tried to sprint to a non-client\n");
279 		return;
280 	}
281 
282 	cl = &svs.clients[entnum - 1];
283 
284 	if (cl->state == cs_server) //FIXME record to mvd?
285 		return;
286 
287 	s = PF_VarString (pr, 1);
288 
289 	MSG_ReliableWrite_Begin (&cl->backbuf, svc_centerprint, 2 + strlen (s));
290 	MSG_ReliableWrite_String (&cl->backbuf, s);
291 
292 	if (sv.recorders) {
293 		sizebuf_t  *dbuf;
294 		dbuf = SVR_WriteBegin (dem_single, entnum - 1, 2 + strlen (s));
295 		MSG_WriteByte (dbuf, svc_centerprint);
296 		MSG_WriteString (dbuf, s);
297 	}
298 }
299 
300 /*
301 	PF_ambientsound
302 	// void (vector pos, string samp, float vol, float atten) ambientsound
303 */
304 static void
PF_ambientsound(progs_t * pr)305 PF_ambientsound (progs_t *pr)
306 {
307 	const char **check;
308 	const char *samp;
309 	float      *pos;
310 	float       vol, attenuation;
311 	int         soundnum;
312 
313 	pos = P_VECTOR (pr, 0);
314 	samp = P_GSTRING (pr, 1);
315 	vol = P_FLOAT (pr, 2);
316 	attenuation = P_FLOAT (pr, 3);
317 
318 	// check to see if samp was properly precached
319 	for (soundnum = 0, check = sv.sound_precache; *check; check++, soundnum++)
320 		if (!strcmp (*check, samp))
321 			break;
322 
323 	if (!*check) {
324 		Sys_Printf ("no precache: %s\n", samp);
325 		return;
326 	}
327 
328 	// add an svc_spawnambient command to the level signon packet
329 	MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
330 	MSG_WriteCoordV (&sv.signon, pos);
331 	MSG_WriteByte (&sv.signon, soundnum);
332 	MSG_WriteByte (&sv.signon, vol * 255);
333 	MSG_WriteByte (&sv.signon, attenuation * 64);
334 
335 }
336 
337 /*
338 	PF_sound
339 
340 	Each entity can have eight independant sound sources, like voice,
341 	weapon, feet, etc.
342 
343 	Channel 0 is an auto-allocate channel, the others override anything
344 	already running on that entity/channel pair.
345 
346 	An attenuation of 0 will play full volume everywhere in the level.
347 	Larger attenuations will drop off.
348 	// void (entity e, float chan, string samp) sound
349 */
350 static void
PF_sound(progs_t * pr)351 PF_sound (progs_t *pr)
352 {
353 	const char *sample;
354 	edict_t    *entity;
355 	float       attenuation;
356 	int         channel, volume;
357 
358 	entity = P_EDICT (pr, 0);
359 	channel = P_FLOAT (pr, 1);
360 	sample = P_GSTRING (pr, 2);
361 	volume = P_FLOAT (pr, 3) * 255;
362 	attenuation = P_FLOAT (pr, 4);
363 
364 	SV_StartSound (entity, channel, sample, volume, attenuation);
365 }
366 
367 /*
368 	PF_traceline
369 
370 	Used for use tracing and shot targeting.
371 	Traces are blocked by bbox and exact bsp entityes, and also slide box
372 	entities if the tryents flag is set.
373 
374 	traceline (vector1, vector2, tryents)
375 	// float (vector v1, vector v2, float tryents) traceline
376 */
377 static void
PF_traceline(progs_t * pr)378 PF_traceline (progs_t *pr)
379 {
380 	float      *v1, *v2;
381 	edict_t    *ent;
382 	int         nomonsters;
383 	trace_t     trace;
384 
385 	v1 = P_VECTOR (pr, 0);
386 	v2 = P_VECTOR (pr, 1);
387 	nomonsters = P_FLOAT (pr, 2);
388 	ent = P_EDICT (pr, 3);
389 
390 	if (sv_antilag->int_val == 2)
391 		nomonsters |= MOVE_LAGGED;
392 
393 	trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
394 
395 	*sv_globals.trace_allsolid = trace.allsolid;
396 	*sv_globals.trace_startsolid = trace.startsolid;
397 	*sv_globals.trace_fraction = trace.fraction;
398 	*sv_globals.trace_inwater = trace.inwater;
399 	*sv_globals.trace_inopen = trace.inopen;
400 	VectorCopy (trace.endpos, *sv_globals.trace_endpos);
401 	VectorCopy (trace.plane.normal, *sv_globals.trace_plane_normal);
402 	*sv_globals.trace_plane_dist = trace.plane.dist;
403 
404 	if (trace.ent)
405 		*sv_globals.trace_ent = EDICT_TO_PROG (pr, trace.ent);
406 	else
407 		*sv_globals.trace_ent = EDICT_TO_PROG (pr, sv.edicts);
408 }
409 
410 /*
411 	PF_tracebox
412 	// void (vector start, vector mins, vector maxs, vector end, float type,
413 	//       entity passent) tracebox
414 
415 	Wrapper around SV_Move, this makes PF_movetoground and PF_traceline
416 	redundant.
417 */
418 static void
PF_tracebox(progs_t * pr)419 PF_tracebox (progs_t *pr)
420 {
421 	edict_t    *ent;
422 	float      *start, *end, *mins, *maxs;
423 	int         type;
424 	trace_t     trace;
425 
426 	start = P_VECTOR (pr, 0);
427 	mins = P_VECTOR (pr, 1);
428 	maxs = P_VECTOR (pr, 2);
429 	end = P_VECTOR (pr, 3);
430 	type = P_FLOAT (pr, 4);
431 	ent = P_EDICT (pr, 5);
432 
433 	trace = SV_Move (start, mins, maxs, end, type, ent);
434 
435 	*sv_globals.trace_allsolid = trace.allsolid;
436 	*sv_globals.trace_startsolid = trace.startsolid;
437 	*sv_globals.trace_fraction = trace.fraction;
438 	*sv_globals.trace_inwater = trace.inwater;
439 	*sv_globals.trace_inopen = trace.inopen;
440 	VectorCopy (trace.endpos, *sv_globals.trace_endpos);
441 	VectorCopy (trace.plane.normal, *sv_globals.trace_plane_normal);
442 	*sv_globals.trace_plane_dist = trace.plane.dist;
443 	if (trace.ent)
444 		*sv_globals.trace_ent = EDICT_TO_PROG (pr, trace.ent);
445 	else
446 		*sv_globals.trace_ent = EDICT_TO_PROG (pr, sv.edicts);
447 }
448 
449 /*
450 	PF_checkpos
451 
452 	Returns true if the given entity can move to the given position from it's
453 	current position by walking or rolling.
454 	FIXME: make work...
455 	scalar checkpos (entity, vector)
456 */
457 static void __attribute__ ((used))
PF_checkpos(progs_t * pr)458 PF_checkpos (progs_t *pr)
459 {
460 }
461 
462 byte        checkpvs[MAX_MAP_LEAFS / 8];
463 
464 static int
PF_newcheckclient(progs_t * pr,int check)465 PF_newcheckclient (progs_t *pr, int check)
466 {
467 	byte       *pvs;
468 	edict_t    *ent;
469 	int         i;
470 	mleaf_t    *leaf;
471 	vec3_t      org;
472 
473 	// cycle to the next one
474 	if (check < 1)
475 		check = 1;
476 	if (check > MAX_CLIENTS)
477 		check = MAX_CLIENTS;
478 
479 	if (check == MAX_CLIENTS)
480 		i = 1;
481 	else
482 		i = check + 1;
483 
484 	for (;; i++) {
485 		if (i == MAX_CLIENTS + 1)
486 			i = 1;
487 
488 		ent = EDICT_NUM (pr, i);
489 
490 		if (i == check)
491 			break;						// didn't find anything else
492 
493 		if (ent->free)
494 			continue;
495 		if (SVfloat (ent, health) <= 0)
496 			continue;
497 		if ((int) SVfloat (ent, flags) & FL_NOTARGET)
498 			continue;
499 
500 		// anything that is a client, or has a client as an enemy
501 		break;
502 	}
503 
504 	// get the PVS for the entity
505 	VectorAdd (SVvector (ent, origin), SVvector (ent, view_ofs), org);
506 	leaf = Mod_PointInLeaf (org, sv.worldmodel);
507 	pvs = Mod_LeafPVS (leaf, sv.worldmodel);
508 	memcpy (checkpvs, pvs, (sv.worldmodel->numleafs + 7) >> 3);
509 
510 	return i;
511 }
512 
513 #define	MAX_CHECK	16
514 int         c_invis, c_notvis;
515 
516 /*
517 	PF_checkclient
518 
519 	Returns a client (or object that has a client enemy) that would be a
520 	valid target.
521 
522 	If there are more than one valid options, they are cycled each frame
523 
524 	If (self.origin + self.viewofs) is not in the PVS of the current target,
525 	it is not returned at all.
526 
527 	name checkclient ()
528 	// entity () clientlist
529 */
530 static void
PF_checkclient(progs_t * pr)531 PF_checkclient (progs_t *pr)
532 {
533 	edict_t    *ent, *self;
534 	int         l;
535 	mleaf_t    *leaf;
536 	vec3_t      view;
537 
538 	// find a new check if on a new frame
539 	if (sv.time - sv.lastchecktime >= 0.1) {
540 		sv.lastcheck = PF_newcheckclient (pr, sv.lastcheck);
541 		sv.lastchecktime = sv.time;
542 	}
543 	// return check if it might be visible
544 	ent = EDICT_NUM (pr, sv.lastcheck);
545 	if (ent->free || SVfloat (ent, health) <= 0) {
546 		RETURN_EDICT (pr, sv.edicts);
547 		return;
548 	}
549 	// if current entity can't possibly see the check entity, return 0
550 	self = PROG_TO_EDICT (pr, *sv_globals.self);
551 	VectorAdd (SVvector (self, origin), SVvector (self, view_ofs), view);
552 	leaf = Mod_PointInLeaf (view, sv.worldmodel);
553 	l = (leaf - sv.worldmodel->leafs) - 1;
554 	if ((l < 0) || !(checkpvs[l >> 3] & (1 << (l & 7)))) {
555 		c_notvis++;
556 		RETURN_EDICT (pr, sv.edicts);
557 		return;
558 	}
559 	// might be able to see it
560 	c_invis++;
561 	RETURN_EDICT (pr, ent);
562 }
563 
564 /*
565 	PF_stuffcmd
566 
567 	Sends text over to the client's execution buffer
568 
569 	stuffcmd (clientent, value)
570 	// void (entity client, string s) stuffcmd
571 */
572 static void
PF_stuffcmd(progs_t * pr)573 PF_stuffcmd (progs_t *pr)
574 {
575 	const char *str;
576 	char       *buf, *p;
577 	client_t   *cl;
578 	int         entnum;
579 
580 	entnum = P_EDICTNUM (pr, 0);
581 	if (entnum < 1 || entnum > MAX_CLIENTS)
582 		PR_RunError (pr, "Parm 0 not a client");
583 
584 	cl = &svs.clients[entnum - 1];
585 
586 	if (cl->state == cs_server) //FIXME record to mvd?
587 		return;
588 
589 	str = P_GSTRING (pr, 1);
590 
591 	buf = cl->stufftext_buf;
592 	if (strlen (buf) + strlen (str) >= MAX_STUFFTEXT)
593 		PR_RunError (pr, "stufftext buffer overflow");
594 	strcat (buf, str);
595 
596 	if (!strcmp (buf, "disconnect\n")) {
597 		// so long and thanks for all the fish
598 		cl->drop = true;
599 		buf[0] = 0;
600 		return;
601 	}
602 
603 	p = strrchr (buf, '\n');
604 	if (p) {
605 		char        t = p[1];
606 		int         len = (p - buf) + 2;
607 		p[1] = 0;
608 		MSG_ReliableWrite_Begin (&cl->backbuf, svc_stufftext, len + 1);
609 		MSG_ReliableWrite_String (&cl->backbuf, buf);
610 		if (sv.recorders) {
611 			sizebuf_t  *dbuf;
612 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, len + 1);
613 			MSG_WriteByte (dbuf, svc_stufftext);
614 			MSG_WriteString (dbuf, buf);
615 		}
616 		p[1] = t;
617 		strcpy (buf, p + 1);		// safe because this is a downward, in
618 									// buffer move
619 	}
620 }
621 
622 /*
623 	PF_localcmd
624 
625 	Inserts text into the server console's execution buffer
626 
627 	localcmd (string)
628 	// void (string s) localcmd
629 */
630 static void
PF_localcmd(progs_t * pr)631 PF_localcmd (progs_t *pr)
632 {
633 	const char       *str;
634 
635 	str = P_GSTRING (pr, 0);
636 	Cbuf_AddText (sv_cbuf, str);
637 }
638 
639 /*
640 	PF_findradius
641 
642 	Returns a chain of entities that have origins within a spherical area
643 
644 	findradius (origin, radius)
645 	// entity (vector org, float rad) findradius
646 */
647 static void
PF_findradius(progs_t * pr)648 PF_findradius (progs_t *pr)
649 {
650 	edict_t    *ent, *chain;
651 	float       rsqr;
652 	vec_t      *emins, *emaxs, *org;
653 	int         i, j;
654 	vec3_t      eorg;
655 
656 	chain = (edict_t *) sv.edicts;
657 
658 	org = P_VECTOR (pr, 0);
659 	rsqr = P_FLOAT (pr, 1);
660 	rsqr *= rsqr;					// Square early, sqrt never
661 
662 	ent = NEXT_EDICT (pr, sv.edicts);
663 	for (i = 1; i < sv.num_edicts; i++, ent = NEXT_EDICT (pr, ent)) {
664 		if (ent->free)
665 			continue;
666 		if (SVfloat (ent, solid) == SOLID_NOT
667 			&& !((int) SVfloat (ent, flags) & FL_FINDABLE_NONSOLID))
668 			continue;
669 		emins = SVvector (ent, absmin);
670 		emaxs = SVvector (ent, absmax);
671 		for (j = 0; j < 3; j++)
672 			eorg[j] = org[j] - 0.5 * (emins[j] + emaxs[j]);
673 		if (DotProduct (eorg, eorg) > rsqr)
674 			continue;
675 
676 		SVentity (ent, chain) = EDICT_TO_PROG (pr, chain);
677 		chain = ent;
678 	}
679 
680 	RETURN_EDICT (pr, chain);
681 }
682 
683 // entity () spawn
684 static void
PF_Spawn(progs_t * pr)685 PF_Spawn (progs_t *pr)
686 {
687 	edict_t    *ed;
688 
689 	ed = ED_Alloc (pr);
690 	RETURN_EDICT (pr, ed);
691 }
692 
693 cvar_t *pr_double_remove;
694 
695 // void (entity e) remove
696 static void
PF_Remove(progs_t * pr)697 PF_Remove (progs_t *pr)
698 {
699 	edict_t    *ed;
700 
701 	ed = P_EDICT (pr, 0);
702 	if (NUM_FOR_EDICT (pr, ed) < *pr->reserved_edicts) {
703 		if (pr_double_remove->int_val == 1) {
704 			PR_DumpState (pr);
705 			Sys_Printf ("Reserved entity remove\n");
706 		} else // == 2
707 			PR_RunError (pr, "Reserved entity remove\n");
708 	}
709 	if (ed->free && pr_double_remove->int_val) {
710 		if (pr_double_remove->int_val == 1) {
711 			PR_DumpState (pr);
712 			Sys_Printf ("Double entity remove\n");
713 		} else // == 2
714 			PR_RunError (pr, "Double entity remove\n");
715 	}
716 	ED_Free (pr, ed);
717 }
718 
719 static void
PR_CheckEmptyString(progs_t * pr,const char * s)720 PR_CheckEmptyString (progs_t *pr, const char *s)
721 {
722 	if (s[0] <= ' ')
723 		PR_RunError (pr, "Bad string");
724 }
725 
726 static void
do_precache(progs_t * pr,const char ** cache,int max,const char * name,const char * func)727 do_precache (progs_t *pr, const char **cache, int max, const char *name,
728 			 const char *func)
729 {
730 	int         i;
731 	char       *s;
732 
733 	if (sv.state != ss_loading)
734 		PR_RunError (pr, "%s: Precache can be done only in spawn functions",
735 					 func);
736 
737 	PR_CheckEmptyString (pr, name);
738 
739 	s = Hunk_TempAlloc (strlen (name) + 1);
740 	for (i = 0; *name; i++, name++) {
741 		int         c = (byte) *name;
742 		s[i] = tolower (c);
743 	}
744 	s[i] = 0;
745 
746 	for (i = 0; i < MAX_SOUNDS; i++) {
747 		if (!cache[i]) {
748 			char *c = Hunk_Alloc (strlen (s) + 1);
749 			strcpy (c, s);
750 			cache[i] = c; // blah, const
751 			Sys_MaskPrintf (SYS_DEV, "%s: %3d %s\n", func, i, s);
752 			return;
753 		}
754 		if (!strcmp (cache[i], s))
755 			return;
756 	}
757 	PR_RunError (pr, "%s: overflow", func);
758 }
759 
760 // string (string s) precache_file
761 // string (string s) precache_file2
762 static void
PF_precache_file(progs_t * pr)763 PF_precache_file (progs_t *pr)
764 {
765 	// precache_file is used only to copy files with qcc, it does nothing
766 	R_INT (pr) = P_INT (pr, 0);
767 }
768 
769 // void (string s) precache_sound
770 // string (string s) precache_sound2
771 static void
PF_precache_sound(progs_t * pr)772 PF_precache_sound (progs_t *pr)
773 {
774 	do_precache (pr, sv.sound_precache, MAX_SOUNDS, P_GSTRING (pr, 0),
775 				 "precache_sound");
776 	R_INT (pr) = P_INT (pr, 0);
777 }
778 
779 // void (string s) precache_model
780 // string (string s) precache_model2
781 static void
PF_precache_model(progs_t * pr)782 PF_precache_model (progs_t *pr)
783 {
784 	do_precache (pr, sv.model_precache, MAX_MODELS, P_GSTRING (pr, 0),
785 				 "precache_model");
786 	R_INT (pr) = P_INT (pr, 0);
787 }
788 
789 /*
790 	PF_walkmove
791 
792 	float (float yaw, float dist) walkmove
793 	// float (float yaw, float dist) walkmove
794 */
795 static void
PF_walkmove(progs_t * pr)796 PF_walkmove (progs_t *pr)
797 {
798 	edict_t    *ent;
799 	float       yaw, dist;
800 	int         oldself;
801 	vec3_t      move;
802 
803 	ent = PROG_TO_EDICT (pr, *sv_globals.self);
804 	yaw = P_FLOAT (pr, 0);
805 	dist = P_FLOAT (pr, 1);
806 
807 	if (!((int) SVfloat (ent, flags) & (FL_ONGROUND | FL_FLY | FL_SWIM))) {
808 		R_FLOAT (pr) = 0;
809 		return;
810 	}
811 
812 	yaw = yaw * M_PI * 2 / 360;
813 
814 	move[0] = cos (yaw) * dist;
815 	move[1] = sin (yaw) * dist;
816 	move[2] = 0;
817 
818 	// save program state, because SV_movestep may call other progs
819 	oldself = *sv_globals.self;
820 
821 	R_FLOAT (pr) = SV_movestep (ent, move, true);
822 
823 	// restore program state
824 	*sv_globals.self = oldself;
825 }
826 
827 /*
828 	PF_droptofloor
829 
830 	void () droptofloor
831 	// float () droptofloor
832 */
833 static void
PF_droptofloor(progs_t * pr)834 PF_droptofloor (progs_t *pr)
835 {
836 	edict_t    *ent;
837 	trace_t     trace;
838 	vec3_t      end;
839 
840 	ent = PROG_TO_EDICT (pr, *sv_globals.self);
841 
842 	VectorCopy (SVvector (ent, origin), end);
843 	end[2] -= 256;
844 
845 	trace = SV_Move (SVvector (ent, origin), SVvector (ent, mins),
846 					 SVvector (ent, maxs), end, false, ent);
847 
848 	if (trace.fraction == 1 || trace.allsolid) {
849 		R_FLOAT (pr) = 0;
850 	} else {
851 		VectorCopy (trace.endpos, SVvector (ent, origin));
852 		SV_LinkEdict (ent, false);
853 		SVfloat (ent, flags) = (int) SVfloat (ent, flags) | FL_ONGROUND;
854 		SVentity (ent, groundentity) = EDICT_TO_PROG (pr, trace.ent);
855 		R_FLOAT (pr) = 1;
856 	}
857 }
858 
859 /*
860 	PF_lightstyle
861 
862 	void (float style, string value) lightstyle
863 	// void (float style, string value) lightstyle
864 */
865 static void
PF_lightstyle(progs_t * pr)866 PF_lightstyle (progs_t *pr)
867 {
868 	const char *val;
869 	client_t   *cl;
870 	int         style, j;
871 
872 	style = P_FLOAT (pr, 0);
873 	val = P_GSTRING (pr, 1);
874 
875 	// change the string in sv
876 	sv.lightstyles[style] = val;
877 
878 	// send message to all clients on this server
879 	if (sv.state != ss_active)
880 		return;
881 
882 	for (j = 0, cl = svs.clients; j < MAX_CLIENTS; j++, cl++)
883 		if (cl->state == cs_spawned) {
884 			MSG_ReliableWrite_Begin (&cl->backbuf, svc_lightstyle,
885 									   strlen (val) + 3);
886 			MSG_ReliableWrite_Char (&cl->backbuf, style);
887 			MSG_ReliableWrite_String (&cl->backbuf, val);
888 		}
889 	if (sv.recorders) {
890 		sizebuf_t  *dbuf;
891 		dbuf = SVR_WriteBegin (dem_all, 0, strlen (val) + 3);
892 		MSG_WriteByte (dbuf, svc_lightstyle);
893 		MSG_WriteByte (dbuf, style);
894 		MSG_WriteString (dbuf, val);
895 	}
896 }
897 
898 // float (entity e) checkbottom
899 static void
PF_checkbottom(progs_t * pr)900 PF_checkbottom (progs_t *pr)
901 {
902 	edict_t    *ent;
903 
904 	ent = P_EDICT (pr, 0);
905 
906 	R_FLOAT (pr) = SV_CheckBottom (ent);
907 }
908 
909 // float (vector v) pointcontents
910 static void
PF_pointcontents(progs_t * pr)911 PF_pointcontents (progs_t *pr)
912 {
913 	float      *v;
914 
915 	v = P_VECTOR (pr, 0);
916 
917 	R_FLOAT (pr) = SV_PointContents (v);
918 }
919 
920 cvar_t     *sv_aim;
921 
922 /*
923 	PF_aim
924 
925 	Pick a vector for the player to shoot along
926 	vector aim (entity, missilespeed)
927 	// vector (entity e, float speed) aim
928 */
929 static void
PF_aim(progs_t * pr)930 PF_aim (progs_t *pr)
931 {
932 	const char *noaim;
933 	edict_t    *ent, *check, *bestent;
934 	float       dist, bestdist, speed;
935 	float      *mins, *maxs, *org;
936 	int         i, j;
937 	trace_t     tr;
938 	vec3_t      start, dir, end, bestdir;
939 
940 	if (sv_aim->value >= 1.0) {
941 		VectorCopy (*sv_globals.v_forward, R_VECTOR (pr));
942 		return;
943 	}
944 
945 	ent = P_EDICT (pr, 0);
946 	// noaim option
947 	i = NUM_FOR_EDICT (pr, ent);
948 	if (i > 0 && i < MAX_CLIENTS) {
949 		noaim = Info_ValueForKey (svs.clients[i - 1].userinfo, "noaim");
950 		if (atoi (noaim) > 0) {
951 			VectorCopy (*sv_globals.v_forward, R_VECTOR (pr));
952 			return;
953 		}
954 	}
955 
956 	speed = P_FLOAT (pr, 1);
957 	(void) speed; //FIXME
958 
959 	VectorCopy (SVvector (ent, origin), start);
960 	start[2] += 20;
961 
962 	// try sending a trace straight
963 	VectorCopy (*sv_globals.v_forward, dir);
964 	VectorMultAdd (start, 2048, dir, end);
965 	tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
966 	if (tr.ent && SVfloat (tr.ent, takedamage) == DAMAGE_AIM
967 		&& (!teamplay->int_val || SVfloat (ent, team) <= 0
968 			|| SVfloat (ent, team) != SVfloat (tr.ent, team))) {
969 		VectorCopy (*sv_globals.v_forward, R_VECTOR (pr));
970 		return;
971 	}
972 
973 	// try all possible entities
974 	VectorCopy (dir, bestdir);
975 	bestdist = sv_aim->value;
976 	bestent = NULL;
977 
978 	check = NEXT_EDICT (pr, sv.edicts);
979 	for (i = 1; i < sv.num_edicts; i++, check = NEXT_EDICT (pr, check)) {
980 		if (SVfloat (check, takedamage) != DAMAGE_AIM)
981 			continue;
982 		if (check == ent)
983 			continue;
984 		if (teamplay->int_val && SVfloat (ent, team) > 0
985 			&& SVfloat (ent, team) == SVfloat (check, team))
986 			continue;	// don't aim at teammate
987 
988 		mins = SVvector (check, mins);
989 		maxs = SVvector (check, maxs);
990 		org = SVvector (check, origin);
991 		for (j = 0; j < 3; j++)
992 			end[j] = org[j] + 0.5 * (mins[j] + maxs[j]);
993 		VectorSubtract (end, start, dir);
994 		VectorNormalize (dir);
995 		dist = DotProduct (dir, *sv_globals.v_forward);
996 		if (dist < bestdist)
997 			continue;					// to far to turn
998 		tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
999 		if (tr.ent == check) {			// can shoot at this one
1000 			bestdist = dist;
1001 			bestent = check;
1002 		}
1003 	}
1004 
1005 	if (bestent) {
1006 		VectorSubtract (SVvector (bestent, origin), SVvector (ent, origin),
1007 						dir);
1008 		dist = DotProduct (dir, *sv_globals.v_forward);
1009 		VectorScale (*sv_globals.v_forward, dist, end);
1010 		end[2] = dir[2];
1011 		VectorNormalize (end);
1012 		VectorCopy (end, R_VECTOR (pr));
1013 	} else {
1014 		VectorCopy (bestdir, R_VECTOR (pr));
1015 	}
1016 }
1017 
1018 /*
1019 	PF_changeyaw
1020 
1021 	This was a major timewaster in progs, so it was converted to C
1022 	// void () ChangeYaw
1023 */
1024 void
PF_changeyaw(progs_t * pr)1025 PF_changeyaw (progs_t *pr)
1026 {
1027 	edict_t    *ent;
1028 	float       ideal, current, move, speed;
1029 
1030 	ent = PROG_TO_EDICT (pr, *sv_globals.self);
1031 	current = anglemod (SVvector (ent, angles)[1]);
1032 	ideal = SVfloat (ent, ideal_yaw);
1033 	speed = SVfloat (ent, yaw_speed);
1034 
1035 	if (current == ideal)
1036 		return;
1037 	move = ideal - current;
1038 	if (ideal > current) {
1039 		if (move >= 180)
1040 			move = move - 360;
1041 	} else {
1042 		if (move <= -180)
1043 			move = move + 360;
1044 	}
1045 	if (move > 0) {
1046 		if (move > speed)
1047 			move = speed;
1048 	} else {
1049 		if (move < -speed)
1050 			move = -speed;
1051 	}
1052 
1053 	SVvector (ent, angles)[1] = anglemod (current + move);
1054 }
1055 
1056 /* MESSAGE WRITING */
1057 
1058 #define	MSG_BROADCAST	0				// unreliable to all
1059 #define	MSG_ONE			1				// reliable to one (msg_entity)
1060 #define	MSG_ALL			2				// reliable to all
1061 #define	MSG_INIT		3				// write to the init string
1062 #define	MSG_MULTICAST	4				// for multicast ()
1063 
1064 static sizebuf_t *
WriteDest(progs_t * pr)1065 WriteDest (progs_t *pr)
1066 {
1067 	int         dest;
1068 
1069 	dest = P_FLOAT (pr, 0);
1070 	switch (dest) {
1071 		case MSG_BROADCAST:
1072 			return &sv.datagram;
1073 
1074 		case MSG_ONE:
1075 			Sys_Error ("Shouldn't be at MSG_ONE");
1076 
1077 		case MSG_ALL:
1078 			return &sv.reliable_datagram;
1079 
1080 		case MSG_INIT:
1081 			if (sv.state != ss_loading)
1082 				PR_RunError (pr, "PF_Write_*: MSG_INIT can be written in only "
1083 							 "spawn functions");
1084 			return &sv.signon;
1085 
1086 		case MSG_MULTICAST:
1087 			return &sv.multicast;
1088 
1089 		default:
1090 			PR_RunError (pr, "WriteDest: bad destination");
1091 			break;
1092 	}
1093 
1094 	return NULL;
1095 }
1096 
1097 static client_t *
Write_GetClient(progs_t * pr)1098 Write_GetClient (progs_t *pr)
1099 {
1100 	edict_t    *ent;
1101 	int         entnum;
1102 
1103 	ent = PROG_TO_EDICT (pr, *sv_globals.msg_entity);
1104 	entnum = NUM_FOR_EDICT (pr, ent);
1105 	if (entnum < 1 || entnum > MAX_CLIENTS)
1106 		PR_RunError (pr, "Write_GetClient: not a client");
1107 	return &svs.clients[entnum - 1];
1108 }
1109 
1110 // void (float to, ...) WriteBytes
1111 static void
PF_WriteBytes(progs_t * pr)1112 PF_WriteBytes (progs_t *pr)
1113 {
1114 	int         i, p;
1115 	int         count = pr->pr_argc - 1;
1116 	byte        buf[MAX_PARMS];
1117 
1118 	for (i = 0; i < count; i++) {
1119 		p = P_FLOAT (pr, i + 1);
1120 		buf[i] = p;
1121 	}
1122 
1123 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1124 		client_t   *cl = Write_GetClient (pr);
1125 
1126 		if (cl->state != cs_server) {
1127 			MSG_ReliableCheckBlock (&cl->backbuf, count);
1128 			MSG_ReliableWrite_SZ (&cl->backbuf, buf, count);
1129 		}
1130 		if (sv.recorders) {
1131 			sizebuf_t  *dbuf;
1132 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, count);
1133 			SZ_Write (dbuf, buf, count);
1134 		}
1135 	} else {
1136 		sizebuf_t  *msg = WriteDest (pr);
1137 		SZ_Write (msg, buf, count);
1138 	}
1139 }
1140 
1141 // void (float to, float f) WriteByte
1142 static void
PF_WriteByte(progs_t * pr)1143 PF_WriteByte (progs_t *pr)
1144 {
1145 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1146 		client_t   *cl = Write_GetClient (pr);
1147 
1148 		if (cl->state != cs_server) {
1149 			MSG_ReliableCheckBlock (&cl->backbuf, 1);
1150 			MSG_ReliableWrite_Byte (&cl->backbuf, P_FLOAT (pr, 1));
1151 		}
1152 		if (sv.recorders) {
1153 			sizebuf_t  *dbuf;
1154 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
1155 			MSG_WriteByte (dbuf, P_FLOAT (pr, 1));
1156 		}
1157 	} else
1158 		MSG_WriteByte (WriteDest (pr), P_FLOAT (pr, 1));
1159 }
1160 
1161 // void (float to, float f) WriteChar
1162 static void
PF_WriteChar(progs_t * pr)1163 PF_WriteChar (progs_t *pr)
1164 {
1165 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1166 		client_t   *cl = Write_GetClient (pr);
1167 
1168 		if (cl->state != cs_server) {
1169 			MSG_ReliableCheckBlock (&cl->backbuf, 1);
1170 			MSG_ReliableWrite_Char (&cl->backbuf, P_FLOAT (pr, 1));
1171 		}
1172 		if (sv.recorders) {
1173 			sizebuf_t  *dbuf;
1174 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
1175 			MSG_WriteByte (dbuf, P_FLOAT (pr, 1));
1176 		}
1177 	} else
1178 		MSG_WriteByte (WriteDest (pr), P_FLOAT (pr, 1));
1179 }
1180 
1181 // void (float to, float f) WriteShort
1182 static void
PF_WriteShort(progs_t * pr)1183 PF_WriteShort (progs_t *pr)
1184 {
1185 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1186 		client_t   *cl = Write_GetClient (pr);
1187 
1188 		if (cl->state != cs_server) {
1189 			MSG_ReliableCheckBlock (&cl->backbuf, 2);
1190 			MSG_ReliableWrite_Short (&cl->backbuf, P_FLOAT (pr, 1));
1191 		}
1192 		if (sv.recorders) {
1193 			sizebuf_t  *dbuf;
1194 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
1195 			MSG_WriteShort (dbuf, P_FLOAT (pr, 1));
1196 		}
1197 	} else
1198 		MSG_WriteShort (WriteDest (pr), P_FLOAT (pr, 1));
1199 }
1200 
1201 // void (float to, float f) WriteLong
1202 static void
PF_WriteLong(progs_t * pr)1203 PF_WriteLong (progs_t *pr)
1204 {
1205 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1206 		client_t   *cl = Write_GetClient (pr);
1207 
1208 		if (cl->state != cs_server) {
1209 			MSG_ReliableCheckBlock (&cl->backbuf, 4);
1210 			MSG_ReliableWrite_Long (&cl->backbuf, P_FLOAT (pr, 1));
1211 		}
1212 		if (sv.recorders) {
1213 			sizebuf_t  *dbuf;
1214 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 4);
1215 			MSG_WriteLong (dbuf, P_FLOAT (pr, 1));
1216 		}
1217 	} else
1218 		MSG_WriteLong (WriteDest (pr), P_FLOAT (pr, 1));
1219 }
1220 
1221 // void (float to, float f) WriteAngle
1222 static void
PF_WriteAngle(progs_t * pr)1223 PF_WriteAngle (progs_t *pr)
1224 {
1225 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1226 		client_t   *cl = Write_GetClient (pr);
1227 
1228 		if (cl->state != cs_server) {
1229 			MSG_ReliableCheckBlock (&cl->backbuf, 1);
1230 			MSG_ReliableWrite_Angle (&cl->backbuf, P_FLOAT (pr, 1));
1231 		}
1232 		if (sv.recorders) {
1233 			sizebuf_t  *dbuf;
1234 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
1235 			MSG_WriteAngle (dbuf, P_FLOAT (pr, 1));
1236 		}
1237 	} else
1238 		MSG_WriteAngle (WriteDest (pr), P_FLOAT (pr, 1));
1239 }
1240 
1241 // void (float to, float f) WriteCoord
1242 static void
PF_WriteCoord(progs_t * pr)1243 PF_WriteCoord (progs_t *pr)
1244 {
1245 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1246 		client_t   *cl = Write_GetClient (pr);
1247 
1248 		if (cl->state != cs_server) {
1249 			MSG_ReliableCheckBlock (&cl->backbuf, 2);
1250 			MSG_ReliableWrite_Coord (&cl->backbuf, P_FLOAT (pr, 1));
1251 		}
1252 		if (sv.recorders) {
1253 			sizebuf_t  *dbuf;
1254 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
1255 			MSG_WriteCoord (dbuf, P_FLOAT (pr, 1));
1256 		}
1257 	} else
1258 		MSG_WriteCoord (WriteDest (pr), P_FLOAT (pr, 1));
1259 }
1260 
1261 // void (float to, vector v) WriteAngleV
1262 static void
PF_WriteAngleV(progs_t * pr)1263 PF_WriteAngleV (progs_t *pr)
1264 {
1265 	float      *ang = P_VECTOR (pr, 1);
1266 
1267 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1268 		client_t   *cl = Write_GetClient (pr);
1269 
1270 		if (cl->state != cs_server) {
1271 			MSG_ReliableCheckBlock (&cl->backbuf, 1);
1272 			MSG_ReliableWrite_AngleV (&cl->backbuf, ang);
1273 		}
1274 		if (sv.recorders) {
1275 			sizebuf_t  *dbuf;
1276 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
1277 			MSG_WriteAngleV (dbuf, ang);
1278 		}
1279 	} else
1280 		MSG_WriteAngleV (WriteDest (pr), ang);
1281 }
1282 
1283 // void (float to, vector v) WriteCoordV
1284 static void
PF_WriteCoordV(progs_t * pr)1285 PF_WriteCoordV (progs_t *pr)
1286 {
1287 	float      *coord = P_VECTOR (pr, 1);
1288 
1289 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1290 		client_t   *cl = Write_GetClient (pr);
1291 
1292 		if (cl->state != cs_server) {
1293 			MSG_ReliableCheckBlock (&cl->backbuf, 2);
1294 			MSG_ReliableWrite_CoordV (&cl->backbuf, coord);
1295 		}
1296 		if (sv.recorders) {
1297 			sizebuf_t  *dbuf;
1298 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
1299 			MSG_WriteCoordV (dbuf, coord);
1300 		}
1301 	} else
1302 		MSG_WriteCoordV (WriteDest (pr), coord);
1303 }
1304 
1305 // void (float to, string s) WriteString
1306 static void
PF_WriteString(progs_t * pr)1307 PF_WriteString (progs_t *pr)
1308 {
1309 	const char *str = P_GSTRING (pr, 1);
1310 
1311 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1312 		client_t   *cl = Write_GetClient (pr);
1313 
1314 		if (cl->state != cs_server) {
1315 			MSG_ReliableCheckBlock (&cl->backbuf, 1 + strlen (str));
1316 			MSG_ReliableWrite_String (&cl->backbuf, str);
1317 		}
1318 		if (sv.recorders) {
1319 			sizebuf_t  *dbuf;
1320 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1 + strlen (str));
1321 			MSG_WriteString (dbuf, str);
1322 		}
1323 	} else
1324 		MSG_WriteString (WriteDest (pr), str);
1325 }
1326 
1327 // void (float to, entity s) WriteEntity
1328 static void
PF_WriteEntity(progs_t * pr)1329 PF_WriteEntity (progs_t *pr)
1330 {
1331 	int         ent = P_EDICTNUM (pr, 1);
1332 
1333 	if (P_FLOAT (pr, 0) == MSG_ONE) {
1334 		client_t   *cl = Write_GetClient (pr);
1335 
1336 		if (cl->state != cs_server) {
1337 			MSG_ReliableCheckBlock (&cl->backbuf, 2);
1338 			MSG_ReliableWrite_Short (&cl->backbuf, ent);
1339 		}
1340 		if (sv.recorders) {
1341 			sizebuf_t  *dbuf;
1342 			dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
1343 			MSG_WriteShort (dbuf, ent);
1344 		}
1345 	} else
1346 		MSG_WriteShort (WriteDest (pr), ent);
1347 }
1348 
1349 // void (entity e) makestatic
1350 static void
PF_makestatic(progs_t * pr)1351 PF_makestatic (progs_t *pr)
1352 {
1353 	const char *model;
1354 	edict_t    *ent;
1355 
1356 	ent = P_EDICT (pr, 0);
1357 
1358 	// flush the signon message out to a separate buffer if nearly full
1359 	SV_FlushSignon ();
1360 
1361 	MSG_WriteByte (&sv.signon, svc_spawnstatic);
1362 
1363 	model = PR_GetString (pr, SVstring (ent, model));
1364 	MSG_WriteByte (&sv.signon, SV_ModelIndex (model));
1365 
1366 	MSG_WriteByte (&sv.signon, SVfloat (ent, frame));
1367 	MSG_WriteByte (&sv.signon, SVfloat (ent, colormap));
1368 	MSG_WriteByte (&sv.signon, SVfloat (ent, skin));
1369 
1370 	MSG_WriteCoordAngleV (&sv.signon, SVvector (ent, origin),
1371 						  SVvector (ent, angles));
1372 
1373 	// throw the entity away now
1374 	ED_Free (pr, ent);
1375 }
1376 
1377 // void (entity e) setspawnparms
1378 static void
PF_setspawnparms(progs_t * pr)1379 PF_setspawnparms (progs_t *pr)
1380 {
1381 	client_t   *client;
1382 	edict_t    *ent;
1383 	int         i;
1384 
1385 	ent = P_EDICT (pr, 0);
1386 	i = NUM_FOR_EDICT (pr, ent);
1387 	if (i < 1 || i > MAX_CLIENTS)
1388 		PR_RunError (pr, "Entity is not a client");
1389 
1390 	// copy spawn parms out of the client_t
1391 	client = svs.clients + (i - 1);
1392 
1393 	if (client->state == cs_server)
1394 		return;
1395 
1396 	for (i = 0; i < NUM_SPAWN_PARMS; i++)
1397 		sv_globals.parms[i] = client->spawn_parms[i];
1398 }
1399 
1400 // void (string s) changelevel
1401 static void
PF_changelevel(progs_t * pr)1402 PF_changelevel (progs_t *pr)
1403 {
1404 	const char *s;
1405 	static int  last_spawncount;
1406 
1407 	// make sure we don't issue two changelevels
1408 	if (svs.spawncount == last_spawncount)
1409 		return;
1410 	last_spawncount = svs.spawncount;
1411 
1412 	s = P_GSTRING (pr, 0);
1413 	Cbuf_AddText (sv_cbuf, va ("map %s\n", s));
1414 }
1415 
1416 /*
1417 	PF_logfrag
1418 
1419 	logfrag (killer, killee)
1420 	// void (entity killer, entity killee) logfrag
1421 */
1422 static void
PF_logfrag(progs_t * pr)1423 PF_logfrag (progs_t *pr)
1424 {
1425 	const char *s;
1426 	edict_t    *ent1, *ent2;
1427 	int         e1, e2;
1428 
1429 	ent1 = P_EDICT (pr, 0);
1430 	ent2 = P_EDICT (pr, 1);
1431 
1432 	e1 = NUM_FOR_EDICT (pr, ent1);
1433 	e2 = NUM_FOR_EDICT (pr, ent2);
1434 
1435 	// do gib event callback
1436 	if (sv_frag_e->func) {
1437 		char buf[16];
1438 		char type1[2], type2[2];
1439 		int u1, u2;
1440 
1441 		type1[1] = type2[1] = 0;
1442 		if (e1 < 1 || e1 > MAX_CLIENTS ||
1443 			svs.clients[e1 - 1].state == cs_server) {
1444 			type1[0] = 'e';
1445 			u1 = e1;
1446 		} else {
1447 			type1[0] = 'c';
1448 			u1 = svs.clients[e1 - 1].userid;
1449 		}
1450 
1451 		if (e2 < 1 || e2 > MAX_CLIENTS ||
1452 			svs.clients[e1 - 1].state == cs_server) {
1453 			type2[0] = 'e';
1454 			u2 = e2;
1455 		} else {
1456 			type2[0] = 'c';
1457 			u2 = svs.clients[e2 - 1].userid;
1458 		}
1459 
1460 		snprintf(buf, sizeof(buf), "%d", u2);
1461 
1462 		GIB_Event_Callback (sv_frag_e, 4, type1, va ("%d", u1), type2, buf);
1463 	}
1464 
1465 	if (e1 < 1 || e1 > MAX_CLIENTS || e2 < 1 || e2 > MAX_CLIENTS)
1466 		return;
1467 
1468 	s = va ("\\%s\\%s\\\n", svs.clients[e1 - 1].name,
1469 			svs.clients[e2 - 1].name);
1470 
1471 	SZ_Print (&svs.log[svs.logsequence & 1], s);
1472 	if (sv_fraglogfile) {
1473 		Qprintf (sv_fraglogfile, "%s", s);
1474 		Qflush (sv_fraglogfile);
1475 	}
1476 }
1477 
1478 /*
1479 	PF_infokey
1480 
1481 	string (entity e, string key) infokey
1482 	// string (entity e, string key) infokey
1483 */
1484 static void
PF_infokey(progs_t * pr)1485 PF_infokey (progs_t *pr)
1486 {
1487 	const char *key, *value;
1488 	edict_t    *e;
1489 	int         e1;
1490 
1491 	e = P_EDICT (pr, 0);
1492 	e1 = NUM_FOR_EDICT (pr, e);
1493 	key = P_GSTRING (pr, 1);
1494 
1495 	if (sv_hide_version_info->int_val
1496 		&& (strequal (key, "*qf_version")
1497 			|| strequal (key, "*qsg_version")
1498 			|| strequal (key, "no_pogo_stick"))) {
1499 		e1 = -1;
1500 	}
1501 
1502 	if (e1 == 0) {
1503 		if ((value = Info_ValueForKey (svs.info, key)) == NULL || !*value)
1504 			value = Info_ValueForKey (localinfo, key);
1505 	} else if (e1 > 0 && e1 <= MAX_CLIENTS
1506 			   && svs.clients[e1 - 1].userinfo) {
1507 		if (!strcmp (key, "ip"))
1508 			value = NET_BaseAdrToString (svs.clients[e1 - 1].netchan.
1509 										 remote_address);
1510 		else if (!strcmp (key, "ping")) {
1511 			int         ping = SV_CalcPing (&svs.clients[e1 - 1]);
1512 
1513 			value = va ("%d", ping);
1514 		} else
1515 			value = Info_ValueForKey (svs.clients[e1 - 1].userinfo, key);
1516 	} else
1517 		value = "";
1518 
1519 	RETURN_STRING (pr, value);
1520 }
1521 
1522 /*
1523 	PF_multicast
1524 
1525 	void (vector where, float set) multicast
1526 	// void (vector where, float set) multicast
1527 */
1528 static void
PF_multicast(progs_t * pr)1529 PF_multicast (progs_t *pr)
1530 {
1531 	float      *o;
1532 	int         to;
1533 
1534 	o = P_VECTOR (pr, 0);
1535 	to = P_FLOAT (pr, 1);
1536 
1537 	SV_Multicast (o, to);
1538 }
1539 
1540 /*
1541 	PF_cfopen
1542 
1543 	float (string path, string mode) cfopen
1544 	// float (string path, string mode) cfopen
1545 */
1546 static void
PF_cfopen(progs_t * pr)1547 PF_cfopen (progs_t *pr)
1548 {
1549 	R_FLOAT (pr) = CF_Open (P_GSTRING (pr, 0), P_GSTRING (pr, 1));
1550 }
1551 
1552 /*
1553 	PF_cfclose
1554 
1555 	void (float desc) cfclose
1556 	// void (float desc) cfclose
1557 */
1558 static void
PF_cfclose(progs_t * pr)1559 PF_cfclose (progs_t *pr)
1560 {
1561 	CF_Close ((int) P_FLOAT (pr, 0));
1562 }
1563 
1564 /*
1565 	PF_cfread
1566 
1567 	string (float desc) cfread
1568 	// string (float desc) cfread
1569 */
1570 static void
PF_cfread(progs_t * pr)1571 PF_cfread (progs_t *pr)
1572 {
1573 	RETURN_STRING (pr, CF_Read ((int) P_FLOAT (pr, 0)));
1574 }
1575 
1576 /*
1577 	PF_cfwrite
1578 
1579 	float (float desc, string buf) cfwrite
1580 	// float (float desc, string buf) cfwrite
1581 */
1582 static void
PF_cfwrite(progs_t * pr)1583 PF_cfwrite (progs_t *pr)
1584 {
1585 	R_FLOAT (pr) = CF_Write ((int) P_FLOAT (pr, 0), P_GSTRING (pr, 1));
1586 }
1587 
1588 /*
1589 	PF_cfeof
1590 
1591 	float () cfeof
1592 	// float (float desc) cfeof
1593 */
1594 static void
PF_cfeof(progs_t * pr)1595 PF_cfeof (progs_t *pr)
1596 {
1597 	R_FLOAT (pr) = CF_EOF ((int) P_FLOAT (pr, 0));
1598 }
1599 
1600 /*
1601 	PF_cfquota
1602 
1603 	float () cfquota
1604 	// float () cfquota
1605 */
1606 static void
PF_cfquota(progs_t * pr)1607 PF_cfquota (progs_t *pr)
1608 {
1609 	R_FLOAT (pr) = CF_Quota ();
1610 }
1611 
1612 // void (entity ent, string key, string value) setinfokey
1613 static void
PF_setinfokey(progs_t * pr)1614 PF_setinfokey (progs_t *pr)
1615 {
1616 	edict_t    *edict = P_EDICT (pr, 0);
1617 	int         e1 = NUM_FOR_EDICT (pr, edict);
1618 	const char *key = P_GSTRING (pr, 1);
1619 	const char *value = P_GSTRING (pr, 2);
1620 
1621 	if (e1 == 0) {
1622 		SV_SetLocalinfo (key, value);
1623 	} else if (e1 <= MAX_CLIENTS) {
1624 		SV_SetUserinfo (&svs.clients[e1 - 1], key, value);
1625 	}
1626 }
1627 
1628 // entity (entity ent) testentitypos
1629 static void
PF_testentitypos(progs_t * pr)1630 PF_testentitypos (progs_t *pr)
1631 {
1632 	edict_t    *ent = P_EDICT (pr, 0);
1633 	ent = SV_TestEntityPosition (ent);
1634 	RETURN_EDICT (pr, ent ? ent : sv.edicts);
1635 }
1636 
1637 #define MAX_PF_HULLS 64		// FIXME make dynamic?
1638 clip_hull_t *pf_hull_list[MAX_PF_HULLS];
1639 
1640 // integer (entity ent, vector point) hullpointcontents
1641 static void
PF_hullpointcontents(progs_t * pr)1642 PF_hullpointcontents (progs_t *pr)
1643 {
1644 	edict_t    *edict = P_EDICT (pr, 0);
1645 	float      *mins = P_VECTOR (pr, 1);
1646 	float      *maxs = P_VECTOR (pr, 2);
1647 	float      *point = P_VECTOR (pr, 3);
1648 	hull_t     *hull;
1649 	vec3_t      offset;
1650 
1651 	hull = SV_HullForEntity (edict, mins, maxs, 0, offset);
1652 	VectorSubtract (point, offset, offset);
1653 	R_INT (pr) = SV_HullPointContents (hull, 0, offset);
1654 }
1655 
1656 // vector (integer hull, integer max) getboxbounds
1657 static void
PF_getboxbounds(progs_t * pr)1658 PF_getboxbounds (progs_t *pr)
1659 {
1660 	clip_hull_t *ch;
1661 	int         h = P_INT (pr, 0) - 1;
1662 
1663 	if (h < 0 || h > MAX_PF_HULLS - 1 || !(ch = pf_hull_list[h]))
1664 		PR_RunError (pr, "PF_getboxbounds: invalid box hull handle\n");
1665 
1666 	if (P_INT (pr, 1)) {
1667 		VectorCopy (ch->maxs, R_VECTOR (pr));
1668 	} else {
1669 		VectorCopy (ch->mins, R_VECTOR (pr));
1670 	}
1671 }
1672 
1673 // integer () getboxhull
1674 static void
PF_getboxhull(progs_t * pr)1675 PF_getboxhull (progs_t *pr)
1676 {
1677 	clip_hull_t *ch = 0;
1678 	int         i;
1679 
1680 	for (i = 0; i < MAX_PF_HULLS; i++) {
1681 		if (!pf_hull_list[i]) {
1682 			ch = MOD_Alloc_Hull (6, 6);
1683 			break;
1684 		}
1685 	}
1686 
1687 	if (ch) {
1688 		pf_hull_list[i] = ch;
1689 		R_INT (pr) = i + 1;
1690 		for (i = 0; i < MAX_MAP_HULLS; i++)
1691 			SV_InitHull (ch->hulls[i], ch->hulls[i]->clipnodes,
1692 						 ch->hulls[i]->planes);
1693 	} else {
1694 		R_INT (pr) = 0;
1695 	}
1696 }
1697 
1698 // void (integer hull) freeboxhull
1699 static void
PF_freeboxhull(progs_t * pr)1700 PF_freeboxhull (progs_t *pr)
1701 {
1702 	int         h = P_INT (pr, 0) - 1;
1703 	clip_hull_t *ch;
1704 
1705 	if (h < 0 || h > MAX_PF_HULLS - 1 || !(ch = pf_hull_list[h]))
1706 		PR_RunError (pr, "PF_freeboxhull: invalid box hull handle\n");
1707 	pf_hull_list[h] = 0;
1708 	MOD_Free_Hull (ch);
1709 }
1710 
1711 static vec_t
calc_dist(vec3_t p,vec3_t n,vec3_t * offsets)1712 calc_dist (vec3_t p, vec3_t n, vec3_t *offsets)
1713 {
1714 	int        i;
1715 	vec_t      d = DotProduct (p, n);
1716 	vec3_t     s, v;
1717 
1718 	VectorScale (n, d, s);
1719 	for (i = 0; i < 3; i++)
1720 		if (s[i] < 0)
1721 			v[i] = offsets[0][i];
1722 		else
1723 			v[i] = offsets[1][i];
1724 	VectorAdd (p, v, v);
1725 	return DotProduct (v, n);
1726 }
1727 
1728 // void (integer hull, vector right, vector forward, vector up, vector mins, vector maxs) rotate_bbox
1729 static void
PF_rotate_bbox(progs_t * pr)1730 PF_rotate_bbox (progs_t *pr)
1731 {
1732 	clip_hull_t *ch;
1733 	float       l;
1734 	float      *mi = P_VECTOR (pr, 4);
1735 	float      *ma = P_VECTOR (pr, 5);
1736 	float      *dir[3] = {
1737 					P_VECTOR (pr, 1),
1738 					P_VECTOR (pr, 2),
1739 					P_VECTOR (pr, 3),
1740 				};
1741 
1742 	hull_t     *hull;
1743 	int         i, j;
1744 	int         h = P_INT (pr, 0) - 1;
1745 
1746 	vec3_t      mins, maxs, d;
1747 	float      *verts[6] = {maxs, mins, maxs, mins, maxs, mins};
1748 	vec3_t      v[8];
1749 	vec3_t      offsets[3][2] = {
1750 					{ {   0,   0,   0 }, {  0,  0,  0} },
1751 					{ { -16, -16, -32 }, { 16, 16, 24} },
1752 					{ { -32, -32, -64 }, { 32, 32, 24} },
1753 				};
1754 
1755 	if (h < 0 || h > MAX_PF_HULLS - 1 || !(ch = pf_hull_list[h]))
1756 		PR_RunError (pr, "PF_rotate_bbox: invalid box hull handle\n");
1757 
1758 	// set up the rotation matrix. the three orientation vectors form the
1759 	// columns of the rotation matrix
1760 	for (i = 0; i < 3; i++) {
1761 		for (j = 0; j < 3; j++) {
1762 			ch->axis[i][j] = dir[j][i];
1763 		}
1764 	}
1765 	// rotate the bounding box points
1766 	for (i = 0; i < 3; i++) {
1767 		mins[i] = DotProduct (ch->axis[i], mi);
1768 		maxs[i] = DotProduct (ch->axis[i], ma);
1769 	}
1770 	// find all 8 corners of the rotated box
1771 	VectorCopy (mins, v[0]);
1772 	VectorCopy (maxs, v[1]);
1773 	VectorSubtract (maxs, mins, d);
1774 	for (i = 0; i < 3; i++) {
1775 		vec3_t      x;
1776 
1777 		l = DotProduct (d, dir[i]);
1778 		VectorScale    (dir[i], l, x);
1779 		VectorAdd      (mins, x, v[2 + i * 2]);
1780 		VectorSubtract (maxs, x, v[3 + i * 2]);
1781 	}
1782 	// now find the aligned bounding box
1783 	VectorCopy (v[0], ch->mins);
1784 	VectorCopy (v[0], ch->maxs);
1785 	for (i = 0; i < 8; i++) {
1786 		for (j = 0; j < 3; j++) {
1787 			ch->mins[j] = min (ch->mins[j], v[i][j]);
1788 			ch->maxs[j] = max (ch->maxs[j], v[i][j]);
1789 		}
1790 	}
1791 
1792 	// set up the 3 size based hulls
1793 	for (j = 0; j < 3; j++) {
1794 		hull = ch->hulls[j];
1795 		VectorScale (offsets[j][1], -1, hull->clip_mins);
1796 		VectorScale (offsets[j][0], -1, hull->clip_maxs);
1797 		// set up the clip planes
1798 		for (i = 0; i < 6; i++) {
1799 			hull->planes[i].dist = calc_dist (verts[i], dir[i / 2],
1800 											  offsets[j]);
1801 			hull->planes[i].type = 4;
1802 			VectorCopy (dir[i / 2], hull->planes[i].normal);
1803 		}
1804 	}
1805 }
1806 
1807 // float () checkextension
1808 static void
PF_checkextension(progs_t * pr)1809 PF_checkextension (progs_t *pr)
1810 {
1811 	R_FLOAT (pr) = 0;	 // FIXME: make this function actually useful :P
1812 }
1813 
1814 static void
PF_sv_cvar(progs_t * pr)1815 PF_sv_cvar (progs_t *pr)
1816 {
1817 	const char      *str;
1818 
1819 	str = P_GSTRING (pr, 0);
1820 
1821 	if (sv_hide_version_info->int_val
1822 		&& strequal (str, "sv_hide_version_info")) {
1823 		R_FLOAT (pr) = 0;
1824 	} else {
1825 		R_FLOAT (pr) = Cvar_VariableValue (str);
1826 	}
1827 }
1828 
1829 // entity () SV_AllocClient
1830 static void
PF_SV_AllocClient(progs_t * pr)1831 PF_SV_AllocClient (progs_t *pr)
1832 {
1833 	client_t   *cl = SV_AllocClient (0, 1);
1834 
1835 	if (!cl) {
1836 		R_var (pr, entity) = 0;
1837 		return;
1838 	}
1839 
1840 	//XXX netchan? Netchan_Setup (&newcl->netchan, adr, qport, NC_READ_QPORT);
1841 	cl->state = cs_server;
1842 	cl->spectator = 0;
1843 	cl->connection_started = realtime;
1844 	RETURN_EDICT (pr, cl->edict);
1845 }
1846 
1847 // void (entity cl) SV_FreeClient
1848 static void
PF_SV_FreeClient(progs_t * pr)1849 PF_SV_FreeClient (progs_t *pr)
1850 {
1851 	int         entnum = P_EDICTNUM (pr, 0);
1852 	client_t   *cl = svs.clients + entnum - 1;
1853 
1854 	if (entnum < 1 || entnum > MAX_CLIENTS || cl->state != cs_server)
1855 		PR_RunError (pr, "not a server client");
1856 
1857 	if (cl->userinfo)
1858 		Info_Destroy (cl->userinfo);
1859 	cl->userinfo = 0;
1860 	SV_FullClientUpdate (cl, &sv.reliable_datagram);
1861 	cl->state = cs_free;
1862 
1863 	//if (sv_client_disconnect_e->func)
1864 	//	GIB_Event_Callback (sv_client_disconnect_e, 2, va ("%u", cl->userid),
1865 	//						"server");
1866 }
1867 
1868 // void (entity cl, string userinfo) SV_SetUserinfo
1869 static void
PF_SV_SetUserinfo(progs_t * pr)1870 PF_SV_SetUserinfo (progs_t *pr)
1871 {
1872 	int         entnum = P_EDICTNUM (pr, 0);
1873 	client_t   *cl = svs.clients + entnum - 1;
1874 	const char *str = P_GSTRING (pr, 1);
1875 
1876 	if (entnum < 1 || entnum > MAX_CLIENTS || cl->state != cs_server)
1877 		PR_RunError (pr, "not a server client");
1878 
1879 	cl->userinfo = Info_ParseString (str, 1023, !sv_highchars->int_val);
1880 	cl->sendinfo = true;
1881 	SV_ExtractFromUserinfo (cl);
1882 }
1883 
1884 // void (entity cl, integer ping) SV_SetPing
1885 static void
PR_SV_SetPing(progs_t * pr)1886 PR_SV_SetPing (progs_t *pr)
1887 {
1888 	int         entnum = P_EDICTNUM (pr, 0);
1889 	client_t   *cl = svs.clients + entnum - 1;
1890 
1891 	if (entnum < 1 || entnum > MAX_CLIENTS || cl->state != cs_server)
1892 		PR_RunError (pr, "not a server client");
1893 	cl->ping = P_INT (pr, 1);
1894 }
1895 
1896 // void (entity cl, float secs, vector angles, vector move, integer buttons, integer impulse) SV_UserCmd
1897 static void
PR_SV_UserCmd(progs_t * pr)1898 PR_SV_UserCmd (progs_t *pr)
1899 {
1900 	usercmd_t   ucmd;
1901 	int         entnum = P_EDICTNUM (pr, 0);
1902 	client_t   *cl = svs.clients + entnum - 1;
1903 
1904 	if (entnum < 1 || entnum > MAX_CLIENTS || cl->state != cs_server)
1905 		PR_RunError (pr, "not a server client");
1906 
1907 	host_client = cl;
1908 	sv_player = host_client->edict;
1909 	ucmd.msec = 1000 * P_FLOAT (pr, 1);
1910 	VectorCopy (P_VECTOR (pr, 2), ucmd.angles);
1911 	VectorCopy (P_VECTOR (pr, 3), &ucmd.forwardmove); //FIXME right order?
1912 	ucmd.buttons = P_INT (pr, 4);
1913 	ucmd.impulse = P_INT (pr, 5);
1914 	cl->localtime = sv.time;
1915 	SV_PreRunCmd ();
1916 	SV_RunCmd (&ucmd, 0);
1917 	SV_PostRunCmd ();
1918 	cl->lastcmd = ucmd;
1919 	cl->lastcmd.buttons = 0;	// avoid multiple fires on lag
1920 }
1921 
1922 // void (entity cl) SV_Spawn
1923 static void
PR_SV_Spawn(progs_t * pr)1924 PR_SV_Spawn (progs_t *pr)
1925 {
1926 	int         entnum = P_EDICTNUM (pr, 0);
1927 	client_t   *cl = svs.clients + entnum - 1;
1928 
1929 	if (entnum < 1 || entnum > MAX_CLIENTS || cl->state != cs_server)
1930 		PR_RunError (pr, "not a server client");
1931 
1932 	SV_Spawn (cl);
1933 }
1934 
1935 #define QF (PR_RANGE_QF << PR_RANGE_SHIFT) |
1936 
1937 static builtin_t builtins[] = {
1938 	{"makevectors",			PF_makevectors,			1},
1939 	{"setorigin",			PF_setorigin,			2},
1940 	{"setmodel",			PF_setmodel,			3},
1941 	{"setsize",				PF_setsize,				4},
1942 
1943 	{"sound",				PF_sound,				8},
1944 
1945 	{"error",				PF_error,				10},
1946 	{"objerror",			PF_objerror,			11},
1947 	{"spawn",				PF_Spawn,				14},
1948 	{"remove",				PF_Remove,				15},
1949 	{"traceline",			PF_traceline,			16},
1950 	{"checkclient",			PF_checkclient,			17},
1951 
1952 	{"precache_sound",		PF_precache_sound,		19},
1953 	{"precache_model",		PF_precache_model,		20},
1954 	{"stuffcmd",			PF_stuffcmd,			21},
1955 	{"findradius",			PF_findradius,			22},
1956 	{"bprint",				PF_bprint,				23},
1957 	{"sprint",				PF_sprint,				24},
1958 
1959 	{"walkmove",			PF_walkmove,			32},
1960 
1961 	{"droptofloor",			PF_droptofloor,			34},
1962 	{"lightstyle",			PF_lightstyle,			35},
1963 
1964 	{"checkbottom",			PF_checkbottom,			40},
1965 	{"pointcontents",		PF_pointcontents,		41},
1966 
1967 	{"aim",					PF_aim,					44},
1968 
1969 	{"localcmd",			PF_localcmd,			46},
1970 
1971 	{"changeyaw",			PF_changeyaw,			49},
1972 
1973 	{"writebyte",			PF_WriteByte,			52},
1974 	{"WriteBytes",			PF_WriteBytes,			-1},
1975 	{"writechar",			PF_WriteChar,			53},
1976 	{"writeshort",			PF_WriteShort,			54},
1977 	{"writelong",			PF_WriteLong,			55},
1978 	{"writecoord",			PF_WriteCoord,			56},
1979 	{"writeangle",			PF_WriteAngle,			57},
1980 	{"WriteCoordV",			PF_WriteCoordV,			-1},
1981 	{"WriteAngleV",			PF_WriteAngleV,			-1},
1982 	{"writestring",			PF_WriteString,			58},
1983 	{"writeentity",			PF_WriteEntity,			59},
1984 
1985 	{"movetogoal",			SV_MoveToGoal,			67},
1986 	{"precache_file",		PF_precache_file,		68},
1987 	{"makestatic",			PF_makestatic,			69},
1988 	{"changelevel",			PF_changelevel,			70},
1989 
1990 	{"centerprint",			PF_centerprint,			73},
1991 	{"ambientsound",		PF_ambientsound,		74},
1992 	{"precache_model2",		PF_precache_model,		75},
1993 	{"precache_sound2",		PF_precache_sound,		76},
1994 	{"precache_file2",		PF_precache_file,		77},
1995 	{"setspawnparms",		PF_setspawnparms,		78},
1996 
1997 	{"logfrag",				PF_logfrag,				79},
1998 	{"infokey",				PF_infokey,				80},
1999 	{"multicast",			PF_multicast,			82},
2000 
2001 	{"testentitypos",		PF_testentitypos,		QF 92},
2002 	{"hullpointcontents",	PF_hullpointcontents,	QF 93},
2003 	{"getboxbounds",		PF_getboxbounds,		QF 94},
2004 	{"getboxhull",			PF_getboxhull,			QF 95},
2005 	{"freeboxhull",			PF_freeboxhull,			QF 96},
2006 	{"rotate_bbox",			PF_rotate_bbox,			QF 97},
2007 	{"tracebox",			PF_tracebox,			QF 98},
2008 	{"checkextension",		PF_checkextension,		QF 99},
2009 	{"setinfokey",			PF_setinfokey,			QF 102},
2010 	{"cfopen",				PF_cfopen,				QF 103},
2011 	{"cfclose",				PF_cfclose,				QF 104},
2012 	{"cfread",				PF_cfread,				QF 105},
2013 	{"cfwrite",				PF_cfwrite,				QF 106},
2014 	{"cfeof",				PF_cfeof,				QF 107},
2015 	{"cfquota",				PF_cfquota,				QF 108},
2016 
2017 	{"SV_AllocClient",		PF_SV_AllocClient,		-1},
2018 	{"SV_FreeClient",		PF_SV_FreeClient,		-1},
2019 	{"SV_SetUserinfo",		PF_SV_SetUserinfo,		-1},
2020 	{"SV_SetPing",			PR_SV_SetPing,			-1},
2021 	{"SV_UserCmd",			PR_SV_UserCmd,			-1},
2022 	{"SV_Spawn",			PR_SV_Spawn,			-1},
2023 
2024 	{"EntityParseFunction", ED_EntityParseFunction,	-1},
2025 
2026 	{0}
2027 };
2028 
2029 void
SV_PR_Cmds_Init()2030 SV_PR_Cmds_Init ()
2031 {
2032 	builtin_t  *bi;
2033 
2034 	RUA_Init (&sv_pr_state, 1);
2035 
2036 	PR_Cmds_Init (&sv_pr_state);
2037 	// (override standard builtin)
2038 	// float (string s) cvar
2039 	bi = PR_FindBuiltin (&sv_pr_state, "cvar");
2040 	bi->proc = PF_sv_cvar;
2041 
2042 	PR_RegisterBuiltins (&sv_pr_state, builtins);
2043 }
2044