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