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