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