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 // sv_phys.c
     21 
     22 #include "qwsvdef.h"
     23 
     24 /*
     25 
     26 
     27 pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
     28 
     29 onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects
     30 
     31 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
     32 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
     33 corpses are SOLID_NOT and MOVETYPE_TOSS
     34 crates are SOLID_BBOX and MOVETYPE_TOSS
     35 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
     36 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
     37 
     38 solid_edge items only clip against bsp models.
     39 
     40 */
     41 
     42 cvar_t	sv_maxvelocity = {"sv_maxvelocity","2000"};
     43 
     44 cvar_t	sv_gravity			 = { "sv_gravity", "800"};
     45 cvar_t	sv_stopspeed		 = { "sv_stopspeed", "100"};
     46 cvar_t	sv_maxspeed			 = { "sv_maxspeed", "320"};
     47 cvar_t	sv_spectatormaxspeed = { "sv_spectatormaxspeed", "500"};
     48 cvar_t	sv_accelerate		 = { "sv_accelerate", "10"};
     49 cvar_t	sv_airaccelerate	 = { "sv_airaccelerate", "0.7"};
     50 cvar_t	sv_wateraccelerate	 = { "sv_wateraccelerate", "10"};
     51 cvar_t	sv_friction			 = { "sv_friction", "4"};
     52 cvar_t	sv_waterfriction	 = { "sv_waterfriction", "4"};
     53 
     54 
     55 #define	MOVE_EPSILON	0.01
     56 
     57 void SV_Physics_Toss (edict_t *ent);
     58 
     59 /*
     60 ================
     61 SV_CheckAllEnts
     62 ================
     63 */
     64 void SV_CheckAllEnts (void)
     65 {
     66 	int			e;
     67 	edict_t		*check;
     68 
     69 // see if any solid entities are inside the final position
     70 	check = NEXT_EDICT(sv.edicts);
     71 	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
     72 	{
     73 		if (check->free)
     74 			continue;
     75 		if (check->v.movetype == MOVETYPE_PUSH
     76 		|| check->v.movetype == MOVETYPE_NONE
     77 		|| check->v.movetype == MOVETYPE_NOCLIP)
     78 			continue;
     79 
     80 		if (SV_TestEntityPosition (check))
     81 			Con_Printf ("entity in invalid position\n");
     82 	}
     83 }
     84 
     85 /*
     86 ================
     87 SV_CheckVelocity
     88 ================
     89 */
     90 void SV_CheckVelocity (edict_t *ent)
     91 {
     92 	int		i;
     93 
     94 //
     95 // bound velocity
     96 //
     97 	for (i=0 ; i<3 ; i++)
     98 	{
     99 		if (IS_NAN(ent->v.velocity[i]))
    100 		{
    101 			Con_Printf ("Got a NaN velocity on %s\n", PR_GetString(ent->v.classname));
    102 			ent->v.velocity[i] = 0;
    103 		}
    104 		if (IS_NAN(ent->v.origin[i]))
    105 		{
    106 			Con_Printf ("Got a NaN origin on %s\n", PR_GetString(ent->v.classname));
    107 			ent->v.origin[i] = 0;
    108 		}
    109 		if (ent->v.velocity[i] > sv_maxvelocity.value)
    110 			ent->v.velocity[i] = sv_maxvelocity.value;
    111 		else if (ent->v.velocity[i] < -sv_maxvelocity.value)
    112 			ent->v.velocity[i] = -sv_maxvelocity.value;
    113 	}
    114 }
    115 
    116 /*
    117 =============
    118 SV_RunThink
    119 
    120 Runs thinking code if time.  There is some play in the exact time the think
    121 function will be called, because it is called before any movement is done
    122 in a frame.  Not used for pushmove objects, because they must be exact.
    123 Returns false if the entity removed itself.
    124 =============
    125 */
    126 qboolean SV_RunThink (edict_t *ent)
    127 {
    128 	float	thinktime;
    129 
    130 	do
    131 	{
    132 		thinktime = ent->v.nextthink;
    133 		if (thinktime <= 0)
    134 			return true;
    135 		if (thinktime > sv.time + host_frametime)
    136 			return true;
    137 
    138 		if (thinktime < sv.time)
    139 			thinktime = sv.time;	// don't let things stay in the past.
    140 									// it is possible to start that way
    141 									// by a trigger with a local time.
    142 		ent->v.nextthink = 0;
    143 		pr_global_struct->time = thinktime;
    144 		pr_global_struct->self = EDICT_TO_PROG(ent);
    145 		pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
    146 		PR_ExecuteProgram (ent->v.think);
    147 
    148 		if (ent->free)
    149 			return false;
    150 	} while (1);
    151 
    152 	return true;
    153 }
    154 
    155 /*
    156 ==================
    157 SV_Impact
    158 
    159 Two entities have touched, so run their touch functions
    160 ==================
    161 */
    162 void SV_Impact (edict_t *e1, edict_t *e2)
    163 {
    164 	int		old_self, old_other;
    165 
    166 	old_self = pr_global_struct->self;
    167 	old_other = pr_global_struct->other;
    168 
    169 	pr_global_struct->time = sv.time;
    170 	if (e1->v.touch && e1->v.solid != SOLID_NOT)
    171 	{
    172 		pr_global_struct->self = EDICT_TO_PROG(e1);
    173 		pr_global_struct->other = EDICT_TO_PROG(e2);
    174 		PR_ExecuteProgram (e1->v.touch);
    175 	}
    176 
    177 	if (e2->v.touch && e2->v.solid != SOLID_NOT)
    178 	{
    179 		pr_global_struct->self = EDICT_TO_PROG(e2);
    180 		pr_global_struct->other = EDICT_TO_PROG(e1);
    181 		PR_ExecuteProgram (e2->v.touch);
    182 	}
    183 
    184 	pr_global_struct->self = old_self;
    185 	pr_global_struct->other = old_other;
    186 }
    187 
    188 
    189 /*
    190 ==================
    191 ClipVelocity
    192 
    193 Slide off of the impacting object
    194 returns the blocked flags (1 = floor, 2 = step / wall)
    195 ==================
    196 */
    197 #define	STOP_EPSILON	0.1
    198 
    199 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
    200 {
    201 	float	backoff;
    202 	float	change;
    203 	int		i, blocked;
    204 
    205 	blocked = 0;
    206 	if (normal[2] > 0)
    207 		blocked |= 1;		// floor
    208 	if (!normal[2])
    209 		blocked |= 2;		// step
    210 
    211 	backoff = DotProduct (in, normal) * overbounce;
    212 
    213 	for (i=0 ; i<3 ; i++)
    214 	{
    215 		change = normal[i]*backoff;
    216 		out[i] = in[i] - change;
    217 		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
    218 			out[i] = 0;
    219 	}
    220 
    221 	return blocked;
    222 }
    223 
    224 
    225 /*
    226 ============
    227 SV_FlyMove
    228 
    229 The basic solid body movement clip that slides along multiple planes
    230 Returns the clipflags if the velocity was modified (hit something solid)
    231 1 = floor
    232 2 = wall / step
    233 4 = dead stop
    234 If steptrace is not NULL, the trace of any vertical wall hit will be stored
    235 ============
    236 */
    237 #define	MAX_CLIP_PLANES	5
    238 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
    239 {
    240 	int			bumpcount, numbumps;
    241 	vec3_t		dir;
    242 	float		d;
    243 	int			numplanes;
    244 	vec3_t		planes[MAX_CLIP_PLANES];
    245 	vec3_t		primal_velocity, original_velocity, new_velocity;
    246 	int			i, j;
    247 	trace_t		trace;
    248 	vec3_t		end;
    249 	float		time_left;
    250 	int			blocked;
    251 
    252 	numbumps = 4;
    253 
    254 	blocked = 0;
    255 	VectorCopy (ent->v.velocity, original_velocity);
    256 	VectorCopy (ent->v.velocity, primal_velocity);
    257 	numplanes = 0;
    258 
    259 	time_left = time;
    260 
    261 	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
    262 	{
    263 		for (i=0 ; i<3 ; i++)
    264 			end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
    265 
    266 		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
    267 
    268 		if (trace.allsolid)
    269 		{	// entity is trapped in another solid
    270 			VectorCopy (vec3_origin, ent->v.velocity);
    271 			return 3;
    272 		}
    273 
    274 		if (trace.fraction > 0)
    275 		{	// actually covered some distance
    276 			VectorCopy (trace.endpos, ent->v.origin);
    277 			VectorCopy (ent->v.velocity, original_velocity);
    278 			numplanes = 0;
    279 		}
    280 
    281 		if (trace.fraction == 1)
    282 			 break;		// moved the entire distance
    283 
    284 		if (!trace.ent)
    285 			SV_Error ("SV_FlyMove: !trace.ent");
    286 
    287 		if (trace.plane.normal[2] > 0.7)
    288 		{
    289 			blocked |= 1;		// floor
    290 			if (trace.ent->v.solid == SOLID_BSP)
    291 			{
    292 				ent->v.flags =	(int)ent->v.flags | FL_ONGROUND;
    293 				ent->v.groundentity = EDICT_TO_PROG(trace.ent);
    294 			}
    295 		}
    296 		if (!trace.plane.normal[2])
    297 		{
    298 			blocked |= 2;		// step
    299 			if (steptrace)
    300 				*steptrace = trace;	// save for player extrafriction
    301 		}
    302 
    303 //
    304 // run the impact function
    305 //
    306 		SV_Impact (ent, trace.ent);
    307 		if (ent->free)
    308 			break;		// removed by the impact function
    309 
    310 
    311 		time_left -= time_left * trace.fraction;
    312 
    313 	// cliped to another plane
    314 		if (numplanes >= MAX_CLIP_PLANES)
    315 		{	// this shouldn't really happen
    316 			VectorCopy (vec3_origin, ent->v.velocity);
    317 			return 3;
    318 		}
    319 
    320 		VectorCopy (trace.plane.normal, planes[numplanes]);
    321 		numplanes++;
    322 
    323 //
    324 // modify original_velocity so it parallels all of the clip planes
    325 //
    326 		for (i=0 ; i<numplanes ; i++)
    327 		{
    328 			ClipVelocity (original_velocity, planes[i], new_velocity, 1);
    329 			for (j=0 ; j<numplanes ; j++)
    330 				if (j != i)
    331 				{
    332 					if (DotProduct (new_velocity, planes[j]) < 0)
    333 						break;	// not ok
    334 				}
    335 			if (j == numplanes)
    336 				break;
    337 		}
    338 
    339 		if (i != numplanes)
    340 		{	// go along this plane
    341 			VectorCopy (new_velocity, ent->v.velocity);
    342 		}
    343 		else
    344 		{	// go along the crease
    345 			if (numplanes != 2)
    346 			{
    347 //				Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
    348 				VectorCopy (vec3_origin, ent->v.velocity);
    349 				return 7;
    350 			}
    351 			CrossProduct (planes[0], planes[1], dir);
    352 			d = DotProduct (dir, ent->v.velocity);
    353 			VectorScale (dir, d, ent->v.velocity);
    354 		}
    355 
    356 //
    357 // if original velocity is against the original velocity, stop dead
    358 // to avoid tiny occilations in sloping corners
    359 //
    360 		if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
    361 		{
    362 			VectorCopy (vec3_origin, ent->v.velocity);
    363 			return blocked;
    364 		}
    365 	}
    366 
    367 	return blocked;
    368 }
    369 
    370 
    371 /*
    372 ============
    373 SV_AddGravity
    374 
    375 ============
    376 */
    377 void SV_AddGravity (edict_t *ent, float scale)
    378 {
    379 	ent->v.velocity[2] -= scale * movevars.gravity * host_frametime;
    380 }
    381 
    382 /*
    383 ===============================================================================
    384 
    385 PUSHMOVE
    386 
    387 ===============================================================================
    388 */
    389 
    390 /*
    391 ============
    392 SV_PushEntity
    393 
    394 Does not change the entities velocity at all
    395 ============
    396 */
    397 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
    398 {
    399 	trace_t	trace;
    400 	vec3_t	end;
    401 
    402 	VectorAdd (ent->v.origin, push, end);
    403 
    404 	if (ent->v.movetype == MOVETYPE_FLYMISSILE)
    405 		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
    406 	else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
    407 	// only clip against bmodels
    408 		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
    409 	else
    410 		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
    411 
    412 	VectorCopy (trace.endpos, ent->v.origin);
    413 	SV_LinkEdict (ent, true);
    414 
    415 	if (trace.ent)
    416 		SV_Impact (ent, trace.ent);
    417 
    418 	return trace;
    419 }
    420 
    421 
    422 /*
    423 ============
    424 SV_Push
    425 
    426 ============
    427 */
    428 qboolean SV_Push (edict_t *pusher, vec3_t move)
    429 {
    430 	int			i, e;
    431 	edict_t		*check, *block;
    432 	vec3_t		mins, maxs;
    433 	vec3_t		pushorig;
    434 	int			num_moved;
    435 	edict_t		*moved_edict[MAX_EDICTS];
    436 	vec3_t		moved_from[MAX_EDICTS];
    437 
    438 	for (i=0 ; i<3 ; i++)
    439 	{
    440 		mins[i] = pusher->v.absmin[i] + move[i];
    441 		maxs[i] = pusher->v.absmax[i] + move[i];
    442 	}
    443 
    444 	VectorCopy (pusher->v.origin, pushorig);
    445 
    446 // move the pusher to it's final position
    447 
    448 	VectorAdd (pusher->v.origin, move, pusher->v.origin);
    449 	SV_LinkEdict (pusher, false);
    450 
    451 // see if any solid entities are inside the final position
    452 	num_moved = 0;
    453 	check = NEXT_EDICT(sv.edicts);
    454 	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
    455 	{
    456 		if (check->free)
    457 			continue;
    458 		if (check->v.movetype == MOVETYPE_PUSH
    459 		|| check->v.movetype == MOVETYPE_NONE
    460 		|| check->v.movetype == MOVETYPE_NOCLIP)
    461 			continue;
    462 
    463 		pusher->v.solid = SOLID_NOT;
    464 		block = SV_TestEntityPosition (check);
    465 		pusher->v.solid = SOLID_BSP;
    466 		if (block)
    467 			continue;
    468 
    469 	// if the entity is standing on the pusher, it will definately be moved
    470 		if ( ! ( ((int)check->v.flags & FL_ONGROUND)
    471 		&& PROG_TO_EDICT(check->v.groundentity) == pusher) )
    472 		{
    473 			if ( check->v.absmin[0] >= maxs[0]
    474 			|| check->v.absmin[1] >= maxs[1]
    475 			|| check->v.absmin[2] >= maxs[2]
    476 			|| check->v.absmax[0] <= mins[0]
    477 			|| check->v.absmax[1] <= mins[1]
    478 			|| check->v.absmax[2] <= mins[2] )
    479 				continue;
    480 
    481 		// see if the ent's bbox is inside the pusher's final position
    482 			if (!SV_TestEntityPosition (check))
    483 				continue;
    484 		}
    485 
    486 		VectorCopy (check->v.origin, moved_from[num_moved]);
    487 		moved_edict[num_moved] = check;
    488 		num_moved++;
    489 
    490 		// try moving the contacted entity
    491 		VectorAdd (check->v.origin, move, check->v.origin);
    492 		block = SV_TestEntityPosition (check);
    493 		if (!block)
    494 		{	// pushed ok
    495 			SV_LinkEdict (check, false);
    496 			continue;
    497 		}
    498 
    499 		// if it is ok to leave in the old position, do it
    500 		VectorSubtract (check->v.origin, move, check->v.origin);
    501 		block = SV_TestEntityPosition (check);
    502 		if (!block)
    503 		{
    504 			num_moved--;
    505 			continue;
    506 		}
    507 
    508 	// if it is still inside the pusher, block
    509 		if (check->v.mins[0] == check->v.maxs[0])
    510 		{
    511 			SV_LinkEdict (check, false);
    512 			continue;
    513 		}
    514 		if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
    515 		{	// corpse
    516 			check->v.mins[0] = check->v.mins[1] = 0;
    517 			VectorCopy (check->v.mins, check->v.maxs);
    518 			SV_LinkEdict (check, false);
    519 			continue;
    520 		}
    521 
    522 		VectorCopy (pushorig, pusher->v.origin);
    523 		SV_LinkEdict (pusher, false);
    524 
    525 		// if the pusher has a "blocked" function, call it
    526 		// otherwise, just stay in place until the obstacle is gone
    527 		if (pusher->v.blocked)
    528 		{
    529 			pr_global_struct->self = EDICT_TO_PROG(pusher);
    530 			pr_global_struct->other = EDICT_TO_PROG(check);
    531 			PR_ExecuteProgram (pusher->v.blocked);
    532 		}
    533 
    534 	// move back any entities we already moved
    535 		for (i=0 ; i<num_moved ; i++)
    536 		{
    537 			VectorCopy (moved_from[i], moved_edict[i]->v.origin);
    538 			SV_LinkEdict (moved_edict[i], false);
    539 		}
    540 		return false;
    541 	}
    542 
    543 	return true;
    544 }
    545 
    546 /*
    547 ============
    548 SV_PushMove
    549 
    550 ============
    551 */
    552 void SV_PushMove (edict_t *pusher, float movetime)
    553 {
    554 	int			i;
    555 	vec3_t		move;
    556 
    557 	if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
    558 	{
    559 		pusher->v.ltime += movetime;
    560 		return;
    561 	}
    562 
    563 	for (i=0 ; i<3 ; i++)
    564 		move[i] = pusher->v.velocity[i] * movetime;
    565 
    566 	if (SV_Push (pusher, move))
    567 		pusher->v.ltime += movetime;
    568 }
    569 
    570 
    571 /*
    572 ================
    573 SV_Physics_Pusher
    574 
    575 ================
    576 */
    577 void SV_Physics_Pusher (edict_t *ent)
    578 {
    579 	float	thinktime;
    580 	float	oldltime;
    581 	float	movetime;
    582 vec3_t oldorg, move;
    583 float	l;
    584 
    585 	oldltime = ent->v.ltime;
    586 
    587 	thinktime = ent->v.nextthink;
    588 	if (thinktime < ent->v.ltime + host_frametime)
    589 	{
    590 		movetime = thinktime - ent->v.ltime;
    591 		if (movetime < 0)
    592 			movetime = 0;
    593 	}
    594 	else
    595 		movetime = host_frametime;
    596 
    597 	if (movetime)
    598 	{
    599 		SV_PushMove (ent, movetime);	// advances ent->v.ltime if not blocked
    600 	}
    601 
    602 	if (thinktime > oldltime && thinktime <= ent->v.ltime)
    603 	{
    604 VectorCopy (ent->v.origin, oldorg);
    605 		ent->v.nextthink = 0;
    606 		pr_global_struct->time = sv.time;
    607 		pr_global_struct->self = EDICT_TO_PROG(ent);
    608 		pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
    609 		PR_ExecuteProgram (ent->v.think);
    610 		if (ent->free)
    611 			return;
    612 VectorSubtract (ent->v.origin, oldorg, move);
    613 
    614 l = Length(move);
    615 if (l > 1.0/64)
    616 {
    617 //	Con_Printf ("**** snap: %f\n", Length (l));
    618 	VectorCopy (oldorg, ent->v.origin);
    619 	SV_Push (ent, move);
    620 }
    621 
    622 	}
    623 
    624 }
    625 
    626 
    627 /*
    628 =============
    629 SV_Physics_None
    630 
    631 Non moving objects can only think
    632 =============
    633 */
    634 void SV_Physics_None (edict_t *ent)
    635 {
    636 // regular thinking
    637 	SV_RunThink (ent);
    638 }
    639 
    640 /*
    641 =============
    642 SV_Physics_Noclip
    643 
    644 A moving object that doesn't obey physics
    645 =============
    646 */
    647 void SV_Physics_Noclip (edict_t *ent)
    648 {
    649 // regular thinking
    650 	if (!SV_RunThink (ent))
    651 		return;
    652 
    653 	VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
    654 	VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
    655 
    656 	SV_LinkEdict (ent, false);
    657 }
    658 
    659 /*
    660 ==============================================================================
    661 
    662 TOSS / BOUNCE
    663 
    664 ==============================================================================
    665 */
    666 
    667 /*
    668 =============
    669 SV_CheckWaterTransition
    670 
    671 =============
    672 */
    673 void SV_CheckWaterTransition (edict_t *ent)
    674 {
    675 	int		cont;
    676 
    677 	cont = SV_PointContents (ent->v.origin);
    678 	if (!ent->v.watertype)
    679 	{	// just spawned here
    680 		ent->v.watertype = cont;
    681 		ent->v.waterlevel = 1;
    682 		return;
    683 	}
    684 
    685 	if (cont <= CONTENTS_WATER)
    686 	{
    687 		if (ent->v.watertype == CONTENTS_EMPTY)
    688 		{	// just crossed into water
    689 			SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
    690 		}
    691 		ent->v.watertype = cont;
    692 		ent->v.waterlevel = 1;
    693 	}
    694 	else
    695 	{
    696 		if (ent->v.watertype != CONTENTS_EMPTY)
    697 		{	// just crossed into water
    698 			SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
    699 		}
    700 		ent->v.watertype = CONTENTS_EMPTY;
    701 		ent->v.waterlevel = cont;
    702 	}
    703 }
    704 
    705 /*
    706 =============
    707 SV_Physics_Toss
    708 
    709 Toss, bounce, and fly movement.  When onground, do nothing.
    710 =============
    711 */
    712 void SV_Physics_Toss (edict_t *ent)
    713 {
    714 	trace_t	trace;
    715 	vec3_t	move;
    716 	float	backoff;
    717 
    718 // regular thinking
    719 	if (!SV_RunThink (ent))
    720 		return;
    721 
    722 	if (ent->v.velocity[2] > 0)
    723 		ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
    724 
    725 // if onground, return without moving
    726 	if ( ((int)ent->v.flags & FL_ONGROUND) )
    727 		return;
    728 
    729 	SV_CheckVelocity (ent);
    730 
    731 // add gravity
    732 	if (ent->v.movetype != MOVETYPE_FLY
    733 	&& ent->v.movetype != MOVETYPE_FLYMISSILE)
    734 		SV_AddGravity (ent, 1.0);
    735 
    736 // move angles
    737 	VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
    738 
    739 // move origin
    740 	VectorScale (ent->v.velocity, host_frametime, move);
    741 	trace = SV_PushEntity (ent, move);
    742 	if (trace.fraction == 1)
    743 		return;
    744 	if (ent->free)
    745 		return;
    746 
    747 	if (ent->v.movetype == MOVETYPE_BOUNCE)
    748 		backoff = 1.5;
    749 	else
    750 		backoff = 1;
    751 
    752 	ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
    753 
    754 // stop if on ground
    755 	if (trace.plane.normal[2] > 0.7)
    756 	{
    757 		if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE )
    758 		{
    759 			ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
    760 			ent->v.groundentity = EDICT_TO_PROG(trace.ent);
    761 			VectorCopy (vec3_origin, ent->v.velocity);
    762 			VectorCopy (vec3_origin, ent->v.avelocity);
    763 		}
    764 	}
    765 
    766 // check for in water
    767 	SV_CheckWaterTransition (ent);
    768 }
    769 
    770 /*
    771 ===============================================================================
    772 
    773 STEPPING MOVEMENT
    774 
    775 ===============================================================================
    776 */
    777 
    778 /*
    779 =============
    780 SV_Physics_Step
    781 
    782 Monsters freefall when they don't have a ground entity, otherwise
    783 all movement is done with discrete steps.
    784 
    785 This is also used for objects that have become still on the ground, but
    786 will fall if the floor is pulled out from under them.
    787 FIXME: is this true?
    788 =============
    789 */
    790 void SV_Physics_Step (edict_t *ent)
    791 {
    792 	qboolean	hitsound;
    793 
    794 // frefall if not onground
    795 	if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
    796 	{
    797 		if (ent->v.velocity[2] < movevars.gravity*-0.1)
    798 			hitsound = true;
    799 		else
    800 			hitsound = false;
    801 
    802 		SV_AddGravity (ent, 1.0);
    803 		SV_CheckVelocity (ent);
    804 		SV_FlyMove (ent, host_frametime, NULL);
    805 		SV_LinkEdict (ent, true);
    806 
    807 		if ( (int)ent->v.flags & FL_ONGROUND )	// just hit ground
    808 		{
    809 			if (hitsound)
    810 				SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
    811 		}
    812 	}
    813 
    814 // regular thinking
    815 	SV_RunThink (ent);
    816 
    817 	SV_CheckWaterTransition (ent);
    818 }
    819 
    820 //============================================================================
    821 
    822 void SV_ProgStartFrame (void)
    823 {
    824 // let the progs know that a new frame has started
    825 	pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
    826 	pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
    827 	pr_global_struct->time = sv.time;
    828 	PR_ExecuteProgram (pr_global_struct->StartFrame);
    829 }
    830 
    831 /*
    832 ================
    833 SV_RunEntity
    834 
    835 ================
    836 */
    837 void SV_RunEntity (edict_t *ent)
    838 {
    839 	if (ent->v.lastruntime == (float)realtime)
    840 		return;
    841 	ent->v.lastruntime = (float)realtime;
    842 
    843 	switch ( (int)ent->v.movetype)
    844 	{
    845 	case MOVETYPE_PUSH:
    846 		SV_Physics_Pusher (ent);
    847 		break;
    848 	case MOVETYPE_NONE:
    849 		SV_Physics_None (ent);
    850 		break;
    851 	case MOVETYPE_NOCLIP:
    852 		SV_Physics_Noclip (ent);
    853 		break;
    854 	case MOVETYPE_STEP:
    855 		SV_Physics_Step (ent);
    856 		break;
    857 	case MOVETYPE_TOSS:
    858 	case MOVETYPE_BOUNCE:
    859 	case MOVETYPE_FLY:
    860 	case MOVETYPE_FLYMISSILE:
    861 		SV_Physics_Toss (ent);
    862 		break;
    863 	default:
    864 		SV_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
    865 	}
    866 }
    867 
    868 /*
    869 ================
    870 SV_RunNewmis
    871 
    872 ================
    873 */
    874 void SV_RunNewmis (void)
    875 {
    876 	edict_t	*ent;
    877 
    878 	if (!pr_global_struct->newmis)
    879 		return;
    880 	ent = PROG_TO_EDICT(pr_global_struct->newmis);
    881 	host_frametime = 0.05;
    882 	pr_global_struct->newmis = 0;
    883 
    884 	SV_RunEntity (ent);
    885 }
    886 
    887 /*
    888 ================
    889 SV_Physics
    890 
    891 ================
    892 */
    893 void SV_Physics (void)
    894 {
    895 	int		i;
    896 	edict_t	*ent;
    897 	static double	old_time;
    898 
    899 // don't bother running a frame if sys_ticrate seconds haven't passed
    900 	host_frametime = realtime - old_time;
    901 	if (host_frametime < sv_mintic.value)
    902 		return;
    903 	if (host_frametime > sv_maxtic.value)
    904 		host_frametime = sv_maxtic.value;
    905 	old_time = realtime;
    906 
    907 	pr_global_struct->frametime = host_frametime;
    908 
    909 	SV_ProgStartFrame ();
    910 
    911 //
    912 // treat each object in turn
    913 // even the world gets a chance to think
    914 //
    915 	ent = sv.edicts;
    916 	for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
    917 	{
    918 		if (ent->free)
    919 			continue;
    920 
    921 		if (pr_global_struct->force_retouch)
    922 			SV_LinkEdict (ent, true);	// force retouch even for stationary
    923 
    924 		if (i > 0 && i <= MAX_CLIENTS)
    925 			continue;		// clients are run directly from packets
    926 
    927 		SV_RunEntity (ent);
    928 		SV_RunNewmis ();
    929 	}
    930 
    931 	if (pr_global_struct->force_retouch)
    932 		pr_global_struct->force_retouch--;
    933 }
    934 
    935 void SV_SetMoveVars(void)
    936 {
    937 	movevars.gravity			= sv_gravity.value;
    938 	movevars.stopspeed		    = sv_stopspeed.value;
    939 	movevars.maxspeed			= sv_maxspeed.value;
    940 	movevars.spectatormaxspeed  = sv_spectatormaxspeed.value;
    941 	movevars.accelerate		    = sv_accelerate.value;
    942 	movevars.airaccelerate	    = sv_airaccelerate.value;
    943 	movevars.wateraccelerate	= sv_wateraccelerate.value;
    944 	movevars.friction			= sv_friction.value;
    945 	movevars.waterfriction	    = sv_waterfriction.value;
    946 	movevars.entgravity			= 1.0;
    947 }
    948