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