]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/cl_physics.qc
some missing files; g_race_qualifying is still broken (ignores fraglimit, no idea...
[divverent/nexuiz.git] / data / qcsrc / server / cl_physics.qc
1 float sv_accelerate;
2 float sv_friction;
3 float sv_maxspeed;
4 float sv_airaccelerate;
5 float sv_maxairspeed;
6 float sv_stopspeed;
7 float sv_gravity;
8 float sv_airaccel_sideways_friction;
9 float sv_airaccel_qw;
10 .float ladder_time;
11 .entity ladder_entity;
12 .float gravity;
13 .float swamp_slowdown;
14 .float lastflags;
15 .float lastground;
16 .float wasFlying;
17
18 #define SHTEST_DELTA 15
19 .float shtest_next;
20 .float shtest_accumulator;
21
22 /*
23 =============
24 PlayerJump
25
26 When you press the jump key
27 =============
28 */
29 void PlayerJump (void)
30 {
31         float mjumpheight;
32
33         mjumpheight = cvar("sv_jumpvelocity");
34         if (self.waterlevel >= 2)
35         {
36                 if (self.watertype == CONTENT_WATER)
37                         self.velocity_z = 200;
38                 else if (self.watertype == CONTENT_SLIME)
39                         self.velocity_z = 80;
40                 else
41                         self.velocity_z = 50;
42
43                 return;
44         }
45
46
47         if (!(self.flags & FL_ONGROUND))
48                 return;
49
50         if(!sv_pogostick)
51                 if (!(self.flags & FL_JUMPRELEASED))
52                         return;
53
54         if(g_runematch)
55         {
56                 if(self.runes & RUNE_SPEED)
57                 {
58                         if(self.runes & CURSE_SLOW)
59                                 mjumpheight = mjumpheight * cvar("g_balance_rune_speed_combo_jumpheight");
60                         else
61                                 mjumpheight = mjumpheight * cvar("g_balance_rune_speed_jumpheight");
62                 }
63                 else if(self.runes & CURSE_SLOW)
64                 {
65                         mjumpheight = mjumpheight * cvar("g_balance_curse_slow_jumpheight");
66                 }
67         }
68
69         if(g_minstagib && (self.items & IT_INVINCIBLE))
70         {
71                 mjumpheight = mjumpheight * cvar("g_minstagib_speed_jumpheight");
72         }
73
74         self.velocity_z = self.velocity_z + mjumpheight;
75         self.oldvelocity_z = self.velocity_z;
76
77         self.flags = self.flags - FL_ONGROUND;
78         self.flags = self.flags - FL_JUMPRELEASED;
79
80         if (self.crouch)
81                 player_setanim(self.anim_duckjump, FALSE, TRUE, TRUE);
82         else
83                 player_setanim(self.anim_jump, FALSE, TRUE, TRUE);
84
85         if(g_jump_grunt)
86                 PlayerSound(playersound_jump, CHAN_PLAYER, 0);
87 }
88
89 void CheckWaterJump()
90 {
91         local vector start, end;
92
93 // check for a jump-out-of-water
94         makevectors (self.angles);
95         start = self.origin;
96         start_z = start_z + 8;
97         v_forward_z = 0;
98         normalize(v_forward);
99         end = start + v_forward*24;
100         traceline (start, end, TRUE, self);
101         if (trace_fraction < 1)
102         {       // solid at waist
103                 start_z = start_z + self.maxs_z - 8;
104                 end = start + v_forward*24;
105                 self.movedir = trace_plane_normal * -50;
106                 traceline (start, end, TRUE, self);
107                 if (trace_fraction == 1)
108                 {       // open at eye level
109                         self.flags = self.flags | FL_WATERJUMP;
110                         self.velocity_z = 225;
111                         self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
112                         self.teleport_time = time + 2;  // safety net
113                         return;
114                 }
115         }
116 };
117
118 .vector movement_old;
119 .float buttons_old;
120 .vector v_angle_old;
121
122 void Nixnex_GiveCurrentWeapon();
123 void SV_PlayerPhysics()
124 {
125         local vector wishvel, wishdir, v;
126         local float wishspeed, f, maxspd_mod, spd, maxairspd, airaccel, swampspd_mod, shtest_score, buttons;
127         string temps;
128
129         buttons = self.BUTTON_ATCK + 2 * self.BUTTON_JUMP + 4 * self.BUTTON_ATCK2 + 8 * self.BUTTON_ZOOM + 16 * self.BUTTON_CROUCH + 32 * self.BUTTON_HOOK + 64 * self.BUTTON_USE;
130         if(!sv_maxidle_spectatorsareidle || self.movetype == MOVETYPE_WALK)
131         {
132                 if(buttons != self.buttons_old || self.movement != self.movement_old || self.v_angle != self.v_angle_old)
133                         self.parm_idlesince = time;
134         }
135         self.buttons_old = buttons;
136         self.movement_old = self.movement;
137         self.v_angle_old = self.v_angle;
138
139         if(time > self.shtest_next)
140         {
141                 if(self.shtest_next > 0)
142                 {
143                         // self.shtest_accumulator:
144                         //   started at time - SHTEST_DELTA
145                         //   should be at SHTEST_DELTA
146                         shtest_score = self.shtest_accumulator / SHTEST_DELTA;
147                         if(shtest_score > 1.2)
148                                 dprint("TIME PARADOX: shtest for ", self.netname, " said ", ftos(shtest_score), "\n");
149                         else if(cvar("developer_shtest"))
150                                 dprint("okay: shtest for ", self.netname, " said ", ftos(shtest_score), "\n");
151                 }
152                 self.shtest_next = time + SHTEST_DELTA;
153                 self.shtest_accumulator = 0;
154         }
155         self.shtest_accumulator += frametime;
156
157         if (clienttype(self) == CLIENTTYPE_BOT)
158                 bot_think();
159
160         if (self.movetype == MOVETYPE_NONE)
161                 return;
162
163         if (self.punchangle != '0 0 0')
164         {
165                 f = vlen(self.punchangle) - 10 * frametime;
166                 if (f > 0)
167                         self.punchangle = normalize(self.punchangle) * f;
168                 else
169                         self.punchangle = '0 0 0';
170         }
171
172         if (self.punchvector != '0 0 0')
173         {
174                 f = vlen(self.punchvector) - 30 * frametime;
175                 if (f > 0)
176                         self.punchvector = normalize(self.punchvector) * f;
177                 else
178                         self.punchvector = '0 0 0';
179         }
180
181         maxspd_mod = 1;
182
183         if(g_runematch)
184         {
185                 if(self.runes & RUNE_SPEED)
186                 {
187                         if(self.runes & CURSE_SLOW)
188                                 maxspd_mod = maxspd_mod * cvar("g_balance_rune_speed_combo_moverate");
189                         else
190                                 maxspd_mod = maxspd_mod * cvar("g_balance_rune_speed_moverate");
191                 }
192                 else if(self.runes & CURSE_SLOW)
193                 {
194                         maxspd_mod = maxspd_mod * cvar("g_balance_curse_slow_moverate");
195                 }
196         }
197
198         if(g_minstagib && (self.items & IT_INVINCIBLE))
199         {
200                 maxspd_mod = cvar("g_minstagib_speed_moverate");
201         }
202
203         swampspd_mod = 1;
204         if(self.in_swamp) {
205                 swampspd_mod = self.swamp_slowdown; //cvar("g_balance_swamp_moverate");
206         }
207
208         if(self.flags & FL_NOTARGET)
209                 maxspd_mod = cvar("sv_spectator_speed_multiplier");
210
211         spd = sv_maxspeed * maxspd_mod * swampspd_mod;
212
213         if(self.speed != spd)
214         {
215                 self.speed = spd;
216                 temps = ftos(spd);
217                 stuffcmd(self, strcat("cl_forwardspeed ", temps, "\n"));
218                 stuffcmd(self, strcat("cl_backspeed ", temps, "\n"));
219                 stuffcmd(self, strcat("cl_sidespeed ", temps, "\n"));
220                 stuffcmd(self, strcat("cl_upspeed ", temps, "\n"));
221
222                 temps = ftos(sv_accelerate * maxspd_mod);
223                 stuffcmd(self, strcat("cl_movement_accelerate ", temps, "\n"));
224         }
225
226         // if dead, behave differently
227         if (self.deadflag)
228                 return;
229
230         if (!self.fixangle)
231         {
232                 self.angles_x = 0;
233                 self.angles_y = self.v_angle_y;
234                 self.angles_z = 0;
235         }
236
237         if(self.flags & FL_ONGROUND)
238         if(self.wasFlying)
239         {
240                 self.wasFlying = 0;
241
242                 if(self.waterlevel < 2)
243                 if(time >= self.ladder_time)
244                 if not(self.hook)
245                 {
246                         self.nextstep = time + 0.3 + random() * 0.1;
247                         trace_dphitq3surfaceflags = 0;
248                         tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self);
249                         if not(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS)
250                         {
251                                 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
252                                         GlobalSound(globalsound_metalfall, CHAN_PLAYER, 0);
253                                 else
254                                         GlobalSound(globalsound_fall, CHAN_PLAYER, 0);
255                         }
256                 }
257         }
258
259         if(IsFlying(self))
260                 self.wasFlying = 1;
261
262         if(self.classname == "player")
263         {
264                 if(sv_doublejump)
265                 {
266                         self.flags = self.flags - (self.flags & FL_ONGROUND);
267                         tracebox(self.origin + '0 0 1', self.mins, self.maxs, self.origin - '0 0 2', MOVE_NORMAL, self);
268                         if(trace_fraction < 1 && trace_plane_normal_z > 0.7)
269                                 self.flags = self.flags | FL_ONGROUND;
270                 }
271
272                 if (self.BUTTON_JUMP)
273                         PlayerJump ();
274                 else
275                         self.flags = self.flags | FL_JUMPRELEASED;
276
277                 if (self.waterlevel == 2)
278                         CheckWaterJump ();
279         }
280
281         if (self.flags & FL_WATERJUMP )
282         {
283                 self.velocity_x = self.movedir_x;
284                 self.velocity_y = self.movedir_y;
285                 if (time > self.teleport_time || self.waterlevel == 0)
286                 {
287                         self.flags = self.flags - (self.flags & FL_WATERJUMP);
288                         self.teleport_time = 0;
289                 }
290         }
291         else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY)
292         {
293                 // noclipping or flying
294                 self.flags = self.flags - (self.flags & FL_ONGROUND);
295
296                 self.velocity = self.velocity * (1 - frametime * sv_friction);
297                 makevectors(self.v_angle);
298                 //wishvel = v_forward * self.movement_x + v_right * self.movement_y + v_up * self.movement_z;
299                 wishvel = v_forward * self.movement_x + v_right * self.movement_y + '0 0 1' * self.movement_z;
300                 // acceleration
301                 wishdir = normalize(wishvel);
302                 wishspeed = vlen(wishvel);
303                 if (wishspeed > sv_maxspeed*maxspd_mod)
304                         wishspeed = sv_maxspeed*maxspd_mod;
305                 if (time >= self.teleport_time)
306                 {
307                         f = wishspeed - (self.velocity * wishdir);
308                         if (f > 0)
309                                 self.velocity = self.velocity + wishdir * min(f, sv_accelerate*maxspd_mod * frametime * wishspeed);
310                 }
311         }
312         else if (self.waterlevel >= 2)
313         {
314                 // swimming
315                 self.flags = self.flags - (self.flags & FL_ONGROUND);
316
317                 makevectors(self.v_angle);
318                 //wishvel = v_forward * self.movement_x + v_right * self.movement_y + v_up * self.movement_z;
319                 wishvel = v_forward * self.movement_x + v_right * self.movement_y + '0 0 1' * self.movement_z;
320                 if (wishvel == '0 0 0')
321                         wishvel = '0 0 -60'; // drift towards bottom
322
323                 wishdir = normalize(wishvel);
324                 wishspeed = vlen(wishvel);
325                 if (wishspeed > sv_maxspeed*maxspd_mod)
326                         wishspeed = sv_maxspeed*maxspd_mod;
327                 wishspeed = wishspeed * 0.7;
328
329                 // water friction
330                 self.velocity = self.velocity * (1 - frametime * sv_friction);
331
332                 // water acceleration
333                 f = wishspeed - (self.velocity * wishdir);
334                 if (f > 0)
335                         self.velocity = self.velocity + wishdir * min(f, sv_accelerate*maxspd_mod * frametime * wishspeed);
336         }
337         else if (time < self.ladder_time)
338         {
339                 // on a spawnfunc_func_ladder or swimming in spawnfunc_func_water
340                 self.flags = self.flags - (self.flags & FL_ONGROUND);
341
342                 self.velocity = self.velocity * (1 - frametime * sv_friction);
343                 makevectors(self.v_angle);
344                 //wishvel = v_forward * self.movement_x + v_right * self.movement_y + v_up * self.movement_z;
345                 wishvel = v_forward * self.movement_x + v_right * self.movement_y + '0 0 1' * self.movement_z;
346                 if (self.gravity)
347                         self.velocity_z = self.velocity_z + self.gravity * sv_gravity * frametime;
348                 else
349                         self.velocity_z = self.velocity_z + sv_gravity * frametime;
350                 if (self.ladder_entity.classname == "func_water")
351                 {
352                         f = vlen(wishvel);
353                         if (f > self.ladder_entity.speed)
354                                 wishvel = wishvel * (self.ladder_entity.speed / f);
355
356                         self.watertype = self.ladder_entity.skin;
357                         f = self.ladder_entity.origin_z + self.ladder_entity.maxs_z;
358                         if ((self.origin_z + self.view_ofs_z) < f)
359                                 self.waterlevel = 3;
360                         else if ((self.origin_z + (self.mins_z + self.maxs_z) * 0.5) < f)
361                                 self.waterlevel = 2;
362                         else if ((self.origin_z + self.mins_z + 1) < f)
363                                 self.waterlevel = 1;
364                         else
365                         {
366                                 self.waterlevel = 0;
367                                 self.watertype = CONTENT_EMPTY;
368                         }
369                 }
370                 // acceleration
371                 wishdir = normalize(wishvel);
372                 wishspeed = vlen(wishvel);
373                 if (wishspeed > sv_maxspeed)
374                         wishspeed = sv_maxspeed;
375                 if (time >= self.teleport_time)
376                 {
377                         f = wishspeed - (self.velocity * wishdir);
378                         if (f > 0)
379                                 self.velocity = self.velocity + wishdir * min(f, sv_accelerate*maxspd_mod * frametime * wishspeed);
380                 }
381         }
382         else if (self.flags & FL_ONGROUND)
383         {
384                 // walking
385                 makevectors(self.v_angle_y * '0 1 0');
386                 wishvel = v_forward * self.movement_x + v_right * self.movement_y;
387
388                 if(!(self.lastflags & FL_ONGROUND))
389                 {
390                         if(cvar("speedmeter"))
391                                 dprint(strcat("landing velocity: ", vtos(self.velocity), " (abs: ", ftos(vlen(self.velocity)), ")\n"));
392                         if(self.lastground < time - 0.3)
393                                 self.velocity = self.velocity * (1 - cvar("sv_friction_on_land"));
394                         if(self.jumppadcount > 1)
395                                 dprint(strcat(ftos(self.jumppadcount), "x jumppad combo\n"));
396                         self.jumppadcount = 0;
397                 }
398
399                 if (self.velocity_x || self.velocity_y)
400                 if (!(self.flags & FL_JUMPRELEASED) || !self.BUTTON_JUMP)
401                 {
402                         v = self.velocity;
403                         v_z = 0;
404                         f = vlen(v);
405                         if (f < sv_stopspeed)
406                                 f = 1 - frametime * (sv_stopspeed / f) * sv_friction;
407                         else
408                                 f = 1 - frametime * sv_friction;
409                         if (f > 0)
410                                 self.velocity = self.velocity * f;
411                         else
412                                 self.velocity = '0 0 0';
413                 }
414                 // acceleration
415                 wishdir = normalize(wishvel);
416                 wishspeed = vlen(wishvel);
417                 if (wishspeed > sv_maxspeed*maxspd_mod)
418                         wishspeed = sv_maxspeed*maxspd_mod;
419                 if (self.crouch)
420                         wishspeed = wishspeed * 0.5;
421                 if (time >= self.teleport_time)
422                 {
423                         f = wishspeed - (self.velocity * wishdir);
424                         if (f > 0)
425                                 self.velocity = self.velocity + wishdir * min(f, sv_accelerate*maxspd_mod * frametime * wishspeed);
426                 }
427         }
428         else
429         {
430                 if(maxspd_mod < 1)
431                 {
432                         maxairspd = sv_maxairspeed*maxspd_mod;
433                         airaccel = sv_airaccelerate*maxspd_mod;
434                 }
435                 else
436                 {
437                         maxairspd = sv_maxairspeed;
438                         airaccel = sv_airaccelerate;
439                 }
440                 // airborn
441                 makevectors(self.v_angle_y * '0 1 0');
442                 wishvel = v_forward * self.movement_x + v_right * self.movement_y;
443                 // acceleration
444                 wishdir = normalize(wishvel);
445                 wishspeed = vlen(wishvel);
446                 if (wishspeed > maxairspd)
447                         wishspeed = maxairspd;
448                 if (self.crouch)
449                         wishspeed = wishspeed * 0.5;
450                 if (time >= self.teleport_time)
451                 {
452                         // NOTE: this does the same as the commented out old code if:
453                         //   sv_airaccel_qw 0
454                         //   sv_airaccel_sideways_friction 0
455                         
456                         float vel_straight;
457                         float vel_z;
458                         vector vel_perpend;
459                         vel_straight = self.velocity * wishdir;
460                         vel_z = self.velocity_z;
461                         vel_perpend = self.velocity - vel_straight * wishdir - vel_z * '0 0 1';
462
463                         f = wishspeed - vel_straight;
464                         if(f > 0)
465                                 vel_straight = vel_straight + min(f, airaccel * frametime * wishspeed) * sv_airaccel_qw;
466                         if(wishspeed > 0)
467                                 vel_straight = vel_straight + min(wishspeed, airaccel * frametime * wishspeed) * (1 - sv_airaccel_qw);
468
469                         // anti-sideways friction to fix QW-style bunnyhopping
470                         vel_perpend = vel_perpend * (1 - frametime * (wishspeed / maxairspd) * sv_airaccel_sideways_friction);
471
472                         self.velocity = vel_straight * wishdir + vel_z * '0 0 1' + vel_perpend;
473
474                         /*
475                         f = wishspeed;// - (self.velocity * wishdir);
476                         if (f > 0)
477                                 self.velocity = self.velocity + wishdir * min(f, airaccel * frametime * wishspeed);
478                         */
479                 }
480         }
481
482         if(self.flags & FL_ONGROUND)
483                 self.lastground = time;
484
485         self.lastflags = self.flags;
486 };