]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_input.c
added button9-16
[divverent/darkplaces.git] / cl_input.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // cl.input.c  -- builds an intended movement command to send to the server
21
22 // Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
23 // rights reserved.
24
25 #include "quakedef.h"
26
27 /*
28 ===============================================================================
29
30 KEY BUTTONS
31
32 Continuous button event tracking is complicated by the fact that two different
33 input sources (say, mouse button 1 and the control key) can both press the
34 same button, but the button should only be released when both of the
35 pressing key have been released.
36
37 When a key event issues a button command (+forward, +attack, etc), it appends
38 its key number as a parameter to the command so it can be matched up with
39 the release.
40
41 state bit 0 is the current state of the key
42 state bit 1 is edge triggered on the up to down transition
43 state bit 2 is edge triggered on the down to up transition
44
45 ===============================================================================
46 */
47
48
49 kbutton_t       in_mlook, in_klook;
50 kbutton_t       in_left, in_right, in_forward, in_back;
51 kbutton_t       in_lookup, in_lookdown, in_moveleft, in_moveright;
52 kbutton_t       in_strafe, in_speed, in_jump, in_attack, in_use;
53 kbutton_t       in_up, in_down;
54 // LordHavoc: added 6 new buttons
55 kbutton_t       in_button3, in_button4, in_button5, in_button6, in_button7, in_button8;
56 //even more
57 kbutton_t       in_button9, in_button10, in_button11, in_button12, in_button13, in_button14, in_button15, in_button16;
58
59 int                     in_impulse;
60
61 extern cvar_t sys_ticrate;
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"};
260 cvar_t cl_forwardspeed = {CVAR_SAVE, "cl_forwardspeed","400"};
261 cvar_t cl_backspeed = {CVAR_SAVE, "cl_backspeed","400"};
262 cvar_t cl_sidespeed = {CVAR_SAVE, "cl_sidespeed","350"};
263
264 cvar_t cl_movespeedkey = {CVAR_SAVE, "cl_movespeedkey","2.0"};
265
266 cvar_t cl_yawspeed = {CVAR_SAVE, "cl_yawspeed","140"};
267 cvar_t cl_pitchspeed = {CVAR_SAVE, "cl_pitchspeed","150"};
268
269 cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5"};
270
271 cvar_t cl_movement = {CVAR_SAVE, "cl_movement", "0"};
272 cvar_t cl_movement_latency = {0, "cl_movement_latency", "0"};
273 cvar_t cl_movement_maxspeed = {0, "cl_movement_maxspeed", "320"};
274 cvar_t cl_movement_maxairspeed = {0, "cl_movement_maxairspeed", "30"};
275 cvar_t cl_movement_stopspeed = {0, "cl_movement_stopspeed", "100"};
276 cvar_t cl_movement_friction = {0, "cl_movement_friction", "4"};
277 cvar_t cl_movement_edgefriction = {0, "cl_movement_edgefriction", "2"};
278 cvar_t cl_movement_stepheight = {0, "cl_movement_stepheight", "18"};
279 cvar_t cl_movement_accelerate = {0, "cl_movement_accelerate", "10"};
280 cvar_t cl_movement_jumpvelocity = {0, "cl_movement_jumpvelocity", "270"};
281 cvar_t cl_gravity = {0, "cl_gravity", "800"};
282 cvar_t cl_slowmo = {0, "cl_slowmo", "1"};
283
284 cvar_t in_pitch_min = {0, "in_pitch_min", "-90"}; // quake used -70
285 cvar_t in_pitch_max = {0, "in_pitch_max", "90"}; // quake used 80
286
287 cvar_t m_filter = {CVAR_SAVE, "m_filter","0"};
288
289
290 /*
291 ================
292 CL_AdjustAngles
293
294 Moves the local angle positions
295 ================
296 */
297 void CL_AdjustAngles (void)
298 {
299         float   speed;
300         float   up, down;
301
302         if (in_speed.state & 1)
303                 speed = host_realframetime * cl_anglespeedkey.value;
304         else
305                 speed = host_realframetime;
306
307         if (!(in_strafe.state & 1))
308         {
309                 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
310                 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
311         }
312         if (in_klook.state & 1)
313         {
314                 V_StopPitchDrift ();
315                 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
316                 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
317         }
318
319         up = CL_KeyState (&in_lookup);
320         down = CL_KeyState(&in_lookdown);
321
322         cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
323         cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
324
325         if (up || down)
326                 V_StopPitchDrift ();
327
328         cl.viewangles[YAW] = ANGLEMOD(cl.viewangles[YAW]);
329         cl.viewangles[PITCH] = ANGLEMOD(cl.viewangles[PITCH]);
330         cl.viewangles[ROLL] = ANGLEMOD(cl.viewangles[ROLL]);
331         if (cl.viewangles[YAW] >= 180)
332                 cl.viewangles[YAW] -= 360;
333         if (cl.viewangles[PITCH] >= 180)
334                 cl.viewangles[PITCH] -= 360;
335         if (cl.viewangles[ROLL] >= 180)
336                 cl.viewangles[ROLL] -= 360;
337
338         cl.viewangles[PITCH] = bound (in_pitch_min.value, cl.viewangles[PITCH], in_pitch_max.value);
339         cl.viewangles[ROLL] = bound(-50, cl.viewangles[ROLL], 50);
340 }
341
342 qboolean cl_ignoremousemove = false;
343
344 /*
345 ================
346 CL_Move
347
348 Send the intended movement message to the server
349 ================
350 */
351 void CL_Move (void)
352 {
353         vec3_t temp;
354         float mx, my;
355         static float old_mouse_x = 0, old_mouse_y = 0;
356
357         // clamp before the move to prevent starting with bad angles
358         CL_AdjustAngles ();
359
360         // get basic movement from keyboard
361         // PRYDON_CLIENTCURSOR needs to survive basemove resets
362         VectorCopy (cl.cmd.cursor_screen, temp);
363         memset (&cl.cmd, 0, sizeof(cl.cmd));
364         VectorCopy (temp, cl.cmd.cursor_screen);
365
366         if (in_strafe.state & 1)
367         {
368                 cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
369                 cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
370         }
371
372         cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
373         cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
374
375         cl.cmd.upmove += cl_upspeed.value * CL_KeyState (&in_up);
376         cl.cmd.upmove -= cl_upspeed.value * CL_KeyState (&in_down);
377
378         if (! (in_klook.state & 1) )
379         {
380                 cl.cmd.forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
381                 cl.cmd.forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
382         }
383
384         // adjust for speed key
385         if (in_speed.state & 1)
386         {
387                 cl.cmd.forwardmove *= cl_movespeedkey.value;
388                 cl.cmd.sidemove *= cl_movespeedkey.value;
389                 cl.cmd.upmove *= cl_movespeedkey.value;
390         }
391
392         in_mouse_x = 0;
393         in_mouse_y = 0;
394
395         // allow mice or other external controllers to add to the move
396         IN_Move ();
397
398         // ignore a mouse move if mouse was activated/deactivated this frame
399         if (cl_ignoremousemove)
400         {
401                 cl_ignoremousemove = false;
402                 in_mouse_x = 0;
403                 in_mouse_y = 0;
404         }
405
406         // apply m_filter if it is on
407         mx = in_mouse_x;
408         my = in_mouse_y;
409         if (m_filter.integer)
410         {
411                 in_mouse_x = (mx + old_mouse_x) * 0.5;
412                 in_mouse_y = (my + old_mouse_y) * 0.5;
413         }
414         old_mouse_x = mx;
415         old_mouse_y = my;
416
417         // if not in menu, apply mouse move to viewangles/movement
418         if (in_client_mouse)
419         {
420                 if (cl_prydoncursor.integer)
421                 {
422                         // mouse interacting with the scene, mostly stationary view
423                         V_StopPitchDrift();
424                         cl.cmd.cursor_screen[0] += in_mouse_x * sensitivity.value / vid.width;
425                         cl.cmd.cursor_screen[1] += in_mouse_y * sensitivity.value / vid.height;
426                 }
427                 else if (in_strafe.state & 1)
428                 {
429                         // strafing mode, all looking is movement
430                         V_StopPitchDrift();
431                         cl.cmd.sidemove += m_side.value * in_mouse_x * sensitivity.value;
432                         if (noclip_anglehack)
433                                 cl.cmd.upmove -= m_forward.value * in_mouse_y * sensitivity.value;
434                         else
435                                 cl.cmd.forwardmove -= m_forward.value * in_mouse_y * sensitivity.value;
436                 }
437                 else if ((in_mlook.state & 1) || freelook.integer)
438                 {
439                         // mouselook, lookstrafe causes turning to become strafing
440                         V_StopPitchDrift();
441                         if (lookstrafe.integer)
442                                 cl.cmd.sidemove += m_side.value * in_mouse_x * sensitivity.value;
443                         else
444                                 cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * sensitivity.value * cl.viewzoom;
445                         cl.viewangles[PITCH] += m_pitch.value * in_mouse_y * sensitivity.value * cl.viewzoom;
446                 }
447                 else
448                 {
449                         // non-mouselook, yaw turning and forward/back movement
450                         cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * sensitivity.value * cl.viewzoom;
451                         cl.cmd.forwardmove -= m_forward.value * in_mouse_y * sensitivity.value;
452                 }
453         }
454
455         // clamp after the move to prevent rendering with bad angles
456         CL_AdjustAngles ();
457 }
458
459 #include "cl_collision.h"
460
461 extern void V_CalcRefdef(void);
462 void CL_UpdatePrydonCursor(void)
463 {
464         vec3_t temp, scale;
465
466         if (!cl_prydoncursor.integer)
467                 VectorClear(cl.cmd.cursor_screen);
468
469         /*
470         if (cl.cmd.cursor_screen[0] < -1)
471         {
472                 cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - -1) * vid.width * sensitivity.value * cl.viewzoom;
473                 cl.cmd.cursor_screen[0] = -1;
474         }
475         if (cl.cmd.cursor_screen[0] > 1)
476         {
477                 cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - 1) * vid.width * sensitivity.value * cl.viewzoom;
478                 cl.cmd.cursor_screen[0] = 1;
479         }
480         if (cl.cmd.cursor_screen[1] < -1)
481         {
482                 cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - -1) * vid.height * sensitivity.value * cl.viewzoom;
483                 cl.cmd.cursor_screen[1] = -1;
484         }
485         if (cl.cmd.cursor_screen[1] > 1)
486         {
487                 cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - 1) * vid.height * sensitivity.value * cl.viewzoom;
488                 cl.cmd.cursor_screen[1] = 1;
489         }
490         */
491         cl.cmd.cursor_screen[0] = bound(-1, cl.cmd.cursor_screen[0], 1);
492         cl.cmd.cursor_screen[1] = bound(-1, cl.cmd.cursor_screen[1], 1);
493         cl.cmd.cursor_screen[2] = 1;
494
495         scale[0] = -r_refdef.frustum_x;
496         scale[1] = -r_refdef.frustum_y;
497         scale[2] = 1;
498
499         // trace distance
500         VectorScale(scale, 1000000, scale);
501
502         // calculate current view matrix
503         V_CalcRefdef();
504         VectorClear(temp);
505         Matrix4x4_Transform(&r_refdef.viewentitymatrix, temp, cl.cmd.cursor_start);
506         VectorSet(temp, cl.cmd.cursor_screen[2] * scale[2], cl.cmd.cursor_screen[0] * scale[0], cl.cmd.cursor_screen[1] * scale[1]);
507         Matrix4x4_Transform(&r_refdef.viewentitymatrix, temp, cl.cmd.cursor_end);
508         // trace from view origin to the cursor
509         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);
510         // makes sparks where cursor is
511         //CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0);
512 }
513
514 void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
515 {
516         int i;
517         int n;
518         // remove stale queue items
519         n = cl.movement_numqueue;
520         cl.movement_numqueue = 0;
521         if (cl.servermovesequence)
522         {
523                 for (i = 0;i < n;i++)
524                         if (cl.movement_queue[i].sequence > cl.servermovesequence)
525                                 cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
526         }
527         else
528         {
529                 double simulatedtime = cl.mtime[0] + cl_movement_latency.value / 1000.0;
530                 for (i = 0;i < n;i++)
531                         if (cl.movement_queue[i].time >= cl.mtime[0] && cl.movement_queue[i].time <= simulatedtime)
532                                 cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
533         }
534         // add to input queue if there is room
535         if (cl_movement.integer && cl.movement_numqueue < (int)(sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0])) && cl.mtime[0] > cl.mtime[1])
536         {
537                 // add to input queue
538                 cl.movement_queue[cl.movement_numqueue].sequence = cl.movesequence;
539                 cl.movement_queue[cl.movement_numqueue].time = cl.mtime[0] + cl_movement_latency.value / 1000.0;
540                 cl.movement_queue[cl.movement_numqueue].frametime = cl.mtime[0] - cl.mtime[1];
541                 VectorCopy(cl.viewangles, cl.movement_queue[cl.movement_numqueue].viewangles);
542                 cl.movement_queue[cl.movement_numqueue].move[0] = cl.cmd.forwardmove;
543                 cl.movement_queue[cl.movement_numqueue].move[1] = cl.cmd.sidemove;
544                 cl.movement_queue[cl.movement_numqueue].move[2] = cl.cmd.upmove;
545                 cl.movement_queue[cl.movement_numqueue].jump = buttonjump;
546                 cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch;
547                 cl.movement_numqueue++;
548         }
549         cl.movement = cl_movement.integer && cl.stats[STAT_HEALTH] > 0 && !cls.demoplayback && !cl.intermission;
550         // clear queue if client movement is disabled
551         if (!cl.movement)
552                 cl.movement_numqueue = 0;
553         cl.movement_replay = true;
554 }
555
556 void CL_ClientMovement_Replay(void)
557 {
558         int i;
559         int bump;
560         int contents;
561         int crouch;
562         int onground;
563         double edgefriction;
564         double frametime;
565         double t;
566         vec_t wishspeed;
567         vec_t addspeed;
568         vec_t accelspeed;
569         vec_t f;
570         vec_t *playermins;
571         vec_t *playermaxs;
572         vec3_t currentorigin;
573         vec3_t currentvelocity;
574         vec3_t forward;
575         vec3_t right;
576         vec3_t up;
577         vec3_t wishvel;
578         vec3_t wishdir;
579         vec3_t neworigin;
580         vec3_t currentorigin2;
581         vec3_t neworigin2;
582         vec3_t yawangles;
583         trace_t trace;
584         trace_t trace2;
585         trace_t trace3;
586         if (!cl.movement_replay)
587                 return;
588         cl.movement_replay = false;
589
590         // fetch current starting values
591         VectorCopy(cl_entities[cl.playerentity].state_current.origin, currentorigin);
592         VectorCopy(cl.mvelocity[0], currentvelocity);
593         // FIXME: try minor nudges in various directions if startsolid to find a
594         // safe place to start the walk (due to network compression in some
595         // protocols this starts in solid)
596         //currentorigin[2] += (1.0 / 32.0); // slight nudge to get out of the floor
597         crouch = false; // this will be updated on first move
598
599         // check if onground
600         VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + 1);
601         VectorSet(neworigin2, currentorigin[0], currentorigin[1], currentorigin[2] - 1);
602         trace = CL_TraceBox(currentorigin2, cl_playercrouchmins, cl_playercrouchmaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
603         onground = trace.fraction < 1 && trace.plane.normal[2] > 0.7;
604         //Con_Printf("%f: ", cl.mtime[0]);
605
606         // replay the input queue to predict current location
607         // note: this relies on the fact there's always one queue item at the end
608
609         for (i = 0;i < cl.movement_numqueue;i++)
610         {
611                 client_movementqueue_t *q = cl.movement_queue + bound(0, i, cl.movement_numqueue - 1);
612                 frametime = q->frametime;
613                 //Con_Printf(" %f", frametime);
614                 //if (frametime > 0)
615                 {
616                         if (q->crouch)
617                         {
618                                 // wants to crouch, this always works...
619                                 if (!crouch)
620                                         crouch = true;
621                         }
622                         else
623                         {
624                                 // wants to stand, if currently crouching we need to check for a
625                                 // low ceiling first
626                                 if (crouch)
627                                 {
628                                         trace = CL_TraceBox(currentorigin, cl_playerstandmins, cl_playerstandmaxs, currentorigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
629                                         if (!trace.startsolid)
630                                                 crouch = false;
631                                 }
632                         }
633                         if (crouch)
634                         {
635                                 playermins = cl_playercrouchmins;
636                                 playermaxs = cl_playercrouchmaxs;
637                         }
638                         else
639                         {
640                                 playermins = cl_playerstandmins;
641                                 playermaxs = cl_playerstandmaxs;
642                         }
643                         // change velocity according to q->viewangles and q->move
644                         contents = CL_PointSuperContents(currentorigin);
645                         if (contents & SUPERCONTENTS_LIQUIDSMASK)
646                         {
647                                 // swim
648                                 AngleVectors(q->viewangles, forward, right, up);
649                                 VectorSet(up, 0, 0, 1);
650                                 VectorMAMAM(q->move[0], forward, q->move[1], right, q->move[2], up, wishvel);
651                                 wishspeed = VectorLength(wishvel);
652                                 if (wishspeed)
653                                         VectorScale(wishvel, 1 / wishspeed, wishdir);
654                                 else
655                                         VectorSet( wishdir, 0.0, 0.0, 0.0 );
656                                 wishspeed = min(wishspeed, cl_movement_maxspeed.value);
657                                 if (crouch)
658                                         wishspeed *= 0.5;
659                                 wishspeed *= 0.6;
660                                 VectorScale(currentvelocity, (1 - frametime * cl_movement_friction.value), currentvelocity);
661                                 f = wishspeed - DotProduct(currentvelocity, wishdir);
662                                 if (f > 0)
663                                 {
664                                         f = min(f, cl_movement_accelerate.value * frametime * wishspeed);
665                                         VectorMA(currentvelocity, f, wishdir, currentvelocity);
666                                 }
667                                 if (q->jump)
668                                 {
669                                         if (contents & SUPERCONTENTS_LAVA)
670                                                 currentvelocity[2] =  50;
671                                         else if (contents & SUPERCONTENTS_SLIME)
672                                                 currentvelocity[2] =  80;
673                                         else
674                                         {
675                                                 if (gamemode == GAME_NEXUIZ)
676                                                         currentvelocity[2] = 200;
677                                                 else
678                                                         currentvelocity[2] = 100;
679                                         }
680                                 }
681                         }
682                         else
683                         {
684                                 // walk
685                                 if (onground && q->jump)
686                                 {
687                                         currentvelocity[2] += cl_movement_jumpvelocity.value;
688                                         onground = false;
689                                 }
690                                 VectorSet(yawangles, 0, q->viewangles[1], 0);
691                                 AngleVectors(yawangles, forward, right, up);
692                                 VectorMAM(q->move[0], forward, q->move[1], right, wishvel);
693                                 wishspeed = VectorLength(wishvel);
694                                 if (wishspeed)
695                                         VectorScale(wishvel, 1 / wishspeed, wishdir);
696                                 else
697                                         VectorSet( wishdir, 0.0, 0.0, 0.0 );
698                                 wishspeed = min(wishspeed, cl_movement_maxspeed.value);
699                                 if (crouch)
700                                         wishspeed *= 0.5;
701                                 // check if onground
702                                 if (onground)
703                                 {
704                                         // apply ground friction
705                                         f = sqrt(currentvelocity[0] * currentvelocity[0] + currentvelocity[1] * currentvelocity[1]);
706                                         edgefriction = 1;
707                                         if (f > 0)
708                                         {
709                                                 VectorSet(currentorigin2, currentorigin[0] + currentvelocity[0]*(16/f), currentorigin[1] + currentvelocity[1]*(16/f), currentorigin[2] + playermins[2]);
710                                                 VectorSet(neworigin2, currentorigin2[0], currentorigin2[1], currentorigin2[2] - 34);
711                                                 trace = CL_TraceBox(currentorigin2, vec3_origin, vec3_origin, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
712                                                 if (trace.fraction == 1)
713                                                         edgefriction = cl_movement_edgefriction.value;
714                                         }
715                                         // apply friction
716                                         f = 1 - frametime * edgefriction * ((f < cl_movement_stopspeed.value) ? (cl_movement_stopspeed.value / f) : 1) * cl_movement_friction.value;
717                                         f = max(f, 0);
718                                         VectorScale(currentvelocity, f, currentvelocity);
719                                 }
720                                 else
721                                 {
722                                         // apply air speed limit
723                                         wishspeed = min(wishspeed, cl_movement_maxairspeed.value);
724                                 }
725                                 if (gamemode == GAME_NEXUIZ)
726                                         addspeed = wishspeed;
727                                 else
728                                         addspeed = wishspeed - DotProduct(currentvelocity, wishdir);
729                                 if (addspeed > 0)
730                                 {
731                                         accelspeed = min(cl_movement_accelerate.value * frametime * wishspeed, addspeed);
732                                         VectorMA(currentvelocity, accelspeed, wishdir, currentvelocity);
733                                 }
734                                 currentvelocity[2] -= cl_gravity.value * frametime;
735                         }
736                 }
737                 //if (i < cl.movement_numqueue - 1 || (cl_movement.integer & 4))
738                 {
739                         if (crouch)
740                         {
741                                 playermins = cl_playercrouchmins;
742                                 playermaxs = cl_playercrouchmaxs;
743                         }
744                         else
745                         {
746                                 playermins = cl_playerstandmins;
747                                 playermaxs = cl_playerstandmaxs;
748                         }
749                         onground = false;
750                         for (bump = 0, t = frametime;bump < 8 && VectorLength2(currentvelocity) > 0;bump++)
751                         {
752                                 VectorMA(currentorigin, t, currentvelocity, neworigin);
753                                 trace = CL_TraceBox(currentorigin, playermins, playermaxs, neworigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
754                                 if (trace.fraction < 1 && trace.plane.normal[2] == 0)
755                                 {
756                                         // may be a step or wall, try stepping up
757                                         // first move forward at a higher level
758                                         VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + cl_movement_stepheight.value);
759                                         VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + cl_movement_stepheight.value);
760                                         trace2 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
761                                         // then move down from there
762                                         VectorCopy(trace2.endpos, currentorigin2);
763                                         VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], currentorigin[2]);
764                                         trace3 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
765                                         //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]);
766                                         // accept the new trace if it made some progress
767                                         if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125)
768                                         {
769                                                 trace = trace2;
770                                                 VectorCopy(trace3.endpos, trace.endpos);
771                                         }
772                                 }
773                                 if (trace.fraction == 1)
774                                 {
775                                         VectorCopy(trace.endpos, currentorigin);
776                                         break;
777                                 }
778                                 if (trace.plane.normal[2] > 0.7)
779                                         onground = true;
780                                 t *= 1 - trace.fraction;
781                                 if (trace.fraction >= 0.001)
782                                         VectorCopy(trace.endpos, currentorigin);
783                                 f = DotProduct(currentvelocity, trace.plane.normal);
784                                 VectorMA(currentvelocity, -f, trace.plane.normal, currentvelocity);
785                         }
786                 }
787         }
788         // store replay location
789         VectorCopy(cl.movement_origin, cl.movement_oldorigin);
790         VectorCopy(currentorigin, cl.movement_origin);
791         VectorCopy(currentvelocity, cl.movement_velocity);
792         //VectorCopy(currentorigin, cl_entities[cl.playerentity].state_current.origin);
793         //VectorSet(cl_entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
794 }
795
796 /*
797 ==============
798 CL_SendMove
799 ==============
800 */
801 void CL_SendMove(void)
802 {
803         int i;
804         int bits;
805         sizebuf_t buf;
806         unsigned char data[128];
807 #define MOVEAVERAGING 0
808 #if MOVEAVERAGING
809         static float forwardmove, sidemove, upmove, total; // accumulation
810 #else
811         float forwardmove, sidemove, upmove;
812 #endif
813
814 #if MOVEAVERAGING
815         // accumulate changes between messages
816         forwardmove += cl.cmd.forwardmove;
817         sidemove += cl.cmd.sidemove;
818         upmove += cl.cmd.upmove;
819         total++;
820 #endif
821         if (cls.signon != SIGNONS)
822                 return;
823 #if MOVEAVERAGING
824         // average the accumulated changes
825         total = 1.0f / total;
826         forwardmove *= total;
827         sidemove *= total;
828         upmove *= total;
829         total = 0;
830 #else
831         // use the latest values
832         forwardmove = cl.cmd.forwardmove;
833         sidemove = cl.cmd.sidemove;
834         upmove = cl.cmd.upmove;
835 #endif
836
837         CL_UpdatePrydonCursor();
838
839         buf.maxsize = 128;
840         buf.cursize = 0;
841         buf.data = data;
842
843         // set button bits
844         // LordHavoc: added 6 new buttons and use and chat buttons, and prydon cursor active button
845         bits = 0;
846         if (in_attack.state   & 3) bits |=   1;in_attack.state  &= ~2;
847         if (in_jump.state     & 3) bits |=   2;in_jump.state    &= ~2;
848         if (in_button3.state  & 3) bits |=   4;in_button3.state &= ~2;
849         if (in_button4.state  & 3) bits |=   8;in_button4.state &= ~2;
850         if (in_button5.state  & 3) bits |=  16;in_button5.state &= ~2;
851         if (in_button6.state  & 3) bits |=  32;in_button6.state &= ~2;
852         if (in_button7.state  & 3) bits |=  64;in_button7.state &= ~2;
853         if (in_button8.state  & 3) bits |= 128;in_button8.state &= ~2;
854         if (in_use.state      & 3) bits |= 256;in_use.state     &= ~2;
855         if (key_dest != key_game || key_consoleactive) bits |= 512;
856         if (cl_prydoncursor.integer) bits |= 1024;
857         if (in_button9.state  & 3)  bits |=   2048;in_button9.state  &= ~2;
858         if (in_button10.state  & 3) bits |=   4096;in_button10.state &= ~2;
859         if (in_button11.state  & 3) bits |=   8192;in_button11.state &= ~2;
860         if (in_button12.state  & 3) bits |=  16384;in_button12.state &= ~2;
861         if (in_button13.state  & 3) bits |=  32768;in_button13.state &= ~2;
862         if (in_button14.state  & 3) bits |=  65536;in_button14.state &= ~2;
863         if (in_button15.state  & 3) bits |= 131072;in_button15.state &= ~2;
864         if (in_button16.state  & 3) bits |= 262144;in_button16.state &= ~2;
865         // button bits 19-31 unused currently
866         // rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen
867         if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
868         if (cl.cmd.cursor_screen[0] >=  1) bits |= 16;
869         if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
870         if (cl.cmd.cursor_screen[1] >=  1) bits |= 64;
871
872         // always dump the first two messages, because they may contain leftover inputs from the last level
873         if (++cl.movemessages >= 2)
874         {
875                 // send the movement message
876                 // PROTOCOL_QUAKE        clc_move = 16 bytes total
877                 // PROTOCOL_QUAKEDP      clc_move = 16 bytes total
878                 // PROTOCOL_NEHAHRAMOVIE clc_move = 16 bytes total
879                 // PROTOCOL_DARKPLACES1  clc_move = 19 bytes total
880                 // PROTOCOL_DARKPLACES2  clc_move = 25 bytes total
881                 // PROTOCOL_DARKPLACES3  clc_move = 25 bytes total
882                 // PROTOCOL_DARKPLACES4  clc_move = 19 bytes total
883                 // PROTOCOL_DARKPLACES5  clc_move = 19 bytes total
884                 // PROTOCOL_DARKPLACES6  clc_move = 52 bytes total
885                 // PROTOCOL_DARKPLACES7  clc_move = 56 bytes total
886                 if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
887                 {
888                         // 5 bytes
889                         MSG_WriteByte (&buf, clc_move);
890                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
891                         // 3 bytes
892                         for (i = 0;i < 3;i++)
893                                 MSG_WriteAngle8i (&buf, cl.viewangles[i]);
894                         // 6 bytes
895                         MSG_WriteCoord16i (&buf, forwardmove);
896                         MSG_WriteCoord16i (&buf, sidemove);
897                         MSG_WriteCoord16i (&buf, upmove);
898                         // 2 bytes
899                         MSG_WriteByte (&buf, bits);
900                         MSG_WriteByte (&buf, in_impulse);
901                 }
902                 else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
903                 {
904                         // 5 bytes
905                         MSG_WriteByte (&buf, clc_move);
906                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
907                         // 12 bytes
908                         for (i = 0;i < 3;i++)
909                                 MSG_WriteAngle32f (&buf, cl.viewangles[i]);
910                         // 6 bytes
911                         MSG_WriteCoord16i (&buf, forwardmove);
912                         MSG_WriteCoord16i (&buf, sidemove);
913                         MSG_WriteCoord16i (&buf, upmove);
914                         // 2 bytes
915                         MSG_WriteByte (&buf, bits);
916                         MSG_WriteByte (&buf, in_impulse);
917                 }
918                 else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
919                 {
920                         // 5 bytes
921                         MSG_WriteByte (&buf, clc_move);
922                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
923                         // 6 bytes
924                         for (i = 0;i < 3;i++)
925                                 MSG_WriteAngle16i (&buf, cl.viewangles[i]);
926                         // 6 bytes
927                         MSG_WriteCoord16i (&buf, forwardmove);
928                         MSG_WriteCoord16i (&buf, sidemove);
929                         MSG_WriteCoord16i (&buf, upmove);
930                         // 2 bytes
931                         MSG_WriteByte (&buf, bits);
932                         MSG_WriteByte (&buf, in_impulse);
933                 }
934                 else
935                 {
936                         // 5 bytes
937                         MSG_WriteByte (&buf, clc_move);
938                         if (cl.protocol != PROTOCOL_DARKPLACES6)
939                         {
940                                 if (cl_movement.integer)
941                                 {
942                                         cl.movesequence++;
943                                         MSG_WriteLong (&buf, cl.movesequence);
944                                 }
945                                 else
946                                         MSG_WriteLong (&buf, 0);
947                         }
948                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
949                         // 6 bytes
950                         for (i = 0;i < 3;i++)
951                                 MSG_WriteAngle16i (&buf, cl.viewangles[i]);
952                         // 6 bytes
953                         MSG_WriteCoord16i (&buf, forwardmove);
954                         MSG_WriteCoord16i (&buf, sidemove);
955                         MSG_WriteCoord16i (&buf, upmove);
956                         // 5 bytes
957                         MSG_WriteLong (&buf, bits);
958                         MSG_WriteByte (&buf, in_impulse);
959                         // PRYDON_CLIENTCURSOR
960                         // 30 bytes
961                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[0] * 32767.0f);
962                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[1] * 32767.0f);
963                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[0]);
964                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[1]);
965                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[2]);
966                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[0]);
967                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[1]);
968                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
969                         MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
970                 }
971         }
972
973 #if MOVEAVERAGING
974         forwardmove = sidemove = upmove = 0;
975 #endif
976         in_impulse = 0;
977
978         // ack the last few frame numbers
979         // (redundent to improve handling of client->server packet loss)
980         // for LATESTFRAMENUMS == 3 case this is 15 bytes
981         for (i = 0;i < LATESTFRAMENUMS;i++)
982         {
983                 if (cl.latestframenums[i] > 0)
984                 {
985                         if (developer_networkentities.integer >= 1)
986                                 Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
987                         MSG_WriteByte(&buf, clc_ackframe);
988                         MSG_WriteLong(&buf, cl.latestframenums[i]);
989                 }
990         }
991
992         // PROTOCOL_DARKPLACES6 = 67 bytes per packet
993         // PROTOCOL_DARKPLACES7 = 71 bytes per packet
994
995         // deliver the message
996         if (cls.demoplayback)
997                 return;
998         // nothing to send
999         if (!buf.cursize)
1000                 return;
1001
1002         // FIXME: bits & 16 is +button5, Nexuiz specific
1003         CL_ClientMovement_Input((bits & 2) != 0, (bits & 16) != 0);
1004
1005         if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
1006         {
1007                 Con_Print("CL_SendMove: lost server connection\n");
1008                 CL_Disconnect();
1009                 Host_ShutdownServer(false);
1010         }
1011 }
1012
1013 /*
1014 ============
1015 CL_InitInput
1016 ============
1017 */
1018 void CL_InitInput (void)
1019 {
1020         Cmd_AddCommand ("+moveup",IN_UpDown);
1021         Cmd_AddCommand ("-moveup",IN_UpUp);
1022         Cmd_AddCommand ("+movedown",IN_DownDown);
1023         Cmd_AddCommand ("-movedown",IN_DownUp);
1024         Cmd_AddCommand ("+left",IN_LeftDown);
1025         Cmd_AddCommand ("-left",IN_LeftUp);
1026         Cmd_AddCommand ("+right",IN_RightDown);
1027         Cmd_AddCommand ("-right",IN_RightUp);
1028         Cmd_AddCommand ("+forward",IN_ForwardDown);
1029         Cmd_AddCommand ("-forward",IN_ForwardUp);
1030         Cmd_AddCommand ("+back",IN_BackDown);
1031         Cmd_AddCommand ("-back",IN_BackUp);
1032         Cmd_AddCommand ("+lookup", IN_LookupDown);
1033         Cmd_AddCommand ("-lookup", IN_LookupUp);
1034         Cmd_AddCommand ("+lookdown", IN_LookdownDown);
1035         Cmd_AddCommand ("-lookdown", IN_LookdownUp);
1036         Cmd_AddCommand ("+strafe", IN_StrafeDown);
1037         Cmd_AddCommand ("-strafe", IN_StrafeUp);
1038         Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
1039         Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
1040         Cmd_AddCommand ("+moveright", IN_MoverightDown);
1041         Cmd_AddCommand ("-moveright", IN_MoverightUp);
1042         Cmd_AddCommand ("+speed", IN_SpeedDown);
1043         Cmd_AddCommand ("-speed", IN_SpeedUp);
1044         Cmd_AddCommand ("+attack", IN_AttackDown);
1045         Cmd_AddCommand ("-attack", IN_AttackUp);
1046         Cmd_AddCommand ("+jump", IN_JumpDown);
1047         Cmd_AddCommand ("-jump", IN_JumpUp);
1048         Cmd_AddCommand ("impulse", IN_Impulse);
1049         Cmd_AddCommand ("+klook", IN_KLookDown);
1050         Cmd_AddCommand ("-klook", IN_KLookUp);
1051         Cmd_AddCommand ("+mlook", IN_MLookDown);
1052         Cmd_AddCommand ("-mlook", IN_MLookUp);
1053
1054         // LordHavoc: added use button
1055         Cmd_AddCommand ("+use", IN_UseDown);
1056         Cmd_AddCommand ("-use", IN_UseUp);
1057
1058         // LordHavoc: added 6 new buttons
1059         Cmd_AddCommand ("+button3", IN_Button3Down);
1060         Cmd_AddCommand ("-button3", IN_Button3Up);
1061         Cmd_AddCommand ("+button4", IN_Button4Down);
1062         Cmd_AddCommand ("-button4", IN_Button4Up);
1063         Cmd_AddCommand ("+button5", IN_Button5Down);
1064         Cmd_AddCommand ("-button5", IN_Button5Up);
1065         Cmd_AddCommand ("+button6", IN_Button6Down);
1066         Cmd_AddCommand ("-button6", IN_Button6Up);
1067         Cmd_AddCommand ("+button7", IN_Button7Down);
1068         Cmd_AddCommand ("-button7", IN_Button7Up);
1069         Cmd_AddCommand ("+button8", IN_Button8Down);
1070         Cmd_AddCommand ("-button8", IN_Button8Up);
1071         Cmd_AddCommand ("+button9", IN_Button9Down);
1072         Cmd_AddCommand ("-button9", IN_Button9Up);
1073         Cmd_AddCommand ("+button10", IN_Button10Down);
1074         Cmd_AddCommand ("-button10", IN_Button10Up);
1075         Cmd_AddCommand ("+button11", IN_Button11Down);
1076         Cmd_AddCommand ("-button11", IN_Button11Up);
1077         Cmd_AddCommand ("+button12", IN_Button12Down);
1078         Cmd_AddCommand ("-button12", IN_Button12Up);
1079         Cmd_AddCommand ("+button13", IN_Button13Down);
1080         Cmd_AddCommand ("-button13", IN_Button13Up);
1081         Cmd_AddCommand ("+button14", IN_Button14Down);
1082         Cmd_AddCommand ("-button14", IN_Button14Up);
1083         Cmd_AddCommand ("+button15", IN_Button15Down);
1084         Cmd_AddCommand ("-button15", IN_Button15Up);
1085         Cmd_AddCommand ("+button16", IN_Button16Down);
1086         Cmd_AddCommand ("-button16", IN_Button16Up);
1087
1088         Cvar_RegisterVariable(&cl_movement);
1089         Cvar_RegisterVariable(&cl_movement_latency);
1090         Cvar_RegisterVariable(&cl_movement_maxspeed);
1091         Cvar_RegisterVariable(&cl_movement_maxairspeed);
1092         Cvar_RegisterVariable(&cl_movement_stopspeed);
1093         Cvar_RegisterVariable(&cl_movement_friction);
1094         Cvar_RegisterVariable(&cl_movement_edgefriction);
1095         Cvar_RegisterVariable(&cl_movement_stepheight);
1096         Cvar_RegisterVariable(&cl_movement_accelerate);
1097         Cvar_RegisterVariable(&cl_movement_jumpvelocity);
1098         Cvar_RegisterVariable(&cl_gravity);
1099         Cvar_RegisterVariable(&cl_slowmo);
1100
1101         Cvar_RegisterVariable(&in_pitch_min);
1102         Cvar_RegisterVariable(&in_pitch_max);
1103         Cvar_RegisterVariable(&m_filter);
1104 }
1105