added support for PROTOCOL_NEHAHRAMOVIE in more places, so now nehahra works again...
[divverent/darkplaces.git] / cl_input.c
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_jump, in_attack;
53 kbutton_t       in_up, in_down;
54 // LordHavoc: added 6 new buttons
55 kbutton_t       in_button3, in_button4, in_button5, in_button6, in_button7, in_button8;
56
57 int                     in_impulse;
58
59 extern cvar_t sys_ticrate;
60
61
62 void KeyDown (kbutton_t *b)
63 {
64         int k;
65         const char *c;
66
67         c = Cmd_Argv(1);
68         if (c[0])
69                 k = atoi(c);
70         else
71                 k = -1;         // typed manually at the console for continuous down
72
73         if (k == b->down[0] || k == b->down[1])
74                 return;         // repeating key
75
76         if (!b->down[0])
77                 b->down[0] = k;
78         else if (!b->down[1])
79                 b->down[1] = k;
80         else
81         {
82                 Con_Print("Three keys down for a button!\n");
83                 return;
84         }
85
86         if (b->state & 1)
87                 return;         // still down
88         b->state |= 1 + 2;      // down + impulse down
89 }
90
91 void KeyUp (kbutton_t *b)
92 {
93         int k;
94         const char *c;
95
96         c = Cmd_Argv(1);
97         if (c[0])
98                 k = atoi(c);
99         else
100         { // typed manually at the console, assume for unsticking, so clear all
101                 b->down[0] = b->down[1] = 0;
102                 b->state = 4;   // impulse up
103                 return;
104         }
105
106         if (b->down[0] == k)
107                 b->down[0] = 0;
108         else if (b->down[1] == k)
109                 b->down[1] = 0;
110         else
111                 return;         // key up without coresponding down (menu pass through)
112         if (b->down[0] || b->down[1])
113                 return;         // some other key is still holding it down
114
115         if (!(b->state & 1))
116                 return;         // still up (this should not happen)
117         b->state &= ~1;         // now up
118         b->state |= 4;          // impulse up
119 }
120
121 void IN_KLookDown (void) {KeyDown(&in_klook);}
122 void IN_KLookUp (void) {KeyUp(&in_klook);}
123 void IN_MLookDown (void) {KeyDown(&in_mlook);}
124 void IN_MLookUp (void)
125 {
126         KeyUp(&in_mlook);
127         if ( !(in_mlook.state&1) && lookspring.value)
128                 V_StartPitchDrift();
129 }
130 void IN_UpDown(void) {KeyDown(&in_up);}
131 void IN_UpUp(void) {KeyUp(&in_up);}
132 void IN_DownDown(void) {KeyDown(&in_down);}
133 void IN_DownUp(void) {KeyUp(&in_down);}
134 void IN_LeftDown(void) {KeyDown(&in_left);}
135 void IN_LeftUp(void) {KeyUp(&in_left);}
136 void IN_RightDown(void) {KeyDown(&in_right);}
137 void IN_RightUp(void) {KeyUp(&in_right);}
138 void IN_ForwardDown(void) {KeyDown(&in_forward);}
139 void IN_ForwardUp(void) {KeyUp(&in_forward);}
140 void IN_BackDown(void) {KeyDown(&in_back);}
141 void IN_BackUp(void) {KeyUp(&in_back);}
142 void IN_LookupDown(void) {KeyDown(&in_lookup);}
143 void IN_LookupUp(void) {KeyUp(&in_lookup);}
144 void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
145 void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
146 void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
147 void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
148 void IN_MoverightDown(void) {KeyDown(&in_moveright);}
149 void IN_MoverightUp(void) {KeyUp(&in_moveright);}
150
151 void IN_SpeedDown(void) {KeyDown(&in_speed);}
152 void IN_SpeedUp(void) {KeyUp(&in_speed);}
153 void IN_StrafeDown(void) {KeyDown(&in_strafe);}
154 void IN_StrafeUp(void) {KeyUp(&in_strafe);}
155
156 void IN_AttackDown(void) {KeyDown(&in_attack);}
157 void IN_AttackUp(void) {KeyUp(&in_attack);}
158
159 // LordHavoc: added 6 new buttons
160 void IN_Button3Down(void) {KeyDown(&in_button3);}
161 void IN_Button3Up(void) {KeyUp(&in_button3);}
162 void IN_Button4Down(void) {KeyDown(&in_button4);}
163 void IN_Button4Up(void) {KeyUp(&in_button4);}
164 void IN_Button5Down(void) {KeyDown(&in_button5);}
165 void IN_Button5Up(void) {KeyUp(&in_button5);}
166 void IN_Button6Down(void) {KeyDown(&in_button6);}
167 void IN_Button6Up(void) {KeyUp(&in_button6);}
168 void IN_Button7Down(void) {KeyDown(&in_button7);}
169 void IN_Button7Up(void) {KeyUp(&in_button7);}
170 void IN_Button8Down(void) {KeyDown(&in_button8);}
171 void IN_Button8Up(void) {KeyUp(&in_button8);}
172
173 void IN_JumpDown (void) {KeyDown(&in_jump);}
174 void IN_JumpUp (void) {KeyUp(&in_jump);}
175
176 void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
177
178 /*
179 ===============
180 CL_KeyState
181
182 Returns 0.25 if a key was pressed and released during the frame,
183 0.5 if it was pressed and held
184 0 if held then released, and
185 1.0 if held for the entire time
186 ===============
187 */
188 float CL_KeyState (kbutton_t *key)
189 {
190         float           val;
191         qboolean        impulsedown, impulseup, down;
192
193         impulsedown = key->state & 2;
194         impulseup = key->state & 4;
195         down = key->state & 1;
196         val = 0;
197
198         if (impulsedown && !impulseup)
199         {
200                 if (down)
201                         val = 0.5;      // pressed and held this frame
202                 else
203                         val = 0;        //      I_Error ();
204         }
205         if (impulseup && !impulsedown)
206         {
207                 if (down)
208                         val = 0;        //      I_Error ();
209                 else
210                         val = 0;        // released this frame
211         }
212         if (!impulsedown && !impulseup)
213         {
214                 if (down)
215                         val = 1.0;      // held the entire frame
216                 else
217                         val = 0;        // up the entire frame
218         }
219         if (impulsedown && impulseup)
220         {
221                 if (down)
222                         val = 0.75;     // released and re-pressed this frame
223                 else
224                         val = 0.25;     // pressed and released this frame
225         }
226
227         key->state &= 1;                // clear impulses
228
229         return val;
230 }
231
232
233
234
235 //==========================================================================
236
237 cvar_t cl_upspeed = {CVAR_SAVE, "cl_upspeed","400"};
238 cvar_t cl_forwardspeed = {CVAR_SAVE, "cl_forwardspeed","400"};
239 cvar_t cl_backspeed = {CVAR_SAVE, "cl_backspeed","400"};
240 cvar_t cl_sidespeed = {CVAR_SAVE, "cl_sidespeed","350"};
241
242 cvar_t cl_movespeedkey = {CVAR_SAVE, "cl_movespeedkey","2.0"};
243
244 cvar_t cl_yawspeed = {CVAR_SAVE, "cl_yawspeed","140"};
245 cvar_t cl_pitchspeed = {CVAR_SAVE, "cl_pitchspeed","150"};
246
247 cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5"};
248
249 /*
250 ================
251 CL_AdjustAngles
252
253 Moves the local angle positions
254 ================
255 */
256 void CL_AdjustAngles (void)
257 {
258         float   speed;
259         float   up, down;
260
261         if (in_speed.state & 1)
262                 speed = host_realframetime * cl_anglespeedkey.value;
263         else
264                 speed = host_realframetime;
265
266         if (!(in_strafe.state & 1))
267         {
268                 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
269                 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
270         }
271         if (in_klook.state & 1)
272         {
273                 V_StopPitchDrift ();
274                 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
275                 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
276         }
277
278         up = CL_KeyState (&in_lookup);
279         down = CL_KeyState(&in_lookdown);
280
281         cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
282         cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
283
284         if (up || down)
285                 V_StopPitchDrift ();
286
287         cl.viewangles[YAW] = ANGLEMOD(cl.viewangles[YAW]);
288         cl.viewangles[PITCH] = ANGLEMOD(cl.viewangles[PITCH]);
289         cl.viewangles[ROLL] = ANGLEMOD(cl.viewangles[ROLL]);
290         if (cl.viewangles[YAW] >= 180)
291                 cl.viewangles[YAW] -= 360;
292         if (cl.viewangles[PITCH] >= 180)
293                 cl.viewangles[PITCH] -= 360;
294         if (cl.viewangles[ROLL] >= 180)
295                 cl.viewangles[ROLL] -= 360;
296
297         cl.viewangles[PITCH] = bound (in_pitch_min.value, cl.viewangles[PITCH], in_pitch_max.value);
298         cl.viewangles[ROLL] = bound(-50, cl.viewangles[ROLL], 50);
299 }
300
301 /*
302 ================
303 CL_BaseMove
304
305 Send the intended movement message to the server
306 ================
307 */
308 void CL_BaseMove (usercmd_t *cmd)
309 {
310         if (cls.signon != SIGNONS)
311                 return;
312
313         CL_AdjustAngles ();
314
315         memset (cmd, 0, sizeof(*cmd));
316
317         if (in_strafe.state & 1)
318         {
319                 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
320                 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
321         }
322
323         cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
324         cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
325
326         cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);
327         cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);
328
329         if (! (in_klook.state & 1) )
330         {
331                 cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
332                 cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
333         }
334
335 //
336 // adjust for speed key
337 //
338         if (in_speed.state & 1)
339         {
340                 cmd->forwardmove *= cl_movespeedkey.value;
341                 cmd->sidemove *= cl_movespeedkey.value;
342                 cmd->upmove *= cl_movespeedkey.value;
343         }
344 }
345
346
347
348 /*
349 ==============
350 CL_SendMove
351 ==============
352 */
353 void CL_SendMove(usercmd_t *cmd)
354 {
355         int i;
356         int bits;
357         sizebuf_t buf;
358         qbyte data[128];
359         static double lastmovetime;
360         static float forwardmove, sidemove, upmove, total; // accumulation
361
362         forwardmove += cmd->forwardmove;
363         sidemove += cmd->sidemove;
364         upmove += cmd->upmove;
365         total++;
366         // LordHavoc: cap outgoing movement messages to sys_ticrate
367         if (!cl.islocalgame && (realtime - lastmovetime < sys_ticrate.value))
368                 return;
369         lastmovetime = realtime;
370         // average what has happened during this time
371         total = 1.0f / total;
372         forwardmove *= total;
373         sidemove *= total;
374         upmove *= total;
375         total = 0;
376
377         buf.maxsize = 128;
378         buf.cursize = 0;
379         buf.data = data;
380
381         cl.cmd = *cmd;
382
383         // send the movement message
384         MSG_WriteByte (&buf, clc_move);
385
386         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
387
388         if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
389         {
390                 for (i = 0;i < 3;i++)
391                         MSG_WriteAngle8i (&buf, cl.viewangles[i]);
392         }
393         else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
394         {
395                 for (i = 0;i < 3;i++)
396                         MSG_WriteAngle32f (&buf, cl.viewangles[i]);
397         }
398         else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
399         {
400                 for (i = 0;i < 3;i++)
401                         MSG_WriteAngle16i (&buf, cl.viewangles[i]);
402         }
403         else
404                 Host_Error("CL_SendMove: unknown cl.protocol %i\n", cl.protocol);
405
406         MSG_WriteCoord16i (&buf, forwardmove);
407         MSG_WriteCoord16i (&buf, sidemove);
408         MSG_WriteCoord16i (&buf, upmove);
409
410         forwardmove = sidemove = upmove = 0;
411         // send button bits
412         bits = 0;
413
414         // LordHavoc: added 6 new buttons
415         if (in_attack.state  & 3) bits |=   1;in_attack.state  &= ~2;
416         if (in_jump.state    & 3) bits |=   2;in_jump.state    &= ~2;
417         if (in_button3.state & 3) bits |=   4;in_button3.state &= ~2;
418         if (in_button4.state & 3) bits |=   8;in_button4.state &= ~2;
419         if (in_button5.state & 3) bits |=  16;in_button5.state &= ~2;
420         if (in_button6.state & 3) bits |=  32;in_button6.state &= ~2;
421         if (in_button7.state & 3) bits |=  64;in_button7.state &= ~2;
422         if (in_button8.state & 3) bits |= 128;in_button8.state &= ~2;
423
424         MSG_WriteByte (&buf, bits);
425
426         MSG_WriteByte (&buf, in_impulse);
427         in_impulse = 0;
428
429         // FIXME: should ack latest 3 frames perhaps?
430         if (cl.latestframenum > 0)
431         {
432                 if (developer_networkentities.integer >= 1)
433                         Con_Printf("send clc_ackentities %i\n", cl.latestframenum);
434                 MSG_WriteByte(&buf, clc_ackentities);
435                 MSG_WriteLong(&buf, cl.latestframenum);
436         }
437
438         // deliver the message
439         if (cls.demoplayback)
440                 return;
441
442         // always dump the first two messages, because they may contain leftover inputs from the last level
443         if (++cl.movemessages <= 2)
444                 return;
445
446         if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
447         {
448                 Con_Print("CL_SendMove: lost server connection\n");
449                 CL_Disconnect();
450                 Host_ShutdownServer(false);
451         }
452 }
453
454 /*
455 ============
456 CL_InitInput
457 ============
458 */
459 void CL_InitInput (void)
460 {
461         Cmd_AddCommand ("+moveup",IN_UpDown);
462         Cmd_AddCommand ("-moveup",IN_UpUp);
463         Cmd_AddCommand ("+movedown",IN_DownDown);
464         Cmd_AddCommand ("-movedown",IN_DownUp);
465         Cmd_AddCommand ("+left",IN_LeftDown);
466         Cmd_AddCommand ("-left",IN_LeftUp);
467         Cmd_AddCommand ("+right",IN_RightDown);
468         Cmd_AddCommand ("-right",IN_RightUp);
469         Cmd_AddCommand ("+forward",IN_ForwardDown);
470         Cmd_AddCommand ("-forward",IN_ForwardUp);
471         Cmd_AddCommand ("+back",IN_BackDown);
472         Cmd_AddCommand ("-back",IN_BackUp);
473         Cmd_AddCommand ("+lookup", IN_LookupDown);
474         Cmd_AddCommand ("-lookup", IN_LookupUp);
475         Cmd_AddCommand ("+lookdown", IN_LookdownDown);
476         Cmd_AddCommand ("-lookdown", IN_LookdownUp);
477         Cmd_AddCommand ("+strafe", IN_StrafeDown);
478         Cmd_AddCommand ("-strafe", IN_StrafeUp);
479         Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
480         Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
481         Cmd_AddCommand ("+moveright", IN_MoverightDown);
482         Cmd_AddCommand ("-moveright", IN_MoverightUp);
483         Cmd_AddCommand ("+speed", IN_SpeedDown);
484         Cmd_AddCommand ("-speed", IN_SpeedUp);
485         Cmd_AddCommand ("+attack", IN_AttackDown);
486         Cmd_AddCommand ("-attack", IN_AttackUp);
487         Cmd_AddCommand ("+jump", IN_JumpDown);
488         Cmd_AddCommand ("-jump", IN_JumpUp);
489         Cmd_AddCommand ("impulse", IN_Impulse);
490         Cmd_AddCommand ("+klook", IN_KLookDown);
491         Cmd_AddCommand ("-klook", IN_KLookUp);
492         Cmd_AddCommand ("+mlook", IN_MLookDown);
493         Cmd_AddCommand ("-mlook", IN_MLookUp);
494
495         // LordHavoc: added 6 new buttons
496         Cmd_AddCommand ("+button3", IN_Button3Down);
497         Cmd_AddCommand ("-button3", IN_Button3Up);
498         Cmd_AddCommand ("+button4", IN_Button4Down);
499         Cmd_AddCommand ("-button4", IN_Button4Up);
500         Cmd_AddCommand ("+button5", IN_Button5Down);
501         Cmd_AddCommand ("-button5", IN_Button5Up);
502         Cmd_AddCommand ("+button6", IN_Button6Down);
503         Cmd_AddCommand ("-button6", IN_Button6Up);
504         Cmd_AddCommand ("+button7", IN_Button7Down);
505         Cmd_AddCommand ("-button7", IN_Button7Up);
506         Cmd_AddCommand ("+button8", IN_Button8Down);
507         Cmd_AddCommand ("-button8", IN_Button8Up);
508 }
509