1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2010-2014 QuakeSpasm developers
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15 See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 
21 */
22 // sv_phys.c
23 
24 #include "quakedef.h"
25 
26 /*
27 
28 
29 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.
30 
31 onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects
32 
33 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
34 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
35 corpses are SOLID_NOT and MOVETYPE_TOSS
36 crates are SOLID_BBOX and MOVETYPE_TOSS
37 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
38 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
39 
40 solid_edge items only clip against bsp models.
41 
42 */
43 
44 cvar_t	sv_friction = {"sv_friction","4",CVAR_NOTIFY|CVAR_SERVERINFO};
45 cvar_t	sv_stopspeed = {"sv_stopspeed","100",CVAR_NONE};
46 cvar_t	sv_gravity = {"sv_gravity","800",CVAR_NOTIFY|CVAR_SERVERINFO};
47 cvar_t	sv_maxvelocity = {"sv_maxvelocity","2000",CVAR_NONE};
48 cvar_t	sv_nostep = {"sv_nostep","0",CVAR_NONE};
49 cvar_t	sv_freezenonclients = {"sv_freezenonclients","0",CVAR_NONE};
50 
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(qcvm->edicts);
68 	for (e=1 ; e<qcvm->num_edicts ; e++, check = NEXT_EDICT(check))
69 	{
70 		if (check->free)
71 			continue;
72 		if (check->v.movetype == MOVETYPE_PUSH
73 		|| check->v.movetype == MOVETYPE_NONE
74 		|| check->v.movetype == MOVETYPE_NOCLIP)
75 			continue;
76 
77 		if (SV_TestEntityPosition (check))
78 			Con_Printf ("entity in invalid position\n");
79 	}
80 }
81 
82 /*
83 ================
84 SV_CheckVelocity
85 ================
86 */
SV_CheckVelocity(edict_t * ent)87 void SV_CheckVelocity (edict_t *ent)
88 {
89 	int		i;
90 
91 //
92 // bound velocity
93 //
94 	for (i=0 ; i<3 ; i++)
95 	{
96 		if (IS_NAN(ent->v.velocity[i]))
97 		{
98 			Con_Printf ("Got a NaN velocity on %s\n", PR_GetString(ent->v.classname));
99 			ent->v.velocity[i] = 0;
100 		}
101 		if (IS_NAN(ent->v.origin[i]))
102 		{
103 			Con_Printf ("Got a NaN origin on %s\n", PR_GetString(ent->v.classname));
104 			ent->v.origin[i] = 0;
105 		}
106 		if (ent->v.velocity[i] > sv_maxvelocity.value)
107 			ent->v.velocity[i] = sv_maxvelocity.value;
108 		else if (ent->v.velocity[i] < -sv_maxvelocity.value)
109 			ent->v.velocity[i] = -sv_maxvelocity.value;
110 	}
111 }
112 
113 /*
114 =============
115 SV_RunThink
116 
117 Runs thinking code if time.  There is some play in the exact time the think
118 function will be called, because it is called before any movement is done
119 in a frame.  Not used for pushmove objects, because they must be exact.
120 Returns false if the entity removed itself.
121 =============
122 */
SV_RunThink(edict_t * ent)123 qboolean SV_RunThink (edict_t *ent)
124 {
125 	float	thinktime;
126 	float	oldframe; //johnfitz
127 	int		i; //johnfitz
128 
129 	thinktime = ent->v.nextthink;
130 	if (thinktime <= 0 || thinktime > qcvm->time + host_frametime)
131 		return true;
132 
133 	if (thinktime < qcvm->time)
134 		thinktime = qcvm->time;	// don't let things stay in the past.
135 								// it is possible to start that way
136 								// by a trigger with a local time.
137 
138 	oldframe = ent->v.frame; //johnfitz
139 
140 	ent->v.nextthink = 0;
141 	pr_global_struct->time = thinktime;
142 	pr_global_struct->self = EDICT_TO_PROG(ent);
143 	pr_global_struct->other = EDICT_TO_PROG(qcvm->edicts);
144 	PR_ExecuteProgram (ent->v.think);
145 
146 //johnfitz -- PROTOCOL_FITZQUAKE
147 //capture interval to nextthink here and send it to client for better
148 //lerp timing, but only if interval is not 0.1 (which client assumes)
149 	ent->sendinterval = false;
150 	if (!ent->free && ent->v.nextthink && (ent->v.movetype == MOVETYPE_STEP || ent->v.frame != oldframe))
151 	{
152 		i = Q_rint((ent->v.nextthink-thinktime)*255);
153 		if (i >= 0 && i < 256 && i != 25 && i != 26) //25 and 26 are close enough to 0.1 to not send
154 			ent->sendinterval = true;
155 	}
156 //johnfitz
157 
158 	return !ent->free;
159 }
160 
161 /*
162 ==================
163 SV_Impact
164 
165 Two entities have touched, so run their touch functions
166 ==================
167 */
SV_Impact(edict_t * e1,edict_t * e2)168 void SV_Impact (edict_t *e1, edict_t *e2)
169 {
170 	int		old_self, old_other;
171 
172 	old_self = pr_global_struct->self;
173 	old_other = pr_global_struct->other;
174 
175 	pr_global_struct->time = qcvm->time;
176 	if (e1->v.touch && e1->v.solid != SOLID_NOT)
177 	{
178 		pr_global_struct->self = EDICT_TO_PROG(e1);
179 		pr_global_struct->other = EDICT_TO_PROG(e2);
180 		PR_ExecuteProgram (e1->v.touch);
181 	}
182 
183 	if (e2->v.touch && e2->v.solid != SOLID_NOT)
184 	{
185 		pr_global_struct->self = EDICT_TO_PROG(e2);
186 		pr_global_struct->other = EDICT_TO_PROG(e1);
187 		PR_ExecuteProgram (e2->v.touch);
188 	}
189 
190 	pr_global_struct->self = old_self;
191 	pr_global_struct->other = old_other;
192 }
193 
194 
195 /*
196 ==================
197 ClipVelocity
198 
199 Slide off of the impacting object
200 returns the blocked flags (1 = floor, 2 = step / wall)
201 ==================
202 */
203 #define	STOP_EPSILON	0.1
204 
ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)205 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
206 {
207 	float	backoff;
208 	float	change;
209 	int		i, blocked;
210 
211 	blocked = 0;
212 	if (normal[2] > 0)
213 		blocked |= 1;		// floor
214 	if (!normal[2])
215 		blocked |= 2;		// step
216 
217 	backoff = DotProduct (in, normal) * overbounce;
218 
219 	for (i=0 ; i<3 ; i++)
220 	{
221 		change = normal[i]*backoff;
222 		out[i] = in[i] - change;
223 		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
224 			out[i] = 0;
225 	}
226 
227 	return blocked;
228 }
229 
230 
231 /*
232 ============
233 SV_FlyMove
234 
235 The basic solid body movement clip that slides along multiple planes
236 Returns the clipflags if the velocity was modified (hit something solid)
237 1 = floor
238 2 = wall / step
239 4 = dead stop
240 If steptrace is not NULL, the trace of any vertical wall hit will be stored
241 ============
242 */
243 #define	MAX_CLIP_PLANES	5
SV_FlyMove(edict_t * ent,float time,trace_t * steptrace)244 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
245 {
246 	int			bumpcount, numbumps;
247 	vec3_t		dir;
248 	float		d;
249 	int			numplanes;
250 	vec3_t		planes[MAX_CLIP_PLANES];
251 	vec3_t		primal_velocity, original_velocity, new_velocity;
252 	int			i, j;
253 	trace_t		trace;
254 	vec3_t		end;
255 	float		time_left;
256 	int			blocked;
257 
258 	numbumps = 4;
259 
260 	blocked = 0;
261 	VectorCopy (ent->v.velocity, original_velocity);
262 	VectorCopy (ent->v.velocity, primal_velocity);
263 	numplanes = 0;
264 
265 	time_left = time;
266 
267 	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
268 	{
269 		if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
270 			break;
271 
272 		for (i=0 ; i<3 ; i++)
273 			end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
274 
275 		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
276 
277 		if (trace.allsolid)
278 		{	// entity is trapped in another solid
279 			VectorCopy (vec3_origin, ent->v.velocity);
280 			return 3;
281 		}
282 
283 		if (trace.fraction > 0)
284 		{	// actually covered some distance
285 			VectorCopy (trace.endpos, ent->v.origin);
286 			VectorCopy (ent->v.velocity, original_velocity);
287 			numplanes = 0;
288 		}
289 
290 		if (trace.fraction == 1)
291 			 break;		// moved the entire distance
292 
293 		if (!trace.ent)
294 			Sys_Error ("SV_FlyMove: !trace.ent");
295 
296 		if (trace.plane.normal[2] > 0.7)
297 		{
298 			blocked |= 1;		// floor
299 			if (trace.ent->v.solid == SOLID_BSP)
300 			{
301 				ent->v.flags =	(int)ent->v.flags | FL_ONGROUND;
302 				ent->v.groundentity = EDICT_TO_PROG(trace.ent);
303 			}
304 		}
305 		if (!trace.plane.normal[2])
306 		{
307 			blocked |= 2;		// step
308 			if (steptrace)
309 				*steptrace = trace;	// save for player extrafriction
310 		}
311 
312 //
313 // run the impact function
314 //
315 		SV_Impact (ent, trace.ent);
316 		if (ent->free)
317 			break;		// removed by the impact function
318 
319 
320 		time_left -= time_left * trace.fraction;
321 
322 	// cliped to another plane
323 		if (numplanes >= MAX_CLIP_PLANES)
324 		{	// this shouldn't really happen
325 			VectorCopy (vec3_origin, ent->v.velocity);
326 			return 3;
327 		}
328 
329 		VectorCopy (trace.plane.normal, planes[numplanes]);
330 		numplanes++;
331 
332 //
333 // modify original_velocity so it parallels all of the clip planes
334 //
335 		for (i=0 ; i<numplanes ; i++)
336 		{
337 			ClipVelocity (original_velocity, planes[i], new_velocity, 1);
338 			for (j=0 ; j<numplanes ; j++)
339 				if (j != i)
340 				{
341 					if (DotProduct (new_velocity, planes[j]) < 0)
342 						break;	// not ok
343 				}
344 			if (j == numplanes)
345 				break;
346 		}
347 
348 		if (i != numplanes)
349 		{	// go along this plane
350 			VectorCopy (new_velocity, ent->v.velocity);
351 		}
352 		else
353 		{	// go along the crease
354 			if (numplanes != 2)
355 			{
356 //				Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
357 				VectorCopy (vec3_origin, ent->v.velocity);
358 				return 7;
359 			}
360 			CrossProduct (planes[0], planes[1], dir);
361 			d = DotProduct (dir, ent->v.velocity);
362 			VectorScale (dir, d, ent->v.velocity);
363 		}
364 
365 //
366 // if original velocity is against the original velocity, stop dead
367 // to avoid tiny occilations in sloping corners
368 //
369 		if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
370 		{
371 			VectorCopy (vec3_origin, ent->v.velocity);
372 			return blocked;
373 		}
374 	}
375 
376 	return blocked;
377 }
378 
379 
380 /*
381 ============
382 SV_AddGravity
383 
384 ============
385 */
SV_AddGravity(edict_t * ent)386 void SV_AddGravity (edict_t *ent)
387 {
388 	float	ent_gravity;
389 	eval_t	*val;
390 
391 	val = GetEdictFieldValue(ent, ED_FindFieldOffset("gravity"));
392 	if (val && val->_float)
393 		ent_gravity = val->_float;
394 	else
395 		ent_gravity = 1.0;
396 
397 	ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
398 }
399 
400 
401 /*
402 ===============================================================================
403 
404 PUSHMOVE
405 
406 ===============================================================================
407 */
408 
409 /*
410 ============
411 SV_PushEntity
412 
413 Does not change the entities velocity at all
414 ============
415 */
SV_PushEntity(edict_t * ent,vec3_t push)416 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
417 {
418 	trace_t	trace;
419 	vec3_t	end;
420 
421 	VectorAdd (ent->v.origin, push, end);
422 
423 	if (ent->v.movetype == MOVETYPE_FLYMISSILE)
424 		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
425 	else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
426 	// only clip against bmodels
427 		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
428 	else
429 		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
430 
431 	VectorCopy (trace.endpos, ent->v.origin);
432 	SV_LinkEdict (ent, true);
433 
434 	if (trace.ent)
435 		SV_Impact (ent, trace.ent);
436 
437 	return trace;
438 }
439 
440 
441 /*
442 ============
443 SV_PushMove
444 ============
445 */
SV_PushMove(edict_t * pusher,float movetime)446 void SV_PushMove (edict_t *pusher, float movetime)
447 {
448 	int			i, e;
449 	edict_t		*check, *block;
450 	vec3_t		mins, maxs, move;
451 	vec3_t		entorig, pushorig;
452 	int			num_moved;
453 	edict_t		**moved_edict; //johnfitz -- dynamically allocate
454 	vec3_t		*moved_from; //johnfitz -- dynamically allocate
455 	int			mark; //johnfitz
456 	float	solid_backup;
457 
458 	if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
459 	{
460 		pusher->v.ltime += movetime;
461 		return;
462 	}
463 
464 	for (i=0 ; i<3 ; i++)
465 	{
466 		move[i] = pusher->v.velocity[i] * movetime;
467 		mins[i] = pusher->v.absmin[i] + move[i];
468 		maxs[i] = pusher->v.absmax[i] + move[i];
469 	}
470 
471 	VectorCopy (pusher->v.origin, pushorig);
472 
473 // move the pusher to it's final position
474 
475 	VectorAdd (pusher->v.origin, move, pusher->v.origin);
476 	pusher->v.ltime += movetime;
477 	SV_LinkEdict (pusher, false);
478 
479 	//johnfitz -- dynamically allocate
480 	mark = Hunk_LowMark ();
481 	moved_edict = (edict_t **) Hunk_Alloc (qcvm->num_edicts*sizeof(edict_t *));
482 	moved_from = (vec3_t *) Hunk_Alloc (qcvm->num_edicts*sizeof(vec3_t));
483 	//johnfitz
484 
485 // see if any solid entities are inside the final position
486 	num_moved = 0;
487 	check = NEXT_EDICT(qcvm->edicts);
488 	for (e=1 ; e<qcvm->num_edicts ; e++, check = NEXT_EDICT(check))
489 	{
490 		if (check->free)
491 			continue;
492 		if (check->v.movetype == MOVETYPE_PUSH
493 		|| check->v.movetype == MOVETYPE_NONE
494 		|| check->v.movetype == MOVETYPE_NOCLIP)
495 			continue;
496 
497 	// if the entity is standing on the pusher, it will definately be moved
498 		if ( ! ( ((int)check->v.flags & FL_ONGROUND)
499 		&& PROG_TO_EDICT(check->v.groundentity) == pusher) )
500 		{
501 			if ( check->v.absmin[0] >= maxs[0]
502 			|| check->v.absmin[1] >= maxs[1]
503 			|| check->v.absmin[2] >= maxs[2]
504 			|| check->v.absmax[0] <= mins[0]
505 			|| check->v.absmax[1] <= mins[1]
506 			|| check->v.absmax[2] <= mins[2] )
507 				continue;
508 
509 		// see if the ent's bbox is inside the pusher's final position
510 			if (pusher->v.skin < 0)
511 			{	//a more precise check...
512 				if (!SV_ClipMoveToEntity (pusher, check->v.origin, check->v.mins, check->v.maxs, check->v.origin, CONTENTMASK_ANYSOLID).startsolid)
513 					continue;
514 			}
515 			else
516 			{
517 				if (!SV_TestEntityPosition (check))
518 					continue;
519 			}
520 		}
521 
522 	// remove the onground flag for non-players
523 		if (check->v.movetype != MOVETYPE_WALK)
524 			check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
525 
526 		VectorCopy (check->v.origin, entorig);
527 		VectorCopy (check->v.origin, moved_from[num_moved]);
528 		moved_edict[num_moved] = check;
529 		num_moved++;
530 
531 		//QIP fix for end.bsp
532 		solid_backup = pusher->v.solid;
533 		if ( solid_backup == SOLID_BSP		// everything that blocks: bsp models = map brushes = doors, plats, etc.
534 		  || solid_backup == SOLID_BBOX		// normally boxes
535 		  || solid_backup == SOLID_SLIDEBOX )	// normally monsters
536 		{
537 			// try moving the contacted entity
538 			pusher->v.solid = SOLID_NOT;
539 			SV_PushEntity (check, move);
540 
541 			// if it is still inside the pusher, block
542 			if (pusher->v.skin < 0)
543 			{	//if it has forced contents then do things in a slightly different order, so water can push properly.
544 				block = SV_TestEntityPosition (check);
545 				pusher->v.solid = solid_backup;
546 			}
547 			else
548 			{
549 				pusher->v.solid = solid_backup;
550 				block = SV_TestEntityPosition (check);
551 			}
552 		}
553 		else
554 			block = NULL;
555 		if (block)
556 		{	// fail the move
557 			if (check->v.mins[0] == check->v.maxs[0])
558 				continue;
559 			if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
560 			{	// corpse
561 				check->v.mins[0] = check->v.mins[1] = 0;
562 				VectorCopy (check->v.mins, check->v.maxs);
563 				continue;
564 			}
565 
566 			VectorCopy (entorig, check->v.origin);
567 			SV_LinkEdict (check, true);
568 
569 			VectorCopy (pushorig, pusher->v.origin);
570 			SV_LinkEdict (pusher, false);
571 			pusher->v.ltime -= movetime;
572 
573 			// if the pusher has a "blocked" function, call it
574 			// otherwise, just stay in place until the obstacle is gone
575 			if (pusher->v.blocked)
576 			{
577 				pr_global_struct->self = EDICT_TO_PROG(pusher);
578 				pr_global_struct->other = EDICT_TO_PROG(check);
579 				PR_ExecuteProgram (pusher->v.blocked);
580 			}
581 
582 		// move back any entities we already moved
583 			for (i=0 ; i<num_moved ; i++)
584 			{
585 				VectorCopy (moved_from[i], moved_edict[i]->v.origin);
586 				SV_LinkEdict (moved_edict[i], false);
587 			}
588 			Hunk_FreeToLowMark (mark); //johnfitz
589 			return;
590 		}
591 	}
592 
593 	Hunk_FreeToLowMark (mark); //johnfitz
594 
595 }
596 
597 /*
598 ================
599 SV_Physics_Pusher
600 
601 ================
602 */
SV_Physics_Pusher(edict_t * ent)603 void SV_Physics_Pusher (edict_t *ent)
604 {
605 	float	thinktime;
606 	float	oldltime;
607 	float	movetime;
608 
609 	oldltime = ent->v.ltime;
610 
611 	thinktime = ent->v.nextthink;
612 	if (thinktime < ent->v.ltime + host_frametime)
613 	{
614 		movetime = thinktime - ent->v.ltime;
615 		if (movetime < 0)
616 			movetime = 0;
617 	}
618 	else
619 		movetime = host_frametime;
620 
621 	if (movetime)
622 	{
623 		SV_PushMove (ent, movetime);	// advances ent->v.ltime if not blocked
624 	}
625 
626 	if (thinktime > oldltime && thinktime <= ent->v.ltime)
627 	{
628 		ent->v.nextthink = 0;
629 		pr_global_struct->time = qcvm->time;
630 		pr_global_struct->self = EDICT_TO_PROG(ent);
631 		pr_global_struct->other = EDICT_TO_PROG(qcvm->edicts);
632 		PR_ExecuteProgram (ent->v.think);
633 		if (ent->free)
634 			return;
635 	}
636 
637 }
638 
639 
640 /*
641 ===============================================================================
642 
643 CLIENT MOVEMENT
644 
645 ===============================================================================
646 */
647 
648 /*
649 =============
650 SV_CheckStuck
651 
652 This is a big hack to try and fix the rare case of getting stuck in the world
653 clipping hull.
654 =============
655 */
SV_CheckStuck(edict_t * ent)656 void SV_CheckStuck (edict_t *ent)
657 {
658 	int		i, j;
659 	int		z;
660 	vec3_t	org;
661 
662 	if (!SV_TestEntityPosition(ent))
663 	{
664 		VectorCopy (ent->v.origin, ent->v.oldorigin);
665 		return;
666 	}
667 
668 	VectorCopy (ent->v.origin, org);
669 	VectorCopy (ent->v.oldorigin, ent->v.origin);
670 	if (!SV_TestEntityPosition(ent))
671 	{
672 		Con_DPrintf ("Unstuck.\n");
673 		SV_LinkEdict (ent, true);
674 		return;
675 	}
676 
677 	for (z=0 ; z< 18 ; z++)
678 		for (i=-1 ; i <= 1 ; i++)
679 			for (j=-1 ; j <= 1 ; j++)
680 			{
681 				ent->v.origin[0] = org[0] + i;
682 				ent->v.origin[1] = org[1] + j;
683 				ent->v.origin[2] = org[2] + z;
684 				if (!SV_TestEntityPosition(ent))
685 				{
686 					Con_DPrintf ("Unstuck.\n");
687 					SV_LinkEdict (ent, true);
688 					return;
689 				}
690 			}
691 
692 	VectorCopy (org, ent->v.origin);
693 	Con_DPrintf ("player is stuck.\n");
694 }
695 
696 
697 /*
698 =============
699 SV_CheckWater
700 =============
701 */
SV_CheckWater(edict_t * ent)702 qboolean SV_CheckWater (edict_t *ent)
703 {
704 	vec3_t	point;
705 	int		cont;
706 
707 	point[0] = ent->v.origin[0];
708 	point[1] = ent->v.origin[1];
709 	point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
710 
711 	ent->v.waterlevel = 0;
712 	ent->v.watertype = CONTENTS_EMPTY;
713 	cont = SV_PointContents (point);
714 	if (cont <= CONTENTS_WATER)
715 	{
716 		ent->v.watertype = cont;
717 		ent->v.waterlevel = 1;
718 		point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
719 		cont = SV_PointContents (point);
720 		if (cont <= CONTENTS_WATER)
721 		{
722 			ent->v.waterlevel = 2;
723 			point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
724 			cont = SV_PointContents (point);
725 			if (cont <= CONTENTS_WATER)
726 				ent->v.waterlevel = 3;
727 		}
728 	}
729 
730 	return ent->v.waterlevel > 1;
731 }
732 
733 /*
734 ============
735 SV_WallFriction
736 
737 ============
738 */
SV_WallFriction(edict_t * ent,trace_t * trace)739 void SV_WallFriction (edict_t *ent, trace_t *trace)
740 {
741 	vec3_t		forward, right, up;
742 	float		d, i;
743 	vec3_t		into, side;
744 
745 	AngleVectors (ent->v.v_angle, forward, right, up);
746 	d = DotProduct (trace->plane.normal, forward);
747 
748 	d += 0.5;
749 	if (d >= 0)
750 		return;
751 
752 // cut the tangential velocity
753 	i = DotProduct (trace->plane.normal, ent->v.velocity);
754 	VectorScale (trace->plane.normal, i, into);
755 	VectorSubtract (ent->v.velocity, into, side);
756 
757 	ent->v.velocity[0] = side[0] * (1 + d);
758 	ent->v.velocity[1] = side[1] * (1 + d);
759 }
760 
761 /*
762 =====================
763 SV_TryUnstick
764 
765 Player has come to a dead stop, possibly due to the problem with limited
766 float precision at some angle joins in the BSP hull.
767 
768 Try fixing by pushing one pixel in each direction.
769 
770 This is a hack, but in the interest of good gameplay...
771 ======================
772 */
SV_TryUnstick(edict_t * ent,vec3_t oldvel)773 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
774 {
775 	int		i;
776 	vec3_t	oldorg;
777 	vec3_t	dir;
778 	int		clip;
779 	trace_t	steptrace;
780 
781 	VectorCopy (ent->v.origin, oldorg);
782 	VectorCopy (vec3_origin, dir);
783 
784 	for (i=0 ; i<8 ; i++)
785 	{
786 // try pushing a little in an axial direction
787 		switch (i)
788 		{
789 			case 0:	dir[0] = 2; dir[1] = 0; break;
790 			case 1:	dir[0] = 0; dir[1] = 2; break;
791 			case 2:	dir[0] = -2; dir[1] = 0; break;
792 			case 3:	dir[0] = 0; dir[1] = -2; break;
793 			case 4:	dir[0] = 2; dir[1] = 2; break;
794 			case 5:	dir[0] = -2; dir[1] = 2; break;
795 			case 6:	dir[0] = 2; dir[1] = -2; break;
796 			case 7:	dir[0] = -2; dir[1] = -2; break;
797 		}
798 
799 		SV_PushEntity (ent, dir);
800 
801 // retry the original move
802 		ent->v.velocity[0] = oldvel[0];
803 		ent->v. velocity[1] = oldvel[1];
804 		ent->v. velocity[2] = 0;
805 		clip = SV_FlyMove (ent, 0.1, &steptrace);
806 
807 		if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
808 		|| fabs(oldorg[0] - ent->v.origin[0]) > 4 )
809 		{
810 //Con_DPrintf ("unstuck!\n");
811 			return clip;
812 		}
813 
814 // go back to the original pos and try again
815 		VectorCopy (oldorg, ent->v.origin);
816 	}
817 
818 	VectorCopy (vec3_origin, ent->v.velocity);
819 	return 7;		// still not moving
820 }
821 
822 /*
823 =====================
824 SV_WalkMove
825 
826 Only used by players
827 ======================
828 */
829 #define	STEPSIZE	18
SV_WalkMove(edict_t * ent)830 void SV_WalkMove (edict_t *ent)
831 {
832 	vec3_t		upmove, downmove;
833 	vec3_t		oldorg, oldvel;
834 	vec3_t		nosteporg, nostepvel;
835 	int			clip;
836 	int			oldonground;
837 	trace_t		steptrace, downtrace;
838 
839 //
840 // do a regular slide move unless it looks like you ran into a step
841 //
842 	oldonground = (int)ent->v.flags & FL_ONGROUND;
843 	ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
844 
845 	VectorCopy (ent->v.origin, oldorg);
846 	VectorCopy (ent->v.velocity, oldvel);
847 
848 	clip = SV_FlyMove (ent, host_frametime, &steptrace);
849 
850 	if ( !(clip & 2) )
851 		return;		// move didn't block on a step
852 
853 	if (!oldonground && ent->v.waterlevel == 0)
854 		return;		// don't stair up while jumping
855 
856 	if (ent->v.movetype != MOVETYPE_WALK)
857 		return;		// gibbed by a trigger
858 
859 	if (sv_nostep.value)
860 		return;
861 
862 	if ( (int)sv_player->v.flags & FL_WATERJUMP )
863 		return;
864 
865 	VectorCopy (ent->v.origin, nosteporg);
866 	VectorCopy (ent->v.velocity, nostepvel);
867 
868 //
869 // try moving up and forward to go up a step
870 //
871 	VectorCopy (oldorg, ent->v.origin);	// back to start pos
872 
873 	VectorCopy (vec3_origin, upmove);
874 	VectorCopy (vec3_origin, downmove);
875 	upmove[2] = STEPSIZE;
876 	downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
877 
878 // move up
879 	SV_PushEntity (ent, upmove);	// FIXME: don't link?
880 
881 // move forward
882 	ent->v.velocity[0] = oldvel[0];
883 	ent->v. velocity[1] = oldvel[1];
884 	ent->v. velocity[2] = 0;
885 	clip = SV_FlyMove (ent, host_frametime, &steptrace);
886 
887 // check for stuckness, possibly due to the limited precision of floats
888 // in the clipping hulls
889 	if (clip)
890 	{
891 		if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
892 		&& fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
893 		{	// stepping up didn't make any progress
894 			clip = SV_TryUnstick (ent, oldvel);
895 		}
896 	}
897 
898 // extra friction based on view angle
899 	if ( clip & 2 )
900 		SV_WallFriction (ent, &steptrace);
901 
902 // move down
903 	downtrace = SV_PushEntity (ent, downmove);	// FIXME: don't link?
904 
905 	if (downtrace.plane.normal[2] > 0.7)
906 	{
907 		if (ent->v.solid == SOLID_BSP)
908 		{
909 			ent->v.flags =	(int)ent->v.flags | FL_ONGROUND;
910 			ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
911 		}
912 	}
913 	else
914 	{
915 // if the push down didn't end up on good ground, use the move without
916 // the step up.  This happens near wall / slope combinations, and can
917 // cause the player to hop up higher on a slope too steep to climb
918 		VectorCopy (nosteporg, ent->v.origin);
919 		VectorCopy (nostepvel, ent->v.velocity);
920 	}
921 }
922 
923 
924 /*
925 ================
926 SV_Physics_Client
927 
928 Player character actions
929 ================
930 */
SV_Physics_Client(edict_t * ent,int num)931 void SV_Physics_Client (edict_t	*ent, int num)
932 {
933 	if ( ! svs.clients[num-1].active )
934 		return;		// unconnected slot
935 
936 //
937 // call standard client pre-think
938 //
939 	pr_global_struct->time = qcvm->time;
940 	pr_global_struct->self = EDICT_TO_PROG(ent);
941 	PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
942 
943 //
944 // do a move
945 //
946 	SV_CheckVelocity (ent);
947 
948 //
949 // decide which move function to call
950 //
951 	switch ((int)ent->v.movetype)
952 	{
953 	case MOVETYPE_NONE:
954 		if (!SV_RunThink (ent))
955 			return;
956 		break;
957 
958 	case MOVETYPE_WALK:
959 		if (!SV_RunThink (ent))
960 			return;
961 		if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
962 			SV_AddGravity (ent);
963 		SV_CheckStuck (ent);
964 		SV_WalkMove (ent);
965 		break;
966 
967 	case MOVETYPE_TOSS:
968 	case MOVETYPE_BOUNCE:
969 	case MOVETYPE_GIB:
970 		SV_Physics_Toss (ent);
971 		break;
972 
973 	case MOVETYPE_FLY:
974 		if (!SV_RunThink (ent))
975 			return;
976 		SV_FlyMove (ent, host_frametime, NULL);
977 		break;
978 
979 	case MOVETYPE_NOCLIP:
980 		if (!SV_RunThink (ent))
981 			return;
982 		VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
983 		break;
984 
985 	default:
986 		Host_EndGame ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
987 	}
988 
989 //
990 // call standard player post-think
991 //
992 	SV_LinkEdict (ent, true);
993 
994 	pr_global_struct->time = qcvm->time;
995 	pr_global_struct->self = EDICT_TO_PROG(ent);
996 	PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
997 }
998 
999 //============================================================================
1000 
1001 /*
1002 =============
1003 SV_Physics_None
1004 
1005 Non moving objects can only think
1006 =============
1007 */
SV_Physics_None(edict_t * ent)1008 void SV_Physics_None (edict_t *ent)
1009 {
1010 // regular thinking
1011 	SV_RunThink (ent);
1012 }
1013 
1014 /*
1015 =============
1016 SV_Physics_Noclip
1017 
1018 A moving object that doesn't obey physics
1019 =============
1020 */
SV_Physics_Noclip(edict_t * ent)1021 void SV_Physics_Noclip (edict_t *ent)
1022 {
1023 // regular thinking
1024 	if (!SV_RunThink (ent))
1025 		return;
1026 
1027 	VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1028 	VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1029 
1030 	SV_LinkEdict (ent, false);
1031 }
1032 
1033 /*
1034 ==============================================================================
1035 
1036 TOSS / BOUNCE
1037 
1038 ==============================================================================
1039 */
1040 
1041 /*
1042 =============
1043 SV_CheckWaterTransition
1044 
1045 =============
1046 */
SV_CheckWaterTransition(edict_t * ent)1047 void SV_CheckWaterTransition (edict_t *ent)
1048 {
1049 	int		cont;
1050 
1051 	cont = SV_PointContents (ent->v.origin);
1052 
1053 	if (!ent->v.watertype)
1054 	{	// just spawned here
1055 		ent->v.watertype = cont;
1056 		ent->v.waterlevel = 1;
1057 		return;
1058 	}
1059 
1060 	if (cont <= CONTENTS_WATER)
1061 	{
1062 		if (ent->v.watertype == CONTENTS_EMPTY)
1063 		{	// just crossed into water
1064 			SV_StartSound (ent, NULL, 0, "misc/h2ohit1.wav", 255, 1);
1065 		}
1066 		ent->v.watertype = cont;
1067 		ent->v.waterlevel = 1;
1068 	}
1069 	else
1070 	{
1071 		if (ent->v.watertype != CONTENTS_EMPTY)
1072 		{	// just crossed into water
1073 			SV_StartSound (ent, NULL, 0, "misc/h2ohit1.wav", 255, 1);
1074 		}
1075 		ent->v.watertype = CONTENTS_EMPTY;
1076 		ent->v.waterlevel = cont;
1077 	}
1078 }
1079 
1080 /*
1081 =============
1082 SV_Physics_Toss
1083 
1084 Toss, bounce, and fly movement.  When onground, do nothing.
1085 =============
1086 */
SV_Physics_Toss(edict_t * ent)1087 void SV_Physics_Toss (edict_t *ent)
1088 {
1089 	trace_t	trace;
1090 	vec3_t	move;
1091 	float	backoff;
1092 
1093 	// regular thinking
1094 	if (!SV_RunThink (ent))
1095 		return;
1096 
1097 // if onground, return without moving
1098 	if ( ((int)ent->v.flags & FL_ONGROUND) )
1099 		return;
1100 
1101 	SV_CheckVelocity (ent);
1102 
1103 // add gravity
1104 	if (ent->v.movetype != MOVETYPE_FLY
1105 	&& ent->v.movetype != MOVETYPE_FLYMISSILE)
1106 		SV_AddGravity (ent);
1107 
1108 // move angles
1109 	VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1110 
1111 // move origin
1112 	VectorScale (ent->v.velocity, host_frametime, move);
1113 	trace = SV_PushEntity (ent, move);
1114 	if (trace.fraction == 1)
1115 		return;
1116 	if (ent->free)
1117 		return;
1118 
1119 	if (ent->v.movetype == MOVETYPE_BOUNCE)
1120 		backoff = 1.5;
1121 	else
1122 		backoff = 1;
1123 
1124 	ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1125 
1126 // stop if on ground
1127 	if (trace.plane.normal[2] > 0.7)
1128 	{
1129 		if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE)
1130 		{
1131 			ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1132 			ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1133 			VectorCopy (vec3_origin, ent->v.velocity);
1134 			VectorCopy (vec3_origin, ent->v.avelocity);
1135 		}
1136 	}
1137 
1138 // check for in water
1139 	SV_CheckWaterTransition (ent);
1140 }
1141 
1142 /*
1143 ===============================================================================
1144 
1145 STEPPING MOVEMENT
1146 
1147 ===============================================================================
1148 */
1149 
1150 /*
1151 =============
1152 SV_Physics_Step
1153 
1154 Monsters freefall when they don't have a ground entity, otherwise
1155 all movement is done with discrete steps.
1156 
1157 This is also used for objects that have become still on the ground, but
1158 will fall if the floor is pulled out from under them.
1159 =============
1160 */
SV_Physics_Step(edict_t * ent)1161 void SV_Physics_Step (edict_t *ent)
1162 {
1163 	qboolean	hitsound;
1164 
1165 // freefall if not onground
1166 	if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1167 	{
1168 		if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1169 			hitsound = true;
1170 		else
1171 			hitsound = false;
1172 
1173 		SV_AddGravity (ent);
1174 		SV_CheckVelocity (ent);
1175 		SV_FlyMove (ent, host_frametime, NULL);
1176 		SV_LinkEdict (ent, true);
1177 
1178 		if ( (int)ent->v.flags & FL_ONGROUND )	// just hit ground
1179 		{
1180 			if (hitsound)
1181 				SV_StartSound (ent, NULL, 0, "demon/dland2.wav", 255, 1);
1182 		}
1183 	}
1184 
1185 // regular thinking
1186 	SV_RunThink (ent);
1187 
1188 	SV_CheckWaterTransition (ent);
1189 }
1190 
1191 
1192 //============================================================================
1193 
1194 /*
1195 ================
1196 SV_Physics
1197 
1198 ================
1199 */
SV_Physics(void)1200 void SV_Physics (void)
1201 {
1202 	int	i;
1203 	int	entity_cap; // For sv_freezenonclients
1204 	edict_t	*ent;
1205 
1206 	int physics_mode;
1207 	if (qcvm->extglobals.physics_mode)
1208 		physics_mode = *qcvm->extglobals.physics_mode;
1209 	else
1210 		physics_mode = (qcvm==&cl.qcvm)?0:2;	//csqc doesn't run thinks by default. it was meant to simplify implementations, but we just force fields to match ssqc so its not that large a burden.
1211 
1212 	if (!physics_mode)
1213 	{
1214 		qcvm->time += host_frametime;
1215 		return;
1216 	}
1217 	else if (physics_mode==1)
1218 	{	//for dp compat. note that this violates MOVETYPE_PUSH.
1219 		for (i=0, ent = qcvm->edicts; i<qcvm->num_edicts ; i++, ent = NEXT_EDICT(ent))
1220 		{
1221 			if (ent->free)
1222 				continue;
1223 			SV_RunThink(ent);
1224 		}
1225 		qcvm->time += host_frametime;
1226 		return;
1227 	}
1228 
1229 // let the progs know that a new frame has started
1230 	if (pr_global_struct->StartFrame)
1231 	{
1232 		pr_global_struct->self = EDICT_TO_PROG(qcvm->edicts);
1233 		pr_global_struct->other = EDICT_TO_PROG(qcvm->edicts);
1234 		pr_global_struct->time = qcvm->time;
1235 		PR_ExecuteProgram (pr_global_struct->StartFrame);
1236 	}
1237 
1238 //SV_CheckAllEnts ();
1239 
1240 //
1241 // treat each object in turn
1242 //
1243 	ent = qcvm->edicts;
1244 
1245 	if (sv_freezenonclients.value && qcvm == &sv.qcvm)
1246 	  entity_cap = svs.maxclients + 1; // Only run physics on clients and the world
1247 	else
1248 		entity_cap = qcvm->num_edicts;
1249 
1250 	//for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1251 	for (i=0 ; i<entity_cap ; i++, ent = NEXT_EDICT(ent))
1252 	{
1253 		if (ent->free)
1254 			continue;
1255 
1256 		if (pr_global_struct->force_retouch)
1257 		{
1258 			SV_LinkEdict (ent, true);	// force retouch even for stationary
1259 		}
1260 
1261 		if (i > 0 && i <= svs.maxclients && qcvm == &sv.qcvm)
1262 			SV_Physics_Client (ent, i);
1263 		else if (ent->v.movetype == MOVETYPE_PUSH)
1264 			SV_Physics_Pusher (ent);
1265 		else if (ent->v.movetype == MOVETYPE_NONE)
1266 			SV_Physics_None (ent);
1267 		else if (ent->v.movetype == MOVETYPE_NOCLIP)
1268 			SV_Physics_Noclip (ent);
1269 		else if (ent->v.movetype == MOVETYPE_STEP)
1270 			SV_Physics_Step (ent);
1271 		else if (ent->v.movetype == MOVETYPE_TOSS
1272 		|| ent->v.movetype == MOVETYPE_GIB
1273 		|| ent->v.movetype == MOVETYPE_BOUNCE
1274 		|| ent->v.movetype == MOVETYPE_FLY
1275 		|| ent->v.movetype == MOVETYPE_FLYMISSILE)
1276 			SV_Physics_Toss (ent);
1277 		else
1278 			Host_EndGame ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1279 	}
1280 
1281 	if (pr_global_struct->force_retouch)
1282 		pr_global_struct->force_retouch--;
1283 
1284 	if (!(sv_freezenonclients.value && qcvm == &sv.qcvm))
1285 	  qcvm->time += host_frametime;
1286 }
1287