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