Too many fixes to mention. (sys_ticrate now controls packet rates, and other stuff)
[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_use, in_jump, in_attack;
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
60 void KeyDown (kbutton_t *b)
61 {
62         int             k;
63         char    *c;
64
65         c = Cmd_Argv(1);
66         if (c[0])
67                 k = atoi(c);
68         else
69                 k = -1;         // typed manually at the console for continuous down
70
71         if (k == b->down[0] || k == b->down[1])
72                 return;         // repeating key
73         
74         if (!b->down[0])
75                 b->down[0] = k;
76         else if (!b->down[1])
77                 b->down[1] = k;
78         else
79         {
80                 Con_Printf ("Three keys down for a button!\n");
81                 return;
82         }
83         
84         if (b->state & 1)
85                 return;         // still down
86         b->state |= 1 + 2;      // down + impulse down
87 }
88
89 void KeyUp (kbutton_t *b)
90 {
91         int             k;
92         char    *c;
93         
94         c = Cmd_Argv(1);
95         if (c[0])
96                 k = atoi(c);
97         else
98         { // typed manually at the console, assume for unsticking, so clear all
99                 b->down[0] = b->down[1] = 0;
100                 b->state = 4;   // impulse up
101                 return;
102         }
103
104         if (b->down[0] == k)
105                 b->down[0] = 0;
106         else if (b->down[1] == k)
107                 b->down[1] = 0;
108         else
109                 return;         // key up without coresponding down (menu pass through)
110         if (b->down[0] || b->down[1])
111                 return;         // some other key is still holding it down
112
113         if (!(b->state & 1))
114                 return;         // still up (this should not happen)
115         b->state &= ~1;         // now up
116         b->state |= 4;          // impulse up
117 }
118
119 void IN_KLookDown (void) {KeyDown(&in_klook);}
120 void IN_KLookUp (void) {KeyUp(&in_klook);}
121 void IN_MLookDown (void) {KeyDown(&in_mlook);}
122 void IN_MLookUp (void) {
123 KeyUp(&in_mlook);
124 if ( !(in_mlook.state&1) &&  lookspring.value)
125         V_StartPitchDrift();
126 }
127 void IN_UpDown(void) {KeyDown(&in_up);}
128 void IN_UpUp(void) {KeyUp(&in_up);}
129 void IN_DownDown(void) {KeyDown(&in_down);}
130 void IN_DownUp(void) {KeyUp(&in_down);}
131 void IN_LeftDown(void) {KeyDown(&in_left);}
132 void IN_LeftUp(void) {KeyUp(&in_left);}
133 void IN_RightDown(void) {KeyDown(&in_right);}
134 void IN_RightUp(void) {KeyUp(&in_right);}
135 void IN_ForwardDown(void) {KeyDown(&in_forward);}
136 void IN_ForwardUp(void) {KeyUp(&in_forward);}
137 void IN_BackDown(void) {KeyDown(&in_back);}
138 void IN_BackUp(void) {KeyUp(&in_back);}
139 void IN_LookupDown(void) {KeyDown(&in_lookup);}
140 void IN_LookupUp(void) {KeyUp(&in_lookup);}
141 void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
142 void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
143 void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
144 void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
145 void IN_MoverightDown(void) {KeyDown(&in_moveright);}
146 void IN_MoverightUp(void) {KeyUp(&in_moveright);}
147
148 void IN_SpeedDown(void) {KeyDown(&in_speed);}
149 void IN_SpeedUp(void) {KeyUp(&in_speed);}
150 void IN_StrafeDown(void) {KeyDown(&in_strafe);}
151 void IN_StrafeUp(void) {KeyUp(&in_strafe);}
152
153 void IN_AttackDown(void) {KeyDown(&in_attack);}
154 void IN_AttackUp(void) {KeyUp(&in_attack);}
155
156 // LordHavoc: added 6 new buttons
157 void IN_Button3Down(void) {KeyDown(&in_button3);} void IN_Button3Up(void) {KeyUp(&in_button3);}
158 void IN_Button4Down(void) {KeyDown(&in_button4);} void IN_Button4Up(void) {KeyUp(&in_button4);}
159 void IN_Button5Down(void) {KeyDown(&in_button5);} void IN_Button5Up(void) {KeyUp(&in_button5);}
160 void IN_Button6Down(void) {KeyDown(&in_button6);} void IN_Button6Up(void) {KeyUp(&in_button6);}
161 void IN_Button7Down(void) {KeyDown(&in_button7);} void IN_Button7Up(void) {KeyUp(&in_button7);}
162 void IN_Button8Down(void) {KeyDown(&in_button8);} void IN_Button8Up(void) {KeyUp(&in_button8);}
163
164 void IN_UseDown (void) {KeyDown(&in_use);}
165 void IN_UseUp (void) {KeyUp(&in_use);}
166 void IN_JumpDown (void) {KeyDown(&in_jump);}
167 void IN_JumpUp (void) {KeyUp(&in_jump);}
168
169 void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
170
171 /*
172 ===============
173 CL_KeyState
174
175 Returns 0.25 if a key was pressed and released during the frame,
176 0.5 if it was pressed and held
177 0 if held then released, and
178 1.0 if held for the entire time
179 ===============
180 */
181 float CL_KeyState (kbutton_t *key)
182 {
183         float           val;
184         qboolean        impulsedown, impulseup, down;
185         
186         impulsedown = key->state & 2;
187         impulseup = key->state & 4;
188         down = key->state & 1;
189         val = 0;
190         
191         if (impulsedown && !impulseup)
192                 if (down)
193                         val = 0.5;      // pressed and held this frame
194                 else
195                         val = 0;        //      I_Error ();
196         if (impulseup && !impulsedown)
197                 if (down)
198                         val = 0;        //      I_Error ();
199                 else
200                         val = 0;        // released this frame
201         if (!impulsedown && !impulseup)
202                 if (down)
203                         val = 1.0;      // held the entire frame
204                 else
205                         val = 0;        // up the entire frame
206         if (impulsedown && impulseup)
207                 if (down)
208                         val = 0.75;     // released and re-pressed this frame
209                 else
210                         val = 0.25;     // pressed and released this frame
211
212         key->state &= 1;                // clear impulses
213         
214         return val;
215 }
216
217
218
219
220 //==========================================================================
221
222 cvar_t  cl_upspeed = {"cl_upspeed","200"};
223 cvar_t  cl_forwardspeed = {"cl_forwardspeed","200", true};
224 cvar_t  cl_backspeed = {"cl_backspeed","200", true};
225 cvar_t  cl_sidespeed = {"cl_sidespeed","350"};
226
227 cvar_t  cl_movespeedkey = {"cl_movespeedkey","2.0"};
228
229 cvar_t  cl_yawspeed = {"cl_yawspeed","140"};
230 cvar_t  cl_pitchspeed = {"cl_pitchspeed","150"};
231
232 cvar_t  cl_anglespeedkey = {"cl_anglespeedkey","1.5"};
233
234
235 /*
236 ================
237 CL_AdjustAngles
238
239 Moves the local angle positions
240 ================
241 */
242 void CL_AdjustAngles (void)
243 {
244         float   speed;
245         float   up, down;
246         
247         if (in_speed.state & 1)
248                 speed = host_frametime * cl_anglespeedkey.value;
249         else
250                 speed = host_frametime;
251
252         if (!(in_strafe.state & 1))
253         {
254                 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
255                 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
256                 cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);
257         }
258         if (in_klook.state & 1)
259         {
260                 V_StopPitchDrift ();
261                 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
262                 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
263         }
264         
265         up = CL_KeyState (&in_lookup);
266         down = CL_KeyState(&in_lookdown);
267         
268         cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
269         cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
270
271         if (up || down)
272                 V_StopPitchDrift ();
273
274         // LordHavoc: changed from 80 to 90 (straight up)
275         if (cl.viewangles[PITCH] > 90)
276                 cl.viewangles[PITCH] = 90;
277         // LordHavoc: changed from -70 to -90 (straight down)
278         if (cl.viewangles[PITCH] < -90)
279                 cl.viewangles[PITCH] = -90;
280
281         if (cl.viewangles[ROLL] > 50)
282                 cl.viewangles[ROLL] = 50;
283         if (cl.viewangles[ROLL] < -50)
284                 cl.viewangles[ROLL] = -50;
285                 
286 }
287
288 /*
289 ================
290 CL_BaseMove
291
292 Send the intended movement message to the server
293 ================
294 */
295 void CL_BaseMove (usercmd_t *cmd)
296 {       
297         if (cls.signon != SIGNONS)
298                 return;
299                         
300         CL_AdjustAngles ();
301         
302         memset (cmd, 0, sizeof(*cmd));
303         
304         if (in_strafe.state & 1)
305         {
306                 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
307                 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
308         }
309
310         cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
311         cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
312
313         cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);
314         cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);
315
316         if (! (in_klook.state & 1) )
317         {       
318                 cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
319                 cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
320         }       
321
322 //
323 // adjust for speed key
324 //
325         if (in_speed.state & 1)
326         {
327                 cmd->forwardmove *= cl_movespeedkey.value;
328                 cmd->sidemove *= cl_movespeedkey.value;
329                 cmd->upmove *= cl_movespeedkey.value;
330         }
331 }
332
333
334
335 /*
336 ==============
337 CL_SendMove
338 ==============
339 */
340 void CL_SendMove (usercmd_t *cmd)
341 {
342         int             i;
343         int             bits;
344         sizebuf_t       buf;
345         byte    data[128];
346         static double lastmovetime;
347         static float forwardmove, sidemove, upmove, total; // accumulation
348
349         forwardmove += cmd->forwardmove;
350         sidemove += cmd->sidemove;
351         upmove += cmd->upmove;
352         total++;
353         // LordHavoc: cap outgoing movement messages to sys_ticrate
354         if (realtime - lastmovetime < sys_ticrate.value)
355                 return;
356         lastmovetime = realtime;
357         // average what has happened during this time
358         total = 1.0f / total;
359         forwardmove *= total;
360         sidemove *= total;
361         upmove *= total;
362         total = 0;
363
364         buf.maxsize = 128;
365         buf.cursize = 0;
366         buf.data = data;
367         
368         cl.cmd = *cmd;
369
370 //
371 // send the movement message
372 //
373     MSG_WriteByte (&buf, clc_move);
374
375         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
376
377         for (i=0 ; i<3 ; i++)
378                 MSG_WriteAngle (&buf, cl.viewangles[i]);
379         
380     MSG_WriteShort (&buf, forwardmove);
381     MSG_WriteShort (&buf, sidemove);
382     MSG_WriteShort (&buf, upmove);
383
384 //
385 // send button bits
386 //
387         bits = 0;
388         
389         if ( in_attack.state & 3 )
390                 bits |= 1;
391         in_attack.state &= ~2;
392         
393         if (in_jump.state & 3)
394                 bits |= 2;
395         in_jump.state &= ~2;
396         // LordHavoc: added 6 new buttons
397         if (in_button3.state & 3) bits |=   4;in_button3.state &= ~2;
398         if (in_button4.state & 3) bits |=   8;in_button4.state &= ~2;
399         if (in_button5.state & 3) bits |=  16;in_button5.state &= ~2;
400         if (in_button6.state & 3) bits |=  32;in_button6.state &= ~2;
401         if (in_button7.state & 3) bits |=  64;in_button7.state &= ~2;
402         if (in_button8.state & 3) bits |= 128;in_button8.state &= ~2;
403         
404     MSG_WriteByte (&buf, bits);
405
406     MSG_WriteByte (&buf, in_impulse);
407         in_impulse = 0;
408
409 //
410 // deliver the message
411 //
412         if (cls.demoplayback)
413                 return;
414
415 //
416 // allways dump the first two message, because it may contain leftover inputs
417 // from the last level
418 //
419         if (++cl.movemessages <= 2)
420                 return;
421
422         if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
423         {
424                 Con_Printf ("CL_SendMove: lost server connection\n");
425                 CL_Disconnect ();
426         }
427 }
428
429 /*
430 ============
431 CL_InitInput
432 ============
433 */
434 void CL_InitInput (void)
435 {
436         Cmd_AddCommand ("+moveup",IN_UpDown);
437         Cmd_AddCommand ("-moveup",IN_UpUp);
438         Cmd_AddCommand ("+movedown",IN_DownDown);
439         Cmd_AddCommand ("-movedown",IN_DownUp);
440         Cmd_AddCommand ("+left",IN_LeftDown);
441         Cmd_AddCommand ("-left",IN_LeftUp);
442         Cmd_AddCommand ("+right",IN_RightDown);
443         Cmd_AddCommand ("-right",IN_RightUp);
444         Cmd_AddCommand ("+forward",IN_ForwardDown);
445         Cmd_AddCommand ("-forward",IN_ForwardUp);
446         Cmd_AddCommand ("+back",IN_BackDown);
447         Cmd_AddCommand ("-back",IN_BackUp);
448         Cmd_AddCommand ("+lookup", IN_LookupDown);
449         Cmd_AddCommand ("-lookup", IN_LookupUp);
450         Cmd_AddCommand ("+lookdown", IN_LookdownDown);
451         Cmd_AddCommand ("-lookdown", IN_LookdownUp);
452         Cmd_AddCommand ("+strafe", IN_StrafeDown);
453         Cmd_AddCommand ("-strafe", IN_StrafeUp);
454         Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
455         Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
456         Cmd_AddCommand ("+moveright", IN_MoverightDown);
457         Cmd_AddCommand ("-moveright", IN_MoverightUp);
458         Cmd_AddCommand ("+speed", IN_SpeedDown);
459         Cmd_AddCommand ("-speed", IN_SpeedUp);
460         Cmd_AddCommand ("+attack", IN_AttackDown);
461         Cmd_AddCommand ("-attack", IN_AttackUp);
462         Cmd_AddCommand ("+use", IN_UseDown);
463         Cmd_AddCommand ("-use", IN_UseUp);
464         Cmd_AddCommand ("+jump", IN_JumpDown);
465         Cmd_AddCommand ("-jump", IN_JumpUp);
466         Cmd_AddCommand ("impulse", IN_Impulse);
467         Cmd_AddCommand ("+klook", IN_KLookDown);
468         Cmd_AddCommand ("-klook", IN_KLookUp);
469         Cmd_AddCommand ("+mlook", IN_MLookDown);
470         Cmd_AddCommand ("-mlook", IN_MLookUp);
471
472         // LordHavoc: added 6 new buttons
473         Cmd_AddCommand ("+button3", IN_Button3Down);
474         Cmd_AddCommand ("-button3", IN_Button3Up);
475         Cmd_AddCommand ("+button4", IN_Button4Down);
476         Cmd_AddCommand ("-button4", IN_Button4Up);
477         Cmd_AddCommand ("+button5", IN_Button5Down);
478         Cmd_AddCommand ("-button5", IN_Button5Up);
479         Cmd_AddCommand ("+button6", IN_Button6Down);
480         Cmd_AddCommand ("-button6", IN_Button6Up);
481         Cmd_AddCommand ("+button7", IN_Button7Down);
482         Cmd_AddCommand ("-button7", IN_Button7Up);
483         Cmd_AddCommand ("+button8", IN_Button8Down);
484         Cmd_AddCommand ("-button8", IN_Button8Up);
485 }