]> icculus.org git repositories - divverent/darkplaces.git/blob - cl_input.c
Changed dp so the new vm fits in.
[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 cvar_t cl_nodelta = {0, "cl_nodelta", "0"};
250
251 /*
252 ================
253 CL_AdjustAngles
254
255 Moves the local angle positions
256 ================
257 */
258 void CL_AdjustAngles (void)
259 {
260         float   speed;
261         float   up, down;
262
263         if (in_speed.state & 1)
264                 speed = cl.frametime * cl_anglespeedkey.value;
265         else
266                 speed = cl.frametime;
267
268         if (!(in_strafe.state & 1))
269         {
270                 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
271                 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
272         }
273         if (in_klook.state & 1)
274         {
275                 V_StopPitchDrift ();
276                 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
277                 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
278         }
279
280         up = CL_KeyState (&in_lookup);
281         down = CL_KeyState(&in_lookdown);
282
283         cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
284         cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
285
286         if (up || down)
287                 V_StopPitchDrift ();
288
289         cl.viewangles[YAW] = ANGLEMOD(cl.viewangles[YAW]);
290         cl.viewangles[PITCH] = ANGLEMOD(cl.viewangles[PITCH]);
291         cl.viewangles[ROLL] = ANGLEMOD(cl.viewangles[ROLL]);
292         if (cl.viewangles[YAW] >= 180)
293                 cl.viewangles[YAW] -= 360;
294         if (cl.viewangles[PITCH] >= 180)
295                 cl.viewangles[PITCH] -= 360;
296         if (cl.viewangles[ROLL] >= 180)
297                 cl.viewangles[ROLL] -= 360;
298
299         cl.viewangles[PITCH] = bound (in_pitch_min.value, cl.viewangles[PITCH], in_pitch_max.value);
300         cl.viewangles[ROLL] = bound(-50, cl.viewangles[ROLL], 50);
301 }
302
303 /*
304 ================
305 CL_BaseMove
306
307 Send the intended movement message to the server
308 ================
309 */
310 void CL_BaseMove (usercmd_t *cmd)
311 {
312         if (cls.signon != SIGNONS)
313                 return;
314
315         CL_AdjustAngles ();
316
317         memset (cmd, 0, sizeof(*cmd));
318
319         if (in_strafe.state & 1)
320         {
321                 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
322                 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
323         }
324
325         cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
326         cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
327
328         cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);
329         cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);
330
331         if (! (in_klook.state & 1) )
332         {
333                 cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
334                 cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
335         }
336
337 //
338 // adjust for speed key
339 //
340         if (in_speed.state & 1)
341         {
342                 cmd->forwardmove *= cl_movespeedkey.value;
343                 cmd->sidemove *= cl_movespeedkey.value;
344                 cmd->upmove *= cl_movespeedkey.value;
345         }
346 }
347
348
349
350 /*
351 ==============
352 CL_SendMove
353 ==============
354 */
355 void CL_SendMove(usercmd_t *cmd)
356 {
357         int i;
358         int bits;
359         sizebuf_t buf;
360         qbyte data[128];
361         static double lastmovetime;
362         static float forwardmove, sidemove, upmove, total; // accumulation
363
364         forwardmove += cmd->forwardmove;
365         sidemove += cmd->sidemove;
366         upmove += cmd->upmove;
367         total++;
368         // LordHavoc: cap outgoing movement messages to sys_ticrate
369         if (!cl.islocalgame && (realtime - lastmovetime < sys_ticrate.value))
370                 return;
371         lastmovetime = realtime;
372         // average what has happened during this time
373         total = 1.0f / total;
374         forwardmove *= total;
375         sidemove *= total;
376         upmove *= total;
377         total = 0;
378
379         buf.maxsize = 128;
380         buf.cursize = 0;
381         buf.data = data;
382
383         cl.cmd = *cmd;
384
385         // send the movement message
386         MSG_WriteByte (&buf, clc_move);
387
388         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
389
390         if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
391         {
392                 for (i = 0;i < 3;i++)
393                         MSG_WriteFloat (&buf, cl.viewangles[i]);
394         }
395         else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4)
396         {
397                 for (i=0 ; i<3 ; i++)
398                         MSG_WritePreciseAngle (&buf, cl.viewangles[i]);
399         }
400         else
401         {
402                 for (i=0 ; i<3 ; i++)
403                         MSG_WriteAngle (&buf, cl.viewangles[i]);
404         }
405
406         MSG_WriteShort (&buf, forwardmove);
407         MSG_WriteShort (&buf, sidemove);
408         MSG_WriteShort (&buf, upmove);
409
410         forwardmove = sidemove = upmove = 0;
411         // send button bits
412         bits = 0;
413
414         if ( in_attack.state & 3 )
415                 bits |= 1;
416         in_attack.state &= ~2;
417
418         if (in_jump.state & 3)
419                 bits |= 2;
420         in_jump.state &= ~2;
421         // LordHavoc: added 6 new buttons
422         if (in_button3.state & 3) bits |=   4;in_button3.state &= ~2;
423         if (in_button4.state & 3) bits |=   8;in_button4.state &= ~2;
424         if (in_button5.state & 3) bits |=  16;in_button5.state &= ~2;
425         if (in_button6.state & 3) bits |=  32;in_button6.state &= ~2;
426         if (in_button7.state & 3) bits |=  64;in_button7.state &= ~2;
427         if (in_button8.state & 3) bits |= 128;in_button8.state &= ~2;
428
429         MSG_WriteByte (&buf, bits);
430
431         MSG_WriteByte (&buf, in_impulse);
432         in_impulse = 0;
433
434         if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
435         {
436                 // LordHavoc: should we ack this on receipt instead?  would waste net bandwidth though
437                 i = EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase);
438                 if (i > 0)
439                 {
440                         MSG_WriteByte(&buf, clc_ackentities);
441                         MSG_WriteLong(&buf, i);
442                 }
443         }
444         else
445         {
446                 if (cl.entitydatabase4)
447                 {
448                         i = cl.entitydatabase4->ackframenum;
449                         if (cl_nodelta.integer)
450                                 i = -1;
451                         if (developer_networkentities.integer >= 1)
452                                 Con_Printf("send clc_ackentities %i\n", i);
453                         MSG_WriteByte(&buf, clc_ackentities);
454                         MSG_WriteLong(&buf, i);
455                 }
456         }
457
458         // deliver the message
459         if (cls.demoplayback)
460                 return;
461
462         // always dump the first two messages, because they may contain leftover inputs from the last level
463         if (++cl.movemessages <= 2)
464                 return;
465
466         if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
467         {
468                 Con_Printf("CL_SendMove: lost server connection\n");
469                 CL_Disconnect();
470         }
471 }
472
473 /*
474 ============
475 CL_InitInput
476 ============
477 */
478 void CL_InitInput (void)
479 {
480         Cmd_AddCommand ("+moveup",IN_UpDown);
481         Cmd_AddCommand ("-moveup",IN_UpUp);
482         Cmd_AddCommand ("+movedown",IN_DownDown);
483         Cmd_AddCommand ("-movedown",IN_DownUp);
484         Cmd_AddCommand ("+left",IN_LeftDown);
485         Cmd_AddCommand ("-left",IN_LeftUp);
486         Cmd_AddCommand ("+right",IN_RightDown);
487         Cmd_AddCommand ("-right",IN_RightUp);
488         Cmd_AddCommand ("+forward",IN_ForwardDown);
489         Cmd_AddCommand ("-forward",IN_ForwardUp);
490         Cmd_AddCommand ("+back",IN_BackDown);
491         Cmd_AddCommand ("-back",IN_BackUp);
492         Cmd_AddCommand ("+lookup", IN_LookupDown);
493         Cmd_AddCommand ("-lookup", IN_LookupUp);
494         Cmd_AddCommand ("+lookdown", IN_LookdownDown);
495         Cmd_AddCommand ("-lookdown", IN_LookdownUp);
496         Cmd_AddCommand ("+strafe", IN_StrafeDown);
497         Cmd_AddCommand ("-strafe", IN_StrafeUp);
498         Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
499         Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
500         Cmd_AddCommand ("+moveright", IN_MoverightDown);
501         Cmd_AddCommand ("-moveright", IN_MoverightUp);
502         Cmd_AddCommand ("+speed", IN_SpeedDown);
503         Cmd_AddCommand ("-speed", IN_SpeedUp);
504         Cmd_AddCommand ("+attack", IN_AttackDown);
505         Cmd_AddCommand ("-attack", IN_AttackUp);
506         Cmd_AddCommand ("+use", IN_UseDown);
507         Cmd_AddCommand ("-use", IN_UseUp);
508         Cmd_AddCommand ("+jump", IN_JumpDown);
509         Cmd_AddCommand ("-jump", IN_JumpUp);
510         Cmd_AddCommand ("impulse", IN_Impulse);
511         Cmd_AddCommand ("+klook", IN_KLookDown);
512         Cmd_AddCommand ("-klook", IN_KLookUp);
513         Cmd_AddCommand ("+mlook", IN_MLookDown);
514         Cmd_AddCommand ("-mlook", IN_MLookUp);
515
516         // LordHavoc: added 6 new buttons
517         Cmd_AddCommand ("+button3", IN_Button3Down);
518         Cmd_AddCommand ("-button3", IN_Button3Up);
519         Cmd_AddCommand ("+button4", IN_Button4Down);
520         Cmd_AddCommand ("-button4", IN_Button4Up);
521         Cmd_AddCommand ("+button5", IN_Button5Down);
522         Cmd_AddCommand ("-button5", IN_Button5Up);
523         Cmd_AddCommand ("+button6", IN_Button6Down);
524         Cmd_AddCommand ("-button6", IN_Button6Up);
525         Cmd_AddCommand ("+button7", IN_Button7Down);
526         Cmd_AddCommand ("-button7", IN_Button7Up);
527         Cmd_AddCommand ("+button8", IN_Button8Down);
528         Cmd_AddCommand ("-button8", IN_Button8Up);
529
530         Cvar_RegisterVariable(&cl_nodelta);
531 }
532