Merge branch 'master' into TimePath/global_self
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / movetypes / walk.qc
1 void _Movetype_Physics_Walk(float dt)  // SV_WalkMove
2 {SELFPARAM();
3         vector stepnormal = '0 0 0';
4
5         // if frametime is 0 (due to client sending the same timestamp twice), don't move
6         if (dt <= 0)
7                 return;
8
9         if (GAMEPLAYFIX_UNSTICKPLAYERS)
10                 _Movetype_UnstickEntity();
11
12         bool applygravity = (!_Movetype_CheckWater(self) && self.move_movetype == MOVETYPE_WALK && !(self.move_flags & FL_WATERJUMP));
13
14         _Movetype_CheckVelocity();
15
16         // do a regular slide move unless it looks like you ran into a step
17         bool oldonground = (self.move_flags & FL_ONGROUND);
18
19         vector start_origin = self.move_origin;
20         vector start_velocity = self.move_velocity;
21
22         int clip = _Movetype_FlyMove(dt, applygravity, stepnormal, GAMEPLAYFIX_STEPMULTIPLETIMES ? PHYS_STEPHEIGHT : 0);
23
24         if (GAMEPLAYFIX_DOWNTRACEONGROUND && !(clip & 1))
25         {
26                 // only try this if there was no floor in the way in the trace (no,
27                 // this check seems to be not REALLY necessary, because if clip & 1,
28                 // our trace will hit that thing too)
29                 vector upmove = self.move_origin + '0 0 1';
30                 vector downmove = self.move_origin - '0 0 1';
31                 int type;
32                 if (self.move_movetype == MOVETYPE_FLYMISSILE)
33                         type = MOVE_MISSILE;
34                 else if (self.move_movetype == MOVETYPE_FLY_WORLDONLY)
35                         type = MOVE_WORLDONLY;
36                 else if (self.solid == SOLID_TRIGGER || self.solid == SOLID_NOT)
37                         type = MOVE_NOMONSTERS;
38                 else type = MOVE_NORMAL;
39                 tracebox(upmove, self.mins, self.maxs, downmove, type, self);
40                 if (trace_fraction < 1 && trace_plane_normal.z > 0.7)
41                         clip |= 1;  // but we HAVE found a floor
42         }
43
44         // if the move did not hit the ground at any point, we're not on ground
45         if (!(clip & 1))
46                 self.move_flags &= ~FL_ONGROUND;
47
48         _Movetype_CheckVelocity();
49         _Movetype_LinkEdict(true);
50
51         if (clip & 8)  // teleport
52                 return;
53
54         if (self.move_flags & FL_WATERJUMP)
55                 return;
56
57         if (PHYS_NOSTEP)
58                 return;
59
60         vector originalmove_origin = self.move_origin;
61         vector originalmove_velocity = self.move_velocity;
62         // originalmove_clip = clip;
63         int originalmove_flags = self.move_flags;
64         entity originalmove_groundentity = self.move_groundentity;
65
66         // if move didn't block on a step, return
67         if (clip & 2)
68         {
69                 // if move was not trying to move into the step, return
70                 if (fabs(start_velocity.x) < 0.03125 && fabs(start_velocity.y) < 0.03125)
71                         return;
72
73                 if (self.move_movetype != MOVETYPE_FLY)
74                 {
75                         // return if gibbed by a trigger
76                         if (self.move_movetype != MOVETYPE_WALK)
77                                 return;
78
79                         // return if attempting to jump while airborn (unless sv_jumpstep)
80                         if (!PHYS_JUMPSTEP)
81                                 if (!oldonground && self.move_waterlevel == 0)
82                                         return;
83                 }
84
85                 // try moving up and forward to go up a step
86                 // back to start pos
87                 self.move_origin = start_origin;
88                 self.move_velocity = start_velocity;
89
90                 // move up
91                 vector upmove = '0 0 1' * PHYS_STEPHEIGHT;
92                 vector prev_origin = self.move_origin;
93                 _Movetype_PushEntity(upmove, true);
94                 if(wasfreed(self))
95                         return;
96                 if(trace_startsolid && self.move_origin != prev_origin)
97                 {
98                         // we got teleported when upstepping... must abort the move
99                         return;
100                 }
101
102                 // move forward
103                 self.move_velocity_z = 0;
104                 clip = _Movetype_FlyMove(dt, applygravity, stepnormal, 0);
105                 self.move_velocity_z += start_velocity.z;
106                 if (clip & 8)
107                 {
108                         // we got teleported when upstepping... must abort the move
109                         // note that z velocity handling may not be what QC expects here, but we cannot help it
110                         return;
111                 }
112
113                 _Movetype_CheckVelocity();
114                 _Movetype_LinkEdict(true);
115
116                 // check for stuckness, possibly due to the limited precision of floats
117                 // in the clipping hulls
118                 if (clip
119                     && fabs(originalmove_origin.y - self.move_origin.y) < 0.03125
120                     && fabs(originalmove_origin.x - self.move_origin.x) < 0.03125)
121                 {
122                         // Con_Printf("wall\n");
123                         // stepping up didn't make any progress, revert to original move
124                         self.move_origin = originalmove_origin;
125                         self.move_velocity = originalmove_velocity;
126                         // clip = originalmove_clip;
127                         self.move_flags = originalmove_flags;
128                         self.move_groundentity = originalmove_groundentity;
129                         // now try to unstick if needed
130                         // clip = SV_TryUnstick (ent, oldvel);
131                         return;
132                 }
133
134                 // Con_Printf("step - ");
135
136                 // extra friction based on view angle
137                 if ((clip & 2) && PHYS_WALLFRICTION)
138                         _Movetype_WallFriction(stepnormal);
139         }
140         // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
141         else if (!GAMEPLAYFIX_STEPDOWN || self.move_waterlevel >= 3 || start_velocity.z >= (1.0 / 32.0) || !oldonground || (self.move_flags & FL_ONGROUND))
142         {
143                 return;
144         }
145
146         // move down
147         vector downmove = '0 0 1' * (-PHYS_STEPHEIGHT + start_velocity.z * dt);
148         vector prev_origin = self.move_origin;
149         _Movetype_PushEntity(downmove, true);
150         if(wasfreed(self))
151                 return;
152
153         if(trace_startsolid && self.move_origin != prev_origin)
154         {
155                 // we got teleported when downstepping... must abort the move
156                 return;
157         }
158
159         if (trace_fraction < 1 && trace_plane_normal.z > 0.7)
160         {
161                 // this has been disabled so that you can't jump when you are stepping
162                 // up while already jumping (also known as the Quake2 double jump bug)
163         }
164         else
165         {
166                 // Con_Printf("slope\n");
167                 // if the push down didn't end up on good ground, use the move without
168                 // the step up.  This happens near wall / slope combinations, and can
169                 // cause the player to hop up higher on a slope too steep to climb
170                 self.move_origin = originalmove_origin;
171                 self.move_velocity = originalmove_velocity;
172                 self.move_flags = originalmove_flags;
173                 self.move_groundentity = originalmove_groundentity;
174         }
175
176         _Movetype_CheckVelocity();
177         _Movetype_LinkEdict(true);
178 }