]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_input.c
remove an unused extern for sys_ticrate, and added a comment warning about improper...
[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.integer && 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 = cl_movement.integer && cl.stats[STAT_HEALTH] > 0 && !cls.demoplayback && !cl.intermission;
552         // clear queue if client movement is disabled
553         if (!cl.movement)
554                 cl.movement_numqueue = 0;
555         cl.movement_replay = true;
556 }
557
558 void CL_ClientMovement_Replay(void)
559 {
560         int i;
561         int bump;
562         int contents;
563         int crouch;
564         int onground;
565         double edgefriction;
566         double frametime;
567         double t;
568         vec_t wishspeed;
569         vec_t addspeed;
570         vec_t accelspeed;
571         vec_t f;
572         vec_t *playermins;
573         vec_t *playermaxs;
574         vec3_t currentorigin;
575         vec3_t currentvelocity;
576         vec3_t forward;
577         vec3_t right;
578         vec3_t up;
579         vec3_t wishvel;
580         vec3_t wishdir;
581         vec3_t neworigin;
582         vec3_t currentorigin2;
583         vec3_t neworigin2;
584         vec3_t yawangles;
585         trace_t trace;
586         trace_t trace2;
587         trace_t trace3;
588         if (!cl.movement_replay)
589                 return;
590         cl.movement_replay = false;
591
592         // fetch current starting values
593         VectorCopy(cl_entities[cl.playerentity].state_current.origin, currentorigin);
594         VectorCopy(cl.mvelocity[0], currentvelocity);
595         // FIXME: try minor nudges in various directions if startsolid to find a
596         // safe place to start the walk (due to network compression in some
597         // protocols this starts in solid)
598         //currentorigin[2] += (1.0 / 32.0); // slight nudge to get out of the floor
599         crouch = false; // this will be updated on first move
600
601         // check if onground
602         VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + 1);
603         VectorSet(neworigin2, currentorigin[0], currentorigin[1], currentorigin[2] - 1);
604         trace = CL_TraceBox(currentorigin2, cl_playercrouchmins, cl_playercrouchmaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
605         onground = trace.fraction < 1 && trace.plane.normal[2] > 0.7;
606         //Con_Printf("%f: ", cl.mtime[0]);
607
608         // replay the input queue to predict current location
609         // note: this relies on the fact there's always one queue item at the end
610
611         for (i = 0;i < cl.movement_numqueue;i++)
612         {
613                 client_movementqueue_t *q = cl.movement_queue + bound(0, i, cl.movement_numqueue - 1);
614                 frametime = q->frametime;
615                 //Con_Printf(" %f", frametime);
616                 //if (frametime > 0)
617                 {
618                         if (q->crouch)
619                         {
620                                 // wants to crouch, this always works...
621                                 if (!crouch)
622                                         crouch = true;
623                         }
624                         else
625                         {
626                                 // wants to stand, if currently crouching we need to check for a
627                                 // low ceiling first
628                                 if (crouch)
629                                 {
630                                         trace = CL_TraceBox(currentorigin, cl_playerstandmins, cl_playerstandmaxs, currentorigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
631                                         if (!trace.startsolid)
632                                                 crouch = false;
633                                 }
634                         }
635                         if (crouch)
636                         {
637                                 playermins = cl_playercrouchmins;
638                                 playermaxs = cl_playercrouchmaxs;
639                         }
640                         else
641                         {
642                                 playermins = cl_playerstandmins;
643                                 playermaxs = cl_playerstandmaxs;
644                         }
645                         // change velocity according to q->viewangles and q->move
646                         contents = CL_PointSuperContents(currentorigin);
647                         if (contents & SUPERCONTENTS_LIQUIDSMASK)
648                         {
649                                 // swim
650                                 AngleVectors(q->viewangles, forward, right, up);
651                                 VectorSet(up, 0, 0, 1);
652                                 VectorMAMAM(q->move[0], forward, q->move[1], right, q->move[2], up, wishvel);
653                                 wishspeed = VectorLength(wishvel);
654                                 if (wishspeed)
655                                         VectorScale(wishvel, 1 / wishspeed, wishdir);
656                                 else
657                                         VectorSet( wishdir, 0.0, 0.0, 0.0 );
658                                 wishspeed = min(wishspeed, cl_movement_maxspeed.value);
659                                 if (crouch)
660                                         wishspeed *= 0.5;
661                                 wishspeed *= 0.6;
662                                 VectorScale(currentvelocity, (1 - frametime * cl_movement_friction.value), currentvelocity);
663                                 f = wishspeed - DotProduct(currentvelocity, wishdir);
664                                 if (f > 0)
665                                 {
666                                         f = min(f, cl_movement_accelerate.value * frametime * wishspeed);
667                                         VectorMA(currentvelocity, f, wishdir, currentvelocity);
668                                 }
669                                 if (q->jump)
670                                 {
671                                         if (contents & SUPERCONTENTS_LAVA)
672                                                 currentvelocity[2] =  50;
673                                         else if (contents & SUPERCONTENTS_SLIME)
674                                                 currentvelocity[2] =  80;
675                                         else
676                                         {
677                                                 if (gamemode == GAME_NEXUIZ)
678                                                         currentvelocity[2] = 200;
679                                                 else
680                                                         currentvelocity[2] = 100;
681                                         }
682                                 }
683                         }
684                         else
685                         {
686                                 // walk
687                                 if (onground && q->jump)
688                                 {
689                                         currentvelocity[2] += cl_movement_jumpvelocity.value;
690                                         onground = false;
691                                 }
692                                 VectorSet(yawangles, 0, q->viewangles[1], 0);
693                                 AngleVectors(yawangles, forward, right, up);
694                                 VectorMAM(q->move[0], forward, q->move[1], right, wishvel);
695                                 wishspeed = VectorLength(wishvel);
696                                 if (wishspeed)
697                                         VectorScale(wishvel, 1 / wishspeed, wishdir);
698                                 else
699                                         VectorSet( wishdir, 0.0, 0.0, 0.0 );
700                                 wishspeed = min(wishspeed, cl_movement_maxspeed.value);
701                                 if (crouch)
702                                         wishspeed *= 0.5;
703                                 // check if onground
704                                 if (onground)
705                                 {
706                                         // apply ground friction
707                                         f = sqrt(currentvelocity[0] * currentvelocity[0] + currentvelocity[1] * currentvelocity[1]);
708                                         edgefriction = 1;
709                                         if (f > 0)
710                                         {
711                                                 VectorSet(currentorigin2, currentorigin[0] + currentvelocity[0]*(16/f), currentorigin[1] + currentvelocity[1]*(16/f), currentorigin[2] + playermins[2]);
712                                                 VectorSet(neworigin2, currentorigin2[0], currentorigin2[1], currentorigin2[2] - 34);
713                                                 trace = CL_TraceBox(currentorigin2, vec3_origin, vec3_origin, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
714                                                 if (trace.fraction == 1)
715                                                         edgefriction = cl_movement_edgefriction.value;
716                                         }
717                                         // apply friction
718                                         f = 1 - frametime * edgefriction * ((f < cl_movement_stopspeed.value) ? (cl_movement_stopspeed.value / f) : 1) * cl_movement_friction.value;
719                                         f = max(f, 0);
720                                         VectorScale(currentvelocity, f, currentvelocity);
721                                 }
722                                 else
723                                 {
724                                         // apply air speed limit
725                                         wishspeed = min(wishspeed, cl_movement_maxairspeed.value);
726                                 }
727                                 if (gamemode == GAME_NEXUIZ)
728                                         addspeed = wishspeed;
729                                 else
730                                         addspeed = wishspeed - DotProduct(currentvelocity, wishdir);
731                                 if (addspeed > 0)
732                                 {
733                                         accelspeed = min(cl_movement_accelerate.value * frametime * wishspeed, addspeed);
734                                         VectorMA(currentvelocity, accelspeed, wishdir, currentvelocity);
735                                 }
736                                 currentvelocity[2] -= cl_gravity.value * frametime;
737                         }
738                 }
739                 //if (i < cl.movement_numqueue - 1 || (cl_movement.integer & 4))
740                 {
741                         if (crouch)
742                         {
743                                 playermins = cl_playercrouchmins;
744                                 playermaxs = cl_playercrouchmaxs;
745                         }
746                         else
747                         {
748                                 playermins = cl_playerstandmins;
749                                 playermaxs = cl_playerstandmaxs;
750                         }
751                         onground = false;
752                         for (bump = 0, t = frametime;bump < 8 && VectorLength2(currentvelocity) > 0;bump++)
753                         {
754                                 VectorMA(currentorigin, t, currentvelocity, neworigin);
755                                 trace = CL_TraceBox(currentorigin, playermins, playermaxs, neworigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
756                                 if (trace.fraction < 1 && trace.plane.normal[2] == 0)
757                                 {
758                                         // may be a step or wall, try stepping up
759                                         // first move forward at a higher level
760                                         VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + cl_movement_stepheight.value);
761                                         VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + cl_movement_stepheight.value);
762                                         trace2 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
763                                         // then move down from there
764                                         VectorCopy(trace2.endpos, currentorigin2);
765                                         VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], currentorigin[2]);
766                                         trace3 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
767                                         //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]);
768                                         // accept the new trace if it made some progress
769                                         if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125)
770                                         {
771                                                 trace = trace2;
772                                                 VectorCopy(trace3.endpos, trace.endpos);
773                                         }
774                                 }
775                                 if (trace.fraction == 1)
776                                 {
777                                         VectorCopy(trace.endpos, currentorigin);
778                                         break;
779                                 }
780                                 if (trace.plane.normal[2] > 0.7)
781                                         onground = true;
782                                 t *= 1 - trace.fraction;
783                                 if (trace.fraction >= 0.001)
784                                         VectorCopy(trace.endpos, currentorigin);
785                                 f = DotProduct(currentvelocity, trace.plane.normal);
786                                 VectorMA(currentvelocity, -f, trace.plane.normal, currentvelocity);
787                         }
788                 }
789         }
790         // store replay location
791         VectorCopy(cl.movement_origin, cl.movement_oldorigin);
792         VectorCopy(currentorigin, cl.movement_origin);
793         VectorCopy(currentvelocity, cl.movement_velocity);
794         //VectorCopy(currentorigin, cl_entities[cl.playerentity].state_current.origin);
795         //VectorSet(cl_entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
796 }
797
798 /*
799 ==============
800 CL_SendMove
801 ==============
802 */
803 extern cvar_t cl_netinputpacketspersecond;
804 void CL_SendMove(void)
805 {
806         int i;
807         int bits;
808         sizebuf_t buf;
809         unsigned char data[128];
810         static double lastsendtime = 0;
811 #define MOVEAVERAGING 0
812 #if MOVEAVERAGING
813         static float forwardmove, sidemove, upmove, total; // accumulation
814 #else
815         float forwardmove, sidemove, upmove;
816 #endif
817
818 #if MOVEAVERAGING
819         // accumulate changes between messages
820         forwardmove += cl.cmd.forwardmove;
821         sidemove += cl.cmd.sidemove;
822         upmove += cl.cmd.upmove;
823         total++;
824 #endif
825         if (cls.signon != SIGNONS)
826                 return;
827         if (realtime < lastsendtime + 1.0 / bound(10, cl_netinputpacketspersecond.value, 100))
828                 return;
829         // don't let it fall behind if CL_SendMove hasn't been called recently
830         // (such is the case when framerate is too low for instance)
831         lastsendtime = max(lastsendtime + 1.0 / bound(10, cl_netinputpacketspersecond.value, 100), realtime);
832 #if MOVEAVERAGING
833         // average the accumulated changes
834         total = 1.0f / total;
835         forwardmove *= total;
836         sidemove *= total;
837         upmove *= total;
838         total = 0;
839 #else
840         // use the latest values
841         forwardmove = cl.cmd.forwardmove;
842         sidemove = cl.cmd.sidemove;
843         upmove = cl.cmd.upmove;
844 #endif
845
846         CL_UpdatePrydonCursor();
847
848         buf.maxsize = 128;
849         buf.cursize = 0;
850         buf.data = data;
851
852         // set button bits
853         // LordHavoc: added 6 new buttons and use and chat buttons, and prydon cursor active button
854         bits = 0;
855         if (in_attack.state   & 3) bits |=   1;in_attack.state  &= ~2;
856         if (in_jump.state     & 3) bits |=   2;in_jump.state    &= ~2;
857         if (in_button3.state  & 3) bits |=   4;in_button3.state &= ~2;
858         if (in_button4.state  & 3) bits |=   8;in_button4.state &= ~2;
859         if (in_button5.state  & 3) bits |=  16;in_button5.state &= ~2;
860         if (in_button6.state  & 3) bits |=  32;in_button6.state &= ~2;
861         if (in_button7.state  & 3) bits |=  64;in_button7.state &= ~2;
862         if (in_button8.state  & 3) bits |= 128;in_button8.state &= ~2;
863         if (in_use.state      & 3) bits |= 256;in_use.state     &= ~2;
864         if (key_dest != key_game || key_consoleactive) bits |= 512;
865         if (cl_prydoncursor.integer) bits |= 1024;
866         if (in_button9.state  & 3)  bits |=   2048;in_button9.state  &= ~2;
867         if (in_button10.state  & 3) bits |=   4096;in_button10.state &= ~2;
868         if (in_button11.state  & 3) bits |=   8192;in_button11.state &= ~2;
869         if (in_button12.state  & 3) bits |=  16384;in_button12.state &= ~2;
870         if (in_button13.state  & 3) bits |=  32768;in_button13.state &= ~2;
871         if (in_button14.state  & 3) bits |=  65536;in_button14.state &= ~2;
872         if (in_button15.state  & 3) bits |= 131072;in_button15.state &= ~2;
873         if (in_button16.state  & 3) bits |= 262144;in_button16.state &= ~2;
874         // button bits 19-31 unused currently
875         // rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen
876         if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
877         if (cl.cmd.cursor_screen[0] >=  1) bits |= 16;
878         if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
879         if (cl.cmd.cursor_screen[1] >=  1) bits |= 64;
880
881         csqc_buttons = bits;
882
883         // always dump the first two messages, because they may contain leftover inputs from the last level
884         if (++cl.movemessages >= 2)
885         {
886                 // send the movement message
887                 // PROTOCOL_QUAKE        clc_move = 16 bytes total
888                 // PROTOCOL_QUAKEDP      clc_move = 16 bytes total
889                 // PROTOCOL_NEHAHRAMOVIE clc_move = 16 bytes total
890                 // PROTOCOL_DARKPLACES1  clc_move = 19 bytes total
891                 // PROTOCOL_DARKPLACES2  clc_move = 25 bytes total
892                 // PROTOCOL_DARKPLACES3  clc_move = 25 bytes total
893                 // PROTOCOL_DARKPLACES4  clc_move = 19 bytes total
894                 // PROTOCOL_DARKPLACES5  clc_move = 19 bytes total
895                 // PROTOCOL_DARKPLACES6  clc_move = 52 bytes total
896                 // PROTOCOL_DARKPLACES7  clc_move = 56 bytes total
897                 if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
898                 {
899                         // 5 bytes
900                         MSG_WriteByte (&buf, clc_move);
901                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
902                         // 3 bytes
903                         for (i = 0;i < 3;i++)
904                                 MSG_WriteAngle8i (&buf, cl.viewangles[i]);
905                         // 6 bytes
906                         MSG_WriteCoord16i (&buf, forwardmove);
907                         MSG_WriteCoord16i (&buf, sidemove);
908                         MSG_WriteCoord16i (&buf, upmove);
909                         // 2 bytes
910                         MSG_WriteByte (&buf, bits);
911                         MSG_WriteByte (&buf, in_impulse);
912                 }
913                 else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
914                 {
915                         // 5 bytes
916                         MSG_WriteByte (&buf, clc_move);
917                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
918                         // 12 bytes
919                         for (i = 0;i < 3;i++)
920                                 MSG_WriteAngle32f (&buf, cl.viewangles[i]);
921                         // 6 bytes
922                         MSG_WriteCoord16i (&buf, forwardmove);
923                         MSG_WriteCoord16i (&buf, sidemove);
924                         MSG_WriteCoord16i (&buf, upmove);
925                         // 2 bytes
926                         MSG_WriteByte (&buf, bits);
927                         MSG_WriteByte (&buf, in_impulse);
928                 }
929                 else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
930                 {
931                         // 5 bytes
932                         MSG_WriteByte (&buf, clc_move);
933                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
934                         // 6 bytes
935                         for (i = 0;i < 3;i++)
936                                 MSG_WriteAngle16i (&buf, cl.viewangles[i]);
937                         // 6 bytes
938                         MSG_WriteCoord16i (&buf, forwardmove);
939                         MSG_WriteCoord16i (&buf, sidemove);
940                         MSG_WriteCoord16i (&buf, upmove);
941                         // 2 bytes
942                         MSG_WriteByte (&buf, bits);
943                         MSG_WriteByte (&buf, in_impulse);
944                 }
945                 else
946                 {
947                         // 5 bytes
948                         MSG_WriteByte (&buf, clc_move);
949                         if (cl.protocol != PROTOCOL_DARKPLACES6)
950                         {
951                                 if (cl_movement.integer)
952                                 {
953                                         cl.movesequence++;
954                                         MSG_WriteLong (&buf, cl.movesequence);
955                                 }
956                                 else
957                                         MSG_WriteLong (&buf, 0);
958                         }
959                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
960                         // 6 bytes
961                         for (i = 0;i < 3;i++)
962                                 MSG_WriteAngle16i (&buf, cl.viewangles[i]);
963                         // 6 bytes
964                         MSG_WriteCoord16i (&buf, forwardmove);
965                         MSG_WriteCoord16i (&buf, sidemove);
966                         MSG_WriteCoord16i (&buf, upmove);
967                         // 5 bytes
968                         MSG_WriteLong (&buf, bits);
969                         MSG_WriteByte (&buf, in_impulse);
970                         // PRYDON_CLIENTCURSOR
971                         // 30 bytes
972                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[0] * 32767.0f);
973                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[1] * 32767.0f);
974                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[0]);
975                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[1]);
976                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[2]);
977                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[0]);
978                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[1]);
979                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
980                         MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
981                 }
982         }
983
984 #if MOVEAVERAGING
985         forwardmove = sidemove = upmove = 0;
986 #endif
987         in_impulse = 0;
988
989         // ack the last few frame numbers
990         // (redundent to improve handling of client->server packet loss)
991         // for LATESTFRAMENUMS == 3 case this is 15 bytes
992         for (i = 0;i < LATESTFRAMENUMS;i++)
993         {
994                 if (cl.latestframenums[i] > 0)
995                 {
996                         if (developer_networkentities.integer >= 1)
997                                 Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
998                         MSG_WriteByte(&buf, clc_ackframe);
999                         MSG_WriteLong(&buf, cl.latestframenums[i]);
1000                 }
1001         }
1002
1003         // PROTOCOL_DARKPLACES6 = 67 bytes per packet
1004         // PROTOCOL_DARKPLACES7 = 71 bytes per packet
1005
1006         // deliver the message
1007         if (cls.demoplayback)
1008                 return;
1009         // nothing to send
1010         if (!buf.cursize)
1011                 return;
1012
1013         // FIXME: bits & 16 is +button5, Nexuiz specific
1014         CL_ClientMovement_Input((bits & 2) != 0, (bits & 16) != 0);
1015
1016         if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
1017         {
1018                 Con_Print("CL_SendMove: lost server connection\n");
1019                 CL_Disconnect();
1020                 Host_ShutdownServer();
1021         }
1022 }
1023
1024 /*
1025 ============
1026 CL_InitInput
1027 ============
1028 */
1029 void CL_InitInput (void)
1030 {
1031         Cmd_AddCommand ("+moveup",IN_UpDown, "swim upward");
1032         Cmd_AddCommand ("-moveup",IN_UpUp, "stop swimming upward");
1033         Cmd_AddCommand ("+movedown",IN_DownDown, "swim downward");
1034         Cmd_AddCommand ("-movedown",IN_DownUp, "stop swimming downward");
1035         Cmd_AddCommand ("+left",IN_LeftDown, "turn left");
1036         Cmd_AddCommand ("-left",IN_LeftUp, "stop turning left");
1037         Cmd_AddCommand ("+right",IN_RightDown, "turn right");
1038         Cmd_AddCommand ("-right",IN_RightUp, "stop turning right");
1039         Cmd_AddCommand ("+forward",IN_ForwardDown, "move forward");
1040         Cmd_AddCommand ("-forward",IN_ForwardUp, "stop moving forward");
1041         Cmd_AddCommand ("+back",IN_BackDown, "move backward");
1042         Cmd_AddCommand ("-back",IN_BackUp, "stop moving backward");
1043         Cmd_AddCommand ("+lookup", IN_LookupDown, "look upward");
1044         Cmd_AddCommand ("-lookup", IN_LookupUp, "stop looking upward");
1045         Cmd_AddCommand ("+lookdown", IN_LookdownDown, "look downward");
1046         Cmd_AddCommand ("-lookdown", IN_LookdownUp, "stop looking downward");
1047         Cmd_AddCommand ("+strafe", IN_StrafeDown, "activate strafing mode (move instead of turn)\n");
1048         Cmd_AddCommand ("-strafe", IN_StrafeUp, "deactivate strafing mode");
1049         Cmd_AddCommand ("+moveleft", IN_MoveleftDown, "strafe left");
1050         Cmd_AddCommand ("-moveleft", IN_MoveleftUp, "stop strafing left");
1051         Cmd_AddCommand ("+moveright", IN_MoverightDown, "strafe right");
1052         Cmd_AddCommand ("-moveright", IN_MoverightUp, "stop strafing right");
1053         Cmd_AddCommand ("+speed", IN_SpeedDown, "activate run mode (faster movement and turning)");
1054         Cmd_AddCommand ("-speed", IN_SpeedUp, "deactivate run mode");
1055         Cmd_AddCommand ("+attack", IN_AttackDown, "begin firing");
1056         Cmd_AddCommand ("-attack", IN_AttackUp, "stop firing");
1057         Cmd_AddCommand ("+jump", IN_JumpDown, "jump");
1058         Cmd_AddCommand ("-jump", IN_JumpUp, "end jump (so you can jump again)");
1059         Cmd_AddCommand ("impulse", IN_Impulse, "send an impulse number to server (select weapon, use item, etc)");
1060         Cmd_AddCommand ("+klook", IN_KLookDown, "activate keyboard looking mode, do not recenter view");
1061         Cmd_AddCommand ("-klook", IN_KLookUp, "deactivate keyboard looking mode");
1062         Cmd_AddCommand ("+mlook", IN_MLookDown, "activate mouse looking mode, do not recenter view");
1063         Cmd_AddCommand ("-mlook", IN_MLookUp, "deactivate mouse looking mode");
1064
1065         // LordHavoc: added use button
1066         Cmd_AddCommand ("+use", IN_UseDown, "use something (may be used by some mods)");
1067         Cmd_AddCommand ("-use", IN_UseUp, "stop using something");
1068
1069         // LordHavoc: added 6 new buttons
1070         Cmd_AddCommand ("+button3", IN_Button3Down, "activate button3 (behavior depends on mod)");
1071         Cmd_AddCommand ("-button3", IN_Button3Up, "deactivate button3");
1072         Cmd_AddCommand ("+button4", IN_Button4Down, "activate button4 (behavior depends on mod)");
1073         Cmd_AddCommand ("-button4", IN_Button4Up, "deactivate button3");
1074         Cmd_AddCommand ("+button5", IN_Button5Down, "activate button4 (behavior depends on mod)");
1075         Cmd_AddCommand ("-button5", IN_Button5Up, "deactivate button3");
1076         Cmd_AddCommand ("+button6", IN_Button6Down, "activate button4 (behavior depends on mod)");
1077         Cmd_AddCommand ("-button6", IN_Button6Up, "deactivate button3");
1078         Cmd_AddCommand ("+button7", IN_Button7Down, "activate button4 (behavior depends on mod)");
1079         Cmd_AddCommand ("-button7", IN_Button7Up, "deactivate button3");
1080         Cmd_AddCommand ("+button8", IN_Button8Down, "activate button4 (behavior depends on mod)");
1081         Cmd_AddCommand ("-button8", IN_Button8Up, "deactivate button3");
1082         Cmd_AddCommand ("+button9", IN_Button9Down, "activate button4 (behavior depends on mod)");
1083         Cmd_AddCommand ("-button9", IN_Button9Up, "deactivate button3");
1084         Cmd_AddCommand ("+button10", IN_Button10Down, "activate button4 (behavior depends on mod)");
1085         Cmd_AddCommand ("-button10", IN_Button10Up, "deactivate button3");
1086         Cmd_AddCommand ("+button11", IN_Button11Down, "activate button4 (behavior depends on mod)");
1087         Cmd_AddCommand ("-button11", IN_Button11Up, "deactivate button3");
1088         Cmd_AddCommand ("+button12", IN_Button12Down, "activate button4 (behavior depends on mod)");
1089         Cmd_AddCommand ("-button12", IN_Button12Up, "deactivate button3");
1090         Cmd_AddCommand ("+button13", IN_Button13Down, "activate button4 (behavior depends on mod)");
1091         Cmd_AddCommand ("-button13", IN_Button13Up, "deactivate button3");
1092         Cmd_AddCommand ("+button14", IN_Button14Down, "activate button4 (behavior depends on mod)");
1093         Cmd_AddCommand ("-button14", IN_Button14Up, "deactivate button3");
1094         Cmd_AddCommand ("+button15", IN_Button15Down, "activate button4 (behavior depends on mod)");
1095         Cmd_AddCommand ("-button15", IN_Button15Up, "deactivate button3");
1096         Cmd_AddCommand ("+button16", IN_Button16Down, "activate button4 (behavior depends on mod)");
1097         Cmd_AddCommand ("-button16", IN_Button16Up, "deactivate button3");
1098
1099         Cvar_RegisterVariable(&cl_movement);
1100         Cvar_RegisterVariable(&cl_movement_latency);
1101         Cvar_RegisterVariable(&cl_movement_maxspeed);
1102         Cvar_RegisterVariable(&cl_movement_maxairspeed);
1103         Cvar_RegisterVariable(&cl_movement_stopspeed);
1104         Cvar_RegisterVariable(&cl_movement_friction);
1105         Cvar_RegisterVariable(&cl_movement_edgefriction);
1106         Cvar_RegisterVariable(&cl_movement_stepheight);
1107         Cvar_RegisterVariable(&cl_movement_accelerate);
1108         Cvar_RegisterVariable(&cl_movement_jumpvelocity);
1109         Cvar_RegisterVariable(&cl_gravity);
1110         Cvar_RegisterVariable(&cl_slowmo);
1111
1112         Cvar_RegisterVariable(&in_pitch_min);
1113         Cvar_RegisterVariable(&in_pitch_max);
1114         Cvar_RegisterVariable(&m_filter);
1115
1116         Cvar_RegisterVariable(&cl_netinputpacketspersecond);
1117 }
1118