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 "client.h"
23 #include "cmd.h"
24 #include "console.h"
25 #include "input.h"
26 #include "quakedef.h"
27 
28 static cvar_t cl_nodelta = { "cl_nodelta", "0" };
29 
30 /*
31 ===============================================================================
32 
33 KEY BUTTONS
34 
35 Continuous button event tracking is complicated by the fact that two different
36 input sources (say, mouse button 1 and the control key) can both press the
37 same button, but the button should only be released when both of the
38 pressing key have been released.
39 
40 When a key event issues a button command (+forward, +attack, etc), it appends
41 its key number as a parameter to the command so it can be matched up with
42 the release.
43 
44 state bit 0 is the current state of the key
45 state bit 1 is edge triggered on the up to down transition
46 state bit 2 is edge triggered on the down to up transition
47 
48 ===============================================================================
49 */
50 
51 
52 kbutton_t in_mlook, in_strafe, in_speed;
53 
54 static kbutton_t in_klook;
55 static kbutton_t in_left, in_right, in_forward, in_back;
56 static kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
57 static kbutton_t in_use, in_jump, in_attack;
58 static kbutton_t in_up, in_down;
59 
60 static int in_impulse;
61 
62 
63 static void
KeyDown(kbutton_t * b)64 KeyDown(kbutton_t *b)
65 {
66     int k;
67     const char *c;
68 
69     c = Cmd_Argv(1);
70     if (c[0])
71 	k = atoi(c);
72     else
73 	k = -1;			// typed manually at the console for continuous down
74 
75     if (k == b->down[0] || k == b->down[1])
76 	return;			// repeating key
77 
78     if (!b->down[0])
79 	b->down[0] = k;
80     else if (!b->down[1])
81 	b->down[1] = k;
82     else {
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 
92 static void
KeyUp(kbutton_t * b)93 KeyUp(kbutton_t *b)
94 {
95     int k;
96     const char *c;
97 
98     c = Cmd_Argv(1);
99     if (c[0])
100 	k = atoi(c);
101     else {			// 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 
122 static void
IN_KLookDown(void)123 IN_KLookDown(void)
124 {
125     KeyDown(&in_klook);
126 }
127 
128 static void
IN_KLookUp(void)129 IN_KLookUp(void)
130 {
131     KeyUp(&in_klook);
132 }
133 
134 static void
IN_MLookDown(void)135 IN_MLookDown(void)
136 {
137     KeyDown(&in_mlook);
138 }
139 
140 static void
IN_MLookUp(void)141 IN_MLookUp(void)
142 {
143     KeyUp(&in_mlook);
144     if (!(in_mlook.state & 1) && lookspring.value)
145 	V_StartPitchDrift();
146 }
147 
148 static void
IN_UpDown(void)149 IN_UpDown(void)
150 {
151     KeyDown(&in_up);
152 }
153 
154 static void
IN_UpUp(void)155 IN_UpUp(void)
156 {
157     KeyUp(&in_up);
158 }
159 
160 static void
IN_DownDown(void)161 IN_DownDown(void)
162 {
163     KeyDown(&in_down);
164 }
165 
166 static void
IN_DownUp(void)167 IN_DownUp(void)
168 {
169     KeyUp(&in_down);
170 }
171 
172 static void
IN_LeftDown(void)173 IN_LeftDown(void)
174 {
175     KeyDown(&in_left);
176 }
177 
178 static void
IN_LeftUp(void)179 IN_LeftUp(void)
180 {
181     KeyUp(&in_left);
182 }
183 
184 static void
IN_RightDown(void)185 IN_RightDown(void)
186 {
187     KeyDown(&in_right);
188 }
189 
190 static void
IN_RightUp(void)191 IN_RightUp(void)
192 {
193     KeyUp(&in_right);
194 }
195 
196 static void
IN_ForwardDown(void)197 IN_ForwardDown(void)
198 {
199     KeyDown(&in_forward);
200 }
201 
202 static void
IN_ForwardUp(void)203 IN_ForwardUp(void)
204 {
205     KeyUp(&in_forward);
206 }
207 
208 static void
IN_BackDown(void)209 IN_BackDown(void)
210 {
211     KeyDown(&in_back);
212 }
213 
214 static void
IN_BackUp(void)215 IN_BackUp(void)
216 {
217     KeyUp(&in_back);
218 }
219 
220 static void
IN_LookupDown(void)221 IN_LookupDown(void)
222 {
223     KeyDown(&in_lookup);
224 }
225 
226 static void
IN_LookupUp(void)227 IN_LookupUp(void)
228 {
229     KeyUp(&in_lookup);
230 }
231 
232 static void
IN_LookdownDown(void)233 IN_LookdownDown(void)
234 {
235     KeyDown(&in_lookdown);
236 }
237 
238 static void
IN_LookdownUp(void)239 IN_LookdownUp(void)
240 {
241     KeyUp(&in_lookdown);
242 }
243 
244 static void
IN_MoveleftDown(void)245 IN_MoveleftDown(void)
246 {
247     KeyDown(&in_moveleft);
248 }
249 
250 static void
IN_MoveleftUp(void)251 IN_MoveleftUp(void)
252 {
253     KeyUp(&in_moveleft);
254 }
255 
256 static void
IN_MoverightDown(void)257 IN_MoverightDown(void)
258 {
259     KeyDown(&in_moveright);
260 }
261 
262 static void
IN_MoverightUp(void)263 IN_MoverightUp(void)
264 {
265     KeyUp(&in_moveright);
266 }
267 
268 static void
IN_SpeedDown(void)269 IN_SpeedDown(void)
270 {
271     KeyDown(&in_speed);
272 }
273 
274 static void
IN_SpeedUp(void)275 IN_SpeedUp(void)
276 {
277     KeyUp(&in_speed);
278 }
279 
280 static void
IN_StrafeDown(void)281 IN_StrafeDown(void)
282 {
283     KeyDown(&in_strafe);
284 }
285 
286 static void
IN_StrafeUp(void)287 IN_StrafeUp(void)
288 {
289     KeyUp(&in_strafe);
290 }
291 
292 static void
IN_AttackDown(void)293 IN_AttackDown(void)
294 {
295     KeyDown(&in_attack);
296 }
297 
298 static void
IN_AttackUp(void)299 IN_AttackUp(void)
300 {
301     KeyUp(&in_attack);
302 }
303 
304 static void
IN_UseDown(void)305 IN_UseDown(void)
306 {
307     KeyDown(&in_use);
308 }
309 
310 static void
IN_UseUp(void)311 IN_UseUp(void)
312 {
313     KeyUp(&in_use);
314 }
315 
316 static void
IN_JumpDown(void)317 IN_JumpDown(void)
318 {
319     KeyDown(&in_jump);
320 }
321 
322 static void
IN_JumpUp(void)323 IN_JumpUp(void)
324 {
325     KeyUp(&in_jump);
326 }
327 
328 static void
IN_Impulse(void)329 IN_Impulse(void)
330 {
331     in_impulse = Q_atoi(Cmd_Argv(1));
332 }
333 
334 /*
335 ===============
336 CL_KeyState
337 
338 Returns 0.25 if a key was pressed and released during the frame,
339 0.5 if it was pressed and held
340 0 if held then released, and
341 1.0 if held for the entire time
342 ===============
343 */
344 static float
CL_KeyState(kbutton_t * key)345 CL_KeyState(kbutton_t *key)
346 {
347     float val;
348     qboolean impulsedown, impulseup, down;
349 
350     impulsedown = key->state & 2;
351     impulseup = key->state & 4;
352     down = key->state & 1;
353     val = 0;
354 
355     if (impulsedown && !impulseup) {
356 	if (down)
357 	    val = 0.5;		// pressed and held this frame
358 	else
359 	    val = 0;		//      I_Error ();
360     }
361     if (impulseup && !impulsedown) {
362 	if (down)
363 	    val = 0;		//      I_Error ();
364 	else
365 	    val = 0;		// released this frame
366     }
367     if (!impulsedown && !impulseup) {
368 	if (down)
369 	    val = 1.0;		// held the entire frame
370 	else
371 	    val = 0;		// up the entire frame
372     }
373     if (impulsedown && impulseup) {
374 	if (down)
375 	    val = 0.75;		// released and re-pressed this frame
376 	else
377 	    val = 0.25;		// pressed and released this frame
378     }
379 
380     key->state &= 1;		// clear impulses
381 
382     return val;
383 }
384 
385 
386 
387 
388 //==========================================================================
389 
390 cvar_t cl_upspeed = { "cl_upspeed", "200" };
391 cvar_t cl_forwardspeed = { "cl_forwardspeed", "200", true };
392 cvar_t cl_backspeed = { "cl_backspeed", "200", true };
393 cvar_t cl_sidespeed = { "cl_sidespeed", "350" };
394 
395 cvar_t cl_movespeedkey = { "cl_movespeedkey", "2.0" };
396 
397 cvar_t cl_yawspeed = { "cl_yawspeed", "140" };
398 cvar_t cl_pitchspeed = { "cl_pitchspeed", "150" };
399 
400 cvar_t cl_anglespeedkey = { "cl_anglespeedkey", "1.5" };
401 
402 
403 /*
404 ================
405 CL_AdjustAngles
406 
407 Moves the local angle positions
408 ================
409 */
410 static void
CL_AdjustAngles(void)411 CL_AdjustAngles(void)
412 {
413     float speed;
414     float up, down;
415 
416     if (in_speed.state & 1)
417 	speed = host_frametime * cl_anglespeedkey.value;
418     else
419 	speed = host_frametime;
420 
421     if (!(in_strafe.state & 1)) {
422 	cl.viewangles[YAW] -=
423 	    speed * cl_yawspeed.value * CL_KeyState(&in_right);
424 	cl.viewangles[YAW] +=
425 	    speed * cl_yawspeed.value * CL_KeyState(&in_left);
426 	cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);
427     }
428     if (in_klook.state & 1) {
429 	V_StopPitchDrift();
430 	cl.viewangles[PITCH] -=
431 	    speed * cl_pitchspeed.value * CL_KeyState(&in_forward);
432 	cl.viewangles[PITCH] +=
433 	    speed * cl_pitchspeed.value * CL_KeyState(&in_back);
434     }
435 
436     up = CL_KeyState(&in_lookup);
437     down = CL_KeyState(&in_lookdown);
438 
439     cl.viewangles[PITCH] -= speed * cl_pitchspeed.value * up;
440     cl.viewangles[PITCH] += speed * cl_pitchspeed.value * down;
441 
442     if (up || down)
443 	V_StopPitchDrift();
444 
445     if (cl.viewangles[PITCH] > 80)
446 	cl.viewangles[PITCH] = 80;
447     if (cl.viewangles[PITCH] < -70)
448 	cl.viewangles[PITCH] = -70;
449 
450     if (cl.viewangles[ROLL] > 50)
451 	cl.viewangles[ROLL] = 50;
452     if (cl.viewangles[ROLL] < -50)
453 	cl.viewangles[ROLL] = -50;
454 
455 }
456 
457 /*
458 ================
459 CL_BaseMove
460 
461 Send the intended movement message to the server
462 ================
463 */
464 void
CL_BaseMove(usercmd_t * cmd)465 CL_BaseMove(usercmd_t *cmd)
466 {
467     CL_AdjustAngles();
468 
469     memset(cmd, 0, sizeof(*cmd));
470 
471     VectorCopy(cl.viewangles, cmd->angles);
472     if (in_strafe.state & 1) {
473 	cmd->sidemove += cl_sidespeed.value * CL_KeyState(&in_right);
474 	cmd->sidemove -= cl_sidespeed.value * CL_KeyState(&in_left);
475     }
476 
477     cmd->sidemove += cl_sidespeed.value * CL_KeyState(&in_moveright);
478     cmd->sidemove -= cl_sidespeed.value * CL_KeyState(&in_moveleft);
479 
480     cmd->upmove += cl_upspeed.value * CL_KeyState(&in_up);
481     cmd->upmove -= cl_upspeed.value * CL_KeyState(&in_down);
482 
483     if (!(in_klook.state & 1)) {
484 	cmd->forwardmove += cl_forwardspeed.value * CL_KeyState(&in_forward);
485 	cmd->forwardmove -= cl_backspeed.value * CL_KeyState(&in_back);
486     }
487 //
488 // adjust for speed key
489 //
490     if (in_speed.state & 1) {
491 	cmd->forwardmove *= cl_movespeedkey.value;
492 	cmd->sidemove *= cl_movespeedkey.value;
493 	cmd->upmove *= cl_movespeedkey.value;
494     }
495 }
496 
497 static int
MakeChar(int i)498 MakeChar(int i)
499 {
500     i &= ~3;
501     if (i < -127 * 4)
502 	i = -127 * 4;
503     if (i > 127 * 4)
504 	i = 127 * 4;
505     return i;
506 }
507 
508 /*
509 ==============
510 CL_FinishMove
511 ==============
512 */
513 static void
CL_FinishMove(usercmd_t * cmd)514 CL_FinishMove(usercmd_t *cmd)
515 {
516     int i;
517     int ms;
518 
519 //
520 // allways dump the first two message, because it may contain leftover inputs
521 // from the last level
522 //
523     if (++cl.movemessages <= 2)
524 	return;
525 //
526 // figure button bits
527 //
528     if (in_attack.state & 3)
529 	cmd->buttons |= 1;
530     in_attack.state &= ~2;
531 
532     if (in_jump.state & 3)
533 	cmd->buttons |= 2;
534     in_jump.state &= ~2;
535 
536     // send milliseconds of time to apply the move
537     ms = host_frametime * 1000;
538     if (ms > 250)
539 	ms = 100;		// time was unreasonable
540     cmd->msec = ms;
541 
542     VectorCopy(cl.viewangles, cmd->angles);
543 
544     cmd->impulse = in_impulse;
545     in_impulse = 0;
546 
547 
548 //
549 // chop down so no extra bits are kept that the server wouldn't get
550 //
551     cmd->forwardmove = MakeChar(cmd->forwardmove);
552     cmd->sidemove = MakeChar(cmd->sidemove);
553     cmd->upmove = MakeChar(cmd->upmove);
554 
555     for (i = 0; i < 3; i++)
556 	cmd->angles[i] =
557 	    ((int)(cmd->angles[i] * 65536.0 / 360) & 65535) * (360.0 /
558 							       65536.0);
559 }
560 
561 /*
562 =================
563 CL_SendCmd
564 =================
565 */
566 void
CL_SendCmd(void)567 CL_SendCmd(void)
568 {
569     sizebuf_t buf;
570     byte data[128];
571     int i;
572     usercmd_t *cmd, *oldcmd;
573     int checksumIndex;
574     int lost;
575     int seq_hash;
576 
577     if (cls.demoplayback)
578 	return;			// sendcmds come from the demo
579 
580     // save this command off for prediction
581     i = cls.netchan.outgoing_sequence & UPDATE_MASK;
582     cmd = &cl.frames[i].cmd;
583     cl.frames[i].senttime = realtime;
584     cl.frames[i].receivedtime = -1;	// we haven't gotten a reply yet
585 
586 //      seq_hash = (cls.netchan.outgoing_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
587     seq_hash = cls.netchan.outgoing_sequence;
588 
589     // get basic movement from keyboard
590     CL_BaseMove(cmd);
591 
592     // allow mice or other external controllers to add to the move
593     IN_Move(cmd);
594 
595     // if we are spectator, try autocam
596     if (cl.spectator)
597 	Cam_Track(cmd);
598 
599     CL_FinishMove(cmd);
600 
601     Cam_FinishMove(cmd);
602 
603 // send this and the previous cmds in the message, so
604 // if the last packet was dropped, it can be recovered
605     buf.maxsize = 128;
606     buf.cursize = 0;
607     buf.data = data;
608 
609     MSG_WriteByte(&buf, clc_move);
610 
611     // save the position for a checksum byte
612     checksumIndex = buf.cursize;
613     MSG_WriteByte(&buf, 0);
614 
615     // write our lossage percentage
616     lost = CL_CalcNet();
617     MSG_WriteByte(&buf, (byte)lost);
618 
619     i = (cls.netchan.outgoing_sequence - 2) & UPDATE_MASK;
620     cmd = &cl.frames[i].cmd;
621     MSG_WriteDeltaUsercmd(&buf, &nullcmd, cmd);
622     oldcmd = cmd;
623 
624     i = (cls.netchan.outgoing_sequence - 1) & UPDATE_MASK;
625     cmd = &cl.frames[i].cmd;
626     MSG_WriteDeltaUsercmd(&buf, oldcmd, cmd);
627     oldcmd = cmd;
628 
629     i = (cls.netchan.outgoing_sequence) & UPDATE_MASK;
630     cmd = &cl.frames[i].cmd;
631     MSG_WriteDeltaUsercmd(&buf, oldcmd, cmd);
632 
633     // calculate a checksum over the move commands
634     buf.data[checksumIndex] =
635 	COM_BlockSequenceCRCByte(buf.data + checksumIndex + 1,
636 				 buf.cursize - checksumIndex - 1, seq_hash);
637 
638     // request delta compression of entities
639     if (cls.netchan.outgoing_sequence - cl.validsequence >= UPDATE_BACKUP - 1)
640 	cl.validsequence = 0;
641 
642     if (cl.validsequence && !cl_nodelta.value && cls.state == ca_active &&
643 	!cls.demorecording) {
644 	cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK].
645 	    delta_sequence = cl.validsequence;
646 	MSG_WriteByte(&buf, clc_delta);
647 	MSG_WriteByte(&buf, cl.validsequence & 255);
648     } else
649 	cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK].
650 	    delta_sequence = -1;
651 
652     if (cls.demorecording)
653 	CL_WriteDemoCmd(cmd);
654 
655 //
656 // deliver the message
657 //
658     Netchan_Transmit(&cls.netchan, buf.cursize, buf.data);
659 }
660 
661 
662 
663 /*
664 ============
665 CL_InitInput
666 ============
667 */
668 void
CL_InitInput(void)669 CL_InitInput(void)
670 {
671     Cmd_AddCommand("+moveup", IN_UpDown);
672     Cmd_AddCommand("-moveup", IN_UpUp);
673     Cmd_AddCommand("+movedown", IN_DownDown);
674     Cmd_AddCommand("-movedown", IN_DownUp);
675     Cmd_AddCommand("+left", IN_LeftDown);
676     Cmd_AddCommand("-left", IN_LeftUp);
677     Cmd_AddCommand("+right", IN_RightDown);
678     Cmd_AddCommand("-right", IN_RightUp);
679     Cmd_AddCommand("+forward", IN_ForwardDown);
680     Cmd_AddCommand("-forward", IN_ForwardUp);
681     Cmd_AddCommand("+back", IN_BackDown);
682     Cmd_AddCommand("-back", IN_BackUp);
683     Cmd_AddCommand("+lookup", IN_LookupDown);
684     Cmd_AddCommand("-lookup", IN_LookupUp);
685     Cmd_AddCommand("+lookdown", IN_LookdownDown);
686     Cmd_AddCommand("-lookdown", IN_LookdownUp);
687     Cmd_AddCommand("+strafe", IN_StrafeDown);
688     Cmd_AddCommand("-strafe", IN_StrafeUp);
689     Cmd_AddCommand("+moveleft", IN_MoveleftDown);
690     Cmd_AddCommand("-moveleft", IN_MoveleftUp);
691     Cmd_AddCommand("+moveright", IN_MoverightDown);
692     Cmd_AddCommand("-moveright", IN_MoverightUp);
693     Cmd_AddCommand("+speed", IN_SpeedDown);
694     Cmd_AddCommand("-speed", IN_SpeedUp);
695     Cmd_AddCommand("+attack", IN_AttackDown);
696     Cmd_AddCommand("-attack", IN_AttackUp);
697     Cmd_AddCommand("+use", IN_UseDown);
698     Cmd_AddCommand("-use", IN_UseUp);
699     Cmd_AddCommand("+jump", IN_JumpDown);
700     Cmd_AddCommand("-jump", IN_JumpUp);
701     Cmd_AddCommand("impulse", IN_Impulse);
702     Cmd_AddCommand("+klook", IN_KLookDown);
703     Cmd_AddCommand("-klook", IN_KLookUp);
704     Cmd_AddCommand("+mlook", IN_MLookDown);
705     Cmd_AddCommand("-mlook", IN_MLookUp);
706 
707     Cvar_RegisterVariable(&cl_nodelta);
708 }
709 
710 // FIXME - unused function?
711 #if 0
712 /*
713 ============
714 CL_ClearStates
715 ============
716 */
717 static void
718 CL_ClearStates(void)
719 {
720 }
721 #endif
722