]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_input.c
fix infinite loop bugs in InfoString_SetValue
[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         int impulse;
806         sizebuf_t buf;
807         unsigned char data[128];
808         static double lastsendtime = 0;
809 #define MOVEAVERAGING 0
810 #if MOVEAVERAGING
811         static float accumforwardmove = 0, accumsidemove = 0, accumupmove = 0, accumtotal = 0; // accumulation
812 #endif
813         float forwardmove, sidemove, upmove;
814
815         // if playing a demo, do nothing
816         if (!cls.netcon)
817                 return;
818
819 #if MOVEAVERAGING
820         // accumulate changes between messages
821         accumforwardmove += cl.cmd.forwardmove;
822         accumsidemove += cl.cmd.sidemove;
823         accumupmove += cl.cmd.upmove;
824         accumtotal++;
825 #endif
826
827         if (cl_movement.integer && cls.signon == SIGNONS)
828         {
829                 if (!cl.movement_needupdate)
830                         return;
831                 cl.movement_needupdate = false;
832                 cl.movement = cl.stats[STAT_HEALTH] > 0 && !cl.intermission;
833         }
834         else
835         {
836                 cl.movement = false;
837                 if (realtime < lastsendtime + 1.0 / bound(10, cl_netinputpacketspersecond.value, 100))
838                         return;
839                 // don't let it fall behind if CL_SendMove hasn't been called recently
840                 // (such is the case when framerate is too low for instance)
841                 lastsendtime = max(lastsendtime + 1.0 / bound(10, cl_netinputpacketspersecond.value, 100), realtime);
842         }
843 #if MOVEAVERAGING
844         // average the accumulated changes
845         accumtotal = 1.0f / accumtotal;
846         forwardmove = accumforwardmove * accumtotal;
847         sidemove = accumsidemove * accumtotal;
848         upmove = accumupmove * accumtotal;
849         accumforwardmove = 0;
850         accumsidemove = 0;
851         accumupmove = 0;
852         accumtotal = 0;
853 #else
854         // use the latest values
855         forwardmove = cl.cmd.forwardmove;
856         sidemove = cl.cmd.sidemove;
857         upmove = cl.cmd.upmove;
858 #endif
859
860         if (cls.signon == SIGNONS)
861                 CL_UpdatePrydonCursor();
862
863         buf.maxsize = 128;
864         buf.cursize = 0;
865         buf.data = data;
866
867         // set button bits
868         // LordHavoc: added 6 new buttons and use and chat buttons, and prydon cursor active button
869         bits = 0;
870         if (in_attack.state   & 3) bits |=   1;in_attack.state  &= ~2;
871         if (in_jump.state     & 3) bits |=   2;in_jump.state    &= ~2;
872         if (in_button3.state  & 3) bits |=   4;in_button3.state &= ~2;
873         if (in_button4.state  & 3) bits |=   8;in_button4.state &= ~2;
874         if (in_button5.state  & 3) bits |=  16;in_button5.state &= ~2;
875         if (in_button6.state  & 3) bits |=  32;in_button6.state &= ~2;
876         if (in_button7.state  & 3) bits |=  64;in_button7.state &= ~2;
877         if (in_button8.state  & 3) bits |= 128;in_button8.state &= ~2;
878         if (in_use.state      & 3) bits |= 256;in_use.state     &= ~2;
879         if (key_dest != key_game || key_consoleactive) bits |= 512;
880         if (cl_prydoncursor.integer) bits |= 1024;
881         if (in_button9.state  & 3)  bits |=   2048;in_button9.state  &= ~2;
882         if (in_button10.state  & 3) bits |=   4096;in_button10.state &= ~2;
883         if (in_button11.state  & 3) bits |=   8192;in_button11.state &= ~2;
884         if (in_button12.state  & 3) bits |=  16384;in_button12.state &= ~2;
885         if (in_button13.state  & 3) bits |=  32768;in_button13.state &= ~2;
886         if (in_button14.state  & 3) bits |=  65536;in_button14.state &= ~2;
887         if (in_button15.state  & 3) bits |= 131072;in_button15.state &= ~2;
888         if (in_button16.state  & 3) bits |= 262144;in_button16.state &= ~2;
889         // button bits 19-31 unused currently
890         // rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen
891         if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
892         if (cl.cmd.cursor_screen[0] >=  1) bits |= 16;
893         if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
894         if (cl.cmd.cursor_screen[1] >=  1) bits |= 64;
895
896         impulse = in_impulse;
897         in_impulse = 0;
898
899         csqc_buttons = bits;
900
901         if (cls.signon == SIGNONS)
902         {
903                 // always dump the first two messages, because they may contain leftover inputs from the last level
904                 if (++cl.movemessages >= 2)
905                 {
906                         // send the movement message
907                         // PROTOCOL_QUAKE        clc_move = 16 bytes total
908                         // PROTOCOL_QUAKEDP      clc_move = 16 bytes total
909                         // PROTOCOL_NEHAHRAMOVIE clc_move = 16 bytes total
910                         // PROTOCOL_DARKPLACES1  clc_move = 19 bytes total
911                         // PROTOCOL_DARKPLACES2  clc_move = 25 bytes total
912                         // PROTOCOL_DARKPLACES3  clc_move = 25 bytes total
913                         // PROTOCOL_DARKPLACES4  clc_move = 19 bytes total
914                         // PROTOCOL_DARKPLACES5  clc_move = 19 bytes total
915                         // PROTOCOL_DARKPLACES6  clc_move = 52 bytes total
916                         // PROTOCOL_DARKPLACES7  clc_move = 56 bytes total
917                         if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
918                         {
919                                 // 5 bytes
920                                 MSG_WriteByte (&buf, clc_move);
921                                 MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
922                                 // 3 bytes
923                                 for (i = 0;i < 3;i++)
924                                         MSG_WriteAngle8i (&buf, cl.viewangles[i]);
925                                 // 6 bytes
926                                 MSG_WriteCoord16i (&buf, forwardmove);
927                                 MSG_WriteCoord16i (&buf, sidemove);
928                                 MSG_WriteCoord16i (&buf, upmove);
929                                 // 2 bytes
930                                 MSG_WriteByte (&buf, bits);
931                                 MSG_WriteByte (&buf, impulse);
932                         }
933                         else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
934                         {
935                                 // 5 bytes
936                                 MSG_WriteByte (&buf, clc_move);
937                                 MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
938                                 // 12 bytes
939                                 for (i = 0;i < 3;i++)
940                                         MSG_WriteAngle32f (&buf, cl.viewangles[i]);
941                                 // 6 bytes
942                                 MSG_WriteCoord16i (&buf, forwardmove);
943                                 MSG_WriteCoord16i (&buf, sidemove);
944                                 MSG_WriteCoord16i (&buf, upmove);
945                                 // 2 bytes
946                                 MSG_WriteByte (&buf, bits);
947                                 MSG_WriteByte (&buf, impulse);
948                         }
949                         else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
950                         {
951                                 // 5 bytes
952                                 MSG_WriteByte (&buf, clc_move);
953                                 MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
954                                 // 6 bytes
955                                 for (i = 0;i < 3;i++)
956                                         MSG_WriteAngle16i (&buf, cl.viewangles[i]);
957                                 // 6 bytes
958                                 MSG_WriteCoord16i (&buf, forwardmove);
959                                 MSG_WriteCoord16i (&buf, sidemove);
960                                 MSG_WriteCoord16i (&buf, upmove);
961                                 // 2 bytes
962                                 MSG_WriteByte (&buf, bits);
963                                 MSG_WriteByte (&buf, impulse);
964                         }
965                         else
966                         {
967                                 // 5 bytes
968                                 MSG_WriteByte (&buf, clc_move);
969                                 if (cl.protocol != PROTOCOL_DARKPLACES6)
970                                 {
971                                         if (cl_movement.integer)
972                                         {
973                                                 cl.movesequence++;
974                                                 MSG_WriteLong (&buf, cl.movesequence);
975                                         }
976                                         else
977                                                 MSG_WriteLong (&buf, 0);
978                                 }
979                                 MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
980                                 // 6 bytes
981                                 for (i = 0;i < 3;i++)
982                                         MSG_WriteAngle16i (&buf, cl.viewangles[i]);
983                                 // 6 bytes
984                                 MSG_WriteCoord16i (&buf, forwardmove);
985                                 MSG_WriteCoord16i (&buf, sidemove);
986                                 MSG_WriteCoord16i (&buf, upmove);
987                                 // 5 bytes
988                                 MSG_WriteLong (&buf, bits);
989                                 MSG_WriteByte (&buf, impulse);
990                                 // PRYDON_CLIENTCURSOR
991                                 // 30 bytes
992                                 MSG_WriteShort (&buf, cl.cmd.cursor_screen[0] * 32767.0f);
993                                 MSG_WriteShort (&buf, cl.cmd.cursor_screen[1] * 32767.0f);
994                                 MSG_WriteFloat (&buf, cl.cmd.cursor_start[0]);
995                                 MSG_WriteFloat (&buf, cl.cmd.cursor_start[1]);
996                                 MSG_WriteFloat (&buf, cl.cmd.cursor_start[2]);
997                                 MSG_WriteFloat (&buf, cl.cmd.cursor_impact[0]);
998                                 MSG_WriteFloat (&buf, cl.cmd.cursor_impact[1]);
999                                 MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
1000                                 MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
1001                         }
1002
1003                         // FIXME: bits & 16 is +button5, Nexuiz specific
1004                         CL_ClientMovement_Input((bits & 2) != 0, (bits & 16) != 0);
1005                 }
1006
1007                 // ack the last few frame numbers
1008                 // (redundent to improve handling of client->server packet loss)
1009                 // for LATESTFRAMENUMS == 3 case this is 15 bytes
1010                 for (i = 0;i < LATESTFRAMENUMS;i++)
1011                 {
1012                         if (cl.latestframenums[i] > 0)
1013                         {
1014                                 if (developer_networkentities.integer >= 1)
1015                                         Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
1016                                 MSG_WriteByte(&buf, clc_ackframe);
1017                                 MSG_WriteLong(&buf, cl.latestframenums[i]);
1018                         }
1019                 }
1020
1021                 // PROTOCOL_DARKPLACES6 = 67 bytes per packet
1022                 // PROTOCOL_DARKPLACES7 = 71 bytes per packet
1023         }
1024
1025         // send the reliable message (forwarded commands) if there is one
1026         NetConn_SendUnreliableMessage(cls.netcon, &buf);
1027
1028         if (cls.netcon->message.overflowed)
1029         {
1030                 Con_Print("CL_SendMove: lost server connection\n");
1031                 CL_Disconnect();
1032                 Host_ShutdownServer();
1033         }
1034 }
1035
1036 /*
1037 ============
1038 CL_InitInput
1039 ============
1040 */
1041 void CL_InitInput (void)
1042 {
1043         Cmd_AddCommand ("+moveup",IN_UpDown, "swim upward");
1044         Cmd_AddCommand ("-moveup",IN_UpUp, "stop swimming upward");
1045         Cmd_AddCommand ("+movedown",IN_DownDown, "swim downward");
1046         Cmd_AddCommand ("-movedown",IN_DownUp, "stop swimming downward");
1047         Cmd_AddCommand ("+left",IN_LeftDown, "turn left");
1048         Cmd_AddCommand ("-left",IN_LeftUp, "stop turning left");
1049         Cmd_AddCommand ("+right",IN_RightDown, "turn right");
1050         Cmd_AddCommand ("-right",IN_RightUp, "stop turning right");
1051         Cmd_AddCommand ("+forward",IN_ForwardDown, "move forward");
1052         Cmd_AddCommand ("-forward",IN_ForwardUp, "stop moving forward");
1053         Cmd_AddCommand ("+back",IN_BackDown, "move backward");
1054         Cmd_AddCommand ("-back",IN_BackUp, "stop moving backward");
1055         Cmd_AddCommand ("+lookup", IN_LookupDown, "look upward");
1056         Cmd_AddCommand ("-lookup", IN_LookupUp, "stop looking upward");
1057         Cmd_AddCommand ("+lookdown", IN_LookdownDown, "look downward");
1058         Cmd_AddCommand ("-lookdown", IN_LookdownUp, "stop looking downward");
1059         Cmd_AddCommand ("+strafe", IN_StrafeDown, "activate strafing mode (move instead of turn)\n");
1060         Cmd_AddCommand ("-strafe", IN_StrafeUp, "deactivate strafing mode");
1061         Cmd_AddCommand ("+moveleft", IN_MoveleftDown, "strafe left");
1062         Cmd_AddCommand ("-moveleft", IN_MoveleftUp, "stop strafing left");
1063         Cmd_AddCommand ("+moveright", IN_MoverightDown, "strafe right");
1064         Cmd_AddCommand ("-moveright", IN_MoverightUp, "stop strafing right");
1065         Cmd_AddCommand ("+speed", IN_SpeedDown, "activate run mode (faster movement and turning)");
1066         Cmd_AddCommand ("-speed", IN_SpeedUp, "deactivate run mode");
1067         Cmd_AddCommand ("+attack", IN_AttackDown, "begin firing");
1068         Cmd_AddCommand ("-attack", IN_AttackUp, "stop firing");
1069         Cmd_AddCommand ("+jump", IN_JumpDown, "jump");
1070         Cmd_AddCommand ("-jump", IN_JumpUp, "end jump (so you can jump again)");
1071         Cmd_AddCommand ("impulse", IN_Impulse, "send an impulse number to server (select weapon, use item, etc)");
1072         Cmd_AddCommand ("+klook", IN_KLookDown, "activate keyboard looking mode, do not recenter view");
1073         Cmd_AddCommand ("-klook", IN_KLookUp, "deactivate keyboard looking mode");
1074         Cmd_AddCommand ("+mlook", IN_MLookDown, "activate mouse looking mode, do not recenter view");
1075         Cmd_AddCommand ("-mlook", IN_MLookUp, "deactivate mouse looking mode");
1076
1077         // LordHavoc: added use button
1078         Cmd_AddCommand ("+use", IN_UseDown, "use something (may be used by some mods)");
1079         Cmd_AddCommand ("-use", IN_UseUp, "stop using something");
1080
1081         // LordHavoc: added 6 new buttons
1082         Cmd_AddCommand ("+button3", IN_Button3Down, "activate button3 (behavior depends on mod)");
1083         Cmd_AddCommand ("-button3", IN_Button3Up, "deactivate button3");
1084         Cmd_AddCommand ("+button4", IN_Button4Down, "activate button4 (behavior depends on mod)");
1085         Cmd_AddCommand ("-button4", IN_Button4Up, "deactivate button4");
1086         Cmd_AddCommand ("+button5", IN_Button5Down, "activate button5 (behavior depends on mod)");
1087         Cmd_AddCommand ("-button5", IN_Button5Up, "deactivate button5");
1088         Cmd_AddCommand ("+button6", IN_Button6Down, "activate button6 (behavior depends on mod)");
1089         Cmd_AddCommand ("-button6", IN_Button6Up, "deactivate button6");
1090         Cmd_AddCommand ("+button7", IN_Button7Down, "activate button7 (behavior depends on mod)");
1091         Cmd_AddCommand ("-button7", IN_Button7Up, "deactivate button7");
1092         Cmd_AddCommand ("+button8", IN_Button8Down, "activate button8 (behavior depends on mod)");
1093         Cmd_AddCommand ("-button8", IN_Button8Up, "deactivate button8");
1094         Cmd_AddCommand ("+button9", IN_Button9Down, "activate button9 (behavior depends on mod)");
1095         Cmd_AddCommand ("-button9", IN_Button9Up, "deactivate button9");
1096         Cmd_AddCommand ("+button10", IN_Button10Down, "activate button10 (behavior depends on mod)");
1097         Cmd_AddCommand ("-button10", IN_Button10Up, "deactivate button10");
1098         Cmd_AddCommand ("+button11", IN_Button11Down, "activate button11 (behavior depends on mod)");
1099         Cmd_AddCommand ("-button11", IN_Button11Up, "deactivate button11");
1100         Cmd_AddCommand ("+button12", IN_Button12Down, "activate button12 (behavior depends on mod)");
1101         Cmd_AddCommand ("-button12", IN_Button12Up, "deactivate button12");
1102         Cmd_AddCommand ("+button13", IN_Button13Down, "activate button13 (behavior depends on mod)");
1103         Cmd_AddCommand ("-button13", IN_Button13Up, "deactivate button13");
1104         Cmd_AddCommand ("+button14", IN_Button14Down, "activate button14 (behavior depends on mod)");
1105         Cmd_AddCommand ("-button14", IN_Button14Up, "deactivate button14");
1106         Cmd_AddCommand ("+button15", IN_Button15Down, "activate button15 (behavior depends on mod)");
1107         Cmd_AddCommand ("-button15", IN_Button15Up, "deactivate button15");
1108         Cmd_AddCommand ("+button16", IN_Button16Down, "activate button16 (behavior depends on mod)");
1109         Cmd_AddCommand ("-button16", IN_Button16Up, "deactivate button16");
1110
1111         Cvar_RegisterVariable(&cl_movement);
1112         Cvar_RegisterVariable(&cl_movement_latency);
1113         Cvar_RegisterVariable(&cl_movement_maxspeed);
1114         Cvar_RegisterVariable(&cl_movement_maxairspeed);
1115         Cvar_RegisterVariable(&cl_movement_stopspeed);
1116         Cvar_RegisterVariable(&cl_movement_friction);
1117         Cvar_RegisterVariable(&cl_movement_edgefriction);
1118         Cvar_RegisterVariable(&cl_movement_stepheight);
1119         Cvar_RegisterVariable(&cl_movement_accelerate);
1120         Cvar_RegisterVariable(&cl_movement_jumpvelocity);
1121         Cvar_RegisterVariable(&cl_gravity);
1122         Cvar_RegisterVariable(&cl_slowmo);
1123
1124         Cvar_RegisterVariable(&in_pitch_min);
1125         Cvar_RegisterVariable(&in_pitch_max);
1126         Cvar_RegisterVariable(&m_filter);
1127
1128         Cvar_RegisterVariable(&cl_netinputpacketspersecond);
1129 }
1130