• 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 #include "quakedef.h"
23 
24 cvar_t	cl_nodelta = CVAR2("cl_nodelta","0");
25 
26 /*
27 ===============================================================================
28 
29 KEY BUTTONS
30 
31 Continuous button event tracking is complicated by the fact that two different
32 input sources (say, mouse button 1 and the control key) can both press the
33 same button, but the button should only be released when both of the
34 pressing key have been released.
35 
36 When a key event issues a button command (+forward, +attack, etc), it appends
37 its key number as a parameter to the command so it can be matched up with
38 the release.
39 
40 state bit 0 is the current state of the key
41 state bit 1 is edge triggered on the up to down transition
42 state bit 2 is edge triggered on the down to up transition
43 
44 ===============================================================================
45 */
46 
47 
48 kbutton_t	in_mlook, in_klook;
49 kbutton_t	in_left, in_right, in_forward, in_back;
50 kbutton_t	in_lookup, in_lookdown, in_moveleft, in_moveright;
51 kbutton_t	in_strafe, in_speed, in_use, in_jump, in_attack;
52 kbutton_t	in_up, in_down;
53 
54 int			in_impulse;
55 
56 
KeyDown(kbutton_t * b)57 void KeyDown (kbutton_t *b)
58 {
59 	int		k;
60 	char	*c;
61 
62 	c = Cmd_Argv(1);
63 	if (c[0])
64 		k = atoi(c);
65 	else
66 		k = -1;		// typed manually at the console for continuous down
67 
68 	if (k == b->down[0] || k == b->down[1])
69 		return;		// repeating key
70 
71 	if (!b->down[0])
72 		b->down[0] = k;
73 	else if (!b->down[1])
74 		b->down[1] = k;
75 	else
76 	{
77 		Con_Printf ("Three keys down for a button!\n");
78 		return;
79 	}
80 
81 	if (b->state & 1)
82 		return;		// still down
83 	b->state |= 1 + 2;	// down + impulse down
84 }
85 
KeyUp(kbutton_t * b)86 void KeyUp (kbutton_t *b)
87 {
88 	int		k;
89 	char	*c;
90 
91 	c = Cmd_Argv(1);
92 	if (c[0])
93 		k = atoi(c);
94 	else
95 	{ // typed manually at the console, assume for unsticking, so clear all
96 		b->down[0] = b->down[1] = 0;
97 		b->state = 4;	// impulse up
98 		return;
99 	}
100 
101 	if (b->down[0] == k)
102 		b->down[0] = 0;
103 	else if (b->down[1] == k)
104 		b->down[1] = 0;
105 	else
106 		return;		// key up without coresponding down (menu pass through)
107 	if (b->down[0] || b->down[1])
108 		return;		// some other key is still holding it down
109 
110 	if (!(b->state & 1))
111 		return;		// still up (this should not happen)
112 	b->state &= ~1;		// now up
113 	b->state |= 4; 		// impulse up
114 }
115 
IN_KLookDown(void)116 void IN_KLookDown (void) {KeyDown(&in_klook);}
IN_KLookUp(void)117 void IN_KLookUp (void) {KeyUp(&in_klook);}
IN_MLookDown(void)118 void IN_MLookDown (void) {KeyDown(&in_mlook);}
IN_MLookUp(void)119 void IN_MLookUp (void) {
120 KeyUp(&in_mlook);
121 if ( !(in_mlook.state&1) &&  lookspring.value)
122 	V_StartPitchDrift();
123 }
IN_UpDown(void)124 void IN_UpDown(void) {KeyDown(&in_up);}
IN_UpUp(void)125 void IN_UpUp(void) {KeyUp(&in_up);}
IN_DownDown(void)126 void IN_DownDown(void) {KeyDown(&in_down);}
IN_DownUp(void)127 void IN_DownUp(void) {KeyUp(&in_down);}
IN_LeftDown(void)128 void IN_LeftDown(void) {KeyDown(&in_left);}
IN_LeftUp(void)129 void IN_LeftUp(void) {KeyUp(&in_left);}
IN_RightDown(void)130 void IN_RightDown(void) {KeyDown(&in_right);}
IN_RightUp(void)131 void IN_RightUp(void) {KeyUp(&in_right);}
IN_ForwardDown(void)132 void IN_ForwardDown(void) {KeyDown(&in_forward);}
IN_ForwardUp(void)133 void IN_ForwardUp(void) {KeyUp(&in_forward);}
IN_BackDown(void)134 void IN_BackDown(void) {KeyDown(&in_back);}
IN_BackUp(void)135 void IN_BackUp(void) {KeyUp(&in_back);}
IN_LookupDown(void)136 void IN_LookupDown(void) {KeyDown(&in_lookup);}
IN_LookupUp(void)137 void IN_LookupUp(void) {KeyUp(&in_lookup);}
IN_LookdownDown(void)138 void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
IN_LookdownUp(void)139 void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
IN_MoveleftDown(void)140 void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
IN_MoveleftUp(void)141 void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
IN_MoverightDown(void)142 void IN_MoverightDown(void) {KeyDown(&in_moveright);}
IN_MoverightUp(void)143 void IN_MoverightUp(void) {KeyUp(&in_moveright);}
144 
IN_SpeedDown(void)145 void IN_SpeedDown(void) {KeyDown(&in_speed);}
IN_SpeedUp(void)146 void IN_SpeedUp(void) {KeyUp(&in_speed);}
IN_StrafeDown(void)147 void IN_StrafeDown(void) {KeyDown(&in_strafe);}
IN_StrafeUp(void)148 void IN_StrafeUp(void) {KeyUp(&in_strafe);}
149 
IN_AttackDown(void)150 void IN_AttackDown(void) {KeyDown(&in_attack);}
IN_AttackUp(void)151 void IN_AttackUp(void) {KeyUp(&in_attack);}
152 
IN_UseDown(void)153 void IN_UseDown (void) {KeyDown(&in_use);}
IN_UseUp(void)154 void IN_UseUp (void) {KeyUp(&in_use);}
IN_JumpDown(void)155 void IN_JumpDown (void) {KeyDown(&in_jump);}
IN_JumpUp(void)156 void IN_JumpUp (void) {KeyUp(&in_jump);}
157 
IN_Impulse(void)158 void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));}
159 
160 /*
161 ===============
162 CL_KeyState
163 
164 Returns 0.25 if a key was pressed and released during the frame,
165 0.5 if it was pressed and held
166 0 if held then released, and
167 1.0 if held for the entire time
168 ===============
169 */
CL_KeyState(kbutton_t * key)170 float CL_KeyState (kbutton_t *key)
171 {
172 	float		val;
173 	qboolean	impulsedown, impulseup, down;
174 
175 	impulsedown = key->state & 2;
176 	impulseup = key->state & 4;
177 	down = key->state & 1;
178 	val = 0;
179 
180 	if (impulsedown && !impulseup) {
181 		if (down)
182 			val = 0.5;	// pressed and held this frame
183 		else
184 			val = 0;	//	I_Error ();
185 	}
186 	if (impulseup && !impulsedown) {
187 		if (down)
188 			val = 0;	//	I_Error ();
189 		else
190 			val = 0;	// released this frame
191 	}
192 	if (!impulsedown && !impulseup) {
193 		if (down)
194 			val = 1.0;	// held the entire frame
195 		else
196 			val = 0;	// up the entire frame
197 	}
198 	if (impulsedown && impulseup) {
199 		if (down)
200 			val = 0.75;	// released and re-pressed this frame
201 		else
202 			val = 0.25;	// pressed and released this frame
203 	}
204 
205 	key->state &= 1;		// clear impulses
206 
207 	return val;
208 }
209 
210 
211 
212 
213 //==========================================================================
214 
215 cvar_t	cl_upspeed = CVAR2("cl_upspeed","200");
216 cvar_t	cl_forwardspeed = CVAR3("cl_forwardspeed","200", true);
217 cvar_t	cl_backspeed = CVAR3("cl_backspeed","200", true);
218 cvar_t	cl_sidespeed = CVAR2("cl_sidespeed","350");
219 
220 cvar_t	cl_movespeedkey = CVAR2("cl_movespeedkey","2.0");
221 
222 cvar_t	cl_yawspeed = CVAR2("cl_yawspeed","140");
223 cvar_t	cl_pitchspeed = CVAR2("cl_pitchspeed","150");
224 
225 cvar_t	cl_anglespeedkey = CVAR2("cl_anglespeedkey","1.5");
226 
227 
228 /*
229 ================
230 CL_AdjustAngles
231 
232 Moves the local angle positions
233 ================
234 */
CL_AdjustAngles(void)235 void CL_AdjustAngles (void)
236 {
237 	float	speed;
238 	float	up, down;
239 
240 	if (in_speed.state & 1)
241 		speed = host_frametime * cl_anglespeedkey.value;
242 	else
243 		speed = host_frametime;
244 
245 	if (!(in_strafe.state & 1))
246 	{
247 		cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
248 		cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
249 		cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);
250 	}
251 	if (in_klook.state & 1)
252 	{
253 		V_StopPitchDrift ();
254 		cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
255 		cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
256 	}
257 
258 	up = CL_KeyState (&in_lookup);
259 	down = CL_KeyState(&in_lookdown);
260 
261 	cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
262 	cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
263 
264 	if (up || down)
265 		V_StopPitchDrift ();
266 
267 	if (cl.viewangles[PITCH] > 80)
268 		cl.viewangles[PITCH] = 80;
269 	if (cl.viewangles[PITCH] < -70)
270 		cl.viewangles[PITCH] = -70;
271 
272 	if (cl.viewangles[ROLL] > 50)
273 		cl.viewangles[ROLL] = 50;
274 	if (cl.viewangles[ROLL] < -50)
275 		cl.viewangles[ROLL] = -50;
276 
277 }
278 
279 /*
280 ================
281 CL_BaseMove
282 
283 Send the intended movement message to the server
284 ================
285 */
CL_BaseMove(usercmd_t * cmd)286 void CL_BaseMove (usercmd_t *cmd)
287 {
288 	CL_AdjustAngles ();
289 
290 	memset (cmd, 0, sizeof(*cmd));
291 
292 	VectorCopy (cl.viewangles, cmd->angles);
293 	if (in_strafe.state & 1)
294 	{
295 		cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
296 		cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
297 	}
298 
299 	cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
300 	cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
301 
302 	cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);
303 	cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);
304 
305 	if (! (in_klook.state & 1) )
306 	{
307 		cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
308 		cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
309 	}
310 
311 //
312 // adjust for speed key
313 //
314 	if (in_speed.state & 1)
315 	{
316 		cmd->forwardmove *= cl_movespeedkey.value;
317 		cmd->sidemove *= cl_movespeedkey.value;
318 		cmd->upmove *= cl_movespeedkey.value;
319 	}
320 }
321 
MakeChar(int i)322 int MakeChar (int i)
323 {
324 	i &= ~3;
325 	if (i < -127*4)
326 		i = -127*4;
327 	if (i > 127*4)
328 		i = 127*4;
329 	return i;
330 }
331 
332 /*
333 ==============
334 CL_FinishMove
335 ==============
336 */
CL_FinishMove(usercmd_t * cmd)337 void CL_FinishMove (usercmd_t *cmd)
338 {
339 	int		i;
340 	int		ms;
341 
342 //
343 // allways dump the first two message, because it may contain leftover inputs
344 // from the last level
345 //
346 	if (++cl.movemessages <= 2)
347 		return;
348 //
349 // figure button bits
350 //
351 	if ( in_attack.state & 3 )
352 		cmd->buttons |= 1;
353 	in_attack.state &= ~2;
354 
355 	if (in_jump.state & 3)
356 		cmd->buttons |= 2;
357 	in_jump.state &= ~2;
358 
359 	// send milliseconds of time to apply the move
360 	ms = host_frametime * 1000;
361 	if (ms > 250)
362 		ms = 100;		// time was unreasonable
363 	cmd->msec = ms;
364 
365 	VectorCopy (cl.viewangles, cmd->angles);
366 
367 	cmd->impulse = in_impulse;
368 	in_impulse = 0;
369 
370 
371 //
372 // chop down so no extra bits are kept that the server wouldn't get
373 //
374 	cmd->forwardmove = MakeChar (cmd->forwardmove);
375 	cmd->sidemove = MakeChar (cmd->sidemove);
376 	cmd->upmove = MakeChar (cmd->upmove);
377 
378 	for (i=0 ; i<3 ; i++)
379 		cmd->angles[i] = ((int)(cmd->angles[i]*65536.0/360)&65535) * (360.0/65536.0);
380 }
381 
382 /*
383 =================
384 CL_SendCmd
385 =================
386 */
CL_SendCmd(void)387 void CL_SendCmd (void)
388 {
389 	sizebuf_t	buf;
390 	byte		data[128];
391 	int			i;
392 	usercmd_t	*cmd, *oldcmd;
393 	int			checksumIndex;
394 	int			lost;
395 	int			seq_hash;
396 
397 	if (cls.demoplayback)
398 		return; // sendcmds come from the demo
399 
400 	// save this command off for prediction
401 	i = cls.netchan.outgoing_sequence & UPDATE_MASK;
402 	cmd = &cl.frames[i].cmd;
403 	cl.frames[i].senttime = realtime;
404 	cl.frames[i].receivedtime = -1;		// we haven't gotten a reply yet
405 
406 //	seq_hash = (cls.netchan.outgoing_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
407 	seq_hash = cls.netchan.outgoing_sequence;
408 
409 	// get basic movement from keyboard
410 	CL_BaseMove (cmd);
411 
412 	// allow mice or other external controllers to add to the move
413 	IN_Move (cmd);
414 
415 	// if we are spectator, try autocam
416 	if (cl.spectator)
417 		Cam_Track(cmd);
418 
419 	CL_FinishMove(cmd);
420 
421 	Cam_FinishMove(cmd);
422 
423 // send this and the previous cmds in the message, so
424 // if the last packet was dropped, it can be recovered
425 	buf.maxsize = 128;
426 	buf.cursize = 0;
427 	buf.data = data;
428 
429 	MSG_WriteByte (&buf, clc_move);
430 
431 	// save the position for a checksum byte
432 	checksumIndex = buf.cursize;
433 	MSG_WriteByte (&buf, 0);
434 
435 	// write our lossage percentage
436 	lost = CL_CalcNet();
437 	MSG_WriteByte (&buf, (byte)lost);
438 
439 	i = (cls.netchan.outgoing_sequence-2) & UPDATE_MASK;
440 	cmd = &cl.frames[i].cmd;
441 	MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
442 	oldcmd = cmd;
443 
444 	i = (cls.netchan.outgoing_sequence-1) & UPDATE_MASK;
445 	cmd = &cl.frames[i].cmd;
446 	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
447 	oldcmd = cmd;
448 
449 	i = (cls.netchan.outgoing_sequence) & UPDATE_MASK;
450 	cmd = &cl.frames[i].cmd;
451 	MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
452 
453 	// calculate a checksum over the move commands
454 	buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
455 		buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
456 		seq_hash);
457 
458 	// request delta compression of entities
459 	if (cls.netchan.outgoing_sequence - cl.validsequence >= UPDATE_BACKUP-1)
460 		cl.validsequence = 0;
461 
462 	if (cl.validsequence && !cl_nodelta.value && cls.state == ca_active &&
463 		!cls.demorecording)
464 	{
465 		cl.frames[cls.netchan.outgoing_sequence&UPDATE_MASK].delta_sequence = cl.validsequence;
466 		MSG_WriteByte (&buf, clc_delta);
467 		MSG_WriteByte (&buf, cl.validsequence&255);
468 	}
469 	else
470 		cl.frames[cls.netchan.outgoing_sequence&UPDATE_MASK].delta_sequence = -1;
471 
472 	if (cls.demorecording)
473 		CL_WriteDemoCmd(cmd);
474 
475 //
476 // deliver the message
477 //
478 	Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);
479 }
480 
481 
482 
483 /*
484 ============
485 CL_InitInput
486 ============
487 */
CL_InitInput(void)488 void CL_InitInput (void)
489 {
490 	Cmd_AddCommand ("+moveup",IN_UpDown);
491 	Cmd_AddCommand ("-moveup",IN_UpUp);
492 	Cmd_AddCommand ("+movedown",IN_DownDown);
493 	Cmd_AddCommand ("-movedown",IN_DownUp);
494 	Cmd_AddCommand ("+left",IN_LeftDown);
495 	Cmd_AddCommand ("-left",IN_LeftUp);
496 	Cmd_AddCommand ("+right",IN_RightDown);
497 	Cmd_AddCommand ("-right",IN_RightUp);
498 	Cmd_AddCommand ("+forward",IN_ForwardDown);
499 	Cmd_AddCommand ("-forward",IN_ForwardUp);
500 	Cmd_AddCommand ("+back",IN_BackDown);
501 	Cmd_AddCommand ("-back",IN_BackUp);
502 	Cmd_AddCommand ("+lookup", IN_LookupDown);
503 	Cmd_AddCommand ("-lookup", IN_LookupUp);
504 	Cmd_AddCommand ("+lookdown", IN_LookdownDown);
505 	Cmd_AddCommand ("-lookdown", IN_LookdownUp);
506 	Cmd_AddCommand ("+strafe", IN_StrafeDown);
507 	Cmd_AddCommand ("-strafe", IN_StrafeUp);
508 	Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
509 	Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
510 	Cmd_AddCommand ("+moveright", IN_MoverightDown);
511 	Cmd_AddCommand ("-moveright", IN_MoverightUp);
512 	Cmd_AddCommand ("+speed", IN_SpeedDown);
513 	Cmd_AddCommand ("-speed", IN_SpeedUp);
514 	Cmd_AddCommand ("+attack", IN_AttackDown);
515 	Cmd_AddCommand ("-attack", IN_AttackUp);
516 	Cmd_AddCommand ("+use", IN_UseDown);
517 	Cmd_AddCommand ("-use", IN_UseUp);
518 	Cmd_AddCommand ("+jump", IN_JumpDown);
519 	Cmd_AddCommand ("-jump", IN_JumpUp);
520 	Cmd_AddCommand ("impulse", IN_Impulse);
521 	Cmd_AddCommand ("+klook", IN_KLookDown);
522 	Cmd_AddCommand ("-klook", IN_KLookUp);
523 	Cmd_AddCommand ("+mlook", IN_MLookDown);
524 	Cmd_AddCommand ("-mlook", IN_MLookUp);
525 
526 	Cvar_RegisterVariable (&cl_nodelta);
527 }
528 
529 /*
530 ============
531 CL_ClearStates
532 ============
533 */
CL_ClearStates(void)534 void CL_ClearStates (void)
535 {
536 }
537 
538