• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "quakedef.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_friction = CVAR4("sv_friction","4",false,true);
43 cvar_t	sv_stopspeed = CVAR2("sv_stopspeed","100");
44 cvar_t	sv_gravity = CVAR4("sv_gravity","800",false,true);
45 cvar_t	sv_maxvelocity = CVAR2("sv_maxvelocity","2000");
46 cvar_t	sv_nostep = CVAR2("sv_nostep","0");
47 
48 #ifdef QUAKE2
49 static	vec3_t	vec_origin = {0.0, 0.0, 0.0};
50 #endif
51 
52 #define	MOVE_EPSILON	0.01
53 
54 void SV_Physics_Toss (edict_t *ent);
55 
56 /*
57 ================
58 SV_CheckAllEnts
59 ================
60 */
SV_CheckAllEnts(void)61 void SV_CheckAllEnts (void)
62 {
63 	int			e;
64 	edict_t		*check;
65 
66 // see if any solid entities are inside the final position
67 	check = NEXT_EDICT(sv.edicts);
68 	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
69 	{
70 		if (check->free)
71 			continue;
72 		if (check->u.v.movetype == MOVETYPE_PUSH
73 		|| check->u.v.movetype == MOVETYPE_NONE
74 #ifdef QUAKE2
75 		|| check->u.v.movetype == MOVETYPE_FOLLOW
76 #endif
77 		|| check->u.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 */
SV_CheckVelocity(edict_t * ent)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->u.v.velocity[i]))
100 		{
101 			Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->u.v.classname);
102 			ent->u.v.velocity[i] = 0;
103 		}
104 		if (IS_NAN(ent->u.v.origin[i]))
105 		{
106 			Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->u.v.classname);
107 			ent->u.v.origin[i] = 0;
108 		}
109 		if (ent->u.v.velocity[i] > sv_maxvelocity.value)
110 			ent->u.v.velocity[i] = sv_maxvelocity.value;
111 		else if (ent->u.v.velocity[i] < -sv_maxvelocity.value)
112 			ent->u.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 */
SV_RunThink(edict_t * ent)126 qboolean SV_RunThink (edict_t *ent)
127 {
128 	float	thinktime;
129 
130 	thinktime = ent->u.v.nextthink;
131 	if (thinktime <= 0 || thinktime > sv.time + host_frametime)
132 		return true;
133 
134 	if (thinktime < sv.time)
135 		thinktime = sv.time;	// don't let things stay in the past.
136 								// it is possible to start that way
137 								// by a trigger with a local time.
138 	ent->u.v.nextthink = 0;
139 	pr_global_struct->time = thinktime;
140 	pr_global_struct->self = EDICT_TO_PROG(ent);
141 	pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
142 	PR_ExecuteProgram (ent->u.v.think);
143 	return !ent->free;
144 }
145 
146 /*
147 ==================
148 SV_Impact
149 
150 Two entities have touched, so run their touch functions
151 ==================
152 */
SV_Impact(edict_t * e1,edict_t * e2)153 void SV_Impact (edict_t *e1, edict_t *e2)
154 {
155 	int		old_self, old_other;
156 
157 	old_self = pr_global_struct->self;
158 	old_other = pr_global_struct->other;
159 
160 	pr_global_struct->time = sv.time;
161 	if (e1->u.v.touch && e1->u.v.solid != SOLID_NOT)
162 	{
163 		pr_global_struct->self = EDICT_TO_PROG(e1);
164 		pr_global_struct->other = EDICT_TO_PROG(e2);
165 		PR_ExecuteProgram (e1->u.v.touch);
166 	}
167 
168 	if (e2->u.v.touch && e2->u.v.solid != SOLID_NOT)
169 	{
170 		pr_global_struct->self = EDICT_TO_PROG(e2);
171 		pr_global_struct->other = EDICT_TO_PROG(e1);
172 		PR_ExecuteProgram (e2->u.v.touch);
173 	}
174 
175 	pr_global_struct->self = old_self;
176 	pr_global_struct->other = old_other;
177 }
178 
179 
180 /*
181 ==================
182 ClipVelocity
183 
184 Slide off of the impacting object
185 returns the blocked flags (1 = floor, 2 = step / wall)
186 ==================
187 */
188 #define	STOP_EPSILON	0.1
189 
ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)190 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
191 {
192 	float	backoff;
193 	float	change;
194 	int		i, blocked;
195 
196 	blocked = 0;
197 	if (normal[2] > 0)
198 		blocked |= 1;		// floor
199 	if (!normal[2])
200 		blocked |= 2;		// step
201 
202 	backoff = DotProduct (in, normal) * overbounce;
203 
204 	for (i=0 ; i<3 ; i++)
205 	{
206 		change = normal[i]*backoff;
207 		out[i] = in[i] - change;
208 		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
209 			out[i] = 0;
210 	}
211 
212 	return blocked;
213 }
214 
215 
216 /*
217 ============
218 SV_FlyMove
219 
220 The basic solid body movement clip that slides along multiple planes
221 Returns the clipflags if the velocity was modified (hit something solid)
222 1 = floor
223 2 = wall / step
224 4 = dead stop
225 If steptrace is not NULL, the trace of any vertical wall hit will be stored
226 ============
227 */
228 #define	MAX_CLIP_PLANES	5
SV_FlyMove(edict_t * ent,float time,trace_t * steptrace)229 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
230 {
231 	int			bumpcount, numbumps;
232 	vec3_t		dir;
233 	float		d;
234 	int			numplanes;
235 	vec3_t		planes[MAX_CLIP_PLANES];
236 	vec3_t		primal_velocity, original_velocity, new_velocity;
237 	int			i, j;
238 	trace_t		trace;
239 	vec3_t		end;
240 	float		time_left;
241 	int			blocked;
242 
243 	numbumps = 4;
244 
245 	blocked = 0;
246 	VectorCopy (ent->u.v.velocity, original_velocity);
247 	VectorCopy (ent->u.v.velocity, primal_velocity);
248 	numplanes = 0;
249 
250 	time_left = time;
251 
252 	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
253 	{
254 		if (!ent->u.v.velocity[0] && !ent->u.v.velocity[1] && !ent->u.v.velocity[2])
255 			break;
256 
257 		for (i=0 ; i<3 ; i++)
258 			end[i] = ent->u.v.origin[i] + time_left * ent->u.v.velocity[i];
259 
260 		trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, end, false, ent);
261 
262 		if (trace.allsolid)
263 		{	// entity is trapped in another solid
264 			VectorCopy (vec3_origin, ent->u.v.velocity);
265 			return 3;
266 		}
267 
268 		if (trace.fraction > 0)
269 		{	// actually covered some distance
270 			VectorCopy (trace.endpos, ent->u.v.origin);
271 			VectorCopy (ent->u.v.velocity, original_velocity);
272 			numplanes = 0;
273 		}
274 
275 		if (trace.fraction == 1)
276 			 break;		// moved the entire distance
277 
278 		if (!trace.ent)
279 			Sys_Error ("SV_FlyMove: !trace.ent");
280 
281 		if (trace.plane.normal[2] > 0.7)
282 		{
283 			blocked |= 1;		// floor
284 			if (trace.ent->u.v.solid == SOLID_BSP)
285 			{
286 				ent->u.v.flags =	(int)ent->u.v.flags | FL_ONGROUND;
287 				ent->u.v.groundentity = EDICT_TO_PROG(trace.ent);
288 			}
289 		}
290 		if (!trace.plane.normal[2])
291 		{
292 			blocked |= 2;		// step
293 			if (steptrace)
294 				*steptrace = trace;	// save for player extrafriction
295 		}
296 
297 //
298 // run the impact function
299 //
300 		SV_Impact (ent, trace.ent);
301 		if (ent->free)
302 			break;		// removed by the impact function
303 
304 
305 		time_left -= time_left * trace.fraction;
306 
307 	// cliped to another plane
308 		if (numplanes >= MAX_CLIP_PLANES)
309 		{	// this shouldn't really happen
310 			VectorCopy (vec3_origin, ent->u.v.velocity);
311 			return 3;
312 		}
313 
314 		VectorCopy (trace.plane.normal, planes[numplanes]);
315 		numplanes++;
316 
317 //
318 // modify original_velocity so it parallels all of the clip planes
319 //
320 		for (i=0 ; i<numplanes ; i++)
321 		{
322 			ClipVelocity (original_velocity, planes[i], new_velocity, 1);
323 			for (j=0 ; j<numplanes ; j++)
324 				if (j != i)
325 				{
326 					if (DotProduct (new_velocity, planes[j]) < 0)
327 						break;	// not ok
328 				}
329 			if (j == numplanes)
330 				break;
331 		}
332 
333 		if (i != numplanes)
334 		{	// go along this plane
335 			VectorCopy (new_velocity, ent->u.v.velocity);
336 		}
337 		else
338 		{	// go along the crease
339 			if (numplanes != 2)
340 			{
341 //				Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
342 				VectorCopy (vec3_origin, ent->u.v.velocity);
343 				return 7;
344 			}
345 			CrossProduct (planes[0], planes[1], dir);
346 			d = DotProduct (dir, ent->u.v.velocity);
347 			VectorScale (dir, d, ent->u.v.velocity);
348 		}
349 
350 //
351 // if original velocity is against the original velocity, stop dead
352 // to avoid tiny occilations in sloping corners
353 //
354 		if (DotProduct (ent->u.v.velocity, primal_velocity) <= 0)
355 		{
356 			VectorCopy (vec3_origin, ent->u.v.velocity);
357 			return blocked;
358 		}
359 	}
360 
361 	return blocked;
362 }
363 
364 
365 /*
366 ============
367 SV_AddGravity
368 
369 ============
370 */
SV_AddGravity(edict_t * ent)371 void SV_AddGravity (edict_t *ent)
372 {
373 	float	ent_gravity;
374 
375 #ifdef QUAKE2
376 	if (ent->u.v.gravity)
377 		ent_gravity = ent->u.v.gravity;
378 	else
379 		ent_gravity = 1.0;
380 #else
381 	eval_t	*val;
382 
383 	val = GetEdictFieldValue(ent, "gravity");
384 	if (val && val->_float)
385 		ent_gravity = val->_float;
386 	else
387 		ent_gravity = 1.0;
388 #endif
389 	ent->u.v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
390 }
391 
392 
393 /*
394 ===============================================================================
395 
396 PUSHMOVE
397 
398 ===============================================================================
399 */
400 
401 /*
402 ============
403 SV_PushEntity
404 
405 Does not change the entities velocity at all
406 ============
407 */
SV_PushEntity(edict_t * ent,vec3_t push)408 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
409 {
410 	trace_t	trace;
411 	vec3_t	end;
412 
413 	VectorAdd (ent->u.v.origin, push, end);
414 
415 	if (ent->u.v.movetype == MOVETYPE_FLYMISSILE)
416 		trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, end, MOVE_MISSILE, ent);
417 	else if (ent->u.v.solid == SOLID_TRIGGER || ent->u.v.solid == SOLID_NOT)
418 	// only clip against bmodels
419 		trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, end, MOVE_NOMONSTERS, ent);
420 	else
421 		trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, end, MOVE_NORMAL, ent);
422 
423 	VectorCopy (trace.endpos, ent->u.v.origin);
424 	SV_LinkEdict (ent, true);
425 
426 	if (trace.ent)
427 		SV_Impact (ent, trace.ent);
428 
429 	return trace;
430 }
431 
432 
433 /*
434 ============
435 SV_PushMove
436 
437 ============
438 */
SV_PushMove(edict_t * pusher,float movetime)439 void SV_PushMove (edict_t *pusher, float movetime)
440 {
441 	int			i, e;
442 	edict_t		*check, *block;
443 	vec3_t		mins, maxs, move;
444 	vec3_t		entorig, pushorig;
445 	int			num_moved;
446 	edict_t		*moved_edict[MAX_EDICTS];
447 	vec3_t		moved_from[MAX_EDICTS];
448 
449 	if (!pusher->u.v.velocity[0] && !pusher->u.v.velocity[1] && !pusher->u.v.velocity[2])
450 	{
451 		pusher->u.v.ltime += movetime;
452 		return;
453 	}
454 
455 	for (i=0 ; i<3 ; i++)
456 	{
457 		move[i] = pusher->u.v.velocity[i] * movetime;
458 		mins[i] = pusher->u.v.absmin[i] + move[i];
459 		maxs[i] = pusher->u.v.absmax[i] + move[i];
460 	}
461 
462 	VectorCopy (pusher->u.v.origin, pushorig);
463 
464 // move the pusher to it's final position
465 
466 	VectorAdd (pusher->u.v.origin, move, pusher->u.v.origin);
467 	pusher->u.v.ltime += movetime;
468 	SV_LinkEdict (pusher, false);
469 
470 
471 // see if any solid entities are inside the final position
472 	num_moved = 0;
473 	check = NEXT_EDICT(sv.edicts);
474 	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
475 	{
476 		if (check->free)
477 			continue;
478 		if (check->u.v.movetype == MOVETYPE_PUSH
479 		|| check->u.v.movetype == MOVETYPE_NONE
480 #ifdef QUAKE2
481 		|| check->u.v.movetype == MOVETYPE_FOLLOW
482 #endif
483 		|| check->u.v.movetype == MOVETYPE_NOCLIP)
484 			continue;
485 
486 	// if the entity is standing on the pusher, it will definately be moved
487 		if ( ! ( ((int)check->u.v.flags & FL_ONGROUND)
488 		&& PROG_TO_EDICT(check->u.v.groundentity) == pusher) )
489 		{
490 			if ( check->u.v.absmin[0] >= maxs[0]
491 			|| check->u.v.absmin[1] >= maxs[1]
492 			|| check->u.v.absmin[2] >= maxs[2]
493 			|| check->u.v.absmax[0] <= mins[0]
494 			|| check->u.v.absmax[1] <= mins[1]
495 			|| check->u.v.absmax[2] <= mins[2] )
496 				continue;
497 
498 		// see if the ent's bbox is inside the pusher's final position
499 			if (!SV_TestEntityPosition (check))
500 				continue;
501 		}
502 
503 	// remove the onground flag for non-players
504 		if (check->u.v.movetype != MOVETYPE_WALK)
505 			check->u.v.flags = (int)check->u.v.flags & ~FL_ONGROUND;
506 
507 		VectorCopy (check->u.v.origin, entorig);
508 		VectorCopy (check->u.v.origin, moved_from[num_moved]);
509 		moved_edict[num_moved] = check;
510 		num_moved++;
511 
512 		// try moving the contacted entity
513 		pusher->u.v.solid = SOLID_NOT;
514 		SV_PushEntity (check, move);
515 		pusher->u.v.solid = SOLID_BSP;
516 
517 	// if it is still inside the pusher, block
518 		block = SV_TestEntityPosition (check);
519 		if (block)
520 		{	// fail the move
521 			if (check->u.v.mins[0] == check->u.v.maxs[0])
522 				continue;
523 			if (check->u.v.solid == SOLID_NOT || check->u.v.solid == SOLID_TRIGGER)
524 			{	// corpse
525 				check->u.v.mins[0] = check->u.v.mins[1] = 0;
526 				VectorCopy (check->u.v.mins, check->u.v.maxs);
527 				continue;
528 			}
529 
530 			VectorCopy (entorig, check->u.v.origin);
531 			SV_LinkEdict (check, true);
532 
533 			VectorCopy (pushorig, pusher->u.v.origin);
534 			SV_LinkEdict (pusher, false);
535 			pusher->u.v.ltime -= movetime;
536 
537 			// if the pusher has a "blocked" function, call it
538 			// otherwise, just stay in place until the obstacle is gone
539 			if (pusher->u.v.blocked)
540 			{
541 				pr_global_struct->self = EDICT_TO_PROG(pusher);
542 				pr_global_struct->other = EDICT_TO_PROG(check);
543 				PR_ExecuteProgram (pusher->u.v.blocked);
544 			}
545 
546 		// move back any entities we already moved
547 			for (i=0 ; i<num_moved ; i++)
548 			{
549 				VectorCopy (moved_from[i], moved_edict[i]->u.v.origin);
550 				SV_LinkEdict (moved_edict[i], false);
551 			}
552 			return;
553 		}
554 	}
555 
556 
557 }
558 
559 #ifdef QUAKE2
560 /*
561 ============
562 SV_PushRotate
563 
564 ============
565 */
SV_PushRotate(edict_t * pusher,float movetime)566 void SV_PushRotate (edict_t *pusher, float movetime)
567 {
568 	int			i, e;
569 	edict_t		*check, *block;
570 	vec3_t		move, a, amove;
571 	vec3_t		entorig, pushorig;
572 	int			num_moved;
573 	edict_t		*moved_edict[MAX_EDICTS];
574 	vec3_t		moved_from[MAX_EDICTS];
575 	vec3_t		org, org2;
576 	vec3_t		forward, right, up;
577 
578 	if (!pusher->u.v.avelocity[0] && !pusher->u.v.avelocity[1] && !pusher->u.v.avelocity[2])
579 	{
580 		pusher->u.v.ltime += movetime;
581 		return;
582 	}
583 
584 	for (i=0 ; i<3 ; i++)
585 		amove[i] = pusher->u.v.avelocity[i] * movetime;
586 
587 	VectorSubtract (vec3_origin, amove, a);
588 	AngleVectors (a, forward, right, up);
589 
590 	VectorCopy (pusher->u.v.angles, pushorig);
591 
592 // move the pusher to it's final position
593 
594 	VectorAdd (pusher->u.v.angles, amove, pusher->u.v.angles);
595 	pusher->u.v.ltime += movetime;
596 	SV_LinkEdict (pusher, false);
597 
598 
599 // see if any solid entities are inside the final position
600 	num_moved = 0;
601 	check = NEXT_EDICT(sv.edicts);
602 	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
603 	{
604 		if (check->free)
605 			continue;
606 		if (check->u.v.movetype == MOVETYPE_PUSH
607 		|| check->u.v.movetype == MOVETYPE_NONE
608 		|| check->u.v.movetype == MOVETYPE_FOLLOW
609 		|| check->u.v.movetype == MOVETYPE_NOCLIP)
610 			continue;
611 
612 	// if the entity is standing on the pusher, it will definately be moved
613 		if ( ! ( ((int)check->u.v.flags & FL_ONGROUND)
614 		&& PROG_TO_EDICT(check->u.v.groundentity) == pusher) )
615 		{
616 			if ( check->u.v.absmin[0] >= pusher->u.v.absmax[0]
617 			|| check->u.v.absmin[1] >= pusher->u.v.absmax[1]
618 			|| check->u.v.absmin[2] >= pusher->u.v.absmax[2]
619 			|| check->u.v.absmax[0] <= pusher->u.v.absmin[0]
620 			|| check->u.v.absmax[1] <= pusher->u.v.absmin[1]
621 			|| check->u.v.absmax[2] <= pusher->u.v.absmin[2] )
622 				continue;
623 
624 		// see if the ent's bbox is inside the pusher's final position
625 			if (!SV_TestEntityPosition (check))
626 				continue;
627 		}
628 
629 	// remove the onground flag for non-players
630 		if (check->u.v.movetype != MOVETYPE_WALK)
631 			check->u.v.flags = (int)check->u.v.flags & ~FL_ONGROUND;
632 
633 		VectorCopy (check->u.v.origin, entorig);
634 		VectorCopy (check->u.v.origin, moved_from[num_moved]);
635 		moved_edict[num_moved] = check;
636 		num_moved++;
637 
638 		// calculate destination position
639 		VectorSubtract (check->u.v.origin, pusher->u.v.origin, org);
640 		org2[0] = DotProduct (org, forward);
641 		org2[1] = -DotProduct (org, right);
642 		org2[2] = DotProduct (org, up);
643 		VectorSubtract (org2, org, move);
644 
645 		// try moving the contacted entity
646 		pusher->u.v.solid = SOLID_NOT;
647 		SV_PushEntity (check, move);
648 		pusher->u.v.solid = SOLID_BSP;
649 
650 	// if it is still inside the pusher, block
651 		block = SV_TestEntityPosition (check);
652 		if (block)
653 		{	// fail the move
654 			if (check->u.v.mins[0] == check->u.v.maxs[0])
655 				continue;
656 			if (check->u.v.solid == SOLID_NOT || check->u.v.solid == SOLID_TRIGGER)
657 			{	// corpse
658 				check->u.v.mins[0] = check->u.v.mins[1] = 0;
659 				VectorCopy (check->u.v.mins, check->u.v.maxs);
660 				continue;
661 			}
662 
663 			VectorCopy (entorig, check->u.v.origin);
664 			SV_LinkEdict (check, true);
665 
666 			VectorCopy (pushorig, pusher->u.v.angles);
667 			SV_LinkEdict (pusher, false);
668 			pusher->u.v.ltime -= movetime;
669 
670 			// if the pusher has a "blocked" function, call it
671 			// otherwise, just stay in place until the obstacle is gone
672 			if (pusher->u.v.blocked)
673 			{
674 				pr_global_struct->self = EDICT_TO_PROG(pusher);
675 				pr_global_struct->other = EDICT_TO_PROG(check);
676 				PR_ExecuteProgram (pusher->u.v.blocked);
677 			}
678 
679 		// move back any entities we already moved
680 			for (i=0 ; i<num_moved ; i++)
681 			{
682 				VectorCopy (moved_from[i], moved_edict[i]->u.v.origin);
683 				VectorSubtract (moved_edict[i]->u.v.angles, amove, moved_edict[i]->u.v.angles);
684 				SV_LinkEdict (moved_edict[i], false);
685 			}
686 			return;
687 		}
688 		else
689 		{
690 			VectorAdd (check->u.v.angles, amove, check->u.v.angles);
691 		}
692 	}
693 
694 
695 }
696 #endif
697 
698 /*
699 ================
700 SV_Physics_Pusher
701 
702 ================
703 */
SV_Physics_Pusher(edict_t * ent)704 void SV_Physics_Pusher (edict_t *ent)
705 {
706 	float	thinktime;
707 	float	oldltime;
708 	float	movetime;
709 
710 	oldltime = ent->u.v.ltime;
711 
712 	thinktime = ent->u.v.nextthink;
713 	if (thinktime < ent->u.v.ltime + host_frametime)
714 	{
715 		movetime = thinktime - ent->u.v.ltime;
716 		if (movetime < 0)
717 			movetime = 0;
718 	}
719 	else
720 		movetime = host_frametime;
721 
722 	if (movetime)
723 	{
724 #ifdef QUAKE2
725 		if (ent->u.v.avelocity[0] || ent->u.v.avelocity[1] || ent->u.v.avelocity[2])
726 			SV_PushRotate (ent, movetime);
727 		else
728 #endif
729 			SV_PushMove (ent, movetime);	// advances ent->u.v.ltime if not blocked
730 	}
731 
732 	if (thinktime > oldltime && thinktime <= ent->u.v.ltime)
733 	{
734 		ent->u.v.nextthink = 0;
735 		pr_global_struct->time = sv.time;
736 		pr_global_struct->self = EDICT_TO_PROG(ent);
737 		pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
738 		PR_ExecuteProgram (ent->u.v.think);
739 		if (ent->free)
740 			return;
741 	}
742 
743 }
744 
745 
746 /*
747 ===============================================================================
748 
749 CLIENT MOVEMENT
750 
751 ===============================================================================
752 */
753 
754 /*
755 =============
756 SV_CheckStuck
757 
758 This is a big hack to try and fix the rare case of getting stuck in the world
759 clipping hull.
760 =============
761 */
SV_CheckStuck(edict_t * ent)762 void SV_CheckStuck (edict_t *ent)
763 {
764 	int		i, j;
765 	int		z;
766 	vec3_t	org;
767 
768 	if (!SV_TestEntityPosition(ent))
769 	{
770 		VectorCopy (ent->u.v.origin, ent->u.v.oldorigin);
771 		return;
772 	}
773 
774 	VectorCopy (ent->u.v.origin, org);
775 	VectorCopy (ent->u.v.oldorigin, ent->u.v.origin);
776 	if (!SV_TestEntityPosition(ent))
777 	{
778 		Con_DPrintf ("Unstuck.\n");
779 		SV_LinkEdict (ent, true);
780 		return;
781 	}
782 
783 	for (z=0 ; z< 18 ; z++)
784 		for (i=-1 ; i <= 1 ; i++)
785 			for (j=-1 ; j <= 1 ; j++)
786 			{
787 				ent->u.v.origin[0] = org[0] + i;
788 				ent->u.v.origin[1] = org[1] + j;
789 				ent->u.v.origin[2] = org[2] + z;
790 				if (!SV_TestEntityPosition(ent))
791 				{
792 					Con_DPrintf ("Unstuck.\n");
793 					SV_LinkEdict (ent, true);
794 					return;
795 				}
796 			}
797 
798 	VectorCopy (org, ent->u.v.origin);
799 	Con_DPrintf ("player is stuck.\n");
800 }
801 
802 
803 /*
804 =============
805 SV_CheckWater
806 =============
807 */
SV_CheckWater(edict_t * ent)808 qboolean SV_CheckWater (edict_t *ent)
809 {
810 	vec3_t	point;
811 	int		cont;
812 #ifdef QUAKE2
813 	int		truecont;
814 #endif
815 
816 	point[0] = ent->u.v.origin[0];
817 	point[1] = ent->u.v.origin[1];
818 	point[2] = ent->u.v.origin[2] + ent->u.v.mins[2] + 1;
819 
820 	ent->u.v.waterlevel = 0;
821 	ent->u.v.watertype = CONTENTS_EMPTY;
822 	cont = SV_PointContents (point);
823 	if (cont <= CONTENTS_WATER)
824 	{
825 #ifdef QUAKE2
826 		truecont = SV_TruePointContents (point);
827 #endif
828 		ent->u.v.watertype = cont;
829 		ent->u.v.waterlevel = 1;
830 		point[2] = ent->u.v.origin[2] + (ent->u.v.mins[2] + ent->u.v.maxs[2])*0.5;
831 		cont = SV_PointContents (point);
832 		if (cont <= CONTENTS_WATER)
833 		{
834 			ent->u.v.waterlevel = 2;
835 			point[2] = ent->u.v.origin[2] + ent->u.v.view_ofs[2];
836 			cont = SV_PointContents (point);
837 			if (cont <= CONTENTS_WATER)
838 				ent->u.v.waterlevel = 3;
839 		}
840 #ifdef QUAKE2
841 		if (truecont <= CONTENTS_CURRENT_0 && truecont >= CONTENTS_CURRENT_DOWN)
842 		{
843 			static vec3_t current_table[] =
844 			{
845 				{1, 0, 0},
846 				{0, 1, 0},
847 				{-1, 0, 0},
848 				{0, -1, 0},
849 				{0, 0, 1},
850 				{0, 0, -1}
851 			};
852 
853 			VectorMA (ent->u.v.basevelocity, 150.0*ent->u.v.waterlevel/3.0, current_table[CONTENTS_CURRENT_0 - truecont], ent->u.v.basevelocity);
854 		}
855 #endif
856 	}
857 
858 	return ent->u.v.waterlevel > 1;
859 }
860 
861 /*
862 ============
863 SV_WallFriction
864 
865 ============
866 */
SV_WallFriction(edict_t * ent,trace_t * trace)867 void SV_WallFriction (edict_t *ent, trace_t *trace)
868 {
869 	vec3_t		forward, right, up;
870 	float		d, i;
871 	vec3_t		into, side;
872 
873 	AngleVectors (ent->u.v.v_angle, forward, right, up);
874 	d = DotProduct (trace->plane.normal, forward);
875 
876 	d += 0.5;
877 	if (d >= 0)
878 		return;
879 
880 // cut the tangential velocity
881 	i = DotProduct (trace->plane.normal, ent->u.v.velocity);
882 	VectorScale (trace->plane.normal, i, into);
883 	VectorSubtract (ent->u.v.velocity, into, side);
884 
885 	ent->u.v.velocity[0] = side[0] * (1 + d);
886 	ent->u.v.velocity[1] = side[1] * (1 + d);
887 }
888 
889 /*
890 =====================
891 SV_TryUnstick
892 
893 Player has come to a dead stop, possibly due to the problem with limited
894 float precision at some angle joins in the BSP hull.
895 
896 Try fixing by pushing one pixel in each direction.
897 
898 This is a hack, but in the interest of good gameplay...
899 ======================
900 */
SV_TryUnstick(edict_t * ent,vec3_t oldvel)901 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
902 {
903 	int		i;
904 	vec3_t	oldorg;
905 	vec3_t	dir;
906 	int		clip;
907 	trace_t	steptrace;
908 
909 	VectorCopy (ent->u.v.origin, oldorg);
910 	VectorCopy (vec3_origin, dir);
911 
912 	for (i=0 ; i<8 ; i++)
913 	{
914 // try pushing a little in an axial direction
915 		switch (i)
916 		{
917 			case 0:	dir[0] = 2; dir[1] = 0; break;
918 			case 1:	dir[0] = 0; dir[1] = 2; break;
919 			case 2:	dir[0] = -2; dir[1] = 0; break;
920 			case 3:	dir[0] = 0; dir[1] = -2; break;
921 			case 4:	dir[0] = 2; dir[1] = 2; break;
922 			case 5:	dir[0] = -2; dir[1] = 2; break;
923 			case 6:	dir[0] = 2; dir[1] = -2; break;
924 			case 7:	dir[0] = -2; dir[1] = -2; break;
925 		}
926 
927 		SV_PushEntity (ent, dir);
928 
929 // retry the original move
930 		ent->u.v.velocity[0] = oldvel[0];
931 		ent->u.v. velocity[1] = oldvel[1];
932 		ent->u.v. velocity[2] = 0;
933 		clip = SV_FlyMove (ent, 0.1, &steptrace);
934 
935 		if ( fabs(oldorg[1] - ent->u.v.origin[1]) > 4
936 		|| fabs(oldorg[0] - ent->u.v.origin[0]) > 4 )
937 		{
938 //Con_DPrintf ("unstuck!\n");
939 			return clip;
940 		}
941 
942 // go back to the original pos and try again
943 		VectorCopy (oldorg, ent->u.v.origin);
944 	}
945 
946 	VectorCopy (vec3_origin, ent->u.v.velocity);
947 	return 7;		// still not moving
948 }
949 
950 /*
951 =====================
952 SV_WalkMove
953 
954 Only used by players
955 ======================
956 */
957 #define	STEPSIZE	18
SV_WalkMove(edict_t * ent)958 void SV_WalkMove (edict_t *ent)
959 {
960 	vec3_t		upmove, downmove;
961 	vec3_t		oldorg, oldvel;
962 	vec3_t		nosteporg, nostepvel;
963 	int			clip;
964 	int			oldonground;
965 	trace_t		steptrace, downtrace;
966 
967 //
968 // do a regular slide move unless it looks like you ran into a step
969 //
970 	oldonground = (int)ent->u.v.flags & FL_ONGROUND;
971 	ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND;
972 
973 	VectorCopy (ent->u.v.origin, oldorg);
974 	VectorCopy (ent->u.v.velocity, oldvel);
975 
976 	clip = SV_FlyMove (ent, host_frametime, &steptrace);
977 
978 	if ( !(clip & 2) )
979 		return;		// move didn't block on a step
980 
981 	if (!oldonground && ent->u.v.waterlevel == 0)
982 		return;		// don't stair up while jumping
983 
984 	if (ent->u.v.movetype != MOVETYPE_WALK)
985 		return;		// gibbed by a trigger
986 
987 	if (sv_nostep.value)
988 		return;
989 
990 	if ( (int)sv_player->u.v.flags & FL_WATERJUMP )
991 		return;
992 
993 	VectorCopy (ent->u.v.origin, nosteporg);
994 	VectorCopy (ent->u.v.velocity, nostepvel);
995 
996 //
997 // try moving up and forward to go up a step
998 //
999 	VectorCopy (oldorg, ent->u.v.origin);	// back to start pos
1000 
1001 	VectorCopy (vec3_origin, upmove);
1002 	VectorCopy (vec3_origin, downmove);
1003 	upmove[2] = STEPSIZE;
1004 	downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
1005 
1006 // move up
1007 	SV_PushEntity (ent, upmove);	// FIXME: don't link?
1008 
1009 // move forward
1010 	ent->u.v.velocity[0] = oldvel[0];
1011 	ent->u.v. velocity[1] = oldvel[1];
1012 	ent->u.v. velocity[2] = 0;
1013 	clip = SV_FlyMove (ent, host_frametime, &steptrace);
1014 
1015 // check for stuckness, possibly due to the limited precision of floats
1016 // in the clipping hulls
1017 	if (clip)
1018 	{
1019 		if ( fabs(oldorg[1] - ent->u.v.origin[1]) < 0.03125
1020 		&& fabs(oldorg[0] - ent->u.v.origin[0]) < 0.03125 )
1021 		{	// stepping up didn't make any progress
1022 			clip = SV_TryUnstick (ent, oldvel);
1023 		}
1024 	}
1025 
1026 // extra friction based on view angle
1027 	if ( clip & 2 )
1028 		SV_WallFriction (ent, &steptrace);
1029 
1030 // move down
1031 	downtrace = SV_PushEntity (ent, downmove);	// FIXME: don't link?
1032 
1033 	if (downtrace.plane.normal[2] > 0.7)
1034 	{
1035 		if (ent->u.v.solid == SOLID_BSP)
1036 		{
1037 			ent->u.v.flags =	(int)ent->u.v.flags | FL_ONGROUND;
1038 			ent->u.v.groundentity = EDICT_TO_PROG(downtrace.ent);
1039 		}
1040 	}
1041 	else
1042 	{
1043 // if the push down didn't end up on good ground, use the move without
1044 // the step up.  This happens near wall / slope combinations, and can
1045 // cause the player to hop up higher on a slope too steep to climb
1046 		VectorCopy (nosteporg, ent->u.v.origin);
1047 		VectorCopy (nostepvel, ent->u.v.velocity);
1048 	}
1049 }
1050 
1051 
1052 /*
1053 ================
1054 SV_Physics_Client
1055 
1056 Player character actions
1057 ================
1058 */
SV_Physics_Client(edict_t * ent,int num)1059 void SV_Physics_Client (edict_t	*ent, int num)
1060 {
1061 	if ( ! svs.clients[num-1].active )
1062 		return;		// unconnected slot
1063 
1064 //
1065 // call standard client pre-think
1066 //
1067 	pr_global_struct->time = sv.time;
1068 	pr_global_struct->self = EDICT_TO_PROG(ent);
1069 	PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1070 
1071 //
1072 // do a move
1073 //
1074 	SV_CheckVelocity (ent);
1075 
1076 //
1077 // decide which move function to call
1078 //
1079 	switch ((int)ent->u.v.movetype)
1080 	{
1081 	case MOVETYPE_NONE:
1082 		if (!SV_RunThink (ent))
1083 			return;
1084 		break;
1085 
1086 	case MOVETYPE_WALK:
1087 		if (!SV_RunThink (ent))
1088 			return;
1089 		if (!SV_CheckWater (ent) && ! ((int)ent->u.v.flags & FL_WATERJUMP) )
1090 			SV_AddGravity (ent);
1091 		SV_CheckStuck (ent);
1092 #ifdef QUAKE2
1093 		VectorAdd (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
1094 #endif
1095 		SV_WalkMove (ent);
1096 
1097 #ifdef QUAKE2
1098 		VectorSubtract (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
1099 #endif
1100 		break;
1101 
1102 	case MOVETYPE_TOSS:
1103 	case MOVETYPE_BOUNCE:
1104 		SV_Physics_Toss (ent);
1105 		break;
1106 
1107 	case MOVETYPE_FLY:
1108 		if (!SV_RunThink (ent))
1109 			return;
1110 		SV_FlyMove (ent, host_frametime, NULL);
1111 		break;
1112 
1113 	case MOVETYPE_NOCLIP:
1114 		if (!SV_RunThink (ent))
1115 			return;
1116 		VectorMA (ent->u.v.origin, host_frametime, ent->u.v.velocity, ent->u.v.origin);
1117 		break;
1118 
1119 	default:
1120 		Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->u.v.movetype);
1121 	}
1122 
1123 //
1124 // call standard player post-think
1125 //
1126 	SV_LinkEdict (ent, true);
1127 
1128 	pr_global_struct->time = sv.time;
1129 	pr_global_struct->self = EDICT_TO_PROG(ent);
1130 	PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1131 }
1132 
1133 //============================================================================
1134 
1135 /*
1136 =============
1137 SV_Physics_None
1138 
1139 Non moving objects can only think
1140 =============
1141 */
SV_Physics_None(edict_t * ent)1142 void SV_Physics_None (edict_t *ent)
1143 {
1144 // regular thinking
1145 	SV_RunThink (ent);
1146 }
1147 
1148 #ifdef QUAKE2
1149 /*
1150 =============
1151 SV_Physics_Follow
1152 
1153 Entities that are "stuck" to another entity
1154 =============
1155 */
SV_Physics_Follow(edict_t * ent)1156 void SV_Physics_Follow (edict_t *ent)
1157 {
1158 // regular thinking
1159 	SV_RunThink (ent);
1160 	VectorAdd (PROG_TO_EDICT(ent->u.v.aiment)->u.v.origin, ent->u.v.v_angle, ent->u.v.origin);
1161 	SV_LinkEdict (ent, true);
1162 }
1163 #endif
1164 
1165 /*
1166 =============
1167 SV_Physics_Noclip
1168 
1169 A moving object that doesn't obey physics
1170 =============
1171 */
SV_Physics_Noclip(edict_t * ent)1172 void SV_Physics_Noclip (edict_t *ent)
1173 {
1174 // regular thinking
1175 	if (!SV_RunThink (ent))
1176 		return;
1177 
1178 	VectorMA (ent->u.v.angles, host_frametime, ent->u.v.avelocity, ent->u.v.angles);
1179 	VectorMA (ent->u.v.origin, host_frametime, ent->u.v.velocity, ent->u.v.origin);
1180 
1181 	SV_LinkEdict (ent, false);
1182 }
1183 
1184 /*
1185 ==============================================================================
1186 
1187 TOSS / BOUNCE
1188 
1189 ==============================================================================
1190 */
1191 
1192 /*
1193 =============
1194 SV_CheckWaterTransition
1195 
1196 =============
1197 */
SV_CheckWaterTransition(edict_t * ent)1198 void SV_CheckWaterTransition (edict_t *ent)
1199 {
1200 	int		cont;
1201 #ifdef QUAKE2
1202 	vec3_t	point;
1203 
1204 	point[0] = ent->u.v.origin[0];
1205 	point[1] = ent->u.v.origin[1];
1206 	point[2] = ent->u.v.origin[2] + ent->u.v.mins[2] + 1;
1207 	cont = SV_PointContents (point);
1208 #else
1209 	cont = SV_PointContents (ent->u.v.origin);
1210 #endif
1211 	if (!ent->u.v.watertype)
1212 	{	// just spawned here
1213 		ent->u.v.watertype = cont;
1214 		ent->u.v.waterlevel = 1;
1215 		return;
1216 	}
1217 
1218 	if (cont <= CONTENTS_WATER)
1219 	{
1220 		if (ent->u.v.watertype == CONTENTS_EMPTY)
1221 		{	// just crossed into water
1222 			SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1223 		}
1224 		ent->u.v.watertype = cont;
1225 		ent->u.v.waterlevel = 1;
1226 	}
1227 	else
1228 	{
1229 		if (ent->u.v.watertype != CONTENTS_EMPTY)
1230 		{	// just crossed into water
1231 			SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1232 		}
1233 		ent->u.v.watertype = CONTENTS_EMPTY;
1234 		ent->u.v.waterlevel = cont;
1235 	}
1236 }
1237 
1238 /*
1239 =============
1240 SV_Physics_Toss
1241 
1242 Toss, bounce, and fly movement.  When onground, do nothing.
1243 =============
1244 */
SV_Physics_Toss(edict_t * ent)1245 void SV_Physics_Toss (edict_t *ent)
1246 {
1247 	trace_t	trace;
1248 	vec3_t	move;
1249 	float	backoff;
1250 #ifdef QUAKE2
1251 	edict_t	*groundentity;
1252 
1253 	groundentity = PROG_TO_EDICT(ent->u.v.groundentity);
1254 	if ((int)groundentity->u.v.flags & FL_CONVEYOR)
1255 		VectorScale(groundentity->u.v.movedir, groundentity->u.v.speed, ent->u.v.basevelocity);
1256 	else
1257 		VectorCopy(vec_origin, ent->u.v.basevelocity);
1258 	SV_CheckWater (ent);
1259 #endif
1260 	// regular thinking
1261 	if (!SV_RunThink (ent))
1262 		return;
1263 
1264 #ifdef QUAKE2
1265 	if (ent->u.v.velocity[2] > 0)
1266 		ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND;
1267 
1268 	if ( ((int)ent->u.v.flags & FL_ONGROUND) )
1269 //@@
1270 		if (VectorCompare(ent->u.v.basevelocity, vec_origin))
1271 			return;
1272 
1273 	SV_CheckVelocity (ent);
1274 
1275 // add gravity
1276 	if (! ((int)ent->u.v.flags & FL_ONGROUND)
1277 		&& ent->u.v.movetype != MOVETYPE_FLY
1278 		&& ent->u.v.movetype != MOVETYPE_BOUNCEMISSILE
1279 		&& ent->u.v.movetype != MOVETYPE_FLYMISSILE)
1280 			SV_AddGravity (ent);
1281 
1282 #else
1283 // if onground, return without moving
1284 	if ( ((int)ent->u.v.flags & FL_ONGROUND) )
1285 		return;
1286 
1287 	SV_CheckVelocity (ent);
1288 
1289 // add gravity
1290 	if (ent->u.v.movetype != MOVETYPE_FLY
1291 	&& ent->u.v.movetype != MOVETYPE_FLYMISSILE)
1292 		SV_AddGravity (ent);
1293 #endif
1294 
1295 // move angles
1296 	VectorMA (ent->u.v.angles, host_frametime, ent->u.v.avelocity, ent->u.v.angles);
1297 
1298 // move origin
1299 #ifdef QUAKE2
1300 	VectorAdd (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
1301 #endif
1302 	VectorScale (ent->u.v.velocity, host_frametime, move);
1303 	trace = SV_PushEntity (ent, move);
1304 #ifdef QUAKE2
1305 	VectorSubtract (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
1306 #endif
1307 	if (trace.fraction == 1)
1308 		return;
1309 	if (ent->free)
1310 		return;
1311 
1312 	if (ent->u.v.movetype == MOVETYPE_BOUNCE)
1313 		backoff = 1.5;
1314 #ifdef QUAKE2
1315 	else if (ent->u.v.movetype == MOVETYPE_BOUNCEMISSILE)
1316 		backoff = 2.0;
1317 #endif
1318 	else
1319 		backoff = 1;
1320 
1321 	ClipVelocity (ent->u.v.velocity, trace.plane.normal, ent->u.v.velocity, backoff);
1322 
1323 // stop if on ground
1324 	if (trace.plane.normal[2] > 0.7)
1325 	{
1326 #ifdef QUAKE2
1327 		if (ent->u.v.velocity[2] < 60 || (ent->u.v.movetype != MOVETYPE_BOUNCE && ent->u.v.movetype != MOVETYPE_BOUNCEMISSILE))
1328 #else
1329 		if (ent->u.v.velocity[2] < 60 || ent->u.v.movetype != MOVETYPE_BOUNCE)
1330 #endif
1331 		{
1332 			ent->u.v.flags = (int)ent->u.v.flags | FL_ONGROUND;
1333 			ent->u.v.groundentity = EDICT_TO_PROG(trace.ent);
1334 			VectorCopy (vec3_origin, ent->u.v.velocity);
1335 			VectorCopy (vec3_origin, ent->u.v.avelocity);
1336 		}
1337 	}
1338 
1339 // check for in water
1340 	SV_CheckWaterTransition (ent);
1341 }
1342 
1343 /*
1344 ===============================================================================
1345 
1346 STEPPING MOVEMENT
1347 
1348 ===============================================================================
1349 */
1350 
1351 /*
1352 =============
1353 SV_Physics_Step
1354 
1355 Monsters freefall when they don't have a ground entity, otherwise
1356 all movement is done with discrete steps.
1357 
1358 This is also used for objects that have become still on the ground, but
1359 will fall if the floor is pulled out from under them.
1360 =============
1361 */
1362 #ifdef QUAKE2
SV_Physics_Step(edict_t * ent)1363 void SV_Physics_Step (edict_t *ent)
1364 {
1365 	qboolean	wasonground;
1366 	qboolean	inwater;
1367 	qboolean	hitsound = false;
1368 	float		*vel;
1369 	float		speed, newspeed, control;
1370 	float		friction;
1371 	edict_t		*groundentity;
1372 
1373 	groundentity = PROG_TO_EDICT(ent->u.v.groundentity);
1374 	if ((int)groundentity->u.v.flags & FL_CONVEYOR)
1375 		VectorScale(groundentity->u.v.movedir, groundentity->u.v.speed, ent->u.v.basevelocity);
1376 	else
1377 		VectorCopy(vec_origin, ent->u.v.basevelocity);
1378 //@@
1379 	pr_global_struct->time = sv.time;
1380 	pr_global_struct->self = EDICT_TO_PROG(ent);
1381 	PF_WaterMove();
1382 
1383 	SV_CheckVelocity (ent);
1384 
1385 	wasonground = (int)ent->u.v.flags & FL_ONGROUND;
1386 //	ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND;
1387 
1388 	// add gravity except:
1389 	//   flying monsters
1390 	//   swimming monsters who are in the water
1391 	inwater = SV_CheckWater(ent);
1392 	if (! wasonground)
1393 		if (!((int)ent->u.v.flags & FL_FLY))
1394 			if (!(((int)ent->u.v.flags & FL_SWIM) && (ent->u.v.waterlevel > 0)))
1395 			{
1396 				if (ent->u.v.velocity[2] < sv_gravity.value*-0.1)
1397 					hitsound = true;
1398 				if (!inwater)
1399 					SV_AddGravity (ent);
1400 			}
1401 
1402 	if (!VectorCompare(ent->u.v.velocity, vec_origin) || !VectorCompare(ent->u.v.basevelocity, vec_origin))
1403 	{
1404 		ent->u.v.flags = (int)ent->u.v.flags & ~FL_ONGROUND;
1405 		// apply friction
1406 		// let dead monsters who aren't completely onground slide
1407 		if (wasonground)
1408 			if (!(ent->u.v.health <= 0.0 && !SV_CheckBottom(ent)))
1409 			{
1410 				vel = ent->u.v.velocity;
1411 				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
1412 				if (speed)
1413 				{
1414 					friction = sv_friction.value;
1415 
1416 					control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
1417 					newspeed = speed - host_frametime*control*friction;
1418 
1419 					if (newspeed < 0)
1420 						newspeed = 0;
1421 					newspeed /= speed;
1422 
1423 					vel[0] = vel[0] * newspeed;
1424 					vel[1] = vel[1] * newspeed;
1425 				}
1426 			}
1427 
1428 		VectorAdd (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
1429 		SV_FlyMove (ent, host_frametime, NULL);
1430 		VectorSubtract (ent->u.v.velocity, ent->u.v.basevelocity, ent->u.v.velocity);
1431 
1432 		// determine if it's on solid ground at all
1433 		{
1434 			vec3_t	mins, maxs, point;
1435 			int		x, y;
1436 
1437 			VectorAdd (ent->u.v.origin, ent->u.v.mins, mins);
1438 			VectorAdd (ent->u.v.origin, ent->u.v.maxs, maxs);
1439 
1440 			point[2] = mins[2] - 1;
1441 			for	(x=0 ; x<=1 ; x++)
1442 				for	(y=0 ; y<=1 ; y++)
1443 				{
1444 					point[0] = x ? maxs[0] : mins[0];
1445 					point[1] = y ? maxs[1] : mins[1];
1446 					if (SV_PointContents (point) == CONTENTS_SOLID)
1447 					{
1448 						ent->u.v.flags = (int)ent->u.v.flags | FL_ONGROUND;
1449 						break;
1450 					}
1451 				}
1452 
1453 		}
1454 
1455 		SV_LinkEdict (ent, true);
1456 
1457 		if ((int)ent->u.v.flags & FL_ONGROUND)
1458 			if (!wasonground)
1459 				if (hitsound)
1460 					SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1461 	}
1462 
1463 // regular thinking
1464 	SV_RunThink (ent);
1465 	SV_CheckWaterTransition (ent);
1466 }
1467 #else
SV_Physics_Step(edict_t * ent)1468 void SV_Physics_Step (edict_t *ent)
1469 {
1470 	qboolean	hitsound;
1471 
1472 // freefall if not onground
1473 	if ( ! ((int)ent->u.v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1474 	{
1475 		if (ent->u.v.velocity[2] < sv_gravity.value*-0.1)
1476 			hitsound = true;
1477 		else
1478 			hitsound = false;
1479 
1480 		SV_AddGravity (ent);
1481 		SV_CheckVelocity (ent);
1482 		SV_FlyMove (ent, host_frametime, NULL);
1483 		SV_LinkEdict (ent, true);
1484 
1485 		if ( (int)ent->u.v.flags & FL_ONGROUND )	// just hit ground
1486 		{
1487 			if (hitsound)
1488 				SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1489 		}
1490 	}
1491 
1492 // regular thinking
1493 	SV_RunThink (ent);
1494 
1495 	SV_CheckWaterTransition (ent);
1496 }
1497 #endif
1498 
1499 //============================================================================
1500 
1501 /*
1502 ================
1503 SV_Physics
1504 
1505 ================
1506 */
SV_Physics(void)1507 void SV_Physics (void)
1508 {
1509 	int		i;
1510 	edict_t	*ent;
1511 
1512 // let the progs know that a new frame has started
1513 	pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1514 	pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1515 	pr_global_struct->time = sv.time;
1516 	PR_ExecuteProgram (pr_global_struct->StartFrame);
1517 
1518 //SV_CheckAllEnts ();
1519 
1520 //
1521 // treat each object in turn
1522 //
1523 	ent = sv.edicts;
1524 	for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1525 	{
1526 		if (ent->free)
1527 			continue;
1528 
1529 		if (pr_global_struct->force_retouch)
1530 		{
1531 			SV_LinkEdict (ent, true);	// force retouch even for stationary
1532 		}
1533 
1534 		if (i > 0 && i <= svs.maxclients)
1535 			SV_Physics_Client (ent, i);
1536 		else if (ent->u.v.movetype == MOVETYPE_PUSH)
1537 			SV_Physics_Pusher (ent);
1538 		else if (ent->u.v.movetype == MOVETYPE_NONE)
1539 			SV_Physics_None (ent);
1540 #ifdef QUAKE2
1541 		else if (ent->u.v.movetype == MOVETYPE_FOLLOW)
1542 			SV_Physics_Follow (ent);
1543 #endif
1544 		else if (ent->u.v.movetype == MOVETYPE_NOCLIP)
1545 			SV_Physics_Noclip (ent);
1546 		else if (ent->u.v.movetype == MOVETYPE_STEP)
1547 			SV_Physics_Step (ent);
1548 		else if (ent->u.v.movetype == MOVETYPE_TOSS
1549 		|| ent->u.v.movetype == MOVETYPE_BOUNCE
1550 #ifdef QUAKE2
1551 		|| ent->u.v.movetype == MOVETYPE_BOUNCEMISSILE
1552 #endif
1553 		|| ent->u.v.movetype == MOVETYPE_FLY
1554 		|| ent->u.v.movetype == MOVETYPE_FLYMISSILE)
1555 			SV_Physics_Toss (ent);
1556 		else
1557 			Sys_Error ("SV_Physics: bad movetype %i", (int)ent->u.v.movetype);
1558 	}
1559 
1560 	if (pr_global_struct->force_retouch)
1561 		pr_global_struct->force_retouch--;
1562 
1563 	sv.time += host_frametime;
1564 }
1565 
1566 
1567 #ifdef QUAKE2
SV_Trace_Toss(edict_t * ent,edict_t * ignore)1568 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1569 {
1570 	edict_t	tempent, *tent;
1571 	trace_t	trace;
1572 	vec3_t	move;
1573 	vec3_t	end;
1574 	double	save_frametime;
1575 //	extern particle_t	*active_particles, *free_particles;
1576 //	particle_t	*p;
1577 
1578 
1579 	save_frametime = host_frametime;
1580 	host_frametime = 0.05;
1581 
1582 	memcpy(&tempent, ent, sizeof(edict_t));
1583 	tent = &tempent;
1584 
1585 	while (1)
1586 	{
1587 		SV_CheckVelocity (tent);
1588 		SV_AddGravity (tent);
1589 		VectorMA (tent->u.v.angles, host_frametime, tent->u.v.avelocity, tent->u.v.angles);
1590 		VectorScale (tent->u.v.velocity, host_frametime, move);
1591 		VectorAdd (tent->u.v.origin, move, end);
1592 		trace = SV_Move (tent->u.v.origin, tent->u.v.mins, tent->u.v.maxs, end, MOVE_NORMAL, tent);
1593 		VectorCopy (trace.endpos, tent->u.v.origin);
1594 
1595 //		p = free_particles;
1596 //		if (p)
1597 //		{
1598 //			free_particles = p->next;
1599 //			p->next = active_particles;
1600 //			active_particles = p;
1601 //
1602 //			p->die = 256;
1603 //			p->color = 15;
1604 //			p->type = pt_static;
1605 //			VectorCopy (vec3_origin, p->vel);
1606 //			VectorCopy (tent->u.v.origin, p->org);
1607 //		}
1608 
1609 		if (trace.ent)
1610 			if (trace.ent != ignore)
1611 				break;
1612 	}
1613 //	p->color = 224;
1614 	host_frametime = save_frametime;
1615 	return trace;
1616 }
1617 #endif
1618