]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_input.c
fix interpolation of cl_movement
[divverent/darkplaces.git] / cl_input.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // cl.input.c  -- builds an intended movement command to send to the server
21
22 // Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
23 // rights reserved.
24
25 #include "quakedef.h"
26
27 /*
28 ===============================================================================
29
30 KEY BUTTONS
31
32 Continuous button event tracking is complicated by the fact that two different
33 input sources (say, mouse button 1 and the control key) can both press the
34 same button, but the button should only be released when both of the
35 pressing key have been released.
36
37 When a key event issues a button command (+forward, +attack, etc), it appends
38 its key number as a parameter to the command so it can be matched up with
39 the release.
40
41 state bit 0 is the current state of the key
42 state bit 1 is edge triggered on the up to down transition
43 state bit 2 is edge triggered on the down to up transition
44
45 ===============================================================================
46 */
47
48
49 kbutton_t       in_mlook, in_klook;
50 kbutton_t       in_left, in_right, in_forward, in_back;
51 kbutton_t       in_lookup, in_lookdown, in_moveleft, in_moveright;
52 kbutton_t       in_strafe, in_speed, in_jump, in_attack, in_use;
53 kbutton_t       in_up, in_down;
54 // LordHavoc: added 6 new buttons
55 kbutton_t       in_button3, in_button4, in_button5, in_button6, in_button7, in_button8;
56
57 int                     in_impulse;
58
59 extern cvar_t sys_ticrate;
60
61
62 void KeyDown (kbutton_t *b)
63 {
64         int k;
65         const char *c;
66
67         c = Cmd_Argv(1);
68         if (c[0])
69                 k = atoi(c);
70         else
71                 k = -1;         // typed manually at the console for continuous down
72
73         if (k == b->down[0] || k == b->down[1])
74                 return;         // repeating key
75
76         if (!b->down[0])
77                 b->down[0] = k;
78         else if (!b->down[1])
79                 b->down[1] = k;
80         else
81         {
82                 Con_Print("Three keys down for a button!\n");
83                 return;
84         }
85
86         if (b->state & 1)
87                 return;         // still down
88         b->state |= 1 + 2;      // down + impulse down
89 }
90
91 void KeyUp (kbutton_t *b)
92 {
93         int k;
94         const char *c;
95
96         c = Cmd_Argv(1);
97         if (c[0])
98                 k = atoi(c);
99         else
100         { // typed manually at the console, assume for unsticking, so clear all
101                 b->down[0] = b->down[1] = 0;
102                 b->state = 4;   // impulse up
103                 return;
104         }
105
106         if (b->down[0] == k)
107                 b->down[0] = 0;
108         else if (b->down[1] == k)
109                 b->down[1] = 0;
110         else
111                 return;         // key up without coresponding down (menu pass through)
112         if (b->down[0] || b->down[1])
113                 return;         // some other key is still holding it down
114
115         if (!(b->state & 1))
116                 return;         // still up (this should not happen)
117         b->state &= ~1;         // now up
118         b->state |= 4;          // impulse up
119 }
120
121 void IN_KLookDown (void) {KeyDown(&in_klook);}
122 void IN_KLookUp (void) {KeyUp(&in_klook);}
123 void IN_MLookDown (void) {KeyDown(&in_mlook);}
124 void IN_MLookUp (void)
125 {
126         KeyUp(&in_mlook);
127         if ( !(in_mlook.state&1) && lookspring.value)
128                 V_StartPitchDrift();
129 }
130 void IN_UpDown(void) {KeyDown(&in_up);}
131 void IN_UpUp(void) {KeyUp(&in_up);}
132 void IN_DownDown(void) {KeyDown(&in_down);}
133 void IN_DownUp(void) {KeyUp(&in_down);}
134 void IN_LeftDown(void) {KeyDown(&in_left);}
135 void IN_LeftUp(void) {KeyUp(&in_left);}
136 void IN_RightDown(void) {KeyDown(&in_right);}
137 void IN_RightUp(void) {KeyUp(&in_right);}
138 void IN_ForwardDown(void) {KeyDown(&in_forward);}
139 void IN_ForwardUp(void) {KeyUp(&in_forward);}
140 void IN_BackDown(void) {KeyDown(&in_back);}
141 void IN_BackUp(void) {KeyUp(&in_back);}
142 void IN_LookupDown(void) {KeyDown(&in_lookup);}
143 void IN_LookupUp(void) {KeyUp(&in_lookup);}
144 void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
145 void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
146 void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
147 void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
148 void IN_MoverightDown(void) {KeyDown(&in_moveright);}
149 void IN_MoverightUp(void) {KeyUp(&in_moveright);}
150
151 void IN_SpeedDown(void) {KeyDown(&in_speed);}
152 void IN_SpeedUp(void) {KeyUp(&in_speed);}
153 void IN_StrafeDown(void) {KeyDown(&in_strafe);}
154 void IN_StrafeUp(void) {KeyUp(&in_strafe);}
155
156 void IN_AttackDown(void) {KeyDown(&in_attack);}
157 void IN_AttackUp(void) {KeyUp(&in_attack);}
158
159 void IN_UseDown(void) {KeyDown(&in_use);}
160 void IN_UseUp(void) {KeyUp(&in_use);}
161
162 // LordHavoc: added 6 new buttons
163 void IN_Button3Down(void) {KeyDown(&in_button3);}
164 void IN_Button3Up(void) {KeyUp(&in_button3);}
165 void IN_Button4Down(void) {KeyDown(&in_button4);}
166 void IN_Button4Up(void) {KeyUp(&in_button4);}
167 void IN_Button5Down(void) {KeyDown(&in_button5);}
168 void IN_Button5Up(void) {KeyUp(&in_button5);}
169 void IN_Button6Down(void) {KeyDown(&in_button6);}
170 void IN_Button6Up(void) {KeyUp(&in_button6);}
171 void IN_Button7Down(void) {KeyDown(&in_button7);}
172 void IN_Button7Up(void) {KeyUp(&in_button7);}
173 void IN_Button8Down(void) {KeyDown(&in_button8);}
174 void IN_Button8Up(void) {KeyUp(&in_button8);}
175
176 void IN_JumpDown (void) {KeyDown(&in_jump);}
177 void IN_JumpUp (void) {KeyUp(&in_jump);}
178
179 void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
180
181 /*
182 ===============
183 CL_KeyState
184
185 Returns 0.25 if a key was pressed and released during the frame,
186 0.5 if it was pressed and held
187 0 if held then released, and
188 1.0 if held for the entire time
189 ===============
190 */
191 float CL_KeyState (kbutton_t *key)
192 {
193         float           val;
194         qboolean        impulsedown, impulseup, down;
195
196         impulsedown = key->state & 2;
197         impulseup = key->state & 4;
198         down = key->state & 1;
199         val = 0;
200
201         if (impulsedown && !impulseup)
202         {
203                 if (down)
204                         val = 0.5;      // pressed and held this frame
205                 else
206                         val = 0;        //      I_Error ();
207         }
208         if (impulseup && !impulsedown)
209         {
210                 if (down)
211                         val = 0;        //      I_Error ();
212                 else
213                         val = 0;        // released this frame
214         }
215         if (!impulsedown && !impulseup)
216         {
217                 if (down)
218                         val = 1.0;      // held the entire frame
219                 else
220                         val = 0;        // up the entire frame
221         }
222         if (impulsedown && impulseup)
223         {
224                 if (down)
225                         val = 0.75;     // released and re-pressed this frame
226                 else
227                         val = 0.25;     // pressed and released this frame
228         }
229
230         key->state &= 1;                // clear impulses
231
232         return val;
233 }
234
235
236
237
238 //==========================================================================
239
240 cvar_t cl_upspeed = {CVAR_SAVE, "cl_upspeed","400"};
241 cvar_t cl_forwardspeed = {CVAR_SAVE, "cl_forwardspeed","400"};
242 cvar_t cl_backspeed = {CVAR_SAVE, "cl_backspeed","400"};
243 cvar_t cl_sidespeed = {CVAR_SAVE, "cl_sidespeed","350"};
244
245 cvar_t cl_movespeedkey = {CVAR_SAVE, "cl_movespeedkey","2.0"};
246
247 cvar_t cl_yawspeed = {CVAR_SAVE, "cl_yawspeed","140"};
248 cvar_t cl_pitchspeed = {CVAR_SAVE, "cl_pitchspeed","150"};
249
250 cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5"};
251
252 cvar_t cl_movement = {CVAR_SAVE, "cl_movement", "0"};
253 cvar_t cl_movement_latency = {0, "cl_movement_latency", "0"};
254 cvar_t cl_movement_maxspeed = {0, "cl_movement_maxspeed", "320"};
255 cvar_t cl_movement_maxairspeed = {0, "cl_movement_maxairspeed", "30"};
256 cvar_t cl_movement_stopspeed = {0, "cl_movement_stopspeed", "100"};
257 cvar_t cl_movement_friction = {0, "cl_movement_friction", "4"};
258 cvar_t cl_movement_edgefriction = {0, "cl_movement_edgefriction", "2"};
259 cvar_t cl_movement_stepheight = {0, "cl_movement_stepheight", "18"};
260 cvar_t cl_movement_accelerate = {0, "cl_movement_accelerate", "10"};
261 cvar_t cl_gravity = {0, "cl_gravity", "800"};
262 cvar_t cl_slowmo = {0, "cl_slowmo", "1"};
263
264 cvar_t in_pitch_min = {0, "in_pitch_min", "-90"}; // quake used -70
265 cvar_t in_pitch_max = {0, "in_pitch_max", "90"}; // quake used 80
266
267 cvar_t m_filter = {CVAR_SAVE, "m_filter","0"};
268
269
270 /*
271 ================
272 CL_AdjustAngles
273
274 Moves the local angle positions
275 ================
276 */
277 void CL_AdjustAngles (void)
278 {
279         float   speed;
280         float   up, down;
281
282         if (in_speed.state & 1)
283                 speed = host_realframetime * cl_anglespeedkey.value;
284         else
285                 speed = host_realframetime;
286
287         if (!(in_strafe.state & 1))
288         {
289                 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
290                 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
291         }
292         if (in_klook.state & 1)
293         {
294                 V_StopPitchDrift ();
295                 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
296                 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
297         }
298
299         up = CL_KeyState (&in_lookup);
300         down = CL_KeyState(&in_lookdown);
301
302         cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
303         cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
304
305         if (up || down)
306                 V_StopPitchDrift ();
307
308         cl.viewangles[YAW] = ANGLEMOD(cl.viewangles[YAW]);
309         cl.viewangles[PITCH] = ANGLEMOD(cl.viewangles[PITCH]);
310         cl.viewangles[ROLL] = ANGLEMOD(cl.viewangles[ROLL]);
311         if (cl.viewangles[YAW] >= 180)
312                 cl.viewangles[YAW] -= 360;
313         if (cl.viewangles[PITCH] >= 180)
314                 cl.viewangles[PITCH] -= 360;
315         if (cl.viewangles[ROLL] >= 180)
316                 cl.viewangles[ROLL] -= 360;
317
318         cl.viewangles[PITCH] = bound (in_pitch_min.value, cl.viewangles[PITCH], in_pitch_max.value);
319         cl.viewangles[ROLL] = bound(-50, cl.viewangles[ROLL], 50);
320 }
321
322 qboolean cl_ignoremousemove = false;
323
324 /*
325 ================
326 CL_Move
327
328 Send the intended movement message to the server
329 ================
330 */
331 void CL_Move (void)
332 {
333         vec3_t temp;
334         float mx, my;
335         static float old_mouse_x = 0, old_mouse_y = 0;
336
337         // clamp before the move to prevent starting with bad angles
338         CL_AdjustAngles ();
339
340         // get basic movement from keyboard
341         // PRYDON_CLIENTCURSOR needs to survive basemove resets
342         VectorCopy (cl.cmd.cursor_screen, temp);
343         memset (&cl.cmd, 0, sizeof(cl.cmd));
344         VectorCopy (temp, cl.cmd.cursor_screen);
345
346         if (in_strafe.state & 1)
347         {
348                 cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
349                 cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
350         }
351
352         cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
353         cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
354
355         cl.cmd.upmove += cl_upspeed.value * CL_KeyState (&in_up);
356         cl.cmd.upmove -= cl_upspeed.value * CL_KeyState (&in_down);
357
358         if (! (in_klook.state & 1) )
359         {
360                 cl.cmd.forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
361                 cl.cmd.forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
362         }
363
364         // adjust for speed key
365         if (in_speed.state & 1)
366         {
367                 cl.cmd.forwardmove *= cl_movespeedkey.value;
368                 cl.cmd.sidemove *= cl_movespeedkey.value;
369                 cl.cmd.upmove *= cl_movespeedkey.value;
370         }
371
372         in_mouse_x = 0;
373         in_mouse_y = 0;
374
375         // allow mice or other external controllers to add to the move
376         IN_Move ();
377
378         // ignore a mouse move if mouse was activated/deactivated this frame
379         if (cl_ignoremousemove)
380         {
381                 cl_ignoremousemove = false;
382                 in_mouse_x = 0;
383                 in_mouse_y = 0;
384         }
385
386         // apply m_filter if it is on
387         mx = in_mouse_x;
388         my = in_mouse_y;
389         if (m_filter.integer)
390         {
391                 in_mouse_x = (mx + old_mouse_x) * 0.5;
392                 in_mouse_y = (my + old_mouse_y) * 0.5;
393         }
394         old_mouse_x = mx;
395         old_mouse_y = my;
396
397         // if not in menu, apply mouse move to viewangles/movement
398         if (in_client_mouse)
399         {
400                 if (cl_prydoncursor.integer)
401                 {
402                         // mouse interacting with the scene, mostly stationary view
403                         V_StopPitchDrift();
404                         cl.cmd.cursor_screen[0] += in_mouse_x * sensitivity.value / vid.width;
405                         cl.cmd.cursor_screen[1] += in_mouse_y * sensitivity.value / vid.height;
406                 }
407                 else if (in_strafe.state & 1)
408                 {
409                         // strafing mode, all looking is movement
410                         V_StopPitchDrift();
411                         cl.cmd.sidemove += m_side.value * in_mouse_x * sensitivity.value * cl.viewzoom;
412                         if (noclip_anglehack)
413                                 cl.cmd.upmove -= m_forward.value * in_mouse_y * sensitivity.value * cl.viewzoom;
414                         else
415                                 cl.cmd.forwardmove -= m_forward.value * in_mouse_y * sensitivity.value * cl.viewzoom;
416                 }
417                 else if ((in_mlook.state & 1) || freelook.integer)
418                 {
419                         // mouselook, lookstrafe causes turning to become strafing
420                         V_StopPitchDrift();
421                         if (lookstrafe.integer)
422                                 cl.cmd.sidemove += m_side.value * in_mouse_x * sensitivity.value * cl.viewzoom;
423                         else
424                                 cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * sensitivity.value * cl.viewzoom;
425                         cl.viewangles[PITCH] += m_pitch.value * in_mouse_y * sensitivity.value * cl.viewzoom;
426                 }
427                 else
428                 {
429                         // non-mouselook, yaw turning and forward/back movement
430                         cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * sensitivity.value * cl.viewzoom;
431                         cl.cmd.forwardmove -= m_forward.value * in_mouse_y * sensitivity.value * cl.viewzoom;
432                 }
433         }
434
435         // clamp after the move to prevent rendering with bad angles
436         CL_AdjustAngles ();
437 }
438
439 #include "cl_collision.h"
440
441 void CL_UpdatePrydonCursor(void)
442 {
443         vec3_t temp, scale;
444
445         if (!cl_prydoncursor.integer)
446                 VectorClear(cl.cmd.cursor_screen);
447
448         /*
449         if (cl.cmd.cursor_screen[0] < -1)
450         {
451                 cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - -1) * vid.width * sensitivity.value * cl.viewzoom;
452                 cl.cmd.cursor_screen[0] = -1;
453         }
454         if (cl.cmd.cursor_screen[0] > 1)
455         {
456                 cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - 1) * vid.width * sensitivity.value * cl.viewzoom;
457                 cl.cmd.cursor_screen[0] = 1;
458         }
459         if (cl.cmd.cursor_screen[1] < -1)
460         {
461                 cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - -1) * vid.height * sensitivity.value * cl.viewzoom;
462                 cl.cmd.cursor_screen[1] = -1;
463         }
464         if (cl.cmd.cursor_screen[1] > 1)
465         {
466                 cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - 1) * vid.height * sensitivity.value * cl.viewzoom;
467                 cl.cmd.cursor_screen[1] = 1;
468         }
469         */
470         cl.cmd.cursor_screen[0] = bound(-1, cl.cmd.cursor_screen[0], 1);
471         cl.cmd.cursor_screen[1] = bound(-1, cl.cmd.cursor_screen[1], 1);
472         cl.cmd.cursor_screen[2] = 1;
473
474         scale[0] = -tan(r_refdef.fov_x * M_PI / 360.0);
475         scale[1] = -tan(r_refdef.fov_y * M_PI / 360.0);
476         scale[2] = 1;
477
478         // trace distance
479         VectorScale(scale, 1000000, scale);
480
481         // FIXME: use something other than renderer variables here
482         // (but they need to match)
483         VectorCopy(r_vieworigin, cl.cmd.cursor_start);
484         VectorSet(temp, cl.cmd.cursor_screen[2] * scale[2], cl.cmd.cursor_screen[0] * scale[0], cl.cmd.cursor_screen[1] * scale[1]);
485         Matrix4x4_Transform(&r_view_matrix, temp, cl.cmd.cursor_end);
486         cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber, (chase_active.integer || cl.intermission) ? &cl_entities[cl.playerentity].render : NULL);
487         // makes sparks where cursor is
488         //CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0);
489 }
490
491 void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
492 {
493         int i;
494         int n;
495         int bump;
496         int contents;
497         int crouch;
498         double edgefriction;
499         double simulatedtime;
500         double currenttime;
501         double newtime;
502         double frametime;
503         double t;
504         vec_t wishspeed;
505         vec_t addspeed;
506         vec_t accelspeed;
507         vec_t f;
508         vec_t *playermins;
509         vec_t *playermaxs;
510         vec3_t currentorigin;
511         vec3_t currentvelocity;
512         vec3_t forward;
513         vec3_t right;
514         vec3_t up;
515         vec3_t wishvel;
516         vec3_t wishdir;
517         vec3_t neworigin;
518         vec3_t currentorigin2;
519         vec3_t neworigin2;
520         vec3_t yawangles;
521         trace_t trace;
522         trace_t trace2;
523         trace_t trace3;
524         // remove stale queue items
525         n = cl.movement_numqueue;
526         cl.movement_numqueue = 0;
527         // calculate time to execute for
528         currenttime = cl.mtime[0];
529         simulatedtime = currenttime + cl_movement_latency.value / 1000.0;
530         for (i = 0;i < n;i++)
531                 if (cl.movement_queue[i].time >= cl.mtime[0] && cl.movement_queue[i].time <= simulatedtime)
532                         cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
533         // add to input queue if there is room
534         if (cl.movement_numqueue < sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0]))
535         {
536                 // add to input queue
537                 cl.movement_queue[cl.movement_numqueue].time = simulatedtime;
538                 VectorCopy(cl.viewangles, cl.movement_queue[cl.movement_numqueue].viewangles);
539                 cl.movement_queue[cl.movement_numqueue].move[0] = cl.cmd.forwardmove;
540                 cl.movement_queue[cl.movement_numqueue].move[1] = cl.cmd.sidemove;
541                 cl.movement_queue[cl.movement_numqueue].move[2] = cl.cmd.upmove;
542                 cl.movement_queue[cl.movement_numqueue].jump = buttonjump;
543                 cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch;
544                 cl.movement_numqueue++;
545         }
546         // fetch current starting values
547         VectorCopy(cl_entities[cl.playerentity].state_current.origin, currentorigin);
548         VectorCopy(cl.mvelocity[0], currentvelocity);
549         // FIXME: try minor nudges in various directions if startsolid to find a
550         // safe place to start the walk (due to network compression in some
551         // protocols this starts in solid)
552         //currentorigin[2] += (1.0 / 32.0); // slight nudge to get out of the floor
553         crouch = false; // this will be updated on first move
554         //Con_Printf("%f: ", currenttime);
555         // replay input queue, and remove any stale queue items
556         // note: this relies on the fact there's always one queue item at the end
557         // abort if client movement is disabled
558         cl.movement = cl_movement.integer && cl.stats[STAT_HEALTH] > 0 && !cls.demoplayback;
559         if (!cl.movement)
560                 cl.movement_numqueue = 0;
561         for (i = 0;i <= cl.movement_numqueue;i++)
562         {
563                 newtime = (i >= cl.movement_numqueue) ? simulatedtime : cl.movement_queue[i].time;
564                 frametime = newtime - currenttime;
565                 if (frametime <= 0)
566                         continue;
567                 //Con_Printf(" %f", frametime);
568                 currenttime = newtime;
569                 if (i >= 1 && i <= cl.movement_numqueue)
570                 if (i > 0 || (cl_movement.integer & 8))
571                 if (i < cl.movement_numqueue - 1 || (cl_movement.integer & 16))
572                 {
573                         client_movementqueue_t *q = cl.movement_queue + i - 1;
574                         if (q->crouch)
575                         {
576                                 // wants to crouch, this always works...
577                                 if (!crouch)
578                                         crouch = true;
579                         }
580                         else
581                         {
582                                 // wants to stand, if currently crouching we need to check for a
583                                 // low ceiling first
584                                 if (crouch)
585                                 {
586                                         trace = CL_TraceBox(currentorigin, cl_playerstandmins, cl_playerstandmaxs, currentorigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
587                                         if (!trace.startsolid)
588                                                 crouch = false;
589                                 }
590                         }
591                         if (crouch)
592                         {
593                                 playermins = cl_playercrouchmins;
594                                 playermaxs = cl_playercrouchmaxs;
595                         }
596                         else
597                         {
598                                 playermins = cl_playerstandmins;
599                                 playermaxs = cl_playerstandmaxs;
600                         }
601                         // change velocity according to q->viewangles and q->move
602                         contents = CL_PointSuperContents(currentorigin);
603                         if (contents & SUPERCONTENTS_LIQUIDSMASK)
604                         {
605                                 // swim
606                                 AngleVectors(q->viewangles, forward, right, up);
607                                 VectorSet(up, 0, 0, 1);
608                                 VectorMAMAM(q->move[0], forward, q->move[1], right, q->move[2], up, wishvel);
609                                 wishspeed = VectorLength(wishvel);
610                                 if (wishspeed)
611                                         VectorScale(wishvel, 1 / wishspeed, wishdir);
612                                 wishspeed = min(wishspeed, cl_movement_maxspeed.value);
613                                 if (crouch)
614                                         wishspeed *= 0.5;
615                                 wishspeed *= 0.6;
616                                 VectorScale(currentvelocity, (1 - frametime * cl_movement_friction.value), currentvelocity);
617                                 f = wishspeed - DotProduct(currentvelocity, wishdir);
618                                 if (f > 0)
619                                 {
620                                         f = min(f, cl_movement_accelerate.value * frametime * wishspeed);
621                                         VectorMA(currentvelocity, f, wishdir, currentvelocity);
622                                 }
623                                 if (q->jump)
624                                 {
625                                         if (contents & SUPERCONTENTS_LAVA)
626                                                 currentvelocity[2] =  50;
627                                         else if (contents & SUPERCONTENTS_SLIME)
628                                                 currentvelocity[2] =  80;
629                                         else
630                                         {
631                                                 if (gamemode == GAME_NEXUIZ)
632                                                         currentvelocity[2] = 200;
633                                                 else
634                                                         currentvelocity[2] = 100;
635                                         }
636                                 }
637                         }
638                         else
639                         {
640                                 // walk
641                                 VectorSet(yawangles, 0, cl.viewangles[1], 0);
642                                 AngleVectors(yawangles, forward, right, up);
643                                 VectorMAM(q->move[0], forward, q->move[1], right, wishvel);
644                                 wishspeed = VectorLength(wishvel);
645                                 if (wishspeed)
646                                         VectorScale(wishvel, 1 / wishspeed, wishdir);
647                                 wishspeed = min(wishspeed, cl_movement_maxspeed.value);
648                                 if (crouch)
649                                         wishspeed *= 0.5;
650                                 // check if onground
651                                 VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + 1);
652                                 VectorSet(neworigin2, currentorigin[0], currentorigin[1], currentorigin[2] - 1);
653                                 trace = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
654                                 if (trace.fraction < 1 && trace.plane.normal[2] > 0.7)
655                                 {
656                                         // apply ground friction
657                                         f = sqrt(currentvelocity[0] * currentvelocity[0] + currentvelocity[1] * currentvelocity[1]);
658                                         edgefriction = 1;
659                                         if (f > 0)
660                                         {
661                                                 VectorSet(currentorigin2, currentorigin[0] + currentvelocity[0]*(16/f), currentorigin[1] + currentvelocity[1]*(16/f), currentorigin[2] + playermins[2]);
662                                                 VectorSet(neworigin2, currentorigin2[0], currentorigin2[1], currentorigin2[2] - 34);
663                                                 trace = CL_TraceBox(currentorigin2, vec3_origin, vec3_origin, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
664                                                 if (trace.fraction == 1)
665                                                         edgefriction = cl_movement_edgefriction.value;
666                                         }
667                                         // apply friction
668                                         f = 1 - frametime * edgefriction * ((f < cl_movement_stopspeed.value) ? (cl_movement_stopspeed.value / f) : 1) * cl_movement_friction.value;
669                                         f = max(f, 0);
670                                         VectorScale(currentvelocity, f, currentvelocity);
671                                 }
672                                 else
673                                 {
674                                         // apply air speed limit
675                                         wishspeed = min(wishspeed, cl_movement_maxairspeed.value);
676                                 }
677                                 if (gamemode == GAME_NEXUIZ)
678                                         addspeed = wishspeed;
679                                 else
680                                         addspeed = wishspeed - DotProduct(currentvelocity, wishdir);
681                                 if (addspeed > 0)
682                                 {
683                                         accelspeed = min(cl_movement_accelerate.value * frametime * wishspeed, addspeed);
684                                         VectorMA(currentvelocity, accelspeed, wishdir, currentvelocity);
685                                 }
686                                 currentvelocity[2] -= cl_gravity.value * frametime;
687                         }
688                 }
689                 if (i > 0 || (cl_movement.integer & 2))
690                 if (i < cl.movement_numqueue - 1 || (cl_movement.integer & 4))
691                 {
692                         if (crouch)
693                         {
694                                 playermins = cl_playercrouchmins;
695                                 playermaxs = cl_playercrouchmaxs;
696                         }
697                         else
698                         {
699                                 playermins = cl_playerstandmins;
700                                 playermaxs = cl_playerstandmaxs;
701                         }
702                         for (bump = 0, t = frametime;bump < 8 && VectorLength2(currentvelocity) > 0;bump++)
703                         {
704                                 VectorMA(currentorigin, t, currentvelocity, neworigin);
705                                 trace = CL_TraceBox(currentorigin, playermins, playermaxs, neworigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
706                                 if (trace.fraction < 1 && trace.plane.normal[2] == 0)
707                                 {
708                                         // may be a step or wall, try stepping up
709                                         // first move forward at a higher level
710                                         VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + cl_movement_stepheight.value);
711                                         VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + cl_movement_stepheight.value);
712                                         trace2 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
713                                         // then move down from there
714                                         VectorCopy(trace2.endpos, currentorigin2);
715                                         VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], currentorigin[2]);
716                                         trace3 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
717                                         //Con_Printf("%f %f %f %f : %f %f %f %f : %f %f %f %f\n", trace.fraction, trace.endpos[0], trace.endpos[1], trace.endpos[2], trace2.fraction, trace2.endpos[0], trace2.endpos[1], trace2.endpos[2], trace3.fraction, trace3.endpos[0], trace3.endpos[1], trace3.endpos[2]);
718                                         // accept the new trace if it made some progress
719                                         if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125)
720                                         {
721                                                 trace = trace2;
722                                                 VectorCopy(trace3.endpos, trace.endpos);
723                                         }
724                                 }
725                                 if (trace.fraction == 1)
726                                 {
727                                         VectorCopy(trace.endpos, currentorigin);
728                                         break;
729                                 }
730                                 t *= 1 - trace.fraction;
731                                 if (trace.fraction >= 0.001)
732                                         VectorCopy(trace.endpos, currentorigin);
733                                 f = DotProduct(currentvelocity, trace.plane.normal);
734                                 VectorMA(currentvelocity, -f, trace.plane.normal, currentvelocity);
735                         }
736                 }
737         }
738         //Con_Printf(" :%f\n", currenttime);
739         // store replay location
740         VectorCopy(cl.movement_origin, cl.movement_oldorigin);
741         VectorCopy(currentorigin, cl.movement_origin);
742         VectorCopy(currentvelocity, cl.movement_velocity);
743         //VectorCopy(currentorigin, cl_entities[cl.playerentity].state_current.origin);
744         //VectorSet(cl_entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
745 }
746
747 /*
748 ==============
749 CL_SendMove
750 ==============
751 */
752 void CL_SendMove(void)
753 {
754         int i;
755         int bits;
756         sizebuf_t buf;
757         qbyte data[128];
758 #define MOVEAVERAGING 0
759 #if MOVEAVERAGING
760         static float forwardmove, sidemove, upmove, total; // accumulation
761 #else
762         float forwardmove, sidemove, upmove;
763 #endif
764
765 #if MOVEAVERAGING
766         // accumulate changes between messages
767         forwardmove += cl.cmd.forwardmove;
768         sidemove += cl.cmd.sidemove;
769         upmove += cl.cmd.upmove;
770         total++;
771 #endif
772         if (cls.signon != SIGNONS)
773                 return;
774 #if MOVEAVERAGING
775         // average the accumulated changes
776         total = 1.0f / total;
777         forwardmove *= total;
778         sidemove *= total;
779         upmove *= total;
780         total = 0;
781 #else
782         // use the latest values
783         forwardmove = cl.cmd.forwardmove;
784         sidemove = cl.cmd.sidemove;
785         upmove = cl.cmd.upmove;
786 #endif
787
788         buf.maxsize = 128;
789         buf.cursize = 0;
790         buf.data = data;
791
792         // set button bits
793         // LordHavoc: added 6 new buttons and use and chat buttons, and prydon cursor active button
794         bits = 0;
795         if (in_attack.state   & 3) bits |=   1;in_attack.state  &= ~2;
796         if (in_jump.state     & 3) bits |=   2;in_jump.state    &= ~2;
797         if (in_button3.state  & 3) bits |=   4;in_button3.state &= ~2;
798         if (in_button4.state  & 3) bits |=   8;in_button4.state &= ~2;
799         if (in_button5.state  & 3) bits |=  16;in_button5.state &= ~2;
800         if (in_button6.state  & 3) bits |=  32;in_button6.state &= ~2;
801         if (in_button7.state  & 3) bits |=  64;in_button7.state &= ~2;
802         if (in_button8.state  & 3) bits |= 128;in_button8.state &= ~2;
803         if (in_use.state      & 3) bits |= 256;in_use.state     &= ~2;
804         if (key_dest != key_game || key_consoleactive) bits |= 512;
805         if (cl_prydoncursor.integer) bits |= 1024;
806         // button bits 11-31 unused currently
807         // rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen
808         if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
809         if (cl.cmd.cursor_screen[0] >=  1) bits |= 16;
810         if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
811         if (cl.cmd.cursor_screen[1] >=  1) bits |= 64;
812
813         // always dump the first two messages, because they may contain leftover inputs from the last level
814         if (++cl.movemessages >= 2)
815         {
816                 // send the movement message
817                 // PROTOCOL_QUAKE       clc_move = 16 bytes total
818                 // PROTOCOL_DARKPLACES1 clc_move = 19 bytes total
819                 // PROTOCOL_DARKPLACES2 clc_move = 25 bytes total
820                 // PROTOCOL_DARKPLACES3 clc_move = 25 bytes total
821                 // PROTOCOL_DARKPLACES4 clc_move = 19 bytes total
822                 // PROTOCOL_DARKPLACES5 clc_move = 19 bytes total
823                 // PROTOCOL_DARKPLACES6 clc_move = 52 bytes total
824                 // 5 bytes
825                 MSG_WriteByte (&buf, clc_move);
826                 MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
827                 if (cl.protocol == PROTOCOL_DARKPLACES6)
828                 {
829                         // 6 bytes
830                         for (i = 0;i < 3;i++)
831                                 MSG_WriteAngle16i (&buf, cl.viewangles[i]);
832                         // 6 bytes
833                         MSG_WriteCoord16i (&buf, forwardmove);
834                         MSG_WriteCoord16i (&buf, sidemove);
835                         MSG_WriteCoord16i (&buf, upmove);
836                         // 5 bytes
837                         MSG_WriteLong (&buf, bits);
838                         MSG_WriteByte (&buf, in_impulse);
839                         // PRYDON_CLIENTCURSOR
840                         // 30 bytes
841                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[0] * 32767.0f);
842                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[1] * 32767.0f);
843                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[0]);
844                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[1]);
845                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[2]);
846                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[0]);
847                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[1]);
848                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
849                         MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
850                 }
851                 else
852                 {
853                         if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
854                         {
855                                 // 3 bytes
856                                 for (i = 0;i < 3;i++)
857                                         MSG_WriteAngle8i (&buf, cl.viewangles[i]);
858                         }
859                         else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
860                         {
861                                 // 12 bytes
862                                 for (i = 0;i < 3;i++)
863                                         MSG_WriteAngle32f (&buf, cl.viewangles[i]);
864                         }
865                         else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
866                         {
867                                 // 6 bytes
868                                 for (i = 0;i < 3;i++)
869                                         MSG_WriteAngle16i (&buf, cl.viewangles[i]);
870                         }
871                         else
872                                 Host_Error("CL_SendMove: unknown cl.protocol %i\n", cl.protocol);
873                         // 6 bytes
874                         MSG_WriteCoord16i (&buf, forwardmove);
875                         MSG_WriteCoord16i (&buf, sidemove);
876                         MSG_WriteCoord16i (&buf, upmove);
877                         // 2 bytes
878                         MSG_WriteByte (&buf, bits);
879                         MSG_WriteByte (&buf, in_impulse);
880                 }
881         }
882
883 #if MOVEAVERAGING
884         forwardmove = sidemove = upmove = 0;
885 #endif
886         in_impulse = 0;
887
888         // ack the last few frame numbers
889         // (redundent to improve handling of client->server packet loss)
890         // for LATESTFRAMENUMS == 3 case this is 15 bytes
891         for (i = 0;i < LATESTFRAMENUMS;i++)
892         {
893                 if (cl.latestframenums[i] > 0)
894                 {
895                         if (developer_networkentities.integer >= 1)
896                                 Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
897                         MSG_WriteByte(&buf, clc_ackframe);
898                         MSG_WriteLong(&buf, cl.latestframenums[i]);
899                 }
900         }
901
902         // PROTOCOL_DARKPLACES6 = 67 bytes per packet
903
904         // deliver the message
905         if (cls.demoplayback)
906                 return;
907         // nothing to send
908         if (!buf.cursize)
909                 return;
910
911         // FIXME: bits & 64 is +button5, Nexuiz specific
912         CL_ClientMovement((bits & 2) != 0, (bits & 64) != 0);
913
914         if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
915         {
916                 Con_Print("CL_SendMove: lost server connection\n");
917                 CL_Disconnect();
918                 Host_ShutdownServer(false);
919         }
920 }
921
922 /*
923 ============
924 CL_InitInput
925 ============
926 */
927 void CL_InitInput (void)
928 {
929         Cmd_AddCommand ("+moveup",IN_UpDown);
930         Cmd_AddCommand ("-moveup",IN_UpUp);
931         Cmd_AddCommand ("+movedown",IN_DownDown);
932         Cmd_AddCommand ("-movedown",IN_DownUp);
933         Cmd_AddCommand ("+left",IN_LeftDown);
934         Cmd_AddCommand ("-left",IN_LeftUp);
935         Cmd_AddCommand ("+right",IN_RightDown);
936         Cmd_AddCommand ("-right",IN_RightUp);
937         Cmd_AddCommand ("+forward",IN_ForwardDown);
938         Cmd_AddCommand ("-forward",IN_ForwardUp);
939         Cmd_AddCommand ("+back",IN_BackDown);
940         Cmd_AddCommand ("-back",IN_BackUp);
941         Cmd_AddCommand ("+lookup", IN_LookupDown);
942         Cmd_AddCommand ("-lookup", IN_LookupUp);
943         Cmd_AddCommand ("+lookdown", IN_LookdownDown);
944         Cmd_AddCommand ("-lookdown", IN_LookdownUp);
945         Cmd_AddCommand ("+strafe", IN_StrafeDown);
946         Cmd_AddCommand ("-strafe", IN_StrafeUp);
947         Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
948         Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
949         Cmd_AddCommand ("+moveright", IN_MoverightDown);
950         Cmd_AddCommand ("-moveright", IN_MoverightUp);
951         Cmd_AddCommand ("+speed", IN_SpeedDown);
952         Cmd_AddCommand ("-speed", IN_SpeedUp);
953         Cmd_AddCommand ("+attack", IN_AttackDown);
954         Cmd_AddCommand ("-attack", IN_AttackUp);
955         Cmd_AddCommand ("+jump", IN_JumpDown);
956         Cmd_AddCommand ("-jump", IN_JumpUp);
957         Cmd_AddCommand ("impulse", IN_Impulse);
958         Cmd_AddCommand ("+klook", IN_KLookDown);
959         Cmd_AddCommand ("-klook", IN_KLookUp);
960         Cmd_AddCommand ("+mlook", IN_MLookDown);
961         Cmd_AddCommand ("-mlook", IN_MLookUp);
962
963         // LordHavoc: added use button
964         Cmd_AddCommand ("+use", IN_UseDown);
965         Cmd_AddCommand ("-use", IN_UseUp);
966
967         // LordHavoc: added 6 new buttons
968         Cmd_AddCommand ("+button3", IN_Button3Down);
969         Cmd_AddCommand ("-button3", IN_Button3Up);
970         Cmd_AddCommand ("+button4", IN_Button4Down);
971         Cmd_AddCommand ("-button4", IN_Button4Up);
972         Cmd_AddCommand ("+button5", IN_Button5Down);
973         Cmd_AddCommand ("-button5", IN_Button5Up);
974         Cmd_AddCommand ("+button6", IN_Button6Down);
975         Cmd_AddCommand ("-button6", IN_Button6Up);
976         Cmd_AddCommand ("+button7", IN_Button7Down);
977         Cmd_AddCommand ("-button7", IN_Button7Up);
978         Cmd_AddCommand ("+button8", IN_Button8Down);
979         Cmd_AddCommand ("-button8", IN_Button8Up);
980
981         Cvar_RegisterVariable(&cl_movement);
982         Cvar_RegisterVariable(&cl_movement_latency);
983         Cvar_RegisterVariable(&cl_movement_maxspeed);
984         Cvar_RegisterVariable(&cl_movement_maxairspeed);
985         Cvar_RegisterVariable(&cl_movement_stopspeed);
986         Cvar_RegisterVariable(&cl_movement_friction);
987         Cvar_RegisterVariable(&cl_movement_edgefriction);
988         Cvar_RegisterVariable(&cl_movement_stepheight);
989         Cvar_RegisterVariable(&cl_movement_accelerate);
990         Cvar_RegisterVariable(&cl_gravity);
991         Cvar_RegisterVariable(&cl_slowmo);
992
993         Cvar_RegisterVariable(&in_pitch_min);
994         Cvar_RegisterVariable(&in_pitch_max);
995         Cvar_RegisterVariable(&m_filter);
996 }
997