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