]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_input.c
added a FIXME note about skyboxes and vid_restart
[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_use, 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
60 void KeyDown (kbutton_t *b)
61 {
62         int k;
63         const char *c;
64
65         c = Cmd_Argv(1);
66         if (c[0])
67                 k = atoi(c);
68         else
69                 k = -1;         // typed manually at the console for continuous down
70
71         if (k == b->down[0] || k == b->down[1])
72                 return;         // repeating key
73
74         if (!b->down[0])
75                 b->down[0] = k;
76         else if (!b->down[1])
77                 b->down[1] = k;
78         else
79         {
80                 Con_Printf ("Three keys down for a button!\n");
81                 return;
82         }
83
84         if (b->state & 1)
85                 return;         // still down
86         b->state |= 1 + 2;      // down + impulse down
87 }
88
89 void KeyUp (kbutton_t *b)
90 {
91         int k;
92         const char *c;
93
94         c = Cmd_Argv(1);
95         if (c[0])
96                 k = atoi(c);
97         else
98         { // typed manually at the console, assume for unsticking, so clear all
99                 b->down[0] = b->down[1] = 0;
100                 b->state = 4;   // impulse up
101                 return;
102         }
103
104         if (b->down[0] == k)
105                 b->down[0] = 0;
106         else if (b->down[1] == k)
107                 b->down[1] = 0;
108         else
109                 return;         // key up without coresponding down (menu pass through)
110         if (b->down[0] || b->down[1])
111                 return;         // some other key is still holding it down
112
113         if (!(b->state & 1))
114                 return;         // still up (this should not happen)
115         b->state &= ~1;         // now up
116         b->state |= 4;          // impulse up
117 }
118
119 void IN_KLookDown (void) {KeyDown(&in_klook);}
120 void IN_KLookUp (void) {KeyUp(&in_klook);}
121 void IN_MLookDown (void) {KeyDown(&in_mlook);}
122 void IN_MLookUp (void)
123 {
124         KeyUp(&in_mlook);
125         if ( !(in_mlook.state&1) && lookspring.value)
126                 V_StartPitchDrift();
127 }
128 void IN_UpDown(void) {KeyDown(&in_up);}
129 void IN_UpUp(void) {KeyUp(&in_up);}
130 void IN_DownDown(void) {KeyDown(&in_down);}
131 void IN_DownUp(void) {KeyUp(&in_down);}
132 void IN_LeftDown(void) {KeyDown(&in_left);}
133 void IN_LeftUp(void) {KeyUp(&in_left);}
134 void IN_RightDown(void) {KeyDown(&in_right);}
135 void IN_RightUp(void) {KeyUp(&in_right);}
136 void IN_ForwardDown(void) {KeyDown(&in_forward);}
137 void IN_ForwardUp(void) {KeyUp(&in_forward);}
138 void IN_BackDown(void) {KeyDown(&in_back);}
139 void IN_BackUp(void) {KeyUp(&in_back);}
140 void IN_LookupDown(void) {KeyDown(&in_lookup);}
141 void IN_LookupUp(void) {KeyUp(&in_lookup);}
142 void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
143 void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
144 void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
145 void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
146 void IN_MoverightDown(void) {KeyDown(&in_moveright);}
147 void IN_MoverightUp(void) {KeyUp(&in_moveright);}
148
149 void IN_SpeedDown(void) {KeyDown(&in_speed);}
150 void IN_SpeedUp(void) {KeyUp(&in_speed);}
151 void IN_StrafeDown(void) {KeyDown(&in_strafe);}
152 void IN_StrafeUp(void) {KeyUp(&in_strafe);}
153
154 void IN_AttackDown(void) {KeyDown(&in_attack);}
155 void IN_AttackUp(void) {KeyUp(&in_attack);}
156
157 // LordHavoc: added 6 new buttons
158 void IN_Button3Down(void) {KeyDown(&in_button3);}
159 void IN_Button3Up(void) {KeyUp(&in_button3);}
160 void IN_Button4Down(void) {KeyDown(&in_button4);}
161 void IN_Button4Up(void) {KeyUp(&in_button4);}
162 void IN_Button5Down(void) {KeyDown(&in_button5);}
163 void IN_Button5Up(void) {KeyUp(&in_button5);}
164 void IN_Button6Down(void) {KeyDown(&in_button6);}
165 void IN_Button6Up(void) {KeyUp(&in_button6);}
166 void IN_Button7Down(void) {KeyDown(&in_button7);}
167 void IN_Button7Up(void) {KeyUp(&in_button7);}
168 void IN_Button8Down(void) {KeyDown(&in_button8);}
169 void IN_Button8Up(void) {KeyUp(&in_button8);}
170
171 void IN_UseDown (void) {KeyDown(&in_use);}
172 void IN_UseUp (void) {KeyUp(&in_use);}
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 ================
252 CL_AdjustAngles
253
254 Moves the local angle positions
255 ================
256 */
257 void CL_AdjustAngles (void)
258 {
259         float   speed;
260         float   up, down;
261
262         if (in_speed.state & 1)
263                 speed = cl.frametime * cl_anglespeedkey.value;
264         else
265                 speed = cl.frametime;
266
267         if (!(in_strafe.state & 1))
268         {
269                 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
270                 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
271         }
272         if (in_klook.state & 1)
273         {
274                 V_StopPitchDrift ();
275                 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
276                 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
277         }
278
279         up = CL_KeyState (&in_lookup);
280         down = CL_KeyState(&in_lookdown);
281
282         cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
283         cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
284
285         if (up || down)
286                 V_StopPitchDrift ();
287
288         cl.viewangles[YAW] = ANGLEMOD(cl.viewangles[YAW]);
289         cl.viewangles[PITCH] = ANGLEMOD(cl.viewangles[PITCH]);
290         cl.viewangles[ROLL] = ANGLEMOD(cl.viewangles[ROLL]);
291         if (cl.viewangles[YAW] >= 180)
292                 cl.viewangles[YAW] -= 360;
293         if (cl.viewangles[PITCH] >= 180)
294                 cl.viewangles[PITCH] -= 360;
295         if (cl.viewangles[ROLL] >= 180)
296                 cl.viewangles[ROLL] -= 360;
297
298         cl.viewangles[PITCH] = bound (in_pitch_min.value, cl.viewangles[PITCH], in_pitch_max.value);
299         cl.viewangles[ROLL] = bound(-50, cl.viewangles[ROLL], 50);
300 }
301
302 /*
303 ================
304 CL_BaseMove
305
306 Send the intended movement message to the server
307 ================
308 */
309 void CL_BaseMove (usercmd_t *cmd)
310 {       
311         if (cls.signon != SIGNONS)
312                 return;
313                         
314         CL_AdjustAngles ();
315         
316         memset (cmd, 0, sizeof(*cmd));
317         
318         if (in_strafe.state & 1)
319         {
320                 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
321                 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
322         }
323
324         cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
325         cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
326
327         cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);
328         cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);
329
330         if (! (in_klook.state & 1) )
331         {       
332                 cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
333                 cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
334         }       
335
336 //
337 // adjust for speed key
338 //
339         if (in_speed.state & 1)
340         {
341                 cmd->forwardmove *= cl_movespeedkey.value;
342                 cmd->sidemove *= cl_movespeedkey.value;
343                 cmd->upmove *= cl_movespeedkey.value;
344         }
345 }
346
347
348
349 /*
350 ==============
351 CL_SendMove
352 ==============
353 */
354 void CL_SendMove (usercmd_t *cmd)
355 {
356         int             i;
357         int             bits;
358         sizebuf_t       buf;
359         qbyte   data[128];
360         static double lastmovetime;
361         static float forwardmove, sidemove, upmove, total; // accumulation
362
363         forwardmove += cmd->forwardmove;
364         sidemove += cmd->sidemove;
365         upmove += cmd->upmove;
366         total++;
367         // LordHavoc: cap outgoing movement messages to sys_ticrate
368         if ((cl.maxclients > 1) && (realtime - lastmovetime < sys_ticrate.value))
369                 return;
370         lastmovetime = realtime;
371         // average what has happened during this time
372         total = 1.0f / total;
373         forwardmove *= total;
374         sidemove *= total;
375         upmove *= total;
376         total = 0;
377
378         buf.maxsize = 128;
379         buf.cursize = 0;
380         buf.data = data;
381
382         cl.cmd = *cmd;
383
384 //
385 // send the movement message
386 //
387     MSG_WriteByte (&buf, clc_move);
388
389         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
390
391         if (dpprotocol == DPPROTOCOL_VERSION2 || dpprotocol == DPPROTOCOL_VERSION3)
392         {
393                 for (i = 0;i < 3;i++)
394                         MSG_WriteFloat (&buf, cl.viewangles[i]);
395         }
396         else if (dpprotocol == DPPROTOCOL_VERSION1)
397         {
398                 for (i=0 ; i<3 ; i++)
399                         MSG_WritePreciseAngle (&buf, cl.viewangles[i]);
400         }
401         else
402         {
403                 for (i=0 ; i<3 ; i++)
404                         MSG_WriteAngle (&buf, cl.viewangles[i]);
405         }
406
407     MSG_WriteShort (&buf, forwardmove);
408     MSG_WriteShort (&buf, sidemove);
409     MSG_WriteShort (&buf, upmove);
410
411         forwardmove = sidemove = upmove = 0;
412 //
413 // send button bits
414 //
415         bits = 0;
416
417         if ( in_attack.state & 3 )
418                 bits |= 1;
419         in_attack.state &= ~2;
420
421         if (in_jump.state & 3)
422                 bits |= 2;
423         in_jump.state &= ~2;
424         // LordHavoc: added 6 new buttons
425         if (in_button3.state & 3) bits |=   4;in_button3.state &= ~2;
426         if (in_button4.state & 3) bits |=   8;in_button4.state &= ~2;
427         if (in_button5.state & 3) bits |=  16;in_button5.state &= ~2;
428         if (in_button6.state & 3) bits |=  32;in_button6.state &= ~2;
429         if (in_button7.state & 3) bits |=  64;in_button7.state &= ~2;
430         if (in_button8.state & 3) bits |= 128;in_button8.state &= ~2;
431
432     MSG_WriteByte (&buf, bits);
433
434     MSG_WriteByte (&buf, in_impulse);
435         in_impulse = 0;
436
437         // LordHavoc: should we ack this on receipt instead?  would waste net bandwidth though
438         i = EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase);
439         if (i > 0)
440         {
441                 MSG_WriteByte (&buf, clc_ackentities);
442                 MSG_WriteLong (&buf, i);
443         }
444
445 //
446 // deliver the message
447 //
448         if (cls.demoplayback)
449                 return;
450
451 //
452 // always dump the first two messages, because they may contain leftover inputs from the last level
453 //
454         if (++cl.movemessages <= 2)
455                 return;
456
457         if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
458         {
459                 Con_Printf ("CL_SendMove: lost server connection\n");
460                 CL_Disconnect ();
461         }
462 }
463
464 /*
465 ============
466 CL_InitInput
467 ============
468 */
469 void CL_InitInput (void)
470 {
471         Cmd_AddCommand ("+moveup",IN_UpDown);
472         Cmd_AddCommand ("-moveup",IN_UpUp);
473         Cmd_AddCommand ("+movedown",IN_DownDown);
474         Cmd_AddCommand ("-movedown",IN_DownUp);
475         Cmd_AddCommand ("+left",IN_LeftDown);
476         Cmd_AddCommand ("-left",IN_LeftUp);
477         Cmd_AddCommand ("+right",IN_RightDown);
478         Cmd_AddCommand ("-right",IN_RightUp);
479         Cmd_AddCommand ("+forward",IN_ForwardDown);
480         Cmd_AddCommand ("-forward",IN_ForwardUp);
481         Cmd_AddCommand ("+back",IN_BackDown);
482         Cmd_AddCommand ("-back",IN_BackUp);
483         Cmd_AddCommand ("+lookup", IN_LookupDown);
484         Cmd_AddCommand ("-lookup", IN_LookupUp);
485         Cmd_AddCommand ("+lookdown", IN_LookdownDown);
486         Cmd_AddCommand ("-lookdown", IN_LookdownUp);
487         Cmd_AddCommand ("+strafe", IN_StrafeDown);
488         Cmd_AddCommand ("-strafe", IN_StrafeUp);
489         Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
490         Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
491         Cmd_AddCommand ("+moveright", IN_MoverightDown);
492         Cmd_AddCommand ("-moveright", IN_MoverightUp);
493         Cmd_AddCommand ("+speed", IN_SpeedDown);
494         Cmd_AddCommand ("-speed", IN_SpeedUp);
495         Cmd_AddCommand ("+attack", IN_AttackDown);
496         Cmd_AddCommand ("-attack", IN_AttackUp);
497         Cmd_AddCommand ("+use", IN_UseDown);
498         Cmd_AddCommand ("-use", IN_UseUp);
499         Cmd_AddCommand ("+jump", IN_JumpDown);
500         Cmd_AddCommand ("-jump", IN_JumpUp);
501         Cmd_AddCommand ("impulse", IN_Impulse);
502         Cmd_AddCommand ("+klook", IN_KLookDown);
503         Cmd_AddCommand ("-klook", IN_KLookUp);
504         Cmd_AddCommand ("+mlook", IN_MLookDown);
505         Cmd_AddCommand ("-mlook", IN_MLookUp);
506
507         // LordHavoc: added 6 new buttons
508         Cmd_AddCommand ("+button3", IN_Button3Down);
509         Cmd_AddCommand ("-button3", IN_Button3Up);
510         Cmd_AddCommand ("+button4", IN_Button4Down);
511         Cmd_AddCommand ("-button4", IN_Button4Up);
512         Cmd_AddCommand ("+button5", IN_Button5Down);
513         Cmd_AddCommand ("-button5", IN_Button5Up);
514         Cmd_AddCommand ("+button6", IN_Button6Down);
515         Cmd_AddCommand ("-button6", IN_Button6Up);
516         Cmd_AddCommand ("+button7", IN_Button7Down);
517         Cmd_AddCommand ("-button7", IN_Button7Up);
518         Cmd_AddCommand ("+button8", IN_Button8Down);
519         Cmd_AddCommand ("-button8", IN_Button8Up);
520 }
521