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
)
100 if (IS_NAN(ent
->v
.velocity
[i
]))
102 Con_Printf ("Got a NaN velocity on %s\n", pr_strings
+ ent
->v
.classname
);
103 ent
->v
.velocity
[i
] = 0;
105 if (IS_NAN(ent
->v
.origin
[i
]))
107 Con_Printf ("Got a NaN origin on %s\n", pr_strings
+ ent
->v
.classname
);
108 ent
->v
.origin
[i
] = 0;
111 if (ent->v.velocity[i] > sv_maxvelocity.value)
112 ent->v.velocity[i] = sv_maxvelocity.value;
113 else if (ent->v.velocity[i] < -sv_maxvelocity.value)
114 ent->v.velocity[i] = -sv_maxvelocity.value;
118 wishspeed
= Length(ent
->v
.velocity
);
119 if (wishspeed
> sv_maxvelocity
.value
)
121 VectorScale (ent
->v
.velocity
, sv_maxvelocity
.value
/wishspeed
, ent
->v
.velocity
);
122 wishspeed
= sv_maxvelocity
.value
;
130 Runs thinking code if time. There is some play in the exact time the think
131 function will be called, because it is called before any movement is done
132 in a frame. Not used for pushmove objects, because they must be exact.
133 Returns false if the entity removed itself.
136 qboolean
SV_RunThink (edict_t
*ent
)
140 thinktime
= ent
->v
.nextthink
;
141 if (thinktime
<= 0 || thinktime
> sv
.time
+ host_frametime
)
144 if (thinktime
< sv
.time
)
145 thinktime
= sv
.time
; // don't let things stay in the past.
146 // it is possible to start that way
147 // by a trigger with a local time.
148 ent
->v
.nextthink
= 0;
149 pr_global_struct
->time
= thinktime
;
150 pr_global_struct
->self
= EDICT_TO_PROG(ent
);
151 pr_global_struct
->other
= EDICT_TO_PROG(sv
.edicts
);
152 PR_ExecuteProgram (ent
->v
.think
);
160 Two entities have touched, so run their touch functions
163 void SV_Impact (edict_t
*e1
, edict_t
*e2
)
165 int old_self
, old_other
;
167 old_self
= pr_global_struct
->self
;
168 old_other
= pr_global_struct
->other
;
170 pr_global_struct
->time
= sv
.time
;
171 if (e1
->v
.touch
&& e1
->v
.solid
!= SOLID_NOT
)
173 pr_global_struct
->self
= EDICT_TO_PROG(e1
);
174 pr_global_struct
->other
= EDICT_TO_PROG(e2
);
175 PR_ExecuteProgram (e1
->v
.touch
);
178 if (e2
->v
.touch
&& e2
->v
.solid
!= SOLID_NOT
)
180 pr_global_struct
->self
= EDICT_TO_PROG(e2
);
181 pr_global_struct
->other
= EDICT_TO_PROG(e1
);
182 PR_ExecuteProgram (e2
->v
.touch
);
185 pr_global_struct
->self
= old_self
;
186 pr_global_struct
->other
= old_other
;
194 Slide off of the impacting object
195 returns the blocked flags (1 = floor, 2 = step / wall)
198 #define STOP_EPSILON 0.1
200 int ClipVelocity (vec3_t in
, vec3_t normal
, vec3_t out
, float overbounce
)
208 blocked
|= 1; // floor
210 blocked
|= 2; // step
212 backoff
= DotProduct (in
, normal
) * overbounce
;
214 for (i
=0 ; i
<3 ; i
++)
216 change
= normal
[i
]*backoff
;
217 out
[i
] = in
[i
] - change
;
218 if (out
[i
] > -STOP_EPSILON
&& out
[i
] < STOP_EPSILON
)
230 The basic solid body movement clip that slides along multiple planes
231 Returns the clipflags if the velocity was modified (hit something solid)
235 If steptrace is not NULL, the trace of any vertical wall hit will be stored
238 #define MAX_CLIP_PLANES 5
239 int SV_FlyMove (edict_t
*ent
, float time
, trace_t
*steptrace
)
241 int bumpcount
, numbumps
;
245 vec3_t planes
[MAX_CLIP_PLANES
];
246 vec3_t primal_velocity
, original_velocity
, new_velocity
;
256 VectorCopy (ent
->v
.velocity
, original_velocity
);
257 VectorCopy (ent
->v
.velocity
, primal_velocity
);
262 for (bumpcount
=0 ; bumpcount
<numbumps
; bumpcount
++)
264 if (!ent
->v
.velocity
[0] && !ent
->v
.velocity
[1] && !ent
->v
.velocity
[2])
267 for (i
=0 ; i
<3 ; i
++)
268 end
[i
] = ent
->v
.origin
[i
] + time_left
* ent
->v
.velocity
[i
];
270 trace
= SV_Move (ent
->v
.origin
, ent
->v
.mins
, ent
->v
.maxs
, end
, false, ent
);
273 { // entity is trapped in another solid
274 VectorCopy (vec3_origin
, ent
->v
.velocity
);
278 if (trace
.fraction
> 0)
279 { // actually covered some distance
280 VectorCopy (trace
.endpos
, ent
->v
.origin
);
281 VectorCopy (ent
->v
.velocity
, original_velocity
);
285 if (trace
.fraction
== 1)
286 break; // moved the entire distance
289 Sys_Error ("SV_FlyMove: !trace.ent");
291 if (trace
.plane
.normal
[2] > 0.7)
293 blocked
|= 1; // floor
294 if (trace
.ent
->v
.solid
== SOLID_BSP
)
296 ent
->v
.flags
= (int)ent
->v
.flags
| FL_ONGROUND
;
297 ent
->v
.groundentity
= EDICT_TO_PROG(trace
.ent
);
300 if (!trace
.plane
.normal
[2])
302 blocked
|= 2; // step
304 *steptrace
= trace
; // save for player extrafriction
308 // run the impact function
310 SV_Impact (ent
, trace
.ent
);
312 break; // removed by the impact function
315 time_left
-= time_left
* trace
.fraction
;
317 // cliped to another plane
318 if (numplanes
>= MAX_CLIP_PLANES
)
319 { // this shouldn't really happen
320 VectorCopy (vec3_origin
, ent
->v
.velocity
);
324 VectorCopy (trace
.plane
.normal
, planes
[numplanes
]);
328 // modify original_velocity so it parallels all of the clip planes
330 for (i
=0 ; i
<numplanes
; i
++)
332 ClipVelocity (original_velocity
, planes
[i
], new_velocity
, 1);
333 for (j
=0 ; j
<numplanes
; j
++)
336 if (DotProduct (new_velocity
, planes
[j
]) < 0)
344 { // go along this plane
345 VectorCopy (new_velocity
, ent
->v
.velocity
);
348 { // go along the crease
351 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
352 VectorCopy (vec3_origin
, ent
->v
.velocity
);
355 CrossProduct (planes
[0], planes
[1], dir
);
356 d
= DotProduct (dir
, ent
->v
.velocity
);
357 VectorScale (dir
, d
, ent
->v
.velocity
);
361 // if original velocity is against the original velocity, stop dead
362 // to avoid tiny occilations in sloping corners
364 if (DotProduct (ent
->v
.velocity
, primal_velocity
) <= 0)
366 VectorCopy (vec3_origin
, ent
->v
.velocity
);
381 void SV_AddGravity (edict_t
*ent
)
387 ent_gravity
= ent
->v
.gravity
;
393 val
= GetEdictFieldValue(ent
, "gravity");
394 if (val
&& val
->_float
)
395 ent_gravity
= val
->_float
;
399 ent
->v
.velocity
[2] -= ent_gravity
* sv_gravity
.value
* host_frametime
;
404 ===============================================================================
408 ===============================================================================
415 Does not change the entities velocity at all
418 trace_t
SV_PushEntity (edict_t
*ent
, vec3_t push
)
423 VectorAdd (ent
->v
.origin
, push
, end
);
425 if (ent
->v
.movetype
== MOVETYPE_FLYMISSILE
)
426 trace
= SV_Move (ent
->v
.origin
, ent
->v
.mins
, ent
->v
.maxs
, end
, MOVE_MISSILE
, ent
);
427 else if (ent
->v
.solid
== SOLID_TRIGGER
|| ent
->v
.solid
== SOLID_NOT
)
428 // only clip against bmodels
429 trace
= SV_Move (ent
->v
.origin
, ent
->v
.mins
, ent
->v
.maxs
, end
, MOVE_NOMONSTERS
, ent
);
431 trace
= SV_Move (ent
->v
.origin
, ent
->v
.mins
, ent
->v
.maxs
, end
, MOVE_NORMAL
, ent
);
433 VectorCopy (trace
.endpos
, ent
->v
.origin
);
434 SV_LinkEdict (ent
, true);
437 SV_Impact (ent
, trace
.ent
);
449 void SV_PushMove (edict_t
*pusher
, float movetime
)
452 edict_t
*check
, *block
;
453 vec3_t mins
, maxs
, move
;
454 vec3_t entorig
, pushorig
;
456 edict_t
*moved_edict
[MAX_EDICTS
];
457 vec3_t moved_from
[MAX_EDICTS
];
459 if (!pusher
->v
.velocity
[0] && !pusher
->v
.velocity
[1] && !pusher
->v
.velocity
[2])
461 pusher
->v
.ltime
+= movetime
;
465 for (i
=0 ; i
<3 ; i
++)
467 move
[i
] = pusher
->v
.velocity
[i
] * movetime
;
468 mins
[i
] = pusher
->v
.absmin
[i
] + move
[i
];
469 maxs
[i
] = pusher
->v
.absmax
[i
] + move
[i
];
472 VectorCopy (pusher
->v
.origin
, pushorig
);
474 // move the pusher to it's final position
476 VectorAdd (pusher
->v
.origin
, move
, pusher
->v
.origin
);
477 pusher
->v
.ltime
+= movetime
;
478 SV_LinkEdict (pusher
, false);
481 // see if any solid entities are inside the final position
483 check
= NEXT_EDICT(sv
.edicts
);
484 for (e
=1 ; e
<sv
.num_edicts
; e
++, check
= NEXT_EDICT(check
))
488 if (check
->v
.movetype
== MOVETYPE_PUSH
489 || check
->v
.movetype
== MOVETYPE_NONE
491 || check
->v
.movetype
== MOVETYPE_FOLLOW
493 || check
->v
.movetype
== MOVETYPE_NOCLIP
)
496 // if the entity is standing on the pusher, it will definately be moved
497 if ( ! ( ((int)check
->v
.flags
& FL_ONGROUND
)
498 && PROG_TO_EDICT(check
->v
.groundentity
) == pusher
) )
500 if ( check
->v
.absmin
[0] >= maxs
[0]
501 || check
->v
.absmin
[1] >= maxs
[1]
502 || check
->v
.absmin
[2] >= maxs
[2]
503 || check
->v
.absmax
[0] <= mins
[0]
504 || check
->v
.absmax
[1] <= mins
[1]
505 || check
->v
.absmax
[2] <= mins
[2] )
508 // see if the ent's bbox is inside the pusher's final position
509 if (!SV_TestEntityPosition (check
))
513 // remove the onground flag for non-players
514 if (check
->v
.movetype
!= MOVETYPE_WALK
)
515 check
->v
.flags
= (int)check
->v
.flags
& ~FL_ONGROUND
;
517 VectorCopy (check
->v
.origin
, entorig
);
518 VectorCopy (check
->v
.origin
, moved_from
[num_moved
]);
519 moved_edict
[num_moved
] = check
;
522 // try moving the contacted entity
523 pusher
->v
.solid
= SOLID_NOT
;
524 SV_PushEntity (check
, move
);
525 pusher
->v
.solid
= SOLID_BSP
;
527 // if it is still inside the pusher, block
528 block
= SV_TestEntityPosition (check
);
531 if (check
->v
.mins
[0] == check
->v
.maxs
[0])
533 if (check
->v
.solid
== SOLID_NOT
|| check
->v
.solid
== SOLID_TRIGGER
)
535 check
->v
.mins
[0] = check
->v
.mins
[1] = 0;
536 VectorCopy (check
->v
.mins
, check
->v
.maxs
);
540 VectorCopy (entorig
, check
->v
.origin
);
541 SV_LinkEdict (check
, true);
543 VectorCopy (pushorig
, pusher
->v
.origin
);
544 SV_LinkEdict (pusher
, false);
545 pusher
->v
.ltime
-= movetime
;
547 // if the pusher has a "blocked" function, call it
548 // otherwise, just stay in place until the obstacle is gone
549 if (pusher
->v
.blocked
)
551 pr_global_struct
->self
= EDICT_TO_PROG(pusher
);
552 pr_global_struct
->other
= EDICT_TO_PROG(check
);
553 PR_ExecuteProgram (pusher
->v
.blocked
);
556 // move back any entities we already moved
557 for (i
=0 ; i
<num_moved
; i
++)
559 VectorCopy (moved_from
[i
], moved_edict
[i
]->v
.origin
);
560 SV_LinkEdict (moved_edict
[i
], false);
576 void SV_PushRotate (edict_t
*pusher
, float movetime
)
579 edict_t
*check
, *block
;
580 vec3_t move
, a
, amove
;
581 vec3_t entorig
, pushorig
;
583 edict_t
*moved_edict
[MAX_EDICTS
];
584 vec3_t moved_from
[MAX_EDICTS
];
586 vec3_t forward
, right
, up
;
588 if (!pusher
->v
.avelocity
[0] && !pusher
->v
.avelocity
[1] && !pusher
->v
.avelocity
[2])
590 pusher
->v
.ltime
+= movetime
;
594 for (i
=0 ; i
<3 ; i
++)
595 amove
[i
] = pusher
->v
.avelocity
[i
] * movetime
;
597 VectorSubtract (vec3_origin
, amove
, a
);
598 AngleVectors (a
, forward
, right
, up
);
600 VectorCopy (pusher
->v
.angles
, pushorig
);
602 // move the pusher to it's final position
604 VectorAdd (pusher
->v
.angles
, amove
, pusher
->v
.angles
);
605 pusher
->v
.ltime
+= movetime
;
606 SV_LinkEdict (pusher
, false);
609 // see if any solid entities are inside the final position
611 check
= NEXT_EDICT(sv
.edicts
);
612 for (e
=1 ; e
<sv
.num_edicts
; e
++, check
= NEXT_EDICT(check
))
616 if (check
->v
.movetype
== MOVETYPE_PUSH
617 || check
->v
.movetype
== MOVETYPE_NONE
618 || check
->v
.movetype
== MOVETYPE_FOLLOW
619 || check
->v
.movetype
== MOVETYPE_NOCLIP
)
622 // if the entity is standing on the pusher, it will definately be moved
623 if ( ! ( ((int)check
->v
.flags
& FL_ONGROUND
)
624 && PROG_TO_EDICT(check
->v
.groundentity
) == pusher
) )
626 if ( check
->v
.absmin
[0] >= pusher
->v
.absmax
[0]
627 || check
->v
.absmin
[1] >= pusher
->v
.absmax
[1]
628 || check
->v
.absmin
[2] >= pusher
->v
.absmax
[2]
629 || check
->v
.absmax
[0] <= pusher
->v
.absmin
[0]
630 || check
->v
.absmax
[1] <= pusher
->v
.absmin
[1]
631 || check
->v
.absmax
[2] <= pusher
->v
.absmin
[2] )
634 // see if the ent's bbox is inside the pusher's final position
635 if (!SV_TestEntityPosition (check
))
639 // remove the onground flag for non-players
640 if (check
->v
.movetype
!= MOVETYPE_WALK
)
641 check
->v
.flags
= (int)check
->v
.flags
& ~FL_ONGROUND
;
643 VectorCopy (check
->v
.origin
, entorig
);
644 VectorCopy (check
->v
.origin
, moved_from
[num_moved
]);
645 moved_edict
[num_moved
] = check
;
648 // calculate destination position
649 VectorSubtract (check
->v
.origin
, pusher
->v
.origin
, org
);
650 org2
[0] = DotProduct (org
, forward
);
651 org2
[1] = -DotProduct (org
, right
);
652 org2
[2] = DotProduct (org
, up
);
653 VectorSubtract (org2
, org
, move
);
655 // try moving the contacted entity
656 pusher
->v
.solid
= SOLID_NOT
;
657 SV_PushEntity (check
, move
);
658 pusher
->v
.solid
= SOLID_BSP
;
660 // if it is still inside the pusher, block
661 block
= SV_TestEntityPosition (check
);
664 if (check
->v
.mins
[0] == check
->v
.maxs
[0])
666 if (check
->v
.solid
== SOLID_NOT
|| check
->v
.solid
== SOLID_TRIGGER
)
668 check
->v
.mins
[0] = check
->v
.mins
[1] = 0;
669 VectorCopy (check
->v
.mins
, check
->v
.maxs
);
673 VectorCopy (entorig
, check
->v
.origin
);
674 SV_LinkEdict (check
, true);
676 VectorCopy (pushorig
, pusher
->v
.angles
);
677 SV_LinkEdict (pusher
, false);
678 pusher
->v
.ltime
-= movetime
;
680 // if the pusher has a "blocked" function, call it
681 // otherwise, just stay in place until the obstacle is gone
682 if (pusher
->v
.blocked
)
684 pr_global_struct
->self
= EDICT_TO_PROG(pusher
);
685 pr_global_struct
->other
= EDICT_TO_PROG(check
);
686 PR_ExecuteProgram (pusher
->v
.blocked
);
689 // move back any entities we already moved
690 for (i
=0 ; i
<num_moved
; i
++)
692 VectorCopy (moved_from
[i
], moved_edict
[i
]->v
.origin
);
693 VectorSubtract (moved_edict
[i
]->v
.angles
, amove
, moved_edict
[i
]->v
.angles
);
694 SV_LinkEdict (moved_edict
[i
], false);
700 VectorAdd (check
->v
.angles
, amove
, check
->v
.angles
);
714 void SV_Physics_Pusher (edict_t
*ent
)
720 oldltime
= ent
->v
.ltime
;
722 thinktime
= ent
->v
.nextthink
;
723 if (thinktime
< ent
->v
.ltime
+ host_frametime
)
725 movetime
= thinktime
- ent
->v
.ltime
;
730 movetime
= host_frametime
;
735 if (ent
->v
.avelocity
[0] || ent
->v
.avelocity
[1] || ent
->v
.avelocity
[2])
736 SV_PushRotate (ent
, movetime
);
739 SV_PushMove (ent
, movetime
); // advances ent->v.ltime if not blocked
742 if (thinktime
> oldltime
&& thinktime
<= ent
->v
.ltime
)
744 ent
->v
.nextthink
= 0;
745 pr_global_struct
->time
= sv
.time
;
746 pr_global_struct
->self
= EDICT_TO_PROG(ent
);
747 pr_global_struct
->other
= EDICT_TO_PROG(sv
.edicts
);
748 PR_ExecuteProgram (ent
->v
.think
);
757 ===============================================================================
761 ===============================================================================
768 This is a big hack to try and fix the rare case of getting stuck in the world
772 void SV_CheckStuck (edict_t
*ent
)
778 if (!SV_TestEntityPosition(ent
))
780 VectorCopy (ent
->v
.origin
, ent
->v
.oldorigin
);
784 VectorCopy (ent
->v
.origin
, org
);
785 VectorCopy (ent
->v
.oldorigin
, ent
->v
.origin
);
786 if (!SV_TestEntityPosition(ent
))
788 Con_DPrintf ("Unstuck.\n");
789 SV_LinkEdict (ent
, true);
793 for (z
=0 ; z
< 18 ; z
++)
794 for (i
=-1 ; i
<= 1 ; i
++)
795 for (j
=-1 ; j
<= 1 ; j
++)
797 ent
->v
.origin
[0] = org
[0] + i
;
798 ent
->v
.origin
[1] = org
[1] + j
;
799 ent
->v
.origin
[2] = org
[2] + z
;
800 if (!SV_TestEntityPosition(ent
))
802 Con_DPrintf ("Unstuck.\n");
803 SV_LinkEdict (ent
, true);
808 VectorCopy (org
, ent
->v
.origin
);
809 Con_DPrintf ("player is stuck.\n");
818 qboolean
SV_CheckWater (edict_t
*ent
)
826 point
[0] = ent
->v
.origin
[0];
827 point
[1] = ent
->v
.origin
[1];
828 point
[2] = ent
->v
.origin
[2] + ent
->v
.mins
[2] + 1;
830 ent
->v
.waterlevel
= 0;
831 ent
->v
.watertype
= CONTENTS_EMPTY
;
832 cont
= SV_PointContents (point
);
833 if (cont
<= CONTENTS_WATER
)
836 truecont
= SV_TruePointContents (point
);
838 ent
->v
.watertype
= cont
;
839 ent
->v
.waterlevel
= 1;
840 point
[2] = ent
->v
.origin
[2] + (ent
->v
.mins
[2] + ent
->v
.maxs
[2])*0.5;
841 cont
= SV_PointContents (point
);
842 if (cont
<= CONTENTS_WATER
)
844 ent
->v
.waterlevel
= 2;
845 point
[2] = ent
->v
.origin
[2] + ent
->v
.view_ofs
[2];
846 cont
= SV_PointContents (point
);
847 if (cont
<= CONTENTS_WATER
)
848 ent
->v
.waterlevel
= 3;
851 if (truecont
<= CONTENTS_CURRENT_0
&& truecont
>= CONTENTS_CURRENT_DOWN
)
853 static vec3_t current_table
[] =
863 VectorMA (ent
->v
.basevelocity
, 150.0*ent
->v
.waterlevel
/3.0, current_table
[CONTENTS_CURRENT_0
- truecont
], ent
->v
.basevelocity
);
868 return ent
->v
.waterlevel
> 1;
877 void SV_WallFriction (edict_t
*ent
, trace_t
*trace
)
879 vec3_t forward
, right
, up
;
883 AngleVectors (ent
->v
.v_angle
, forward
, right
, up
);
884 d
= DotProduct (trace
->plane
.normal
, forward
);
890 // cut the tangential velocity
891 i
= DotProduct (trace
->plane
.normal
, ent
->v
.velocity
);
892 VectorScale (trace
->plane
.normal
, i
, into
);
893 VectorSubtract (ent
->v
.velocity
, into
, side
);
895 ent
->v
.velocity
[0] = side
[0] * (1 + d
);
896 ent
->v
.velocity
[1] = side
[1] * (1 + d
);
900 =====================
903 Player has come to a dead stop, possibly due to the problem with limited
904 float precision at some angle joins in the BSP hull.
906 Try fixing by pushing one pixel in each direction.
908 This is a hack, but in the interest of good gameplay...
909 ======================
911 int SV_TryUnstick (edict_t
*ent
, vec3_t oldvel
)
919 VectorCopy (ent
->v
.origin
, oldorg
);
920 VectorCopy (vec3_origin
, dir
);
922 for (i
=0 ; i
<8 ; i
++)
924 // try pushing a little in an axial direction
927 case 0: dir
[0] = 2; dir
[1] = 0; break;
928 case 1: dir
[0] = 0; dir
[1] = 2; break;
929 case 2: dir
[0] = -2; dir
[1] = 0; break;
930 case 3: dir
[0] = 0; dir
[1] = -2; break;
931 case 4: dir
[0] = 2; dir
[1] = 2; break;
932 case 5: dir
[0] = -2; dir
[1] = 2; break;
933 case 6: dir
[0] = 2; dir
[1] = -2; break;
934 case 7: dir
[0] = -2; dir
[1] = -2; break;
937 SV_PushEntity (ent
, dir
);
939 // retry the original move
940 ent
->v
.velocity
[0] = oldvel
[0];
941 ent
->v
. velocity
[1] = oldvel
[1];
942 ent
->v
. velocity
[2] = 0;
943 clip
= SV_FlyMove (ent
, 0.1, &steptrace
);
945 if ( fabsf(oldorg
[1] - ent
->v
.origin
[1]) > 4
946 || fabsf(oldorg
[0] - ent
->v
.origin
[0]) > 4 )
948 //Con_DPrintf ("unstuck!\n");
952 // go back to the original pos and try again
953 VectorCopy (oldorg
, ent
->v
.origin
);
956 VectorCopy (vec3_origin
, ent
->v
.velocity
);
957 return 7; // still not moving
961 =====================
965 ======================
968 void SV_WalkMove (edict_t
*ent
)
970 vec3_t upmove
, downmove
;
971 vec3_t oldorg
, oldvel
;
972 vec3_t nosteporg
, nostepvel
;
975 trace_t steptrace
, downtrace
;
978 // do a regular slide move unless it looks like you ran into a step
980 oldonground
= (int)ent
->v
.flags
& FL_ONGROUND
;
981 ent
->v
.flags
= (int)ent
->v
.flags
& ~FL_ONGROUND
;
983 VectorCopy (ent
->v
.origin
, oldorg
);
984 VectorCopy (ent
->v
.velocity
, oldvel
);
986 clip
= SV_FlyMove (ent
, host_frametime
, &steptrace
);
989 return; // move didn't block on a step
991 if (!oldonground
&& ent
->v
.waterlevel
== 0)
992 return; // don't stair up while jumping
994 if (ent
->v
.movetype
!= MOVETYPE_WALK
)
995 return; // gibbed by a trigger
1000 if ( (int)sv_player
->v
.flags
& FL_WATERJUMP
)
1003 VectorCopy (ent
->v
.origin
, nosteporg
);
1004 VectorCopy (ent
->v
.velocity
, nostepvel
);
1007 // try moving up and forward to go up a step
1009 VectorCopy (oldorg
, ent
->v
.origin
); // back to start pos
1011 VectorCopy (vec3_origin
, upmove
);
1012 VectorCopy (vec3_origin
, downmove
);
1013 upmove
[2] = STEPSIZE
;
1014 downmove
[2] = -STEPSIZE
+ oldvel
[2]*host_frametime
;
1017 SV_PushEntity (ent
, upmove
); // FIXME: don't link?
1020 ent
->v
.velocity
[0] = oldvel
[0];
1021 ent
->v
. velocity
[1] = oldvel
[1];
1022 ent
->v
. velocity
[2] = 0;
1023 clip
= SV_FlyMove (ent
, host_frametime
, &steptrace
);
1025 // check for stuckness, possibly due to the limited precision of floats
1026 // in the clipping hulls
1029 if ( fabsf(oldorg
[1] - ent
->v
.origin
[1]) < 0.03125
1030 && fabsf(oldorg
[0] - ent
->v
.origin
[0]) < 0.03125 )
1031 { // stepping up didn't make any progress
1032 clip
= SV_TryUnstick (ent
, oldvel
);
1036 // extra friction based on view angle
1038 SV_WallFriction (ent
, &steptrace
);
1041 downtrace
= SV_PushEntity (ent
, downmove
); // FIXME: don't link?
1043 if (downtrace
.plane
.normal
[2] > 0.7)
1045 if (ent
->v
.solid
== SOLID_BSP
)
1047 ent
->v
.flags
= (int)ent
->v
.flags
| FL_ONGROUND
;
1048 ent
->v
.groundentity
= EDICT_TO_PROG(downtrace
.ent
);
1053 // if the push down didn't end up on good ground, use the move without
1054 // the step up. This happens near wall / slope combinations, and can
1055 // cause the player to hop up higher on a slope too steep to climb
1056 VectorCopy (nosteporg
, ent
->v
.origin
);
1057 VectorCopy (nostepvel
, ent
->v
.velocity
);
1066 Player character actions
1069 void SV_Physics_Client (edict_t
*ent
, int num
)
1071 if ( ! svs
.clients
[num
-1].active
)
1072 return; // unconnected slot
1075 // call standard client pre-think
1077 pr_global_struct
->time
= sv
.time
;
1078 pr_global_struct
->self
= EDICT_TO_PROG(ent
);
1079 PR_ExecuteProgram (pr_global_struct
->PlayerPreThink
);
1084 SV_CheckVelocity (ent
);
1087 // decide which move function to call
1089 switch ((int)ent
->v
.movetype
)
1092 if (!SV_RunThink (ent
))
1097 if (!SV_RunThink (ent
))
1099 if (!SV_CheckWater (ent
) && ! ((int)ent
->v
.flags
& FL_WATERJUMP
) )
1100 SV_AddGravity (ent
);
1101 SV_CheckStuck (ent
);
1103 VectorAdd (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1108 VectorSubtract (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1113 case MOVETYPE_BOUNCE
:
1114 SV_Physics_Toss (ent
);
1118 if (!SV_RunThink (ent
))
1120 SV_FlyMove (ent
, host_frametime
, NULL
);
1123 case MOVETYPE_NOCLIP
:
1124 if (!SV_RunThink (ent
))
1126 VectorMA (ent
->v
.origin
, host_frametime
, ent
->v
.velocity
, ent
->v
.origin
);
1130 Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent
->v
.movetype
);
1134 // call standard player post-think
1136 SV_LinkEdict (ent
, true);
1138 pr_global_struct
->time
= sv
.time
;
1139 pr_global_struct
->self
= EDICT_TO_PROG(ent
);
1140 PR_ExecuteProgram (pr_global_struct
->PlayerPostThink
);
1143 //============================================================================
1149 Non moving objects can only think
1152 void SV_Physics_None (edict_t
*ent
)
1163 Entities that are "stuck" to another entity
1166 void SV_Physics_Follow (edict_t
*ent
)
1170 VectorAdd (PROG_TO_EDICT(ent
->v
.aiment
)->v
.origin
, ent
->v
.v_angle
, ent
->v
.origin
);
1171 SV_LinkEdict (ent
, true);
1179 A moving object that doesn't obey physics
1182 void SV_Physics_Noclip (edict_t
*ent
)
1185 if (!SV_RunThink (ent
))
1188 VectorMA (ent
->v
.angles
, host_frametime
, ent
->v
.avelocity
, ent
->v
.angles
);
1189 VectorMA (ent
->v
.origin
, host_frametime
, ent
->v
.velocity
, ent
->v
.origin
);
1191 SV_LinkEdict (ent
, false);
1195 ==============================================================================
1199 ==============================================================================
1204 SV_CheckWaterTransition
1208 void SV_CheckWaterTransition (edict_t
*ent
)
1214 point
[0] = ent
->v
.origin
[0];
1215 point
[1] = ent
->v
.origin
[1];
1216 point
[2] = ent
->v
.origin
[2] + ent
->v
.mins
[2] + 1;
1217 cont
= SV_PointContents (point
);
1219 cont
= SV_PointContents (ent
->v
.origin
);
1221 if (!ent
->v
.watertype
)
1222 { // just spawned here
1223 ent
->v
.watertype
= cont
;
1224 ent
->v
.waterlevel
= 1;
1228 if (cont
<= CONTENTS_WATER
)
1230 if (ent
->v
.watertype
== CONTENTS_EMPTY
)
1231 { // just crossed into water
1232 SV_StartSound (ent
, 0, "misc/h2ohit1.wav", 255, 1);
1234 ent
->v
.watertype
= cont
;
1235 ent
->v
.waterlevel
= 1;
1239 if (ent
->v
.watertype
!= CONTENTS_EMPTY
)
1240 { // just crossed into water
1241 SV_StartSound (ent
, 0, "misc/h2ohit1.wav", 255, 1);
1243 ent
->v
.watertype
= CONTENTS_EMPTY
;
1244 ent
->v
.waterlevel
= cont
;
1252 Toss, bounce, and fly movement. When onground, do nothing.
1255 void SV_Physics_Toss (edict_t
*ent
)
1261 edict_t
*groundentity
;
1263 groundentity
= PROG_TO_EDICT(ent
->v
.groundentity
);
1264 if ((int)groundentity
->v
.flags
& FL_CONVEYOR
)
1265 VectorScale(groundentity
->v
.movedir
, groundentity
->v
.speed
, ent
->v
.basevelocity
);
1267 VectorCopy(vec_origin
, ent
->v
.basevelocity
);
1268 SV_CheckWater (ent
);
1271 if (!SV_RunThink (ent
))
1275 if (ent
->v
.velocity
[2] > 0)
1276 ent
->v
.flags
= (int)ent
->v
.flags
& ~FL_ONGROUND
;
1278 if ( ((int)ent
->v
.flags
& FL_ONGROUND
) )
1280 if (VectorCompare(ent
->v
.basevelocity
, vec_origin
))
1283 SV_CheckVelocity (ent
);
1286 if (! ((int)ent
->v
.flags
& FL_ONGROUND
)
1287 && ent
->v
.movetype
!= MOVETYPE_FLY
1288 && ent
->v
.movetype
!= MOVETYPE_BOUNCEMISSILE
1289 && ent
->v
.movetype
!= MOVETYPE_FLYMISSILE
)
1290 SV_AddGravity (ent
);
1293 // if onground, return without moving
1294 if ( ((int)ent
->v
.flags
& FL_ONGROUND
) )
1297 SV_CheckVelocity (ent
);
1300 if (ent
->v
.movetype
!= MOVETYPE_FLY
1301 && ent
->v
.movetype
!= MOVETYPE_FLYMISSILE
)
1302 SV_AddGravity (ent
);
1306 VectorMA (ent
->v
.angles
, host_frametime
, ent
->v
.avelocity
, ent
->v
.angles
);
1310 VectorAdd (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1312 VectorScale (ent
->v
.velocity
, host_frametime
, move
);
1313 trace
= SV_PushEntity (ent
, move
);
1315 VectorSubtract (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1317 if (trace
.fraction
== 1)
1322 if (ent
->v
.movetype
== MOVETYPE_BOUNCE
)
1325 else if (ent
->v
.movetype
== MOVETYPE_BOUNCEMISSILE
)
1331 ClipVelocity (ent
->v
.velocity
, trace
.plane
.normal
, ent
->v
.velocity
, backoff
);
1333 // stop if on ground
1334 if (trace
.plane
.normal
[2] > 0.7)
1337 if (ent
->v
.velocity
[2] < 60 || (ent
->v
.movetype
!= MOVETYPE_BOUNCE
&& ent
->v
.movetype
!= MOVETYPE_BOUNCEMISSILE
))
1339 if (ent
->v
.velocity
[2] < 60 || ent
->v
.movetype
!= MOVETYPE_BOUNCE
)
1342 ent
->v
.flags
= (int)ent
->v
.flags
| FL_ONGROUND
;
1343 ent
->v
.groundentity
= EDICT_TO_PROG(trace
.ent
);
1344 VectorCopy (vec3_origin
, ent
->v
.velocity
);
1345 VectorCopy (vec3_origin
, ent
->v
.avelocity
);
1349 // check for in water
1350 SV_CheckWaterTransition (ent
);
1354 ===============================================================================
1358 ===============================================================================
1365 Monsters freefall when they don't have a ground entity, otherwise
1366 all movement is done with discrete steps.
1368 This is also used for objects that have become still on the ground, but
1369 will fall if the floor is pulled out from under them.
1373 void SV_Physics_Step (edict_t
*ent
)
1375 qboolean wasonground
;
1377 qboolean hitsound
= false;
1379 float speed
, newspeed
, control
;
1381 edict_t
*groundentity
;
1383 groundentity
= PROG_TO_EDICT(ent
->v
.groundentity
);
1384 if ((int)groundentity
->v
.flags
& FL_CONVEYOR
)
1385 VectorScale(groundentity
->v
.movedir
, groundentity
->v
.speed
, ent
->v
.basevelocity
);
1387 VectorCopy(vec_origin
, ent
->v
.basevelocity
);
1389 pr_global_struct
->time
= sv
.time
;
1390 pr_global_struct
->self
= EDICT_TO_PROG(ent
);
1393 SV_CheckVelocity (ent
);
1395 wasonground
= (int)ent
->v
.flags
& FL_ONGROUND
;
1396 // ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1398 // add gravity except:
1400 // swimming monsters who are in the water
1401 inwater
= SV_CheckWater(ent
);
1403 if (!((int)ent
->v
.flags
& FL_FLY
))
1404 if (!(((int)ent
->v
.flags
& FL_SWIM
) && (ent
->v
.waterlevel
> 0)))
1406 if (ent
->v
.velocity
[2] < sv_gravity
.value
*-0.1)
1409 SV_AddGravity (ent
);
1412 if (!VectorCompare(ent
->v
.velocity
, vec_origin
) || !VectorCompare(ent
->v
.basevelocity
, vec_origin
))
1414 ent
->v
.flags
= (int)ent
->v
.flags
& ~FL_ONGROUND
;
1416 // let dead monsters who aren't completely onground slide
1418 if (!(ent
->v
.health
<= 0.0 && !SV_CheckBottom(ent
)))
1420 vel
= ent
->v
.velocity
;
1421 speed
= sqrtf(vel
[0]*vel
[0] +vel
[1]*vel
[1]);
1424 friction
= sv_friction
.value
;
1426 control
= speed
< sv_stopspeed
.value
? sv_stopspeed
.value
: speed
;
1427 newspeed
= speed
- host_frametime
*control
*friction
;
1433 vel
[0] = vel
[0] * newspeed
;
1434 vel
[1] = vel
[1] * newspeed
;
1438 VectorAdd (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1439 SV_FlyMove (ent
, host_frametime
, NULL
);
1440 VectorSubtract (ent
->v
.velocity
, ent
->v
.basevelocity
, ent
->v
.velocity
);
1442 // determine if it's on solid ground at all
1444 vec3_t mins
, maxs
, point
;
1447 VectorAdd (ent
->v
.origin
, ent
->v
.mins
, mins
);
1448 VectorAdd (ent
->v
.origin
, ent
->v
.maxs
, maxs
);
1450 point
[2] = mins
[2] - 1;
1451 for (x
=0 ; x
<=1 ; x
++)
1452 for (y
=0 ; y
<=1 ; y
++)
1454 point
[0] = x
? maxs
[0] : mins
[0];
1455 point
[1] = y
? maxs
[1] : mins
[1];
1456 if (SV_PointContents (point
) == CONTENTS_SOLID
)
1458 ent
->v
.flags
= (int)ent
->v
.flags
| FL_ONGROUND
;
1465 SV_LinkEdict (ent
, true);
1467 if ((int)ent
->v
.flags
& FL_ONGROUND
)
1470 SV_StartSound (ent
, 0, "demon/dland2.wav", 255, 1);
1475 SV_CheckWaterTransition (ent
);
1478 void SV_Physics_Step (edict_t
*ent
)
1482 // freefall if not onground
1483 if ( ! ((int)ent
->v
.flags
& (FL_ONGROUND
| FL_FLY
| FL_SWIM
) ) )
1485 if (ent
->v
.velocity
[2] < sv_gravity
.value
*-0.1)
1490 SV_AddGravity (ent
);
1491 SV_CheckVelocity (ent
);
1492 SV_FlyMove (ent
, host_frametime
, NULL
);
1493 SV_LinkEdict (ent
, true);
1495 if ( (int)ent
->v
.flags
& FL_ONGROUND
) // just hit ground
1498 SV_StartSound (ent
, 0, "demon/dland2.wav", 255, 1);
1505 SV_CheckWaterTransition (ent
);
1509 //============================================================================
1517 void SV_Physics (void)
1522 // let the progs know that a new frame has started
1523 pr_global_struct
->self
= EDICT_TO_PROG(sv
.edicts
);
1524 pr_global_struct
->other
= EDICT_TO_PROG(sv
.edicts
);
1525 pr_global_struct
->time
= sv
.time
;
1526 PR_ExecuteProgram (pr_global_struct
->StartFrame
);
1528 //SV_CheckAllEnts ();
1531 // treat each object in turn
1534 for (i
=0 ; i
<sv
.num_edicts
; i
++, ent
= NEXT_EDICT(ent
))
1539 if (pr_global_struct
->force_retouch
)
1541 SV_LinkEdict (ent
, true); // force retouch even for stationary
1544 if (i
> 0 && i
<= svs
.maxclients
)
1545 SV_Physics_Client (ent
, i
);
1546 else if (ent
->v
.movetype
== MOVETYPE_PUSH
)
1547 SV_Physics_Pusher (ent
);
1548 else if (ent
->v
.movetype
== MOVETYPE_NONE
)
1549 SV_Physics_None (ent
);
1551 else if (ent
->v
.movetype
== MOVETYPE_FOLLOW
)
1552 SV_Physics_Follow (ent
);
1554 else if (ent
->v
.movetype
== MOVETYPE_NOCLIP
)
1555 SV_Physics_Noclip (ent
);
1556 else if (ent
->v
.movetype
== MOVETYPE_STEP
)
1557 SV_Physics_Step (ent
);
1558 else if (ent
->v
.movetype
== MOVETYPE_TOSS
1559 || ent
->v
.movetype
== MOVETYPE_BOUNCE
1561 || ent
->v
.movetype
== MOVETYPE_BOUNCEMISSILE
1563 || ent
->v
.movetype
== MOVETYPE_FLY
1564 || ent
->v
.movetype
== MOVETYPE_FLYMISSILE
)
1565 SV_Physics_Toss (ent
);
1567 Sys_Error ("SV_Physics: bad movetype %i", (int)ent
->v
.movetype
);
1570 if (pr_global_struct
->force_retouch
)
1571 pr_global_struct
->force_retouch
--;
1573 sv
.time
+= host_frametime
;
1578 trace_t
SV_Trace_Toss (edict_t
*ent
, edict_t
*ignore
)
1580 edict_t tempent
, *tent
;
1584 double save_frametime
;
1585 // extern particle_t *active_particles, *free_particles;
1589 save_frametime
= host_frametime
;
1590 host_frametime
= 0.05;
1592 memcpy(&tempent
, ent
, sizeof(edict_t
));
1597 SV_CheckVelocity (tent
);
1598 SV_AddGravity (tent
);
1599 VectorMA (tent
->v
.angles
, host_frametime
, tent
->v
.avelocity
, tent
->v
.angles
);
1600 VectorScale (tent
->v
.velocity
, host_frametime
, move
);
1601 VectorAdd (tent
->v
.origin
, move
, end
);
1602 trace
= SV_Move (tent
->v
.origin
, tent
->v
.mins
, tent
->v
.maxs
, end
, MOVE_NORMAL
, tent
);
1603 VectorCopy (trace
.endpos
, tent
->v
.origin
);
1605 // p = free_particles;
1608 // free_particles = p->next;
1609 // p->next = active_particles;
1610 // active_particles = p;
1614 // p->type = pt_static;
1615 // VectorCopy (vec3_origin, p->vel);
1616 // VectorCopy (tent->v.origin, p->org);
1620 if (trace
.ent
!= ignore
)
1624 host_frametime
= save_frametime
;