*** empty log message ***
[divverent/darkplaces.git] / sv_user.qc
1 float lastclientthink, sv_maxspeed, sv_friction, sv_accelerate, sv_stopspeed;
2 float sv_edgefriction, cl_rollangle, cl_divspeed;
3 .vector movement;
4
5 // LordHavoc:
6 // Highly optimized port of SV_ClientThink from engine code to QuakeC.
7 // No behavior changes!  This code is much shorter and probably faster than
8 // the engine code :)
9
10 // note that darkplaces engine will call this function if it finds it,
11 // so modify for your own mods and enjoy...
12
13 // note also, this code uses some builtin functions from dpextensions.qc
14 // (included with darkplaces engine releases)
15
16 // P.S. if you find something weird in this code, it's just mimicing weird
17 // stuff in the original quake engine code (which was so unreadable it was
18 // hard to even identify what it was doing)
19
20 void() SV_PlayerPhysics =
21 {
22         local vector wishvel, wishdir, v;
23         local float wishspeed, f, limit;
24
25         if (self.movetype == MOVETYPE_NONE)
26                 return;
27
28         if (self.punchangle != '0 0 0')
29         {
30                 f = vlen(self.punchangle) - 10 * frametime;
31                 if (f > 0)
32                         self.punchangle = normalize(self.punchangle) * f;
33                 else
34                         self.punchangle = '0 0 0';
35         }
36
37         // if dead, behave differently
38         if (self.health <= 0)
39                 return;
40
41         if (time != lastclientthink)
42         {
43                 lastclientthink = time;
44                 sv_maxspeed = cvar("sv_maxspeed");
45                 sv_friction = cvar("sv_friction");
46                 sv_accelerate = cvar("sv_accelerate");
47                 sv_stopspeed = cvar("sv_stopspeed");
48                 sv_edgefriction = cvar("edgefriction");
49                 // LordHavoc: this * 4 is an optimization
50                 cl_rollangle = cvar("cl_rollangle") * 4;
51                 // LordHavoc: this 1 / is an optimization
52                 cl_divspeed = 1 / cvar("cl_rollspeed");
53         }
54
55         // show 1/3 the pitch angle and all the roll angle
56         f = (self.velocity * v_right) * cl_divspeed;
57         if (f < -1)
58                 f = -1;
59         if (f > 1)
60                 f = 1;
61         self.angles_z = f * cl_rollangle;
62         if (!self.fixangle)
63         {
64                 self.angles_x = (self.v_angle_x + self.punchangle_x) * -0.333;
65                 self.angles_y = self.v_angle_y + self.punchangle_y;
66         }
67
68         if (self.flags & FL_WATERJUMP )
69         {
70                 self.velocity_x = self.movedir_x;
71                 self.velocity_y = self.movedir_y;
72                 if (time > self.teleport_time || self.waterlevel == 0)
73                 {
74                         self.flags = self.flags - (self.flags & FL_WATERJUMP);
75                         self.teleport_time = 0;
76                 }
77                 return;
78         }
79
80         // swim
81         if (self.waterlevel >= 2)
82         if (self.movetype != MOVETYPE_NOCLIP)
83         {
84                 makevectors(self.v_angle);
85                 if (self.movement == '0 0 0')
86                         wishvel = '0 0 -60'; // drift towards bottom
87                 else
88                         wishvel = v_forward * self.movement_x + v_right * self.movement_y + '0 0 1' * self.movement_z;
89
90                 wishspeed = vlen(wishvel);
91                 if (wishspeed > sv_maxspeed)
92                         wishspeed = sv_maxspeed * 0.7;
93                 else
94                         wishspeed = wishspeed * 0.7;
95
96                 // water friction
97                 if (self.velocity != '0 0 0')
98                 {
99                         f = vlen(self.velocity) * (1 - frametime * sv_friction);
100                         if (f > 0)
101                                 self.velocity = normalize(self.velocity) * f;
102                         else
103                                 self.velocity = '0 0 0';
104                 }
105                 else
106                         f = 0;
107
108                 // water acceleration
109                 if (wishspeed <= f)
110                         return;
111
112                 limit = sv_accelerate * wishspeed * frametime;
113                 f = wishspeed - f;
114                 if (f > limit)
115                         self.velocity = self.velocity + normalize(wishvel) * limit;
116                 else
117                         self.velocity = self.velocity + normalize(wishvel) * f;
118                 return;
119         }
120
121         if (self.movetype == MOVETYPE_FLY)
122                 makevectors(self.v_angle);
123         else
124                 makevectors(self.v_angle_y * '0 1 0');
125
126         // hack to not let you back into teleporter
127         wishvel = v_right * self.movement_y;
128         if (time >= self.teleport_time || self.movement_x > 0)
129                 wishvel = wishvel + v_forward * self.movement_x;
130         if (self.movetype != MOVETYPE_WALK)
131                 wishvel_z = wishvel_z + self.movement_z;
132
133         wishdir = normalize(wishvel);
134         wishspeed = vlen(wishvel);
135         if (wishspeed > sv_maxspeed)
136                 wishspeed = sv_maxspeed;
137
138         if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY)
139         {
140                 self.velocity = wishdir * wishspeed;
141                 return;
142         }
143
144         if (self.flags & FL_ONGROUND) // walking
145         {
146                 // friction
147                 if (self.velocity_x || self.velocity_y)
148                 {
149                         v = self.velocity;
150                         v_z = 0;
151                         f = vlen(v);
152
153                         // if the leading edge is over a dropoff, increase friction
154                         v = self.origin + normalize(v) * 16 + '0 0 1' * self.mins_z;
155
156                         traceline(v, v + '0 0 -34', TRUE, self);
157
158                         // apply friction
159                         if (trace_fraction == 1.0)
160                         {
161                                 if (f < sv_stopspeed)
162                                         f = 1 - frametime * (sv_stopspeed / f) * sv_friction * sv_edgefriction;
163                                 else
164                                         f = 1 - frametime * sv_friction * sv_edgefriction;
165                         }
166                         else
167                         {
168                                 if (f < sv_stopspeed)
169                                         f = 1 - frametime * (sv_stopspeed / f) * sv_friction;
170                                 else
171                                         f = 1 - frametime * sv_friction;
172                         }
173
174                         if (f < 0)
175                                 self.velocity = '0 0 0';
176                         else
177                                 self.velocity = self.velocity * f;
178                 }
179         }
180         else // airborn
181                 if (wishspeed > 30)
182                         wishspeed = 30;
183
184         // acceleration
185         f = wishspeed - (self.velocity * wishdir);
186         if (f > 0)
187         {
188                 limit = sv_accelerate * frametime * wishspeed;
189                 if (f > limit)
190                         f = limit;
191                 self.velocity = self.velocity + wishdir * f;
192         }
193 }