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