2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
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.
29 onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
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
38 solid_edge items only clip against bsp models.
42 cvar_t sv_friction
= {"sv_friction","4",false,true};
43 cvar_t sv_stopspeed
= {"sv_stopspeed","100"};
44 cvar_t sv_gravity
= {"sv_gravity","800",false,true};
45 cvar_t sv_maxvelocity
= {"sv_maxvelocity","2000"};
46 cvar_t sv_nostep
= {"sv_nostep","0"};
49 static vec3_t vec_origin
= {0.0, 0.0, 0.0};
52 #define MOVE_EPSILON 0.01
54 void SV_Physics_Toss (edict_t
*ent
);
61 void SV_CheckAllEnts (void)
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
))
72 if (check
->v
.movetype
== MOVETYPE_PUSH
73 || check
->v
.movetype
== MOVETYPE_NONE
75 || check
->v
.movetype
== MOVETYPE_FOLLOW
77 || check
->v
.movetype
== MOVETYPE_NOCLIP
)
80 if (SV_TestEntityPosition (check
))
81 Con_Printf ("entity in invalid position\n");
90 void SV_CheckVelocity (edict_t
*ent
)
99 if (IS_NAN(ent
->v
.velocity
[i
]))
101 Con_Printf ("Got a NaN velocity on %s\n", pr_strings
+ ent
->v
.classname
);
102 ent
->v
.velocity
[i
] = 0;
104 if (IS_NAN(ent
->v
.origin
[i
]))
106 Con_Printf ("Got a NaN origin on %s\n", pr_strings
+ ent
->v
.classname
);
107 ent
->v
.origin
[i
] = 0;
109 if (ent
->v
.velocity
[i
] > sv_maxvelocity
.value
)
110 ent
->v
.velocity
[i
] = sv_maxvelocity
.value
;
111 else if (ent
->v
.velocity
[i
] < -sv_maxvelocity
.value
)
112 ent
->v
.velocity
[i
] = -sv_maxvelocity
.value
;
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.
126 qboolean
SV_RunThink (edict_t
*ent
)
130 thinktime
= ent
->v
.nextthink
;
131 if (thinktime
<= 0 || thinktime
> sv
.time
+ host_frametime
)
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
->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
->v
.think
);
150 Two entities have touched, so run their touch functions
153 void SV_Impact (edict_t
*e1
, edict_t
*e2
)
155 int old_self
, old_other
;
157 old_self
= pr_global_struct
->self
;
158 old_other
= pr_global_struct
->other
;
160 pr_global_struct
->time
= sv
.time
;
161 if (e1
->v
.touch
&& e1
->v
.solid
!= SOLID_NOT
)
163 pr_global_struct
->self
= EDICT_TO_PROG(e1
);
164 pr_global_struct
->other
= EDICT_TO_PROG(e2
);
165 PR_ExecuteProgram (e1
->v
.touch
);
168 if (e2
->v
.touch
&& e2
->v
.solid
!= SOLID_NOT
)
170 pr_global_struct
->self
= EDICT_TO_PROG(e2
);
171 pr_global_struct
->other
= EDICT_TO_PROG(e1
);
172 PR_ExecuteProgram (e2
->v
.touch
);
175 pr_global_struct
->self
= old_self
;
176 pr_global_struct
->other
= old_other
;
184 Slide off of the impacting object
185 returns the blocked flags (1 = floor, 2 = step / wall)
188 #define STOP_EPSILON 0.1
190 int ClipVelocity (vec3_t in
, vec3_t normal
, vec3_t out
, float overbounce
)
198 blocked
|= 1; // floor
200 blocked
|= 2; // step
202 backoff
= DotProduct (in
, normal
) * overbounce
;
204 for (i
=0 ; i
<3 ; i
++)
206 change
= normal
[i
]*backoff
;
207 out
[i
] = in
[i
] - change
;
208 if (out
[i
] > -STOP_EPSILON
&& out
[i
] < STOP_EPSILON
)
220 The basic solid body movement clip that slides along multiple planes
221 Returns the clipflags if the velocity was modified (hit something solid)
225 If steptrace is not NULL, the trace of any vertical wall hit will be stored
228 #define MAX_CLIP_PLANES 5
229 int SV_FlyMove (edict_t
*ent
, float time
, trace_t
*steptrace
)
231 int bumpcount
, numbumps
;
235 vec3_t planes
[MAX_CLIP_PLANES
];
236 vec3_t primal_velocity
, original_velocity
, new_velocity
;
246 VectorCopy (ent
->v
.velocity
, original_velocity
);
247 VectorCopy (ent
->v
.velocity
, primal_velocity
);
252 for (bumpcount
=0 ; bumpcount
<numbumps
; bumpcount
++)
254 if (!ent
->v
.velocity
[0] && !ent
->v
.velocity
[1] && !ent
->v
.velocity
[2])
257 for (i
=0 ; i
<3 ; i
++)
258 end
[i
] = ent
->v
.origin
[i
] + time_left
* ent
->v
.velocity
[i
];
260 trace
= SV_Move (ent
->v
.origin
, ent
->v
.mins
, ent
->v
.maxs
, end
, false, ent
);
263 { // entity is trapped in another solid
264 VectorCopy (vec3_origin
, ent
->v
.velocity
);
268 if (trace
.fraction
> 0)
269 { // actually covered some distance
270 VectorCopy (trace
.endpos
, ent
->v
.origin
);
271 VectorCopy (ent
->v
.velocity
, original_velocity
);
275 if (trace
.fraction
== 1)
276 break; // moved the entire distance
279 Sys_Error ("SV_FlyMove: !trace.ent");
281 if (trace
.plane
.normal
[2] > 0.7)
283 blocked
|= 1; // floor
284 if (trace
.ent
->v
.solid
== SOLID_BSP
)
286 ent
->v
.flags
= (int)ent
->v
.flags
| FL_ONGROUND
;
287 ent
->v
.groundentity
= EDICT_TO_PROG(trace
.ent
);
290 if (!trace
.plane
.normal
[2])
292 blocked
|= 2; // step
294 *steptrace
= trace
; // save for player extrafriction
298 // run the impact function
300 SV_Impact (ent
, trace
.ent
);
302 break; // removed by the impact function
305 time_left
-= time_left
* trace
.fraction
;
307 // cliped to another plane
308 if (numplanes
>= MAX_CLIP_PLANES
)
309 { // this shouldn't really happen
310 VectorCopy (vec3_origin
, ent
->v
.velocity
);
314 VectorCopy (trace
.plane
.normal
, planes
[numplanes
]);
318 // modify original_velocity so it parallels all of the clip planes
320 for (i
=0 ; i
<numplanes
; i
++)
322 ClipVelocity (original_velocity
, planes
[i
], new_velocity
, 1);
323 for (j
=0 ; j
<numplanes
; j
++)
326 if (DotProduct (new_velocity
, planes
[j
]) < 0)
334 { // go along this plane
335 VectorCopy (new_velocity
, ent
->v
.velocity
);
338 { // go along the crease
341 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
342 VectorCopy (vec3_origin
, ent
->v
.velocity
);
345 CrossProduct (planes
[0], planes
[1], dir
);
346 d
= DotProduct (dir
, ent
->v
.velocity
);
347 VectorScale (dir
, d
, ent
->v
.velocity
);
351 // if original velocity is against the original velocity, stop dead
352 // to avoid tiny occilations in sloping corners
354 if (DotProduct (ent
->v
.velocity
, primal_velocity
) <= 0)
356 VectorCopy (vec3_origin
, ent
->v
.velocity
);
371 void SV_AddGravity (edict_t
*ent
)
377 ent_gravity
= ent
->v
.gravity
;
383 val
= GetEdictFieldValue(ent
, "gravity");
384 if (val
&& val
->_float
)
385 ent_gravity
= val
->_float
;
389 ent
->v
.velocity
[2] -= ent_gravity
* sv_gravity
.value
* host_frametime
;
394 ===============================================================================
398 ===============================================================================
405 Does not change the entities velocity at all
408 trace_t
SV_PushEntity (edict_t
*ent
, vec3_t push
)
413 VectorAdd (ent
->v
.origin
, push
, end
);
415 if (ent
->v
.movetype
== MOVETYPE_FLYMISSILE
)
416 trace
= SV_Move (ent
->v
.origin
, ent
->v
.mins
, ent
->v
.maxs
, end
, MOVE_MISSILE
, ent
);
417 else if (ent
->v
.solid
== SOLID_TRIGGER
|| ent
->v
.solid
== SOLID_NOT
)
418 // only clip against bmodels
419 trace
= SV_Move (ent
->v
.origin
, ent
->v
.mins
, ent
->v
.maxs
, end
, MOVE_NOMONSTERS
, ent
);
421 trace
= SV_Move (ent
->v
.origin
, ent
->v
.mins
, ent
->v
.maxs
, end
, MOVE_NORMAL
, ent
);
423 VectorCopy (trace
.endpos
, ent
->v
.origin
);
424 SV_LinkEdict (ent
, true);
427 SV_Impact (ent
, trace
.ent
);
439 void SV_PushMove (edict_t
*pusher
, float movetime
)
442 edict_t
*check
, *block
;
443 vec3_t mins
, maxs
, move
;
444 vec3_t entorig
, pushorig
;
446 edict_t
*moved_edict
[MAX_EDICTS
];
447 vec3_t moved_from
[MAX_EDICTS
];
449 if (!pusher
->v
.velocity
[0] && !pusher
->v
.velocity
[1] && !pusher
->v
.velocity
[2])
451 pusher
->v
.ltime
+= movetime
;
455 for (i
=0 ; i
<3 ; i
++)
457 move
[i
] = pusher
->v
.velocity
[i
] * movetime
;
458 mins
[i
] = pusher
->v
.absmin
[i
] + move
[i
];
459 maxs
[i
] = pusher
->v
.absmax
[i
] + move
[i
];
462 VectorCopy (pusher
->v
.origin
, pushorig
);
464 // move the pusher to it's final position
466 VectorAdd (pusher
->v
.origin
, move
, pusher
->v
.origin
);
467 pusher
->v
.ltime
+= movetime
;
468 SV_LinkEdict (pusher
, false);
471 // see if any solid entities are inside the final position
473 check
= NEXT_EDICT(sv
.edicts
);
474 for (e
=1 ; e
<sv
.num_edicts
; e
++, check
= NEXT_EDICT(check
))
478 if (check
->v
.movetype
== MOVETYPE_PUSH
479 || check
->v
.movetype
== MOVETYPE_NONE
481 || check
->v
.movetype
== MOVETYPE_FOLLOW
483 || check
->v
.movetype
== MOVETYPE_NOCLIP
)
486 // if the entity is standing on the pusher, it will definately be moved
487 if ( ! ( ((int)check
->v
.flags
& FL_ONGROUND
)
488 && PROG_TO_EDICT(check
->v
.groundentity
) == pusher
) )
490 if ( check
->v
.absmin
[0] >= maxs
[0]
491 || check
->v
.absmin
[1] >= maxs
[1]
492 || check
->v
.absmin
[2] >= maxs
[2]
493 || check
->v
.absmax
[0] <= mins
[0]
494 || check
->v
.absmax
[1] <= mins
[1]
495 || check
->v
.absmax
[2] <= mins
[2] )
498 // see if the ent's bbox is inside the pusher's final position
499 if (!SV_TestEntityPosition (check
))
503 // remove the onground flag for non-players
504 if (check
->v
.movetype
!= MOVETYPE_WALK
)
505 check
->v
.flags
= (int)check
->v
.flags
& ~FL_ONGROUND
;
507 VectorCopy (check
->v
.origin
, entorig
);
508 VectorCopy (check
->v
.origin
, moved_from
[num_moved
]);
509 moved_edict
[num_moved
] = check
;
512 // try moving the contacted entity
513 pusher
->v
.solid
= SOLID_NOT
;
514 SV_PushEntity (check
, move
);
515 pusher
->v
.solid
= SOLID_BSP
;
517 // if it is still inside the pusher, block
518 block
= SV_TestEntityPosition (check
);
521 if (check
->v
.mins
[0] == check
->v
.maxs
[0])
523 if (check
->v
.solid
== SOLID_NOT
|| check
->v
.solid
== SOLID_TRIGGER
)
525 check
->v
.mins
[0] = check
->v
.mins
[1] = 0;
526 VectorCopy (check
->v
.mins
, check
->v
.maxs
);
530 VectorCopy (entorig
, check
->v
.origin
);
531 SV_LinkEdict (check
, true);
533 VectorCopy (pushorig
, pusher
->v
.origin
);
534 SV_LinkEdict (pusher
, false);
535 pusher
->v
.ltime
-= movetime
;
537 // if the pusher has a "blocked" function, call it
538 // otherwise, just stay in place until the obstacle is gone
539 if (pusher
->v
.blocked
)
541 pr_global_struct
->self
= EDICT_TO_PROG(pusher
);
542 pr_global_struct
->other
= EDICT_TO_PROG(check
);
543 PR_ExecuteProgram (pusher
->v
.blocked
);
546 // move back any entities we already moved
547 for (i
=0 ; i
<num_moved
; i
++)
549 VectorCopy (moved_from
[i
], moved_edict
[i
]->v
.origin
);
550 SV_LinkEdict (moved_edict
[i
], false);
566 void SV_PushRotate (edict_t
*pusher
, float movetime
)
569 edict_t
*check
, *block
;
570 vec3_t move
, a
, amove
;
571 vec3_t entorig
, pushorig
;
573 edict_t
*moved_edict
[MAX_EDICTS
];
574 vec3_t moved_from
[MAX_EDICTS
];
576 vec3_t forward
, right
, up
;
578 if (!pusher
->v
.avelocity
[0] && !pusher
->v
.avelocity
[1] && !pusher
->v
.avelocity
[2])
580 pusher
->v
.ltime
+= movetime
;
584 for (i
=0 ; i
<3 ; i
++)
585 amove
[i
] = pusher
->v
.avelocity
[i
] * movetime
;
587 VectorSubtract (vec3_origin
, amove
, a
);
588 AngleVectors (a
, forward
, right
, up
);
590 VectorCopy (pusher
->v
.angles
, pushorig
);
592 // move the pusher to it's final position
594 VectorAdd (pusher
->v
.angles
, amove
, pusher
->v
.angles
);
595 pusher
->v
.ltime
+= movetime
;
596 SV_LinkEdict (pusher
, false);
599 // see if any solid entities are inside the final position
601 check
= NEXT_EDICT(sv
.edicts
);
602 for (e
=1 ; e
<sv
.num_edicts
; e
++, check
= NEXT_EDICT(check
))
606 if (check
->v
.movetype
== MOVETYPE_PUSH
607 || check
->v
.movetype
== MOVETYPE_NONE
608 || check
->v
.movetype
== MOVETYPE_FOLLOW
609 || check
->v
.movetype
== MOVETYPE_NOCLIP
)
612 // if the entity is standing on the pusher, it will definately be moved
613 if ( ! ( ((int)check
->v
.flags
& FL_ONGROUND
)
614 && PROG_TO_EDICT(check
->v
.groundentity
) == pusher
) )
616 if ( check
->v
.absmin
[0] >= pusher
->v
.absmax
[0]
617 || check
->v
.absmin
[1] >= pusher
->v
.absmax
[1]
618 || check
->v
.absmin
[2] >= pusher
->v
.absmax
[2]
619 || check
->v
.absmax
[0] <= pusher
->v
.absmin
[0]
620 || check
->v
.absmax
[1] <= pusher
->v
.absmin
[1]
621 || check
->v
.absmax
[2] <= pusher
->v
.absmin
[2] )
624 // see if the ent's bbox is inside the pusher's final position
625 if (!SV_TestEntityPosition (check
))
629 // remove the onground flag for non-players
630 if (check
->v
.movetype
!= MOVETYPE_WALK
)
631 check
->v
.flags
= (int)check
->v
.flags
& ~FL_ONGROUND
;
633 VectorCopy (check
->v
.origin
, entorig
);
634 VectorCopy (check
->v
.origin
, moved_from
[num_moved
]);
635 moved_edict
[num_moved
] = check
;
638 // calculate destination position
639 VectorSubtract (check
->v
.origin
, pusher
->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
);
645 // try moving the contacted entity
646 pusher
->v
.solid
= SOLID_NOT
;
647 SV_PushEntity (check
, move
);
648 pusher
->v
.solid
= SOLID_BSP
;
650 // if it is still inside the pusher, block
651 block
= SV_TestEntityPosition (check
);
654 if (check
->v
.mins
[0] == check
->v
.maxs
[0])
656 if (check
->v
.solid
== SOLID_NOT
|| check
->v
.solid
== SOLID_TRIGGER
)
658 check
->v
.mins
[0] = check
->v
.mins
[1] = 0;
659 VectorCopy (check
->v
.mins
, check
->v
.maxs
);
663 VectorCopy (entorig
, check
->v
.origin
);
664 SV_LinkEdict (check
, true);
666 VectorCopy (pushorig
, pusher
->v
.angles
);
667 SV_LinkEdict (pusher
, false);
668 pusher
->v
.ltime
-= movetime
;
670 // if the pusher has a "blocked" function, call it
671 // otherwise, just stay in place until the obstacle is gone
672 if (pusher
->v
.blocked
)
674 pr_global_struct
->self
= EDICT_TO_PROG(pusher
);
675 pr_global_struct
->other
= EDICT_TO_PROG(check
);
676 PR_ExecuteProgram (pusher
->v
.blocked
);
679 // move back any entities we already moved
680 for (i
=0 ; i
<num_moved
; i
++)
682 VectorCopy (moved_from
[i
], moved_edict
[i
]->v
.origin
);
683 VectorSubtract (moved_edict
[i
]->v
.angles
, amove
, moved_edict
[i
]->v
.angles
);
684 SV_LinkEdict (moved_edict
[i
], false);
690 VectorAdd (check
->v
.angles
, amove
, check
->v
.angles
);
704 void SV_Physics_Pusher (edict_t
*ent
)
710 oldltime
= ent
->v
.ltime
;
712 thinktime
= ent
->v
.nextthink
;
713 if (thinktime
< ent
->v
.ltime
+ host_frametime
)
715 movetime
= thinktime
- ent
->v
.ltime
;
720 movetime
= host_frametime
;
725 if (ent
->v
.avelocity
[0] || ent
->v
.avelocity
[1] || ent
->v
.avelocity
[2])
726 SV_PushRotate (ent
, movetime
);
729 SV_PushMove (ent
, movetime
); // advances ent->v.ltime if not blocked
732 if (thinktime
> oldltime
&& thinktime
<= ent
->v
.ltime
)
734 ent
->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
->v
.think
);
747 ===============================================================================
751 ===============================================================================
758 This is a big hack to try and fix the rare case of getting stuck in the world
762 void SV_CheckStuck (edict_t
*ent
)
768 if (!SV_TestEntityPosition(ent
))
770 VectorCopy (ent
->v
.origin
, ent
->v
.oldorigin
);
774 VectorCopy (ent
->v
.origin
, org
);
775 VectorCopy (ent
->v
.oldorigin
, ent
->v
.origin
);
776 if (!SV_TestEntityPosition(ent
))
778 Con_DPrintf ("Unstuck.\n");
779 SV_LinkEdict (ent
, true);
783 for (z
=0 ; z
< 18 ; z
++)
784 for (i
=-1 ; i
<= 1 ; i
++)
785 for (j
=-1 ; j
<= 1 ; j
++)
787 ent
->v
.origin
[0] = org
[0] + i
;
788 ent
->v
.origin
[1] = org
[1] + j
;
789 ent
->v
.origin
[2] = org
[2] + z
;
790 if (!SV_TestEntityPosition(ent
))
792 Con_DPrintf ("Unstuck.\n");
793 SV_LinkEdict (ent
, true);
798 VectorCopy (org
, ent
->v
.origin
);
799 Con_DPrintf ("player is stuck.\n");
808 qboolean
SV_CheckWater (edict_t
*ent
)
816 point
[0] = ent
->v
.origin
[0];
817 point
[1] = ent
->v
.origin
[1];
818 point
[2] = ent
->v
.origin
[2] + ent
->v
.mins
[2] + 1;
820 ent
->v
.waterlevel
= 0;
821 ent
->v
.watertype
= CONTENTS_EMPTY
;
822 cont
= SV_PointContents (point
);
823 if (cont
<= CONTENTS_WATER
)
826 truecont
= SV_TruePointContents (point
);
828 ent
->v
.watertype
= cont
;
829 ent
->v
.waterlevel
= 1;
830 point
[2] = ent
->v
.origin
[2] + (ent
->v
.mins
[2] + ent
->v
.maxs
[2])*0.5;
831 cont
= SV_PointContents (point
);
832 if (cont
<= CONTENTS_WATER
)
834 ent
->v
.waterlevel
= 2;
835 point
[2] = ent
->v
.origin
[2] + ent
->v
.view_ofs
[2];
836 cont
= SV_PointContents (point
);
837 if (cont
<= CONTENTS_WATER
)
838 ent
->v
.waterlevel
= 3;
841 if (truecont
<= CONTENTS_CURRENT_0
&& truecont
>= CONTENTS_CURRENT_DOWN
)
843 static vec3_t current_table
[] =
853 VectorMA (ent
->v
.basevelocity
, 150.0*ent
->v
.waterlevel
/3.0, current_table
[CONTENTS_CURRENT_0
- truecont
], ent
->v
.basevelocity
);
858 return ent
->v
.waterlevel
> 1;
867 void SV_WallFriction (edict_t
*ent
, trace_t
*trace
)
869 vec3_t forward
, right
, up
;
873 AngleVectors (ent
->v
.v_angle
, forward
, right
, up
);
874 d
= DotProduct (trace
->plane
.normal
, forward
);
880 // cut the tangential velocity
881 i
= DotProduct (trace
->plane
.normal
, ent
->v
.velocity
);
882 VectorScale (trace
->plane
.normal
, i
, into
);
883 VectorSubtract (ent
->v
.velocity
, into
, side
);
885 ent
->v
.velocity
[0] = side
[0] * (1 + d
);
886 ent
->v
.velocity
[1] = side
[1] * (1 + d
);
890 =====================
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.
896 Try fixing by pushing one pixel in each direction.
898 This is a hack, but in the interest of good gameplay...
899 ======================
901 int SV_TryUnstick (edict_t
*ent
, vec3_t oldvel
)
909 VectorCopy (ent
->v
.origin
, oldorg
);
910 VectorCopy (vec3_origin
, dir
);
912 for (i
=0 ; i
<8 ; i
++)
914 // try pushing a little in an axial direction
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;
927 SV_PushEntity (ent
, dir
);
929 // retry the original move
930 ent
->v
.velocity
[0] = oldvel
[0];
931 ent
->v
. velocity
[1] = oldvel
[1];
932 ent
->v
. velocity
[2] = 0;
933 clip
= SV_FlyMove (ent
, 0.1, &steptrace
);
935 if ( fabs(oldorg
[1] - ent
->v
.origin
[1]) > 4
936 || fabs(oldorg
[0] - ent
->v
.origin
[0]) > 4 )
938 //Con_DPrintf ("unstuck!\n");
942 // go back to the original pos and try again
943 VectorCopy (oldorg
, ent
->v
.origin
);
946 VectorCopy (vec3_origin
, ent
->v
.velocity
);
947 return 7; // still not moving
951 =====================
955 ======================
958 void SV_WalkMove (edict_t
*ent
)
960 vec3_t upmove
, downmove
;
961 vec3_t oldorg
, oldvel
;
962 vec3_t nosteporg
, nostepvel
;
965 trace_t steptrace
, downtrace
;
968 // do a regular slide move unless it looks like you ran into a step
970 oldonground
= (int)ent
->v
.flags
& FL_ONGROUND
;
971 ent
->v
.flags
= (int)ent
->v
.flags
& ~FL_ONGROUND
;
973 VectorCopy (ent
->v
.origin
, oldorg
);
974 VectorCopy (ent
->v
.velocity
, oldvel
);
976 clip
= SV_FlyMove (ent
, host_frametime
, &steptrace
);
979 return; // move didn't block on a step
981 if (!oldonground
&& ent
->v
.waterlevel
== 0)
982 return; // don't stair up while jumping
984 if (ent
->v
.movetype
!= MOVETYPE_WALK
)
985 return; // gibbed by a trigger
990 if ( (int)sv_player
->v
.flags
& FL_WATERJUMP
)
993 VectorCopy (ent
->v
.origin
, nosteporg
);
994 VectorCopy (ent
->v
.velocity
, nostepvel
);
997 // try moving up and forward to go up a step
999 VectorCopy (oldorg
, ent
->v
.origin
); // back to start pos
1001 VectorCopy (vec3_origin
, upmove
);
1002 VectorCopy (vec3_origin
, downmove
);
1003 upmove
[2] = STEPSIZE
;
1004 downmove
[2] = -STEPSIZE
+ oldvel
[2]*host_frametime
;
1007 SV_PushEntity (ent
, upmove
); // FIXME: don't link?
1010 ent
->v
.velocity
[0] = oldvel
[0];
1011 ent
->v
. velocity
[1] = oldvel
[1];
1012 ent
->v
. velocity
[2] = 0;
1013 clip
= SV_FlyMove (ent
, host_frametime
, &steptrace
);
1015 // check for stuckness, possibly due to the limited precision of floats
1016 // in the clipping hulls
1019 if ( fabs(oldorg
[1] - ent
->v
.origin
[1]) < 0.03125
1020 && fabs(oldorg
[0] - ent
->v
.origin
[0]) < 0.03125 )
1021 { // stepping up didn't make any progress
1022 clip
= SV_TryUnstick (ent
, oldvel
);
1026 // extra friction based on view angle
1028 SV_WallFriction (ent
, &steptrace
);
1031 downtrace
= SV_PushEntity (ent
, downmove
); // FIXME: don't link?
1033 if (downtrace
.plane
.normal
[2] > 0.7)
1035 if (ent
->v
.solid
== SOLID_BSP
)
1037 ent
->v
.flags
= (int)ent
->v
.flags
| FL_ONGROUND
;
1038 ent
->v
.groundentity
= EDICT_TO_PROG(downtrace
.ent
);
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
->v
.origin
);
1047 VectorCopy (nostepvel
, ent
->v
.velocity
);
1056 Player character actions
1059 void SV_Physics_Client (edict_t
*ent
, int num
)
1061 if ( ! svs
.clients
[num
-1].active
)
1062 return; // unconnected slot
1065 // call standard client pre-think
1067 pr_global_struct
->time
= sv
.time
;
1068 pr_global_struct
->self
= EDICT_TO_PROG(ent
);
1069 PR_ExecuteProgram (pr_global_struct
->PlayerPreThink
);
1074 SV_CheckVelocity (ent
);
1077 // decide which move function to call
1079 switch ((int)ent
->v
.movetype
)
1082 if (!SV_RunThink (ent
))
1087 if (!SV_RunThink (ent
))
1089 if (!SV_CheckWater (ent
) && ! ((int)ent
->v
.flags
& FL_WATERJUMP
) )
1090 SV_AddGravity (ent
);
1091 SV_CheckStuck (ent
);
1093 VectorAdd (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1098 VectorSubtract (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1103 case MOVETYPE_BOUNCE
:
1104 SV_Physics_Toss (ent
);
1108 if (!SV_RunThink (ent
))
1110 SV_FlyMove (ent
, host_frametime
, NULL
);
1113 case MOVETYPE_NOCLIP
:
1114 if (!SV_RunThink (ent
))
1116 VectorMA (ent
->v
.origin
, host_frametime
, ent
->v
.velocity
, ent
->v
.origin
);
1120 Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent
->v
.movetype
);
1124 // call standard player post-think
1126 SV_LinkEdict (ent
, true);
1128 pr_global_struct
->time
= sv
.time
;
1129 pr_global_struct
->self
= EDICT_TO_PROG(ent
);
1130 PR_ExecuteProgram (pr_global_struct
->PlayerPostThink
);
1133 //============================================================================
1139 Non moving objects can only think
1142 void SV_Physics_None (edict_t
*ent
)
1153 Entities that are "stuck" to another entity
1156 void SV_Physics_Follow (edict_t
*ent
)
1160 VectorAdd (PROG_TO_EDICT(ent
->v
.aiment
)->v
.origin
, ent
->v
.v_angle
, ent
->v
.origin
);
1161 SV_LinkEdict (ent
, true);
1169 A moving object that doesn't obey physics
1172 void SV_Physics_Noclip (edict_t
*ent
)
1175 if (!SV_RunThink (ent
))
1178 VectorMA (ent
->v
.angles
, host_frametime
, ent
->v
.avelocity
, ent
->v
.angles
);
1179 VectorMA (ent
->v
.origin
, host_frametime
, ent
->v
.velocity
, ent
->v
.origin
);
1181 SV_LinkEdict (ent
, false);
1185 ==============================================================================
1189 ==============================================================================
1194 SV_CheckWaterTransition
1198 void SV_CheckWaterTransition (edict_t
*ent
)
1204 point
[0] = ent
->v
.origin
[0];
1205 point
[1] = ent
->v
.origin
[1];
1206 point
[2] = ent
->v
.origin
[2] + ent
->v
.mins
[2] + 1;
1207 cont
= SV_PointContents (point
);
1209 cont
= SV_PointContents (ent
->v
.origin
);
1211 if (!ent
->v
.watertype
)
1212 { // just spawned here
1213 ent
->v
.watertype
= cont
;
1214 ent
->v
.waterlevel
= 1;
1218 if (cont
<= CONTENTS_WATER
)
1220 if (ent
->v
.watertype
== CONTENTS_EMPTY
)
1221 { // just crossed into water
1222 SV_StartSound (ent
, 0, "misc/h2ohit1.wav", 255, 1);
1224 ent
->v
.watertype
= cont
;
1225 ent
->v
.waterlevel
= 1;
1229 if (ent
->v
.watertype
!= CONTENTS_EMPTY
)
1230 { // just crossed into water
1231 SV_StartSound (ent
, 0, "misc/h2ohit1.wav", 255, 1);
1233 ent
->v
.watertype
= CONTENTS_EMPTY
;
1234 ent
->v
.waterlevel
= cont
;
1242 Toss, bounce, and fly movement. When onground, do nothing.
1245 void SV_Physics_Toss (edict_t
*ent
)
1251 edict_t
*groundentity
;
1253 groundentity
= PROG_TO_EDICT(ent
->v
.groundentity
);
1254 if ((int)groundentity
->v
.flags
& FL_CONVEYOR
)
1255 VectorScale(groundentity
->v
.movedir
, groundentity
->v
.speed
, ent
->v
.basevelocity
);
1257 VectorCopy(vec_origin
, ent
->v
.basevelocity
);
1258 SV_CheckWater (ent
);
1261 if (!SV_RunThink (ent
))
1265 if (ent
->v
.velocity
[2] > 0)
1266 ent
->v
.flags
= (int)ent
->v
.flags
& ~FL_ONGROUND
;
1268 if ( ((int)ent
->v
.flags
& FL_ONGROUND
) )
1270 if (VectorCompare(ent
->v
.basevelocity
, vec_origin
))
1273 SV_CheckVelocity (ent
);
1276 if (! ((int)ent
->v
.flags
& FL_ONGROUND
)
1277 && ent
->v
.movetype
!= MOVETYPE_FLY
1278 && ent
->v
.movetype
!= MOVETYPE_BOUNCEMISSILE
1279 && ent
->v
.movetype
!= MOVETYPE_FLYMISSILE
)
1280 SV_AddGravity (ent
);
1283 // if onground, return without moving
1284 if ( ((int)ent
->v
.flags
& FL_ONGROUND
) )
1287 SV_CheckVelocity (ent
);
1290 if (ent
->v
.movetype
!= MOVETYPE_FLY
1291 && ent
->v
.movetype
!= MOVETYPE_FLYMISSILE
)
1292 SV_AddGravity (ent
);
1296 VectorMA (ent
->v
.angles
, host_frametime
, ent
->v
.avelocity
, ent
->v
.angles
);
1300 VectorAdd (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1302 VectorScale (ent
->v
.velocity
, host_frametime
, move
);
1303 trace
= SV_PushEntity (ent
, move
);
1305 VectorSubtract (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1307 if (trace
.fraction
== 1)
1312 if (ent
->v
.movetype
== MOVETYPE_BOUNCE
)
1315 else if (ent
->v
.movetype
== MOVETYPE_BOUNCEMISSILE
)
1321 ClipVelocity (ent
->v
.velocity
, trace
.plane
.normal
, ent
->v
.velocity
, backoff
);
1323 // stop if on ground
1324 if (trace
.plane
.normal
[2] > 0.7)
1327 if (ent
->v
.velocity
[2] < 60 || (ent
->v
.movetype
!= MOVETYPE_BOUNCE
&& ent
->v
.movetype
!= MOVETYPE_BOUNCEMISSILE
))
1329 if (ent
->v
.velocity
[2] < 60 || ent
->v
.movetype
!= MOVETYPE_BOUNCE
)
1332 ent
->v
.flags
= (int)ent
->v
.flags
| FL_ONGROUND
;
1333 ent
->v
.groundentity
= EDICT_TO_PROG(trace
.ent
);
1334 VectorCopy (vec3_origin
, ent
->v
.velocity
);
1335 VectorCopy (vec3_origin
, ent
->v
.avelocity
);
1339 // check for in water
1340 SV_CheckWaterTransition (ent
);
1344 ===============================================================================
1348 ===============================================================================
1355 Monsters freefall when they don't have a ground entity, otherwise
1356 all movement is done with discrete steps.
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.
1363 void SV_Physics_Step (edict_t
*ent
)
1365 qboolean wasonground
;
1367 qboolean hitsound
= false;
1369 float speed
, newspeed
, control
;
1371 edict_t
*groundentity
;
1373 groundentity
= PROG_TO_EDICT(ent
->v
.groundentity
);
1374 if ((int)groundentity
->v
.flags
& FL_CONVEYOR
)
1375 VectorScale(groundentity
->v
.movedir
, groundentity
->v
.speed
, ent
->v
.basevelocity
);
1377 VectorCopy(vec_origin
, ent
->v
.basevelocity
);
1379 pr_global_struct
->time
= sv
.time
;
1380 pr_global_struct
->self
= EDICT_TO_PROG(ent
);
1383 SV_CheckVelocity (ent
);
1385 wasonground
= (int)ent
->v
.flags
& FL_ONGROUND
;
1386 // ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1388 // add gravity except:
1390 // swimming monsters who are in the water
1391 inwater
= SV_CheckWater(ent
);
1393 if (!((int)ent
->v
.flags
& FL_FLY
))
1394 if (!(((int)ent
->v
.flags
& FL_SWIM
) && (ent
->v
.waterlevel
> 0)))
1396 if (ent
->v
.velocity
[2] < sv_gravity
.value
*-0.1)
1399 SV_AddGravity (ent
);
1402 if (!VectorCompare(ent
->v
.velocity
, vec_origin
) || !VectorCompare(ent
->v
.basevelocity
, vec_origin
))
1404 ent
->v
.flags
= (int)ent
->v
.flags
& ~FL_ONGROUND
;
1406 // let dead monsters who aren't completely onground slide
1408 if (!(ent
->v
.health
<= 0.0 && !SV_CheckBottom(ent
)))
1410 vel
= ent
->v
.velocity
;
1411 speed
= sqrt(vel
[0]*vel
[0] +vel
[1]*vel
[1]);
1414 friction
= sv_friction
.value
;
1416 control
= speed
< sv_stopspeed
.value
? sv_stopspeed
.value
: speed
;
1417 newspeed
= speed
- host_frametime
*control
*friction
;
1423 vel
[0] = vel
[0] * newspeed
;
1424 vel
[1] = vel
[1] * newspeed
;
1428 VectorAdd (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1429 SV_FlyMove (ent
, host_frametime
, NULL
);
1430 VectorSubtract (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1432 // determine if it's on solid ground at all
1434 vec3_t mins
, maxs
, point
;
1437 VectorAdd (ent
->v
.origin
, ent
->v
.mins
, mins
);
1438 VectorAdd (ent
->v
.origin
, ent
->v
.maxs
, maxs
);
1440 point
[2] = mins
[2] - 1;
1441 for (x
=0 ; x
<=1 ; x
++)
1442 for (y
=0 ; y
<=1 ; y
++)
1444 point
[0] = x
? maxs
[0] : mins
[0];
1445 point
[1] = y
? maxs
[1] : mins
[1];
1446 if (SV_PointContents (point
) == CONTENTS_SOLID
)
1448 ent
->v
.flags
= (int)ent
->v
.flags
| FL_ONGROUND
;
1455 SV_LinkEdict (ent
, true);
1457 if ((int)ent
->v
.flags
& FL_ONGROUND
)
1460 SV_StartSound (ent
, 0, "demon/dland2.wav", 255, 1);
1465 SV_CheckWaterTransition (ent
);
1468 void SV_Physics_Step (edict_t
*ent
)
1472 // freefall if not onground
1473 if ( ! ((int)ent
->v
.flags
& (FL_ONGROUND
| FL_FLY
| FL_SWIM
) ) )
1475 if (ent
->v
.velocity
[2] < sv_gravity
.value
*-0.1)
1480 SV_AddGravity (ent
);
1481 SV_CheckVelocity (ent
);
1482 SV_FlyMove (ent
, host_frametime
, NULL
);
1483 SV_LinkEdict (ent
, true);
1485 if ( (int)ent
->v
.flags
& FL_ONGROUND
) // just hit ground
1488 SV_StartSound (ent
, 0, "demon/dland2.wav", 255, 1);
1495 SV_CheckWaterTransition (ent
);
1499 //============================================================================
1507 void SV_Physics (void)
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
);
1518 //SV_CheckAllEnts ();
1521 // treat each object in turn
1524 for (i
=0 ; i
<sv
.num_edicts
; i
++, ent
= NEXT_EDICT(ent
))
1529 if (pr_global_struct
->force_retouch
)
1531 SV_LinkEdict (ent
, true); // force retouch even for stationary
1534 if (i
> 0 && i
<= svs
.maxclients
)
1535 SV_Physics_Client (ent
, i
);
1536 else if (ent
->v
.movetype
== MOVETYPE_PUSH
)
1537 SV_Physics_Pusher (ent
);
1538 else if (ent
->v
.movetype
== MOVETYPE_NONE
)
1539 SV_Physics_None (ent
);
1541 else if (ent
->v
.movetype
== MOVETYPE_FOLLOW
)
1542 SV_Physics_Follow (ent
);
1544 else if (ent
->v
.movetype
== MOVETYPE_NOCLIP
)
1545 SV_Physics_Noclip (ent
);
1546 else if (ent
->v
.movetype
== MOVETYPE_STEP
)
1547 SV_Physics_Step (ent
);
1548 else if (ent
->v
.movetype
== MOVETYPE_TOSS
1549 || ent
->v
.movetype
== MOVETYPE_BOUNCE
1551 || ent
->v
.movetype
== MOVETYPE_BOUNCEMISSILE
1553 || ent
->v
.movetype
== MOVETYPE_FLY
1554 || ent
->v
.movetype
== MOVETYPE_FLYMISSILE
)
1555 SV_Physics_Toss (ent
);
1557 Sys_Error ("SV_Physics: bad movetype %i", (int)ent
->v
.movetype
);
1560 if (pr_global_struct
->force_retouch
)
1561 pr_global_struct
->force_retouch
--;
1563 sv
.time
+= host_frametime
;
1568 trace_t
SV_Trace_Toss (edict_t
*ent
, edict_t
*ignore
)
1570 edict_t tempent
, *tent
;
1574 double save_frametime
;
1575 // extern particle_t *active_particles, *free_particles;
1579 save_frametime
= host_frametime
;
1580 host_frametime
= 0.05;
1582 memcpy(&tempent
, ent
, sizeof(edict_t
));
1587 SV_CheckVelocity (tent
);
1588 SV_AddGravity (tent
);
1589 VectorMA (tent
->v
.angles
, host_frametime
, tent
->v
.avelocity
, tent
->v
.angles
);
1590 VectorScale (tent
->v
.velocity
, host_frametime
, move
);
1591 VectorAdd (tent
->v
.origin
, move
, end
);
1592 trace
= SV_Move (tent
->v
.origin
, tent
->v
.mins
, tent
->v
.maxs
, end
, MOVE_NORMAL
, tent
);
1593 VectorCopy (trace
.endpos
, tent
->v
.origin
);
1595 // p = free_particles;
1598 // free_particles = p->next;
1599 // p->next = active_particles;
1600 // active_particles = p;
1604 // p->type = pt_static;
1605 // VectorCopy (vec3_origin, p->vel);
1606 // VectorCopy (tent->v.origin, p->org);
1610 if (trace
.ent
!= ignore
)
1614 host_frametime
= save_frametime
;