1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2010-2014 QuakeSpasm developers
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
15 See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21 */
22 // cl.input.c -- builds an intended movement command to send to the server
23
24 // Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
25 // rights reserved.
26
27 #include "quakedef.h"
28
29 extern cvar_t cl_maxpitch; //johnfitz -- variable pitch clamping
30 extern cvar_t cl_minpitch; //johnfitz -- variable pitch clamping
31
32 /*
33 ===============================================================================
34
35 KEY BUTTONS
36
37 Continuous button event tracking is complicated by the fact that two different
38 input sources (say, mouse button 1 and the control key) can both press the
39 same button, but the button should only be released when both of the
40 pressing key have been released.
41
42 When a key event issues a button command (+forward, +attack, etc), it appends
43 its key number as a parameter to the command so it can be matched up with
44 the release.
45
46 state bit 0 is the current state of the key
47 state bit 1 is edge triggered on the up to down transition
48 state bit 2 is edge triggered on the down to up transition
49
50 ===============================================================================
51 */
52
53
54 kbutton_t in_mlook, in_klook;
55 kbutton_t in_left, in_right, in_forward, in_back;
56 kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
57 kbutton_t in_strafe, in_speed, in_use, in_jump, in_attack;
58 kbutton_t in_up, in_down;
59
60 int in_impulse;
61
62
KeyDown(kbutton_t * b)63 void KeyDown (kbutton_t *b)
64 {
65 int k;
66 const char *c;
67
68 c = Cmd_Argv(1);
69 if (c[0])
70 k = atoi(c);
71 else
72 k = -1; // typed manually at the console for continuous down
73
74 if (k == b->down[0] || k == b->down[1])
75 return; // repeating key
76
77 if (!b->down[0])
78 b->down[0] = k;
79 else if (!b->down[1])
80 b->down[1] = k;
81 else
82 {
83 Con_Printf ("Three keys down for a button!\n");
84 return;
85 }
86
87 if (b->state & 1)
88 return; // still down
89 b->state |= 1 + 2; // down + impulse down
90 }
91
KeyUp(kbutton_t * b)92 void KeyUp (kbutton_t *b)
93 {
94 int k;
95 const char *c;
96
97 c = Cmd_Argv(1);
98 if (c[0])
99 k = atoi(c);
100 else
101 { // typed manually at the console, assume for unsticking, so clear all
102 b->down[0] = b->down[1] = 0;
103 b->state = 4; // impulse up
104 return;
105 }
106
107 if (b->down[0] == k)
108 b->down[0] = 0;
109 else if (b->down[1] == k)
110 b->down[1] = 0;
111 else
112 return; // key up without coresponding down (menu pass through)
113 if (b->down[0] || b->down[1])
114 return; // some other key is still holding it down
115
116 if (!(b->state & 1))
117 return; // still up (this should not happen)
118 b->state &= ~1; // now up
119 b->state |= 4; // impulse up
120 }
121
IN_KLookDown(void)122 void IN_KLookDown (void) {KeyDown(&in_klook);}
IN_KLookUp(void)123 void IN_KLookUp (void) {KeyUp(&in_klook);}
IN_MLookDown(void)124 void IN_MLookDown (void) {KeyDown(&in_mlook);}
IN_MLookUp(void)125 void IN_MLookUp (void) {
126 KeyUp(&in_mlook);
127 if ( !(in_mlook.state&1) && lookspring.value)
128 V_StartPitchDrift();
129 }
IN_UpDown(void)130 void IN_UpDown(void) {KeyDown(&in_up);}
IN_UpUp(void)131 void IN_UpUp(void) {KeyUp(&in_up);}
IN_DownDown(void)132 void IN_DownDown(void) {KeyDown(&in_down);}
IN_DownUp(void)133 void IN_DownUp(void) {KeyUp(&in_down);}
IN_LeftDown(void)134 void IN_LeftDown(void) {KeyDown(&in_left);}
IN_LeftUp(void)135 void IN_LeftUp(void) {KeyUp(&in_left);}
IN_RightDown(void)136 void IN_RightDown(void) {KeyDown(&in_right);}
IN_RightUp(void)137 void IN_RightUp(void) {KeyUp(&in_right);}
IN_ForwardDown(void)138 void IN_ForwardDown(void) {KeyDown(&in_forward);}
IN_ForwardUp(void)139 void IN_ForwardUp(void) {KeyUp(&in_forward);}
IN_BackDown(void)140 void IN_BackDown(void) {KeyDown(&in_back);}
IN_BackUp(void)141 void IN_BackUp(void) {KeyUp(&in_back);}
IN_LookupDown(void)142 void IN_LookupDown(void) {KeyDown(&in_lookup);}
IN_LookupUp(void)143 void IN_LookupUp(void) {KeyUp(&in_lookup);}
IN_LookdownDown(void)144 void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
IN_LookdownUp(void)145 void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
IN_MoveleftDown(void)146 void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
IN_MoveleftUp(void)147 void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
IN_MoverightDown(void)148 void IN_MoverightDown(void) {KeyDown(&in_moveright);}
IN_MoverightUp(void)149 void IN_MoverightUp(void) {KeyUp(&in_moveright);}
150
IN_SpeedDown(void)151 void IN_SpeedDown(void) {KeyDown(&in_speed);}
IN_SpeedUp(void)152 void IN_SpeedUp(void) {KeyUp(&in_speed);}
IN_StrafeDown(void)153 void IN_StrafeDown(void) {KeyDown(&in_strafe);}
IN_StrafeUp(void)154 void IN_StrafeUp(void) {KeyUp(&in_strafe);}
155
IN_AttackDown(void)156 void IN_AttackDown(void) {KeyDown(&in_attack);}
IN_AttackUp(void)157 void IN_AttackUp(void) {KeyUp(&in_attack);}
158
IN_UseDown(void)159 void IN_UseDown (void) {KeyDown(&in_use);}
IN_UseUp(void)160 void IN_UseUp (void) {KeyUp(&in_use);}
IN_JumpDown(void)161 void IN_JumpDown (void) {KeyDown(&in_jump);}
IN_JumpUp(void)162 void IN_JumpUp (void) {KeyUp(&in_jump);}
163
IN_Impulse(void)164 void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));}
165
166 /*
167 ===============
168 CL_KeyState
169
170 Returns 0.25 if a key was pressed and released during the frame,
171 0.5 if it was pressed and held
172 0 if held then released, and
173 1.0 if held for the entire time
174 ===============
175 */
CL_KeyState(kbutton_t * key)176 float CL_KeyState (kbutton_t *key)
177 {
178 float val;
179 qboolean impulsedown, impulseup, down;
180
181 impulsedown = key->state & 2;
182 impulseup = key->state & 4;
183 down = key->state & 1;
184 val = 0;
185
186 if (impulsedown && !impulseup)
187 {
188 if (down)
189 val = 0.5; // pressed and held this frame
190 else
191 val = 0; // I_Error ();
192 }
193 if (impulseup && !impulsedown)
194 {
195 if (down)
196 val = 0; // I_Error ();
197 else
198 val = 0; // released this frame
199 }
200 if (!impulsedown && !impulseup)
201 {
202 if (down)
203 val = 1.0; // held the entire frame
204 else
205 val = 0; // up the entire frame
206 }
207 if (impulsedown && impulseup)
208 {
209 if (down)
210 val = 0.75; // released and re-pressed this frame
211 else
212 val = 0.25; // pressed and released this frame
213 }
214
215 key->state &= 1; // clear impulses
216
217 return val;
218 }
219
220
221 //==========================================================================
222
223 cvar_t cl_upspeed = {"cl_upspeed","200",CVAR_NONE};
224 cvar_t cl_forwardspeed = {"cl_forwardspeed","200", CVAR_ARCHIVE};
225 cvar_t cl_backspeed = {"cl_backspeed","200", CVAR_ARCHIVE};
226 cvar_t cl_sidespeed = {"cl_sidespeed","350",CVAR_NONE};
227
228 cvar_t cl_movespeedkey = {"cl_movespeedkey","2.0",CVAR_NONE};
229
230 cvar_t cl_yawspeed = {"cl_yawspeed","140",CVAR_NONE};
231 cvar_t cl_pitchspeed = {"cl_pitchspeed","150",CVAR_NONE};
232
233 cvar_t cl_anglespeedkey = {"cl_anglespeedkey","1.5",CVAR_NONE};
234
235 cvar_t cl_alwaysrun = {"cl_alwaysrun","0",CVAR_ARCHIVE}; // QuakeSpasm -- new always run
236
237 /*
238 ================
239 CL_AdjustAngles
240
241 Moves the local angle positions
242 ================
243 */
CL_AdjustAngles(void)244 void CL_AdjustAngles (void)
245 {
246 float speed;
247 float up, down;
248
249 if ((in_speed.state & 1) ^ (cl_alwaysrun.value != 0.0))
250 speed = host_frametime * cl_anglespeedkey.value;
251 else
252 speed = host_frametime;
253
254 if (!(in_strafe.state & 1))
255 {
256 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
257 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
258 cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);
259 }
260 if (in_klook.state & 1)
261 {
262 V_StopPitchDrift ();
263 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
264 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
265 }
266
267 up = CL_KeyState (&in_lookup);
268 down = CL_KeyState(&in_lookdown);
269
270 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
271 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
272
273 if (up || down)
274 V_StopPitchDrift ();
275
276 //johnfitz -- variable pitch clamping
277 if (cl.viewangles[PITCH] > cl_maxpitch.value)
278 cl.viewangles[PITCH] = cl_maxpitch.value;
279 if (cl.viewangles[PITCH] < cl_minpitch.value)
280 cl.viewangles[PITCH] = cl_minpitch.value;
281 //johnfitz
282
283 if (cl.viewangles[ROLL] > 50)
284 cl.viewangles[ROLL] = 50;
285 if (cl.viewangles[ROLL] < -50)
286 cl.viewangles[ROLL] = -50;
287 }
288
289 /*
290 ================
291 CL_BaseMove
292
293 Send the intended movement message to the server
294 ================
295 */
CL_BaseMove(usercmd_t * cmd)296 void CL_BaseMove (usercmd_t *cmd)
297 {
298 Q_memset (cmd, 0, sizeof(*cmd));
299
300 VectorCopy(cl.viewangles, cmd->viewangles);
301
302 if (cls.signon != SIGNONS)
303 return;
304
305 if (in_strafe.state & 1)
306 {
307 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
308 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
309 }
310
311 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
312 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
313
314 cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);
315 cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);
316
317 if (! (in_klook.state & 1) )
318 {
319 cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
320 cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
321 }
322
323 //
324 // adjust for speed key
325 //
326 if ((in_speed.state & 1) ^ (cl_alwaysrun.value != 0.0))
327 {
328 cmd->forwardmove *= cl_movespeedkey.value;
329 cmd->sidemove *= cl_movespeedkey.value;
330 cmd->upmove *= cl_movespeedkey.value;
331 }
332 }
333
CL_FinishMove(usercmd_t * cmd)334 void CL_FinishMove(usercmd_t *cmd)
335 {
336 unsigned int bits;
337 //
338 // send button bits
339 //
340 bits = 0;
341
342 if ( in_attack.state & 3 )
343 bits |= 1;
344 in_attack.state &= ~2;
345
346 if (in_jump.state & 3)
347 bits |= 2;
348 in_jump.state &= ~2;
349
350 if (in_use.state & 3)
351 bits |= 4;
352 in_use.state &= ~2;
353
354 cmd->buttons = bits;
355 cmd->impulse = in_impulse;
356
357 in_impulse = 0;
358 }
359
360 /*
361 ==============
362 CL_SendMove
363 ==============
364 */
CL_SendMove(const usercmd_t * cmd)365 void CL_SendMove (const usercmd_t *cmd)
366 {
367 unsigned int i;
368 sizebuf_t buf;
369 byte data[1024];
370
371 buf.maxsize = sizeof(data);
372 buf.cursize = 0;
373 buf.data = data;
374
375 for (i = 0; i < cl.ackframes_count; i++)
376 {
377 MSG_WriteByte(&buf, clcdp_ackframe);
378 MSG_WriteLong(&buf, cl.ackframes[i]);
379 }
380 cl.ackframes_count = 0;
381
382 if (cmd)
383 {
384 int dump = buf.cursize;
385 unsigned int bits = cmd->buttons;
386
387 //
388 // send the movement message
389 //
390 MSG_WriteByte (&buf, clc_move);
391
392 if (cl.protocol_pext2 & PEXT2_PREDINFO)
393 {
394 MSG_WriteShort(&buf, cl.movemessages&0xffff); //server will ack this once it has been applied to the player's entity state
395 MSG_WriteFloat (&buf, cmd->servertime); // so server can get cmd timing (pings will be calculated by entframe acks).
396 }
397 else
398 MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
399
400 for (i=0 ; i<3 ; i++)
401 //johnfitz -- 16-bit angles for PROTOCOL_FITZQUAKE
402 //spike -- nq+bjp3 use 8bit angles. all other supported protocols use 16bit ones.
403 //spike -- proquake servers bump client->server angles up to at least 16bit. this is safe because it only happens when both client+server advertise it, and because it never actually gets recorded into demos anyway.
404 //spike -- predinfo also always means 16bit angles, even if for some reason the server doesn't advertise proquake (like dp).
405 if (cl.protocol == PROTOCOL_NETQUAKE && !NET_QSocketGetProQuakeAngleHack(cls.netcon) && !(cl.protocol_pext2 & PEXT2_PREDINFO))
406 MSG_WriteAngle (&buf, cl.viewangles[i], cl.protocolflags);
407 else
408 MSG_WriteAngle16 (&buf, cl.viewangles[i], cl.protocolflags);
409 //johnfitz
410
411 MSG_WriteShort (&buf, cmd->forwardmove);
412 MSG_WriteShort (&buf, cmd->sidemove);
413 MSG_WriteShort (&buf, cmd->upmove);
414
415 MSG_WriteByte (&buf, bits);
416 MSG_WriteByte (&buf, cmd->impulse);
417 if (bits & (1u<<30))
418 MSG_WriteLong (&buf, cmd->weapon);
419 in_impulse = 0;
420
421 cl.movecmds[cl.movemessages&MOVECMDS_MASK] = *cmd;
422
423 //
424 // allways dump the first two message, because it may contain leftover inputs
425 // from the last level
426 //
427 if (++cl.movemessages <= 2)
428 buf.cursize = dump;
429 }
430
431 //fixme: nops if we're still connecting, or something.
432
433 //
434 // deliver the message
435 //
436 if (cls.demoplayback || !buf.cursize)
437 return;
438
439 if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
440 {
441 Con_Printf ("CL_SendMove: lost server connection\n");
442 CL_Disconnect ();
443 }
444 }
445
446 /*
447 ============
448 CL_InitInput
449 ============
450 */
CL_InitInput(void)451 void CL_InitInput (void)
452 {
453 Cmd_AddCommand ("+moveup",IN_UpDown);
454 Cmd_AddCommand ("-moveup",IN_UpUp);
455 Cmd_AddCommand ("+movedown",IN_DownDown);
456 Cmd_AddCommand ("-movedown",IN_DownUp);
457 Cmd_AddCommand ("+left",IN_LeftDown);
458 Cmd_AddCommand ("-left",IN_LeftUp);
459 Cmd_AddCommand ("+right",IN_RightDown);
460 Cmd_AddCommand ("-right",IN_RightUp);
461 Cmd_AddCommand ("+forward",IN_ForwardDown);
462 Cmd_AddCommand ("-forward",IN_ForwardUp);
463 Cmd_AddCommand ("+back",IN_BackDown);
464 Cmd_AddCommand ("-back",IN_BackUp);
465 Cmd_AddCommand ("+lookup", IN_LookupDown);
466 Cmd_AddCommand ("-lookup", IN_LookupUp);
467 Cmd_AddCommand ("+lookdown", IN_LookdownDown);
468 Cmd_AddCommand ("-lookdown", IN_LookdownUp);
469 Cmd_AddCommand ("+strafe", IN_StrafeDown);
470 Cmd_AddCommand ("-strafe", IN_StrafeUp);
471 Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
472 Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
473 Cmd_AddCommand ("+moveright", IN_MoverightDown);
474 Cmd_AddCommand ("-moveright", IN_MoverightUp);
475 Cmd_AddCommand ("+speed", IN_SpeedDown);
476 Cmd_AddCommand ("-speed", IN_SpeedUp);
477 Cmd_AddCommand ("+attack", IN_AttackDown);
478 Cmd_AddCommand ("-attack", IN_AttackUp);
479 Cmd_AddCommand ("+use", IN_UseDown);
480 Cmd_AddCommand ("-use", IN_UseUp);
481 Cmd_AddCommand ("+jump", IN_JumpDown);
482 Cmd_AddCommand ("-jump", IN_JumpUp);
483 Cmd_AddCommand ("impulse", IN_Impulse);
484 Cmd_AddCommand ("+klook", IN_KLookDown);
485 Cmd_AddCommand ("-klook", IN_KLookUp);
486 Cmd_AddCommand ("+mlook", IN_MLookDown);
487 Cmd_AddCommand ("-mlook", IN_MLookUp);
488
489 }
490
491