1 // g_phys.c
2 
3 #include "g_local.h"
4 
5 /*
6 
7 
8 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.
9 
10 onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects
11 
12 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
13 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
14 corpses are SOLID_NOT and MOVETYPE_TOSS
15 crates are SOLID_BBOX and MOVETYPE_TOSS
16 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
17 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
18 
19 solid_edge items only clip against bsp models.
20 
21 */
22 
23 
24 /*
25 ============
26 SV_TestEntityPosition
27 
28 ============
29 */
SV_TestEntityPosition(edict_t * ent)30 edict_t	*SV_TestEntityPosition (edict_t *ent)
31 {
32 	trace_t	trace;
33 
34 	trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, MASK_SOLID);
35 
36 	if (trace.startsolid)
37 		return g_edicts;
38 
39 	return NULL;
40 }
41 
42 
43 /*
44 ================
45 SV_CheckVelocity
46 ================
47 */
SV_CheckVelocity(edict_t * ent)48 void SV_CheckVelocity (edict_t *ent)
49 {
50 	int		i;
51 
52 //
53 // bound velocity
54 //
55 	for (i=0 ; i<3 ; i++)
56 	{
57 		if (ent->velocity[i] > sv_maxvelocity->value)
58 			ent->velocity[i] = sv_maxvelocity->value;
59 		else if (ent->velocity[i] < -sv_maxvelocity->value)
60 			ent->velocity[i] = -sv_maxvelocity->value;
61 	}
62 }
63 
64 /*
65 =============
66 SV_RunThink
67 
68 Runs thinking code for this frame if necessary
69 =============
70 */
SV_RunThink(edict_t * ent)71 qboolean SV_RunThink (edict_t *ent)
72 {
73 	float	thinktime;
74 
75 	thinktime = ent->nextthink;
76 	if (thinktime <= 0)
77 		return true;
78 	if (thinktime > level.time+0.001)
79 		return true;
80 
81 	ent->nextthink = 0;
82 	if (!ent->think)
83 		gi.error ("NULL ent->think");
84 	ent->think (ent);
85 
86 	return false;
87 }
88 
89 /*
90 ==================
91 SV_Impact
92 
93 Two entities have touched, so run their touch functions
94 ==================
95 */
SV_Impact(edict_t * e1,trace_t * trace)96 void SV_Impact (edict_t *e1, trace_t *trace)
97 {
98 	edict_t		*e2;
99 //	cplane_t	backplane;
100 
101 	e2 = trace->ent;
102 
103 	if (e1->touch && e1->solid != SOLID_NOT)
104 		e1->touch (e1, e2, &trace->plane, trace->surface);
105 
106 	if (e2->touch && e2->solid != SOLID_NOT)
107 		e2->touch (e2, e1, NULL, NULL);
108 }
109 
110 
111 /*
112 ==================
113 ClipVelocity
114 
115 Slide off of the impacting object
116 returns the blocked flags (1 = floor, 2 = step / wall)
117 ==================
118 */
119 #define	STOP_EPSILON	0.1
120 
ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)121 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
122 {
123 	float	backoff;
124 	float	change;
125 	int		i, blocked;
126 
127 	blocked = 0;
128 	if (normal[2] > 0)
129 		blocked |= 1;		// floor
130 	if (!normal[2])
131 		blocked |= 2;		// step
132 
133 	backoff = DotProduct (in, normal) * overbounce;
134 
135 	for (i=0 ; i<3 ; i++)
136 	{
137 		change = normal[i]*backoff;
138 		out[i] = in[i] - change;
139 		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
140 			out[i] = 0;
141 	}
142 
143 	return blocked;
144 }
145 
146 
147 /*
148 ============
149 SV_FlyMove
150 
151 The basic solid body movement clip that slides along multiple planes
152 Returns the clipflags if the velocity was modified (hit something solid)
153 1 = floor
154 2 = wall / step
155 4 = dead stop
156 ============
157 */
158 #define	MAX_CLIP_PLANES	5
SV_FlyMove(edict_t * ent,float time,int mask)159 int SV_FlyMove (edict_t *ent, float time, int mask)
160 {
161 	edict_t		*hit;
162 	int			bumpcount, numbumps;
163 	vec3_t		dir;
164 	float		d;
165 	int			numplanes;
166 	vec3_t		planes[MAX_CLIP_PLANES];
167 	vec3_t		primal_velocity, original_velocity, new_velocity;
168 	int			i, j;
169 	trace_t		trace;
170 	vec3_t		end;
171 	float		time_left;
172 	int			blocked;
173 
174 	numbumps = 4;
175 
176 	blocked = 0;
177 	VectorCopy (ent->velocity, original_velocity);
178 	VectorCopy (ent->velocity, primal_velocity);
179 	numplanes = 0;
180 
181 	time_left = time;
182 
183 	ent->groundentity = NULL;
184 	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
185 	{
186 		for (i=0 ; i<3 ; i++)
187 			end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
188 
189 		trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
190 
191 		if (trace.allsolid)
192 		{	// entity is trapped in another solid
193 			VectorCopy (vec3_origin, ent->velocity);
194 			return 3;
195 		}
196 
197 		if (trace.fraction > 0)
198 		{	// actually covered some distance
199 			VectorCopy (trace.endpos, ent->s.origin);
200 			VectorCopy (ent->velocity, original_velocity);
201 			numplanes = 0;
202 		}
203 
204 		if (trace.fraction == 1)
205 			 break;		// moved the entire distance
206 
207 		hit = trace.ent;
208 
209 		if (trace.plane.normal[2] > 0.7)
210 		{
211 			blocked |= 1;		// floor
212 			if ( hit->solid == SOLID_BSP)
213 			{
214 				ent->groundentity = hit;
215 				ent->groundentity_linkcount = hit->linkcount;
216 			}
217 		}
218 		if (!trace.plane.normal[2])
219 		{
220 			blocked |= 2;		// step
221 		}
222 
223 //
224 // run the impact function
225 //
226 		SV_Impact (ent, &trace);
227 		if (!ent->inuse)
228 			break;		// removed by the impact function
229 
230 
231 		time_left -= time_left * trace.fraction;
232 
233 	// cliped to another plane
234 		if (numplanes >= MAX_CLIP_PLANES)
235 		{	// this shouldn't really happen
236 			VectorCopy (vec3_origin, ent->velocity);
237 			return 3;
238 		}
239 
240 		VectorCopy (trace.plane.normal, planes[numplanes]);
241 		numplanes++;
242 
243 //
244 // modify original_velocity so it parallels all of the clip planes
245 //
246 //numplanes = 0;
247 //PON-CTF
248 		i = false;
249 		if(ctf->value)
250 		{
251 			if(ent->client->ctf_grapple != NULL
252 				&& ent->client->ctf_grapplestate != CTF_GRAPPLE_STATE_FLY
253 				/*&& ent->waterlevel <= 1*/) i = true;
254 		}
255 		if(!i){if(!ent->groundentity) i = true;}
256 //PON-CTF
257 		if(!i/*ent->client*/)
258 		{
259 			if(!ent->client->zc.trapped
260 				&& !i)
261 			{
262 				numplanes = 0;
263 				if(ent->waterlevel || (!ent->groundentity && ent->velocity[2] > 10 )) goto VELCX;
264 				i =0;
265 				if(/*ent->groundentity ||*/ ent->velocity[2] > 10) goto VELC;
266 			}
267 		}
268 
269 		for (i=0 ; i<numplanes ; i++)
270 		{
271 			ClipVelocity (original_velocity, planes[i], new_velocity, 1);
272 
273 			for (j=0 ; j<numplanes ; j++)
274 				if (j != i)
275 				{
276 					if (DotProduct (new_velocity, planes[j]) < 0)
277 						break;	// not ok
278 				}
279 			if (j == numplanes)
280 				break;
281 		}
282 //ponko
283 
284 //ponko
285 VELC:
286 		if (i != numplanes)
287 		{	// go along this plane
288 			VectorCopy (new_velocity, ent->velocity);
289 		}
290 		else
291 		{	// go along the crease
292 			if (numplanes != 2)
293 			{
294 //				gi.dprintf ("clip velocity, numplanes == %i\n",numplanes);
295 				VectorCopy (vec3_origin, ent->velocity);
296 				return 7;
297 			}
298 			CrossProduct (planes[0], planes[1], dir);
299 			d = DotProduct (dir, ent->velocity);
300 			VectorScale (dir, d, ent->velocity);
301 		}
302 VELCX:
303 //
304 // if original velocity is against the original velocity, stop dead
305 // to avoid tiny occilations in sloping corners
306 //
307 		if (DotProduct (ent->velocity, primal_velocity) <= 0)
308 		{
309 			VectorCopy (vec3_origin, ent->velocity);
310 			return blocked;
311 		}
312 	}
313 
314 	return blocked;
315 }
316 
317 
318 /*
319 ============
320 SV_AddGravity
321 
322 ============
323 */
SV_AddGravity(edict_t * ent)324 void SV_AddGravity (edict_t *ent)
325 {
326 //	gi.bprintf(PRINT_HIGH,"gravadd %f\n",ent->gravity * sv_gravity->value * FRAMETIME);
327 	ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME;
328 }
329 
330 /*
331 ===============================================================================
332 
333 PUSHMOVE
334 
335 ===============================================================================
336 */
337 
338 /*
339 ============
340 SV_PushEntity
341 
342 Does not change the entities velocity at all
343 ============
344 */
SV_PushEntity(edict_t * ent,vec3_t push)345 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
346 {
347 	trace_t	trace;
348 	vec3_t	start;
349 	vec3_t	end;
350 	int		mask;
351 
352 	VectorCopy (ent->s.origin, start);
353 	VectorAdd (start, push, end);
354 
355 retry:
356 	if (ent->clipmask)
357 		mask = ent->clipmask;
358 	else
359 		mask = MASK_SOLID;
360 
361 	trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
362 
363 	VectorCopy (trace.endpos, ent->s.origin);
364 	gi.linkentity (ent);
365 
366 	if (trace.fraction != 1.0)
367 	{
368 		SV_Impact (ent, &trace);
369 
370 		// if the pushed entity went away and the pusher is still there
371 		if (!trace.ent->inuse && ent->inuse)
372 		{
373 			// move the pusher back and try again
374 			VectorCopy (start, ent->s.origin);
375 			gi.linkentity (ent);
376 			goto retry;
377 		}
378 	}
379 
380 	if (ent->inuse)
381 		G_TouchTriggers (ent);
382 
383 	return trace;
384 }
385 
386 
387 typedef struct
388 {
389 	edict_t	*ent;
390 	vec3_t	origin;
391 	vec3_t	angles;
392 	float	deltayaw;
393 } pushed_t;
394 pushed_t	pushed[MAX_EDICTS], *pushed_p;
395 
396 edict_t	*obstacle;
397 
398 /*
399 ============
400 SV_Push
401 
402 Objects need to be moved back on a failed push,
403 otherwise riders would continue to slide.
404 ============
405 */
SV_Push(edict_t * pusher,vec3_t move,vec3_t amove)406 qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove)
407 {
408 	int			i, e;
409 	edict_t		*check, *block;
410 	vec3_t		mins, maxs;
411 	pushed_t	*p;
412 	vec3_t		org, org2, move2, forward, right, up;
413 
414 	// clamp the move to 1/8 units, so the position will
415 	// be accurate for client side prediction
416 	for (i=0 ; i<3 ; i++)
417 	{
418 		float	temp;
419 		temp = move[i]*8.0;
420 		if (temp > 0.0)
421 			temp += 0.5;
422 		else
423 			temp -= 0.5;
424 		move[i] = 0.125 * (int)temp;
425 	}
426 
427 	// find the bounding box
428 	for (i=0 ; i<3 ; i++)
429 	{
430 		mins[i] = pusher->absmin[i] + move[i];
431 		maxs[i] = pusher->absmax[i] + move[i];
432 	}
433 
434 // we need this for pushing things later
435 	VectorSubtract (vec3_origin, amove, org);
436 	AngleVectors (org, forward, right, up);
437 
438 // save the pusher's original position
439 	pushed_p->ent = pusher;
440 	VectorCopy (pusher->s.origin, pushed_p->origin);
441 	VectorCopy (pusher->s.angles, pushed_p->angles);
442 	if (pusher->client)
443 		pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW];
444 	pushed_p++;
445 
446 // move the pusher to it's final position
447 	VectorAdd (pusher->s.origin, move, pusher->s.origin);
448 	VectorAdd (pusher->s.angles, amove, pusher->s.angles);
449 	gi.linkentity (pusher);
450 
451 // see if any solid entities are inside the final position
452 	check = g_edicts+1;
453 	for (e = 1; e < globals.num_edicts; e++, check++)
454 	{
455 		if (!check->inuse)
456 			continue;
457 		if (!check->solid) continue;
458 
459 //ponko
460 		if(check->classname[0] == 'R' && (check->classname[6] == 'X' || check->classname[6] == '3') ) continue;
461 
462 		if (check->movetype == MOVETYPE_PUSH
463 		|| check->movetype == MOVETYPE_STOP
464 		|| check->movetype == MOVETYPE_NONE
465 		|| check->movetype == MOVETYPE_NOCLIP)
466 			continue;
467 
468 //		if(check->movetype == MOVETYPE_STEP) M_CheckGround(check);
469 		if (!check->area.prev)
470 			continue;		// not linked in anywhere
471 
472 	// if the entity is standing on the pusher, it will definitely be moved
473 		if (check->groundentity != pusher)
474 		{
475 			// see if the ent needs to be tested
476 			if ( check->absmin[0] >= maxs[0]
477 			|| check->absmin[1] >= maxs[1]
478 			|| check->absmin[2] >= maxs[2]
479 			|| check->absmax[0] <= mins[0]
480 			|| check->absmax[1] <= mins[1]
481 			|| check->absmax[2] <= mins[2] )
482 				continue;
483 
484 			// see if the ent's bbox is inside the pusher's final position
485 			if (!SV_TestEntityPosition (check))
486 				continue;
487 		}
488 
489 		if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher))
490 		{
491 			// move this entity
492 			pushed_p->ent = check;
493 			VectorCopy (check->s.origin, pushed_p->origin);
494 			VectorCopy (check->s.angles, pushed_p->angles);
495 			pushed_p++;
496 
497 			// try moving the contacted entity
498 			VectorAdd (check->s.origin, move, check->s.origin);
499 			if (check->client)
500 			{	// FIXME: doesn't rotate monsters?
501 				check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
502 			}
503 
504 			// figure movement due to the pusher's amove
505 			VectorSubtract (check->s.origin, pusher->s.origin, org);
506 			org2[0] = DotProduct (org, forward);
507 			org2[1] = -DotProduct (org, right);
508 			org2[2] = DotProduct (org, up);
509 			VectorSubtract (org2, org, move2);
510 			VectorAdd (check->s.origin, move2, check->s.origin);
511 
512 			// may have pushed them off an edge
513 			if (check->groundentity != pusher)
514 				check->groundentity = NULL;
515 
516 			block = SV_TestEntityPosition (check);
517 			if (!block)
518 			{	// pushed ok
519 				gi.linkentity (check);
520 				// impact?
521 				continue;
522 			}
523 
524 			// if it is ok to leave in the old position, do it
525 			// this is only relevent for riding entities, not pushed
526 			// FIXME: this doesn't acount for rotation
527 			VectorSubtract (check->s.origin, move, check->s.origin);
528 			block = SV_TestEntityPosition (check);
529 			if (!block)
530 			{
531 				pushed_p--;
532 				continue;
533 			}
534 		}
535 
536 		// save off the obstacle so we can call the block function
537 		obstacle = check;
538 
539 		// move back any entities we already moved
540 		// go backwards, so if the same entity was pushed
541 		// twice, it goes back to the original position
542 		for (p=pushed_p-1 ; p>=pushed ; p--)
543 		{
544 			VectorCopy (p->origin, p->ent->s.origin);
545 			VectorCopy (p->angles, p->ent->s.angles);
546 			if (p->ent->client)
547 			{
548 				p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw;
549 			}
550 			gi.linkentity (p->ent);
551 		}
552 		return false;
553 	}
554 
555 //FIXME: is there a better way to handle this?
556 	// see if anything we moved has touched a trigger
557 	for (p=pushed_p-1 ; p>=pushed ; p--)
558 		G_TouchTriggers (p->ent);
559 
560 	return true;
561 }
562 
563 /*
564 ================
565 SV_Physics_Pusher
566 
567 Bmodel objects don't interact with each other, but
568 push all box objects
569 ================
570 */
SV_Physics_Pusher(edict_t * ent)571 void SV_Physics_Pusher (edict_t *ent)
572 {
573 	vec3_t		move, amove;
574 	edict_t		*part, *mv;
575 
576 	// if not a team captain, so movement will be handled elsewhere
577 	if ( ent->flags & FL_TEAMSLAVE)
578 		return;
579 
580 	// make sure all team slaves can move before commiting
581 	// any moves or calling any think functions
582 	// if the move is blocked, all moved objects will be backed out
583 //retry:
584 	pushed_p = pushed;
585 	for (part = ent ; part ; part=part->teamchain)
586 	{
587 		if (part->velocity[0] || part->velocity[1] || part->velocity[2] ||
588 			part->avelocity[0] || part->avelocity[1] || part->avelocity[2]
589 			)
590 		{	// object is moving
591 			VectorScale (part->velocity, FRAMETIME, move);
592 			VectorScale (part->avelocity, FRAMETIME, amove);
593 
594 			if (!SV_Push (part, move, amove))
595 				break;	// move was blocked
596 		}
597 	}
598 	if (pushed_p > &pushed[MAX_EDICTS])
599 		gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
600 
601 	if (part)
602 	{
603 		// the move failed, bump all nextthink times and back out moves
604 		for (mv = ent ; mv ; mv=mv->teamchain)
605 		{
606 			if (mv->nextthink > 0)
607 				mv->nextthink += FRAMETIME;
608 		}
609 
610 		// if the pusher has a "blocked" function, call it
611 		// otherwise, just stay in place until the obstacle is gone
612 		if (part->blocked)
613 		{
614 			part->blocked (part, obstacle);
615 		}
616 
617 #if 0
618 		// if the pushed entity went away and the pusher is still there
619 		if (!obstacle->inuse && part->inuse)
620 			goto retry;
621 #endif
622 	}
623 	else
624 	{
625 		// the move succeeded, so call all think functions
626 		for (part = ent ; part ; part=part->teamchain)
627 		{
628 			SV_RunThink (part);
629 		}
630 	}
631 }
632 
633 //==================================================================
634 
635 /*
636 =============
637 SV_Physics_None
638 
639 Non moving objects can only think
640 =============
641 */
SV_Physics_None(edict_t * ent)642 void SV_Physics_None (edict_t *ent)
643 {
644 // regular thinking
645 	SV_RunThink (ent);
646 }
647 
648 /*
649 =============
650 SV_Physics_Noclip
651 
652 A moving object that doesn't obey physics
653 =============
654 */
SV_Physics_Noclip(edict_t * ent)655 void SV_Physics_Noclip (edict_t *ent)
656 {
657 // regular thinking
658 	if (!SV_RunThink (ent))
659 		return;
660 
661 	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
662 	VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin);
663 
664 	gi.linkentity (ent);
665 }
666 
667 /*
668 ==============================================================================
669 
670 TOSS / BOUNCE
671 
672 ==============================================================================
673 */
674 
675 /*
676 =============
677 SV_Physics_Toss
678 
679 Toss, bounce, and fly movement.  When onground, do nothing.
680 =============
681 */
SV_Physics_Toss(edict_t * ent)682 void SV_Physics_Toss (edict_t *ent)
683 {
684 	trace_t		trace;
685 	vec3_t		move;
686 	float		backoff;
687 	edict_t		*slave;
688 	qboolean	wasinwater;
689 	qboolean	isinwater;
690 	vec3_t		old_origin;
691 
692 	qboolean	forcethrough = false;
693 
694 // regular thinking
695 	SV_RunThink (ent);
696 
697 	// if not a team captain, so movement will be handled elsewhere
698 	if ( ent->flags & FL_TEAMSLAVE)
699 		return;
700 
701 	if (ent->velocity[2] > 0)
702 		ent->groundentity = NULL;
703 
704 // check for the groundentity going away
705 	if (ent->groundentity)
706 		if (!ent->groundentity->inuse)
707 			ent->groundentity = NULL;
708 
709 // if onground, return without moving
710 	if ( ent->groundentity )
711 		return;
712 
713 	VectorCopy (ent->s.origin, old_origin);
714 
715 	SV_CheckVelocity (ent);
716 
717 // add gravity
718 	if (ent->movetype != MOVETYPE_FLY
719 	&& ent->movetype != MOVETYPE_FLYMISSILE
720 	// RAFAEL
721 	// move type for rippergun projectile
722 	&& ent->movetype != MOVETYPE_WALLBOUNCE)
723 		SV_AddGravity (ent);
724 
725 // move angles
726 	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
727 
728 // move origin
729 	VectorScale (ent->velocity, FRAMETIME, move);
730 
731 
732 	if(ent->classname[0] == 'R' && (ent->classname[6] == 'X' || ent->classname[6] == '3'))
733 	{
734 		ent->groundentity = ent->union_ent;
735 		ent->groundentity_linkcount = ent->union_ent->linkcount;
736 		VectorCopy (ent->union_ent->velocity, ent->velocity);
737 		VectorCopy (ent->union_ent->avelocity, ent->avelocity);
738 
739 		VectorAdd(ent->union_ent->s.origin,ent->moveinfo.dir,ent->s.origin);
740 	}
741 	trace = SV_PushEntity (ent, move);
742 
743 	if (!ent->inuse)
744 		return;
745 
746 
747 	if (trace.fraction < 1 && !forcethrough)
748 	{
749 		// RAFAEL
750 		if (ent->movetype == MOVETYPE_WALLBOUNCE)
751 			backoff = 2.0;
752 		// RAFAEL ( else )
753 		else if (ent->movetype == MOVETYPE_BOUNCE)
754 			backoff = 1.5;
755 		else
756 			backoff = 1;
757 
758 		ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
759 
760 		// RAFAEL
761 		if (ent->movetype == MOVETYPE_WALLBOUNCE)
762 			vectoangles (ent->velocity, ent->s.angles);
763 
764 	// stop if on ground
765 		// RAFAEL
766 		if (trace.plane.normal[2] > 0.7 && ent->movetype != MOVETYPE_WALLBOUNCE)
767 		{
768 			if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
769 			{
770 				ent->groundentity = trace.ent;
771 				ent->groundentity_linkcount = trace.ent->linkcount;
772 				VectorCopy (vec3_origin, ent->velocity);
773 				VectorCopy (vec3_origin, ent->avelocity);
774 			}
775 		}
776 
777 //		if (ent->touch)
778 //			ent->touch (ent, trace.ent, &trace.plane, trace.surface);
779 	}
780 
781 // check for water transition
782 	wasinwater = (ent->watertype & MASK_WATER);
783 	ent->watertype = gi.pointcontents (ent->s.origin);
784 	isinwater = ent->watertype & MASK_WATER;
785 
786 	if (isinwater)
787 		ent->waterlevel = 1;
788 	else
789 		ent->waterlevel = 0;
790 
791 	if (!wasinwater && isinwater)
792 		gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
793 	else if (wasinwater && !isinwater)
794 		gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
795 
796 // move teamslaves
797 	for (slave = ent->teamchain; slave; slave = slave->teamchain)
798 	{
799 		VectorCopy (ent->s.origin, slave->s.origin);
800 		gi.linkentity (slave);
801 	}
802 }
803 
804 /*
805 ===============================================================================
806 
807 STEPPING MOVEMENT
808 
809 ===============================================================================
810 */
811 
812 /*
813 =============
814 SV_Physics_Step
815 
816 Monsters freefall when they don't have a ground entity, otherwise
817 all movement is done with discrete steps.
818 
819 This is also used for objects that have become still on the ground, but
820 will fall if the floor is pulled out from under them.
821 FIXME: is this true?
822 =============
823 */
824 
825 //FIXME: hacked in for E3 demo
826 #define	sv_stopspeed		100
827 #define sv_friction			6
828 #define sv_waterfriction	1
829 
SV_AddRotationalFriction(edict_t * ent)830 void SV_AddRotationalFriction (edict_t *ent)
831 {
832 	int		n;
833 	float	adjustment;
834 
835 	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
836 	adjustment = FRAMETIME * sv_stopspeed * sv_friction;
837 	for (n = 0; n < 3; n++)
838 	{
839 		if (ent->avelocity[n] > 0)
840 		{
841 			ent->avelocity[n] -= adjustment;
842 			if (ent->avelocity[n] < 0)
843 				ent->avelocity[n] = 0;
844 		}
845 		else
846 		{
847 			ent->avelocity[n] += adjustment;
848 			if (ent->avelocity[n] > 0)
849 				ent->avelocity[n] = 0;
850 		}
851 	}
852 }
853 
854 void P_FallingDamage (edict_t *ent);
SV_Physics_Step(edict_t * ent)855 void SV_Physics_Step (edict_t *ent)
856 {
857 	qboolean	wasonground;
858 	qboolean	hitsound = false;
859 	float		*vel;
860 	float		speed, newspeed, control;
861 	float		friction;
862 	edict_t		*groundentity;
863 	int			mask;
864 //	vec3_t		dir;
865 
866 
867 	// airborn monsters should always check for ground
868 //	if (!ent->groundentity)
869 		M_CheckGround (ent);
870 
871 	groundentity = ent->groundentity;
872 
873 	SV_CheckVelocity (ent);
874 
875 	if (groundentity)
876 		wasonground = true;
877 	else
878 		wasonground = false;
879 
880 //	if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
881 //		SV_AddRotationalFriction (ent);
882 
883 	// add gravity except:
884 	//   flying monsters
885 	//   swimming monsters who are in the water
886 	if (! wasonground)
887 		if (!(ent->flags & FL_FLY))
888 			if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
889 			{
890 				if (ent->velocity[2] < sv_gravity->value*-0.1)
891 					hitsound = true;
892 				if (ent->waterlevel == 0)
893 					SV_AddGravity (ent);
894 			}
895 
896 	// friction for flying monsters that have been given vertical velocity
897 	if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
898 	{
899 //gi.bprintf(PRINT_HIGH,"FLY!\n");
900 		speed = fabs(ent->velocity[2]);
901 		control = speed < sv_stopspeed ? sv_stopspeed : speed;
902 		friction = sv_friction/3;
903 		newspeed = speed - (FRAMETIME * control * friction);
904 		if (newspeed < 0)
905 			newspeed = 0;
906 		newspeed /= speed;
907 		ent->velocity[2] *= newspeed;
908 	}
909 
910 	// friction for flying monsters that have been given vertical velocity
911 	if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
912 	{
913 //gi.bprintf(PRINT_HIGH,"SWIM!\n");
914 		speed = fabs(ent->velocity[2]);
915 		control = speed < sv_stopspeed ? sv_stopspeed : speed;
916 		newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
917 		if (newspeed < 0)
918 			newspeed = 0;
919 		newspeed /= speed;
920 		ent->velocity[2] *= newspeed;
921 	}
922 
923 //	if(ent->client){if(ent->client->ctf_grapple) if(ent->client->ctf_grapplestate == CTF_GRAPPLE_STATE_FLY) ent->velocity[2] = 0;}
924 
925 	if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
926 	{
927 		// apply friction
928 		// let dead monsters who aren't completely onground slide
929 		if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
930 			if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
931 			{
932 				vel = ent->velocity;
933 				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
934 				if (speed)
935 				{
936 					friction = sv_friction;
937 
938 					control = speed < sv_stopspeed ? sv_stopspeed : speed;
939 					newspeed = speed - FRAMETIME*control*friction;
940 
941 					if (newspeed < 0)
942 						newspeed = 0;
943 					newspeed /= speed;
944 
945 					vel[0] *= newspeed;
946 					vel[1] *= newspeed;
947 				}
948 			}
949 
950 		if (ent->svflags & SVF_MONSTER)
951 		{
952 			if(!deathmatch->value) mask = MASK_MONSTERSOLID;
953 			else mask = MASK_BOTSOLIDX;//MASK_PLAYERSOLID;
954 		}
955 		else
956 			mask = MASK_SOLID;
957 		SV_FlyMove (ent, FRAMETIME, mask);
958 
959 		gi.linkentity (ent);
960 //		G_TouchTriggers (ent);
961 
962 /*		if (ent->groundentity)
963 		{
964 			if (!wasonground)
965 			{
966 				speed = ent->s.old_origin[2] - ent->s.origin[2];
967 				VectorSubtract(ent->s.old_origin,ent->s.origin,dir);
968 				VectorNormalize(dir);
969 				if (hitsound && !ent->waterlevel && speed > 0)
970 				{
971 
972 					if( speed < 5 ) gi.sound (ent, 0, gi.soundindex("player/land1.wav"), 1, 1, 0);
973 					else if( speed < 40 || ent->client == NULL)
974 					{
975 						gi.sound (ent, 0, gi.soundindex("player/step3.wav"), 1, 1, 0);
976 //						gi.bprintf(PRINT_HIGH,"level 1\n");
977 					}
978 					else if( speed < 60 )
979 					{
980 						gi.sound (ent, 0, gi.soundindex("*fall2.wav"), 1, 1, 0);
981 						ent->pain_debounce_time = level.time + FRAMETIME * 10;
982 						T_Damage (ent, world, world, dir, ent->s.origin, ent->s.origin, (int)(random()*(15)), 0, 0, MOD_FALLING);
983 //						gi.bprintf(PRINT_HIGH,"level 2\n");
984 					}
985 					else
986 					{
987 						gi.sound (ent, 0, gi.soundindex("*fall1.wav"), 1, 1, 0);
988 						ent->pain_debounce_time = level.time + FRAMETIME * 10;
989 						T_Damage (ent, world, world, dir, ent->s.origin, ent->s.origin, (int)(random() * (25)), 0, 0, MOD_FALLING);
990 //						gi.bprintf(PRINT_HIGH,"level 3\n");
991 					}
992 				}
993 			}
994 		}*/
995 	}
996 
997 // regular thinking
998 	SV_RunThink (ent);
999 }
1000 
1001 //============================================================================
1002 /*
1003 ================
1004 G_RunEntity
1005 
1006 ================
1007 */
G_RunEntity(edict_t * ent)1008 void G_RunEntity (edict_t *ent)
1009 {
1010 
1011 	if (ent->prethink)
1012 		ent->prethink (ent);
1013 
1014 	switch ( (int)ent->movetype)
1015 	{
1016 	case MOVETYPE_PUSH:
1017 	case MOVETYPE_STOP:
1018 		SV_Physics_Pusher (ent);
1019 		break;
1020 	case MOVETYPE_NONE:
1021 		SV_Physics_None (ent);
1022 		break;
1023 	case MOVETYPE_NOCLIP:
1024 		SV_Physics_Noclip (ent);
1025 		break;
1026 	case MOVETYPE_STEP:
1027 		SV_Physics_Step (ent);
1028 		break;
1029 	case MOVETYPE_TOSS:
1030 	case MOVETYPE_BOUNCE:
1031 	case MOVETYPE_FLY:
1032 	case MOVETYPE_FLYMISSILE:
1033 		SV_Physics_Toss (ent);
1034 		break;
1035 	// RAFAEL
1036 	case MOVETYPE_WALLBOUNCE:
1037 		SV_Physics_Toss (ent);
1038 		break;
1039 	default:
1040 		gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);
1041 	}
1042 }
1043