changed protocol back to using float coordinates, unless the mod specifies EF_LOWPREC...
[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         {
193                 if (down)
194                         val = 0.5;      // pressed and held this frame
195                 else
196                         val = 0;        //      I_Error ();
197         }
198         if (impulseup && !impulsedown)
199         {
200                 if (down)
201                         val = 0;        //      I_Error ();
202                 else
203                         val = 0;        // released this frame
204         }
205         if (!impulsedown && !impulseup)
206         {
207                 if (down)
208                         val = 1.0;      // held the entire frame
209                 else
210                         val = 0;        // up the entire frame
211         }
212         if (impulsedown && impulseup)
213         {
214                 if (down)
215                         val = 0.75;     // released and re-pressed this frame
216                 else
217                         val = 0.25;     // pressed and released this frame
218         }
219
220         key->state &= 1;                // clear impulses
221         
222         return val;
223 }
224
225
226
227
228 //==========================================================================
229
230 cvar_t cl_upspeed = {CVAR_SAVE, "cl_upspeed","400"};
231 cvar_t cl_forwardspeed = {CVAR_SAVE, "cl_forwardspeed","400"};
232 cvar_t cl_backspeed = {CVAR_SAVE, "cl_backspeed","400"};
233 cvar_t cl_sidespeed = {CVAR_SAVE, "cl_sidespeed","350"};
234
235 cvar_t cl_movespeedkey = {CVAR_SAVE, "cl_movespeedkey","2.0"};
236
237 cvar_t cl_yawspeed = {CVAR_SAVE, "cl_yawspeed","140"};
238 cvar_t cl_pitchspeed = {CVAR_SAVE, "cl_pitchspeed","150"};
239
240 cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5"};
241
242
243 /*
244 ================
245 CL_AdjustAngles
246
247 Moves the local angle positions
248 ================
249 */
250 void CL_AdjustAngles (void)
251 {
252         float   speed;
253         float   up, down;
254
255         if (in_speed.state & 1)
256                 speed = cl.frametime * cl_anglespeedkey.value;
257         else
258                 speed = cl.frametime;
259
260         if (!(in_strafe.state & 1))
261         {
262                 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
263                 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
264         }
265         if (in_klook.state & 1)
266         {
267                 V_StopPitchDrift ();
268                 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
269                 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
270         }
271
272         up = CL_KeyState (&in_lookup);
273         down = CL_KeyState(&in_lookdown);
274
275         cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
276         cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
277
278         if (up || down)
279                 V_StopPitchDrift ();
280
281         cl.viewangles[YAW] = ANGLEMOD(cl.viewangles[YAW]);
282         cl.viewangles[PITCH] = ANGLEMOD(cl.viewangles[PITCH]);
283         cl.viewangles[ROLL] = ANGLEMOD(cl.viewangles[ROLL]);
284         if (cl.viewangles[YAW] >= 180)
285                 cl.viewangles[YAW] -= 360;
286         if (cl.viewangles[PITCH] >= 180)
287                 cl.viewangles[PITCH] -= 360;
288         if (cl.viewangles[ROLL] >= 180)
289                 cl.viewangles[ROLL] -= 360;
290
291         cl.viewangles[PITCH] = bound (in_pitch_min.value, cl.viewangles[PITCH], in_pitch_max.value);
292         cl.viewangles[ROLL] = bound(-50, cl.viewangles[ROLL], 50);
293 }
294
295 /*
296 ================
297 CL_BaseMove
298
299 Send the intended movement message to the server
300 ================
301 */
302 void CL_BaseMove (usercmd_t *cmd)
303 {       
304         if (cls.signon != SIGNONS)
305                 return;
306                         
307         CL_AdjustAngles ();
308         
309         memset (cmd, 0, sizeof(*cmd));
310         
311         if (in_strafe.state & 1)
312         {
313                 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
314                 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
315         }
316
317         cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
318         cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
319
320         cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);
321         cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);
322
323         if (! (in_klook.state & 1) )
324         {       
325                 cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
326                 cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
327         }       
328
329 //
330 // adjust for speed key
331 //
332         if (in_speed.state & 1)
333         {
334                 cmd->forwardmove *= cl_movespeedkey.value;
335                 cmd->sidemove *= cl_movespeedkey.value;
336                 cmd->upmove *= cl_movespeedkey.value;
337         }
338 }
339
340
341
342 /*
343 ==============
344 CL_SendMove
345 ==============
346 */
347 void CL_SendMove (usercmd_t *cmd)
348 {
349         int             i;
350         int             bits;
351         sizebuf_t       buf;
352         qbyte   data[128];
353         static double lastmovetime;
354         static float forwardmove, sidemove, upmove, total; // accumulation
355
356         forwardmove += cmd->forwardmove;
357         sidemove += cmd->sidemove;
358         upmove += cmd->upmove;
359         total++;
360         // LordHavoc: cap outgoing movement messages to sys_ticrate
361         if ((cl.maxclients > 1) && (realtime - lastmovetime < sys_ticrate.value))
362                 return;
363         lastmovetime = realtime;
364         // average what has happened during this time
365         total = 1.0f / total;
366         forwardmove *= total;
367         sidemove *= total;
368         upmove *= total;
369         total = 0;
370
371         buf.maxsize = 128;
372         buf.cursize = 0;
373         buf.data = data;
374
375         cl.cmd = *cmd;
376
377 //
378 // send the movement message
379 //
380     MSG_WriteByte (&buf, clc_move);
381
382         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
383
384         if (dpprotocol == DPPROTOCOL_VERSION2 || dpprotocol == DPPROTOCOL_VERSION3)
385         {
386                 for (i = 0;i < 3;i++)
387                         MSG_WriteFloat (&buf, cl.viewangles[i]);
388         }
389         else if (dpprotocol == DPPROTOCOL_VERSION1)
390         {
391                 for (i=0 ; i<3 ; i++)
392                         MSG_WritePreciseAngle (&buf, cl.viewangles[i]);
393         }
394         else
395         {
396                 for (i=0 ; i<3 ; i++)
397                         MSG_WriteAngle (&buf, cl.viewangles[i]);
398         }
399
400     MSG_WriteShort (&buf, forwardmove);
401     MSG_WriteShort (&buf, sidemove);
402     MSG_WriteShort (&buf, upmove);
403
404         forwardmove = sidemove = upmove = 0;
405 //
406 // send button bits
407 //
408         bits = 0;
409
410         if ( in_attack.state & 3 )
411                 bits |= 1;
412         in_attack.state &= ~2;
413
414         if (in_jump.state & 3)
415                 bits |= 2;
416         in_jump.state &= ~2;
417         // LordHavoc: added 6 new buttons
418         if (in_button3.state & 3) bits |=   4;in_button3.state &= ~2;
419         if (in_button4.state & 3) bits |=   8;in_button4.state &= ~2;
420         if (in_button5.state & 3) bits |=  16;in_button5.state &= ~2;
421         if (in_button6.state & 3) bits |=  32;in_button6.state &= ~2;
422         if (in_button7.state & 3) bits |=  64;in_button7.state &= ~2;
423         if (in_button8.state & 3) bits |= 128;in_button8.state &= ~2;
424
425     MSG_WriteByte (&buf, bits);
426
427     MSG_WriteByte (&buf, in_impulse);
428         in_impulse = 0;
429
430         // LordHavoc: should we ack this on receipt instead?  would waste net bandwidth though
431         i = EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase);
432         if (i > 0)
433         {
434                 MSG_WriteByte (&buf, clc_ackentities);
435                 MSG_WriteLong (&buf, i);
436         }
437
438 //
439 // deliver the message
440 //
441         if (cls.demoplayback)
442                 return;
443
444 //
445 // always dump the first two messages, because they may contain leftover inputs from the last level
446 //
447         if (++cl.movemessages <= 2)
448                 return;
449
450         if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
451         {
452                 Con_Printf ("CL_SendMove: lost server connection\n");
453                 CL_Disconnect ();
454         }
455 }
456
457 /*
458 ============
459 CL_InitInput
460 ============
461 */
462 void CL_InitInput (void)
463 {
464         Cmd_AddCommand ("+moveup",IN_UpDown);
465         Cmd_AddCommand ("-moveup",IN_UpUp);
466         Cmd_AddCommand ("+movedown",IN_DownDown);
467         Cmd_AddCommand ("-movedown",IN_DownUp);
468         Cmd_AddCommand ("+left",IN_LeftDown);
469         Cmd_AddCommand ("-left",IN_LeftUp);
470         Cmd_AddCommand ("+right",IN_RightDown);
471         Cmd_AddCommand ("-right",IN_RightUp);
472         Cmd_AddCommand ("+forward",IN_ForwardDown);
473         Cmd_AddCommand ("-forward",IN_ForwardUp);
474         Cmd_AddCommand ("+back",IN_BackDown);
475         Cmd_AddCommand ("-back",IN_BackUp);
476         Cmd_AddCommand ("+lookup", IN_LookupDown);
477         Cmd_AddCommand ("-lookup", IN_LookupUp);
478         Cmd_AddCommand ("+lookdown", IN_LookdownDown);
479         Cmd_AddCommand ("-lookdown", IN_LookdownUp);
480         Cmd_AddCommand ("+strafe", IN_StrafeDown);
481         Cmd_AddCommand ("-strafe", IN_StrafeUp);
482         Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
483         Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
484         Cmd_AddCommand ("+moveright", IN_MoverightDown);
485         Cmd_AddCommand ("-moveright", IN_MoverightUp);
486         Cmd_AddCommand ("+speed", IN_SpeedDown);
487         Cmd_AddCommand ("-speed", IN_SpeedUp);
488         Cmd_AddCommand ("+attack", IN_AttackDown);
489         Cmd_AddCommand ("-attack", IN_AttackUp);
490         Cmd_AddCommand ("+use", IN_UseDown);
491         Cmd_AddCommand ("-use", IN_UseUp);
492         Cmd_AddCommand ("+jump", IN_JumpDown);
493         Cmd_AddCommand ("-jump", IN_JumpUp);
494         Cmd_AddCommand ("impulse", IN_Impulse);
495         Cmd_AddCommand ("+klook", IN_KLookDown);
496         Cmd_AddCommand ("-klook", IN_KLookUp);
497         Cmd_AddCommand ("+mlook", IN_MLookDown);
498         Cmd_AddCommand ("-mlook", IN_MLookUp);
499
500         // LordHavoc: added 6 new buttons
501         Cmd_AddCommand ("+button3", IN_Button3Down);
502         Cmd_AddCommand ("-button3", IN_Button3Up);
503         Cmd_AddCommand ("+button4", IN_Button4Down);
504         Cmd_AddCommand ("-button4", IN_Button4Up);
505         Cmd_AddCommand ("+button5", IN_Button5Down);
506         Cmd_AddCommand ("-button5", IN_Button5Up);
507         Cmd_AddCommand ("+button6", IN_Button6Down);
508         Cmd_AddCommand ("-button6", IN_Button6Up);
509         Cmd_AddCommand ("+button7", IN_Button7Down);
510         Cmd_AddCommand ("-button7", IN_Button7Up);
511         Cmd_AddCommand ("+button8", IN_Button8Down);
512         Cmd_AddCommand ("-button8", IN_Button8Up);
513 }