]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_input.c
no longer hits triangles of your own player model when tracing the prydoncursor from...
[divverent/darkplaces.git] / cl_input.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // cl.input.c  -- builds an intended movement command to send to the server
21
22 // Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
23 // rights reserved.
24
25 #include "quakedef.h"
26
27 /*
28 ===============================================================================
29
30 KEY BUTTONS
31
32 Continuous button event tracking is complicated by the fact that two different
33 input sources (say, mouse button 1 and the control key) can both press the
34 same button, but the button should only be released when both of the
35 pressing key have been released.
36
37 When a key event issues a button command (+forward, +attack, etc), it appends
38 its key number as a parameter to the command so it can be matched up with
39 the release.
40
41 state bit 0 is the current state of the key
42 state bit 1 is edge triggered on the up to down transition
43 state bit 2 is edge triggered on the down to up transition
44
45 ===============================================================================
46 */
47
48
49 kbutton_t       in_mlook, in_klook;
50 kbutton_t       in_left, in_right, in_forward, in_back;
51 kbutton_t       in_lookup, in_lookdown, in_moveleft, in_moveright;
52 kbutton_t       in_strafe, in_speed, in_jump, in_attack, in_use;
53 kbutton_t       in_up, in_down;
54 // LordHavoc: added 6 new buttons
55 kbutton_t       in_button3, in_button4, in_button5, in_button6, in_button7, in_button8;
56
57 int                     in_impulse;
58
59 extern cvar_t sys_ticrate;
60
61
62 void KeyDown (kbutton_t *b)
63 {
64         int k;
65         const char *c;
66
67         c = Cmd_Argv(1);
68         if (c[0])
69                 k = atoi(c);
70         else
71                 k = -1;         // typed manually at the console for continuous down
72
73         if (k == b->down[0] || k == b->down[1])
74                 return;         // repeating key
75
76         if (!b->down[0])
77                 b->down[0] = k;
78         else if (!b->down[1])
79                 b->down[1] = k;
80         else
81         {
82                 Con_Print("Three keys down for a button!\n");
83                 return;
84         }
85
86         if (b->state & 1)
87                 return;         // still down
88         b->state |= 1 + 2;      // down + impulse down
89 }
90
91 void KeyUp (kbutton_t *b)
92 {
93         int k;
94         const char *c;
95
96         c = Cmd_Argv(1);
97         if (c[0])
98                 k = atoi(c);
99         else
100         { // typed manually at the console, assume for unsticking, so clear all
101                 b->down[0] = b->down[1] = 0;
102                 b->state = 4;   // impulse up
103                 return;
104         }
105
106         if (b->down[0] == k)
107                 b->down[0] = 0;
108         else if (b->down[1] == k)
109                 b->down[1] = 0;
110         else
111                 return;         // key up without coresponding down (menu pass through)
112         if (b->down[0] || b->down[1])
113                 return;         // some other key is still holding it down
114
115         if (!(b->state & 1))
116                 return;         // still up (this should not happen)
117         b->state &= ~1;         // now up
118         b->state |= 4;          // impulse up
119 }
120
121 void IN_KLookDown (void) {KeyDown(&in_klook);}
122 void IN_KLookUp (void) {KeyUp(&in_klook);}
123 void IN_MLookDown (void) {KeyDown(&in_mlook);}
124 void IN_MLookUp (void)
125 {
126         KeyUp(&in_mlook);
127         if ( !(in_mlook.state&1) && lookspring.value)
128                 V_StartPitchDrift();
129 }
130 void IN_UpDown(void) {KeyDown(&in_up);}
131 void IN_UpUp(void) {KeyUp(&in_up);}
132 void IN_DownDown(void) {KeyDown(&in_down);}
133 void IN_DownUp(void) {KeyUp(&in_down);}
134 void IN_LeftDown(void) {KeyDown(&in_left);}
135 void IN_LeftUp(void) {KeyUp(&in_left);}
136 void IN_RightDown(void) {KeyDown(&in_right);}
137 void IN_RightUp(void) {KeyUp(&in_right);}
138 void IN_ForwardDown(void) {KeyDown(&in_forward);}
139 void IN_ForwardUp(void) {KeyUp(&in_forward);}
140 void IN_BackDown(void) {KeyDown(&in_back);}
141 void IN_BackUp(void) {KeyUp(&in_back);}
142 void IN_LookupDown(void) {KeyDown(&in_lookup);}
143 void IN_LookupUp(void) {KeyUp(&in_lookup);}
144 void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
145 void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
146 void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
147 void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
148 void IN_MoverightDown(void) {KeyDown(&in_moveright);}
149 void IN_MoverightUp(void) {KeyUp(&in_moveright);}
150
151 void IN_SpeedDown(void) {KeyDown(&in_speed);}
152 void IN_SpeedUp(void) {KeyUp(&in_speed);}
153 void IN_StrafeDown(void) {KeyDown(&in_strafe);}
154 void IN_StrafeUp(void) {KeyUp(&in_strafe);}
155
156 void IN_AttackDown(void) {KeyDown(&in_attack);}
157 void IN_AttackUp(void) {KeyUp(&in_attack);}
158
159 void IN_UseDown(void) {KeyDown(&in_use);}
160 void IN_UseUp(void) {KeyUp(&in_use);}
161
162 // LordHavoc: added 6 new buttons
163 void IN_Button3Down(void) {KeyDown(&in_button3);}
164 void IN_Button3Up(void) {KeyUp(&in_button3);}
165 void IN_Button4Down(void) {KeyDown(&in_button4);}
166 void IN_Button4Up(void) {KeyUp(&in_button4);}
167 void IN_Button5Down(void) {KeyDown(&in_button5);}
168 void IN_Button5Up(void) {KeyUp(&in_button5);}
169 void IN_Button6Down(void) {KeyDown(&in_button6);}
170 void IN_Button6Up(void) {KeyUp(&in_button6);}
171 void IN_Button7Down(void) {KeyDown(&in_button7);}
172 void IN_Button7Up(void) {KeyUp(&in_button7);}
173 void IN_Button8Down(void) {KeyDown(&in_button8);}
174 void IN_Button8Up(void) {KeyUp(&in_button8);}
175
176 void IN_JumpDown (void) {KeyDown(&in_jump);}
177 void IN_JumpUp (void) {KeyUp(&in_jump);}
178
179 void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
180
181 /*
182 ===============
183 CL_KeyState
184
185 Returns 0.25 if a key was pressed and released during the frame,
186 0.5 if it was pressed and held
187 0 if held then released, and
188 1.0 if held for the entire time
189 ===============
190 */
191 float CL_KeyState (kbutton_t *key)
192 {
193         float           val;
194         qboolean        impulsedown, impulseup, down;
195
196         impulsedown = key->state & 2;
197         impulseup = key->state & 4;
198         down = key->state & 1;
199         val = 0;
200
201         if (impulsedown && !impulseup)
202         {
203                 if (down)
204                         val = 0.5;      // pressed and held this frame
205                 else
206                         val = 0;        //      I_Error ();
207         }
208         if (impulseup && !impulsedown)
209         {
210                 if (down)
211                         val = 0;        //      I_Error ();
212                 else
213                         val = 0;        // released this frame
214         }
215         if (!impulsedown && !impulseup)
216         {
217                 if (down)
218                         val = 1.0;      // held the entire frame
219                 else
220                         val = 0;        // up the entire frame
221         }
222         if (impulsedown && impulseup)
223         {
224                 if (down)
225                         val = 0.75;     // released and re-pressed this frame
226                 else
227                         val = 0.25;     // pressed and released this frame
228         }
229
230         key->state &= 1;                // clear impulses
231
232         return val;
233 }
234
235
236
237
238 //==========================================================================
239
240 cvar_t cl_upspeed = {CVAR_SAVE, "cl_upspeed","400"};
241 cvar_t cl_forwardspeed = {CVAR_SAVE, "cl_forwardspeed","400"};
242 cvar_t cl_backspeed = {CVAR_SAVE, "cl_backspeed","400"};
243 cvar_t cl_sidespeed = {CVAR_SAVE, "cl_sidespeed","350"};
244
245 cvar_t cl_movespeedkey = {CVAR_SAVE, "cl_movespeedkey","2.0"};
246
247 cvar_t cl_yawspeed = {CVAR_SAVE, "cl_yawspeed","140"};
248 cvar_t cl_pitchspeed = {CVAR_SAVE, "cl_pitchspeed","150"};
249
250 cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5"};
251
252 /*
253 ================
254 CL_AdjustAngles
255
256 Moves the local angle positions
257 ================
258 */
259 void CL_AdjustAngles (void)
260 {
261         float   speed;
262         float   up, down;
263
264         if (in_speed.state & 1)
265                 speed = host_realframetime * cl_anglespeedkey.value;
266         else
267                 speed = host_realframetime;
268
269         if (!(in_strafe.state & 1))
270         {
271                 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
272                 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
273         }
274         if (in_klook.state & 1)
275         {
276                 V_StopPitchDrift ();
277                 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
278                 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
279         }
280
281         up = CL_KeyState (&in_lookup);
282         down = CL_KeyState(&in_lookdown);
283
284         cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
285         cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
286
287         if (up || down)
288                 V_StopPitchDrift ();
289
290         cl.viewangles[YAW] = ANGLEMOD(cl.viewangles[YAW]);
291         cl.viewangles[PITCH] = ANGLEMOD(cl.viewangles[PITCH]);
292         cl.viewangles[ROLL] = ANGLEMOD(cl.viewangles[ROLL]);
293         if (cl.viewangles[YAW] >= 180)
294                 cl.viewangles[YAW] -= 360;
295         if (cl.viewangles[PITCH] >= 180)
296                 cl.viewangles[PITCH] -= 360;
297         if (cl.viewangles[ROLL] >= 180)
298                 cl.viewangles[ROLL] -= 360;
299
300         cl.viewangles[PITCH] = bound (in_pitch_min.value, cl.viewangles[PITCH], in_pitch_max.value);
301         cl.viewangles[ROLL] = bound(-50, cl.viewangles[ROLL], 50);
302 }
303
304 /*
305 ================
306 CL_BaseMove
307
308 Send the intended movement message to the server
309 ================
310 */
311 void CL_BaseMove (void)
312 {
313         vec3_t temp;
314         if (cls.signon != SIGNONS)
315                 return;
316
317         CL_AdjustAngles ();
318
319         // PRYDON_CLIENTCURSOR needs to survive basemove resets
320         VectorCopy (cl.cmd.cursor_screen, temp);
321         memset (&cl.cmd, 0, sizeof(cl.cmd));
322         VectorCopy (temp, cl.cmd.cursor_screen);
323
324         if (in_strafe.state & 1)
325         {
326                 cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
327                 cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
328         }
329
330         cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
331         cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
332
333         cl.cmd.upmove += cl_upspeed.value * CL_KeyState (&in_up);
334         cl.cmd.upmove -= cl_upspeed.value * CL_KeyState (&in_down);
335
336         if (! (in_klook.state & 1) )
337         {
338                 cl.cmd.forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
339                 cl.cmd.forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
340         }
341
342 //
343 // adjust for speed key
344 //
345         if (in_speed.state & 1)
346         {
347                 cl.cmd.forwardmove *= cl_movespeedkey.value;
348                 cl.cmd.sidemove *= cl_movespeedkey.value;
349                 cl.cmd.upmove *= cl_movespeedkey.value;
350         }
351 }
352
353
354 #include "cl_collision.h"
355
356 void CL_UpdatePrydonCursor(void)
357 {
358         vec3_t temp, scale;
359
360         if (!cl_prydoncursor.integer)
361                 VectorClear(cl.cmd.cursor_screen);
362
363         /*
364         if (cl.cmd.cursor_screen[0] < -1)
365         {
366                 cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - -1) * vid.realwidth * sensitivity.value * cl.viewzoom;
367                 cl.cmd.cursor_screen[0] = -1;
368         }
369         if (cl.cmd.cursor_screen[0] > 1)
370         {
371                 cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - 1) * vid.realwidth * sensitivity.value * cl.viewzoom;
372                 cl.cmd.cursor_screen[0] = 1;
373         }
374         if (cl.cmd.cursor_screen[1] < -1)
375         {
376                 cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - -1) * vid.realheight * sensitivity.value * cl.viewzoom;
377                 cl.cmd.cursor_screen[1] = -1;
378         }
379         if (cl.cmd.cursor_screen[1] > 1)
380         {
381                 cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - 1) * vid.realheight * sensitivity.value * cl.viewzoom;
382                 cl.cmd.cursor_screen[1] = 1;
383         }
384         */
385         cl.cmd.cursor_screen[0] = bound(-1, cl.cmd.cursor_screen[0], 1);
386         cl.cmd.cursor_screen[1] = bound(-1, cl.cmd.cursor_screen[1], 1);
387         cl.cmd.cursor_screen[2] = 1;
388
389         scale[0] = -tan(r_refdef.fov_x * M_PI / 360.0);
390         scale[1] = -tan(r_refdef.fov_y * M_PI / 360.0);
391         scale[2] = 1;
392
393         // trace distance
394         VectorScale(scale, 1000000, scale);
395
396         // FIXME: use something other than renderer variables here
397         // (but they need to match)
398         VectorCopy(r_vieworigin, cl.cmd.cursor_start);
399         VectorSet(temp, cl.cmd.cursor_screen[2] * scale[2], cl.cmd.cursor_screen[0] * scale[0], cl.cmd.cursor_screen[1] * scale[1]);
400         Matrix4x4_Transform(&r_view_matrix, temp, cl.cmd.cursor_end);
401         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);
402         // makes sparks where cursor is
403         //CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0);
404 }
405
406 /*
407 ==============
408 CL_SendMove
409 ==============
410 */
411 void CL_SendMove(void)
412 {
413         int i;
414         int bits;
415         sizebuf_t buf;
416         qbyte data[128];
417         static double lastmovetime = 0;
418 #define MOVEAVERAGING 0
419 #if MOVEAVERAGING
420         static float forwardmove, sidemove, upmove, total; // accumulation
421 #else
422         float forwardmove, sidemove, upmove;
423 #endif
424
425         CL_UpdatePrydonCursor();
426
427 #if MOVEAVERAGING
428         // accumulate changes between messages
429         forwardmove += cl.cmd.forwardmove;
430         sidemove += cl.cmd.sidemove;
431         upmove += cl.cmd.upmove;
432         total++;
433 #endif
434         // LordHavoc: cap outgoing movement messages to sys_ticrate
435         if (!cl.islocalgame && (realtime - lastmovetime < sys_ticrate.value))
436                 return;
437         lastmovetime = max(lastmovetime + sys_ticrate.value, realtime);
438 #if MOVEAVERAGING
439         // average the accumulated changes
440         total = 1.0f / total;
441         forwardmove *= total;
442         sidemove *= total;
443         upmove *= total;
444         total = 0;
445 #else
446         // use the latest values
447         forwardmove = cl.cmd.forwardmove;
448         sidemove = cl.cmd.sidemove;
449         upmove = cl.cmd.upmove;
450 #endif
451
452         buf.maxsize = 128;
453         buf.cursize = 0;
454         buf.data = data;
455
456         // set button bits
457         // LordHavoc: added 6 new buttons and use and chat buttons, and prydon cursor active button
458         bits = 0;
459         if (in_attack.state   & 3) bits |=   1;in_attack.state  &= ~2;
460         if (in_jump.state     & 3) bits |=   2;in_jump.state    &= ~2;
461         if (in_button3.state  & 3) bits |=   4;in_button3.state &= ~2;
462         if (in_button4.state  & 3) bits |=   8;in_button4.state &= ~2;
463         if (in_button5.state  & 3) bits |=  16;in_button5.state &= ~2;
464         if (in_button6.state  & 3) bits |=  32;in_button6.state &= ~2;
465         if (in_button7.state  & 3) bits |=  64;in_button7.state &= ~2;
466         if (in_button8.state  & 3) bits |= 128;in_button8.state &= ~2;
467         if (in_use.state      & 3) bits |= 256;in_use.state     &= ~2;
468         if (key_dest != key_game || key_consoleactive) bits |= 512;
469         if (cl_prydoncursor.integer) bits |= 1024;
470         // button bits 11-31 unused currently
471         // rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen
472         if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
473         if (cl.cmd.cursor_screen[0] >=  1) bits |= 16;
474         if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
475         if (cl.cmd.cursor_screen[1] >=  1) bits |= 64;
476
477         // always dump the first two messages, because they may contain leftover inputs from the last level
478         if (++cl.movemessages >= 2)
479         {
480                 // send the movement message
481                 // PROTOCOL_QUAKE       clc_move = 16 bytes total
482                 // PROTOCOL_DARKPLACES1 clc_move = 19 bytes total
483                 // PROTOCOL_DARKPLACES2 clc_move = 25 bytes total
484                 // PROTOCOL_DARKPLACES3 clc_move = 25 bytes total
485                 // PROTOCOL_DARKPLACES4 clc_move = 19 bytes total
486                 // PROTOCOL_DARKPLACES5 clc_move = 19 bytes total
487                 // PROTOCOL_DARKPLACES6 clc_move = 52 bytes total
488                 // 5 bytes
489                 MSG_WriteByte (&buf, clc_move);
490                 MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
491                 if (cl.protocol == PROTOCOL_DARKPLACES6)
492                 {
493                         // 6 bytes
494                         for (i = 0;i < 3;i++)
495                                 MSG_WriteAngle16i (&buf, cl.viewangles[i]);
496                         // 6 bytes
497                         MSG_WriteCoord16i (&buf, forwardmove);
498                         MSG_WriteCoord16i (&buf, sidemove);
499                         MSG_WriteCoord16i (&buf, upmove);
500                         // 5 bytes
501                         MSG_WriteLong (&buf, bits);
502                         MSG_WriteByte (&buf, in_impulse);
503                         // PRYDON_CLIENTCURSOR
504                         // 30 bytes
505                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[0] * 32767.0f);
506                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[1] * 32767.0f);
507                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[0]);
508                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[1]);
509                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[2]);
510                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[0]);
511                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[1]);
512                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
513                         MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
514                 }
515                 else
516                 {
517                         if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
518                         {
519                                 // 3 bytes
520                                 for (i = 0;i < 3;i++)
521                                         MSG_WriteAngle8i (&buf, cl.viewangles[i]);
522                         }
523                         else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
524                         {
525                                 // 12 bytes
526                                 for (i = 0;i < 3;i++)
527                                         MSG_WriteAngle32f (&buf, cl.viewangles[i]);
528                         }
529                         else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
530                         {
531                                 // 6 bytes
532                                 for (i = 0;i < 3;i++)
533                                         MSG_WriteAngle16i (&buf, cl.viewangles[i]);
534                         }
535                         else
536                                 Host_Error("CL_SendMove: unknown cl.protocol %i\n", cl.protocol);
537                         // 6 bytes
538                         MSG_WriteCoord16i (&buf, forwardmove);
539                         MSG_WriteCoord16i (&buf, sidemove);
540                         MSG_WriteCoord16i (&buf, upmove);
541                         // 2 bytes
542                         MSG_WriteByte (&buf, bits);
543                         MSG_WriteByte (&buf, in_impulse);
544                 }
545         }
546
547 #if MOVEAVERAGING
548         forwardmove = sidemove = upmove = 0;
549 #endif
550         in_impulse = 0;
551
552         // ack the last few frame numbers
553         // (redundent to improve handling of client->server packet loss)
554         // for LATESTFRAMENUMS == 3 case this is 15 bytes
555         for (i = 0;i < LATESTFRAMENUMS;i++)
556         {
557                 if (cl.latestframenums[i] > 0)
558                 {
559                         if (developer_networkentities.integer >= 1)
560                                 Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
561                         MSG_WriteByte(&buf, clc_ackframe);
562                         MSG_WriteLong(&buf, cl.latestframenums[i]);
563                 }
564         }
565
566         // PROTOCOL_DARKPLACES6 = 67 bytes per packet
567
568         // deliver the message
569         if (cls.demoplayback)
570                 return;
571         // nothing to send
572         if (!buf.cursize)
573                 return;
574
575         if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
576         {
577                 Con_Print("CL_SendMove: lost server connection\n");
578                 CL_Disconnect();
579                 Host_ShutdownServer(false);
580         }
581 }
582
583 /*
584 ============
585 CL_InitInput
586 ============
587 */
588 void CL_InitInput (void)
589 {
590         Cmd_AddCommand ("+moveup",IN_UpDown);
591         Cmd_AddCommand ("-moveup",IN_UpUp);
592         Cmd_AddCommand ("+movedown",IN_DownDown);
593         Cmd_AddCommand ("-movedown",IN_DownUp);
594         Cmd_AddCommand ("+left",IN_LeftDown);
595         Cmd_AddCommand ("-left",IN_LeftUp);
596         Cmd_AddCommand ("+right",IN_RightDown);
597         Cmd_AddCommand ("-right",IN_RightUp);
598         Cmd_AddCommand ("+forward",IN_ForwardDown);
599         Cmd_AddCommand ("-forward",IN_ForwardUp);
600         Cmd_AddCommand ("+back",IN_BackDown);
601         Cmd_AddCommand ("-back",IN_BackUp);
602         Cmd_AddCommand ("+lookup", IN_LookupDown);
603         Cmd_AddCommand ("-lookup", IN_LookupUp);
604         Cmd_AddCommand ("+lookdown", IN_LookdownDown);
605         Cmd_AddCommand ("-lookdown", IN_LookdownUp);
606         Cmd_AddCommand ("+strafe", IN_StrafeDown);
607         Cmd_AddCommand ("-strafe", IN_StrafeUp);
608         Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
609         Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
610         Cmd_AddCommand ("+moveright", IN_MoverightDown);
611         Cmd_AddCommand ("-moveright", IN_MoverightUp);
612         Cmd_AddCommand ("+speed", IN_SpeedDown);
613         Cmd_AddCommand ("-speed", IN_SpeedUp);
614         Cmd_AddCommand ("+attack", IN_AttackDown);
615         Cmd_AddCommand ("-attack", IN_AttackUp);
616         Cmd_AddCommand ("+jump", IN_JumpDown);
617         Cmd_AddCommand ("-jump", IN_JumpUp);
618         Cmd_AddCommand ("impulse", IN_Impulse);
619         Cmd_AddCommand ("+klook", IN_KLookDown);
620         Cmd_AddCommand ("-klook", IN_KLookUp);
621         Cmd_AddCommand ("+mlook", IN_MLookDown);
622         Cmd_AddCommand ("-mlook", IN_MLookUp);
623
624         // LordHavoc: added use button
625         Cmd_AddCommand ("+use", IN_UseDown);
626         Cmd_AddCommand ("-use", IN_UseUp);
627
628         // LordHavoc: added 6 new buttons
629         Cmd_AddCommand ("+button3", IN_Button3Down);
630         Cmd_AddCommand ("-button3", IN_Button3Up);
631         Cmd_AddCommand ("+button4", IN_Button4Down);
632         Cmd_AddCommand ("-button4", IN_Button4Up);
633         Cmd_AddCommand ("+button5", IN_Button5Down);
634         Cmd_AddCommand ("-button5", IN_Button5Up);
635         Cmd_AddCommand ("+button6", IN_Button6Down);
636         Cmd_AddCommand ("-button6", IN_Button6Up);
637         Cmd_AddCommand ("+button7", IN_Button7Down);
638         Cmd_AddCommand ("-button7", IN_Button7Up);
639         Cmd_AddCommand ("+button8", IN_Button8Down);
640         Cmd_AddCommand ("-button8", IN_Button8Up);
641 }
642