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