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