|
|
1.1 root 1: // cl_main.c -- client main loop
1.1.1.2 root 2:
1.1 root 3: #include "client.h"
1.1.1.2 root 4:
1.1 root 5: cvar_t *freelook;
6:
7: cvar_t *adr0;
8: cvar_t *adr1;
9: cvar_t *adr2;
10: cvar_t *adr3;
11: cvar_t *adr4;
12: cvar_t *adr5;
13: cvar_t *adr6;
14: cvar_t *adr7;
15: cvar_t *adr8;
16:
17: cvar_t *cl_stereo_separation;
18: cvar_t *cl_stereo;
1.1.1.2 root 19:
1.1 root 20: cvar_t *rcon_client_password;
21: cvar_t *rcon_address;
22:
23: cvar_t *cl_noskins;
24: cvar_t *cl_autoskins;
25: cvar_t *cl_footsteps;
26: cvar_t *cl_timeout;
27: cvar_t *cl_predict;
1.1.1.2 root 28: //cvar_t *cl_minfps;
1.1 root 29: cvar_t *cl_maxfps;
30: cvar_t *cl_gun;
1.1.1.2 root 31:
1.1 root 32: cvar_t *cl_add_particles;
33: cvar_t *cl_add_lights;
34: cvar_t *cl_add_entities;
35: cvar_t *cl_add_blend;
1.1.1.2 root 36:
1.1 root 37: cvar_t *cl_shownet;
38: cvar_t *cl_showmiss;
39: cvar_t *cl_showclamp;
1.1.1.2 root 40:
1.1 root 41: cvar_t *cl_paused;
42: cvar_t *cl_timedemo;
1.1.1.2 root 43:
1.1 root 44: cvar_t *lookspring;
45: cvar_t *lookstrafe;
46: cvar_t *sensitivity;
1.1.1.2 root 47:
1.1 root 48: cvar_t *m_pitch;
49: cvar_t *m_yaw;
50: cvar_t *m_forward;
51: cvar_t *m_side;
1.1.1.2 root 52:
1.1 root 53: cvar_t *cl_lightlevel;
1.1.1.2 root 54:
1.1 root 55: //
56: // userinfo
57: //
58: cvar_t *info_password;
1.1.1.3 ! root 59: cvar_t *info_spectator;
1.1 root 60: cvar_t *name;
61: cvar_t *skin;
62: cvar_t *rate;
63: cvar_t *fov;
64: cvar_t *msg;
65: cvar_t *hand;
1.1.1.2 root 66: cvar_t *gender;
67: cvar_t *gender_auto;
68:
69: cvar_t *cl_vwep;
70:
1.1 root 71: client_static_t cls;
72: client_state_t cl;
1.1.1.2 root 73:
1.1 root 74: centity_t cl_entities[MAX_EDICTS];
75:
76: entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
77:
1.1.1.2 root 78: extern cvar_t *allow_download;
79: extern cvar_t *allow_download_players;
80: extern cvar_t *allow_download_models;
81: extern cvar_t *allow_download_sounds;
82: extern cvar_t *allow_download_maps;
83:
1.1 root 84: //======================================================================
85:
86:
87: /*
88: ====================
89: CL_WriteDemoMessage
90:
91: Dumps the current net message, prefixed by the length
92: ====================
93: */
94: void CL_WriteDemoMessage (void)
95: {
96: int len, swlen;
97:
98: // the first eight bytes are just packet sequencing stuff
99: len = net_message.cursize-8;
100: swlen = LittleLong(len);
101: fwrite (&swlen, 4, 1, cls.demofile);
102: fwrite (net_message.data+8, len, 1, cls.demofile);
103: }
104:
105:
106: /*
107: ====================
108: CL_Stop_f
109:
110: stop recording a demo
111: ====================
112: */
113: void CL_Stop_f (void)
114: {
115: int len;
116:
117: if (!cls.demorecording)
118: {
119: Com_Printf ("Not recording a demo.\n");
120: return;
121: }
122:
123: // finish up
124: len = -1;
125: fwrite (&len, 4, 1, cls.demofile);
126: fclose (cls.demofile);
127: cls.demofile = NULL;
128: cls.demorecording = false;
129: Com_Printf ("Stopped demo.\n");
130: }
131:
132: /*
133: ====================
134: CL_Record_f
135:
136: record <demoname>
137:
138: Begins recording a demo from the current position
139: ====================
140: */
141: void CL_Record_f (void)
142: {
143: char name[MAX_OSPATH];
144: char buf_data[MAX_MSGLEN];
145: sizebuf_t buf;
146: int i;
147: int len;
148: entity_state_t *ent;
149: entity_state_t nullstate;
150:
151: if (Cmd_Argc() != 2)
152: {
153: Com_Printf ("record <demoname>\n");
154: return;
155: }
156:
157: if (cls.demorecording)
158: {
159: Com_Printf ("Already recording.\n");
160: return;
161: }
162:
163: if (cls.state != ca_active)
164: {
165: Com_Printf ("You must be in a level to record.\n");
166: return;
167: }
168:
169: //
170: // open the demo file
171: //
172: Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
173:
174: Com_Printf ("recording to %s.\n", name);
175: FS_CreatePath (name);
176: cls.demofile = fopen (name, "wb");
177: if (!cls.demofile)
178: {
179: Com_Printf ("ERROR: couldn't open.\n");
180: return;
181: }
182: cls.demorecording = true;
183:
184: // don't start saving messages until a non-delta compressed message is received
185: cls.demowaiting = true;
186:
187: //
188: // write out messages to hold the startup information
189: //
190: SZ_Init (&buf, buf_data, sizeof(buf_data));
191:
192: // send the serverdata
193: MSG_WriteByte (&buf, svc_serverdata);
194: MSG_WriteLong (&buf, PROTOCOL_VERSION);
195: MSG_WriteLong (&buf, 0x10000 + cl.servercount);
196: MSG_WriteByte (&buf, 1); // demos are always attract loops
197: MSG_WriteString (&buf, cl.gamedir);
198: MSG_WriteShort (&buf, cl.playernum);
199:
200: MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
201:
202: // configstrings
203: for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
204: {
205: if (cl.configstrings[i][0])
206: {
207: if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
208: { // write it out
209: len = LittleLong (buf.cursize);
210: fwrite (&len, 4, 1, cls.demofile);
211: fwrite (buf.data, buf.cursize, 1, cls.demofile);
212: buf.cursize = 0;
213: }
214:
215: MSG_WriteByte (&buf, svc_configstring);
216: MSG_WriteShort (&buf, i);
217: MSG_WriteString (&buf, cl.configstrings[i]);
218: }
219:
220: }
221:
222: // baselines
223: memset (&nullstate, 0, sizeof(nullstate));
224: for (i=0; i<MAX_EDICTS ; i++)
225: {
226: ent = &cl_entities[i].baseline;
227: if (!ent->modelindex)
228: continue;
229:
230: if (buf.cursize + 64 > buf.maxsize)
231: { // write it out
232: len = LittleLong (buf.cursize);
233: fwrite (&len, 4, 1, cls.demofile);
234: fwrite (buf.data, buf.cursize, 1, cls.demofile);
235: buf.cursize = 0;
236: }
237:
238: MSG_WriteByte (&buf, svc_spawnbaseline);
1.1.1.2 root 239: MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
1.1 root 240: }
241:
242: MSG_WriteByte (&buf, svc_stufftext);
243: MSG_WriteString (&buf, "precache\n");
244:
245: // write it to the demo file
246:
247: len = LittleLong (buf.cursize);
248: fwrite (&len, 4, 1, cls.demofile);
249: fwrite (buf.data, buf.cursize, 1, cls.demofile);
250:
251: // the rest of the demo file will be individual frames
252: }
253:
254: //======================================================================
1.1.1.2 root 255:
1.1 root 256: /*
257: ===================
258: Cmd_ForwardToServer
1.1.1.2 root 259:
1.1 root 260: adds the current command line as a clc_stringcmd to the client message.
261: things like godmode, noclip, etc, are commands directed to the server,
262: so when they are typed in at the console, they will need to be forwarded.
263: ===================
264: */
265: void Cmd_ForwardToServer (void)
266: {
267: char *cmd;
268:
269: cmd = Cmd_Argv(0);
270: if (cls.state <= ca_connected || *cmd == '-' || *cmd == '+')
271: {
272: Com_Printf ("Unknown command \"%s\"\n", cmd);
273: return;
274: }
275:
276: MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
277: SZ_Print (&cls.netchan.message, cmd);
278: if (Cmd_Argc() > 1)
279: {
280: SZ_Print (&cls.netchan.message, " ");
281: SZ_Print (&cls.netchan.message, Cmd_Args());
282: }
283: }
1.1.1.2 root 284:
1.1 root 285: void CL_Setenv_f( void )
286: {
287: int argc = Cmd_Argc();
1.1.1.2 root 288:
1.1 root 289: if ( argc > 2 )
290: {
291: char buffer[1000];
292: int i;
1.1.1.2 root 293:
1.1 root 294: strcpy( buffer, Cmd_Argv(1) );
295: strcat( buffer, "=" );
1.1.1.2 root 296:
1.1 root 297: for ( i = 2; i < argc; i++ )
298: {
299: strcat( buffer, Cmd_Argv( i ) );
300: strcat( buffer, " " );
301: }
1.1.1.2 root 302:
1.1 root 303: putenv( buffer );
304: }
305: else if ( argc == 2 )
306: {
307: char *env = getenv( Cmd_Argv(1) );
308:
309: if ( env )
310: {
311: Com_Printf( "%s=%s\n", Cmd_Argv(1), env );
312: }
313: else
314: {
315: Com_Printf( "%s undefined\n", Cmd_Argv(1), env );
316: }
317: }
318: }
1.1.1.2 root 319:
320:
1.1 root 321: /*
322: ==================
323: CL_ForwardToServer_f
324: ==================
325: */
326: void CL_ForwardToServer_f (void)
327: {
328: if (cls.state != ca_connected && cls.state != ca_active)
329: {
330: Com_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
331: return;
332: }
333:
334: // don't forward the first argument
335: if (Cmd_Argc() > 1)
336: {
337: MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
338: SZ_Print (&cls.netchan.message, Cmd_Args());
339: }
340: }
1.1.1.2 root 341:
342:
1.1 root 343: /*
344: ==================
345: CL_Pause_f
346: ==================
347: */
348: void CL_Pause_f (void)
349: {
350: // never pause in multiplayer
351: if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
352: {
353: Cvar_SetValue ("paused", 0);
354: return;
355: }
356:
357: Cvar_SetValue ("paused", !cl_paused->value);
358: }
1.1.1.2 root 359:
1.1 root 360: /*
361: ==================
362: CL_Quit_f
363: ==================
364: */
365: void CL_Quit_f (void)
366: {
367: CL_Disconnect ();
368: Com_Quit ();
369: }
1.1.1.2 root 370:
1.1 root 371: /*
372: ================
373: CL_Drop
1.1.1.2 root 374:
1.1 root 375: Called after an ERR_DROP was thrown
376: ================
377: */
378: void CL_Drop (void)
379: {
380: if (cls.state == ca_uninitialized)
381: return;
382: if (cls.state == ca_disconnected)
383: return;
1.1.1.2 root 384:
1.1 root 385: CL_Disconnect ();
1.1.1.2 root 386:
1.1 root 387: // drop loading plaque unless this is the initial game start
388: if (cls.disable_servercount != -1)
389: SCR_EndLoadingPlaque (); // get rid of loading plaque
390: }
1.1.1.2 root 391:
392:
1.1 root 393: /*
394: =======================
395: CL_SendConnectPacket
396:
397: We have gotten a challenge from the server, so try and
398: connect.
399: ======================
400: */
401: void CL_SendConnectPacket (void)
402: {
403: netadr_t adr;
404: int port;
405:
406: if (!NET_StringToAdr (cls.servername, &adr))
407: {
408: Com_Printf ("Bad server address\n");
409: cls.connect_time = 0;
410: return;
411: }
412: if (adr.port == 0)
413: adr.port = BigShort (PORT_SERVER);
414:
415: port = Cvar_VariableValue ("qport");
416: userinfo_modified = false;
417:
418: Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
419: PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
420: }
421:
422: /*
423: =================
424: CL_CheckForResend
1.1.1.2 root 425:
1.1 root 426: Resend a connect message if the last one has timed out
427: =================
428: */
429: void CL_CheckForResend (void)
430: {
431: netadr_t adr;
432:
433: // if the local server is running and we aren't
434: // then connect
435: if (cls.state == ca_disconnected && Com_ServerState() )
436: {
437: cls.state = ca_connecting;
438: strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
439: // we don't need a challenge on the localhost
440: CL_SendConnectPacket ();
441: return;
442: // cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
443: }
1.1.1.2 root 444:
1.1 root 445: // resend if we haven't gotten a reply yet
446: if (cls.state != ca_connecting)
447: return;
1.1.1.2 root 448:
1.1 root 449: if (cls.realtime - cls.connect_time < 3000)
450: return;
451:
452: if (!NET_StringToAdr (cls.servername, &adr))
453: {
454: Com_Printf ("Bad server address\n");
455: cls.state = ca_disconnected;
456: return;
457: }
458: if (adr.port == 0)
459: adr.port = BigShort (PORT_SERVER);
460:
461: cls.connect_time = cls.realtime; // for retransmit requests
462:
463: Com_Printf ("Connecting to %s...\n", cls.servername);
464:
465: Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
466: }
1.1.1.2 root 467:
468:
1.1 root 469: /*
470: ================
471: CL_Connect_f
1.1.1.2 root 472:
1.1 root 473: ================
474: */
475: void CL_Connect_f (void)
476: {
477: char *server;
1.1.1.2 root 478:
1.1 root 479: if (Cmd_Argc() != 2)
480: {
481: Com_Printf ("usage: connect <server>\n");
482: return;
483: }
484:
485: if (Com_ServerState ())
486: { // if running a local server, kill it and reissue
487: SV_Shutdown (va("Server quit\n", msg), false);
488: }
489: else
490: {
491: CL_Disconnect ();
492: }
1.1.1.2 root 493:
1.1 root 494: server = Cmd_Argv (1);
1.1.1.2 root 495:
1.1 root 496: NET_Config (true); // allow remote
1.1.1.2 root 497:
1.1 root 498: CL_Disconnect ();
1.1.1.2 root 499:
1.1 root 500: cls.state = ca_connecting;
501: strncpy (cls.servername, server, sizeof(cls.servername)-1);
502: cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
503: }
1.1.1.2 root 504:
505:
1.1 root 506: /*
507: =====================
508: CL_Rcon_f
1.1.1.2 root 509:
1.1 root 510: Send the rest of the command line over as
511: an unconnected command.
512: =====================
513: */
514: void CL_Rcon_f (void)
515: {
516: char message[1024];
517: int i;
518: netadr_t to;
1.1.1.2 root 519:
1.1 root 520: if (!rcon_client_password->string)
521: {
522: Com_Printf ("You must set 'rcon_password' before\n"
523: "issuing an rcon command.\n");
524: return;
525: }
1.1.1.2 root 526:
1.1 root 527: message[0] = (char)255;
528: message[1] = (char)255;
529: message[2] = (char)255;
530: message[3] = (char)255;
531: message[4] = 0;
532:
533: NET_Config (true); // allow remote
1.1.1.2 root 534:
1.1 root 535: strcat (message, "rcon ");
1.1.1.2 root 536:
1.1 root 537: strcat (message, rcon_client_password->string);
538: strcat (message, " ");
1.1.1.2 root 539:
1.1 root 540: for (i=1 ; i<Cmd_Argc() ; i++)
541: {
542: strcat (message, Cmd_Argv(i));
543: strcat (message, " ");
544: }
1.1.1.2 root 545:
1.1 root 546: if (cls.state >= ca_connected)
547: to = cls.netchan.remote_address;
548: else
549: {
550: if (!strlen(rcon_address->string))
551: {
552: Com_Printf ("You must either be connected,\n"
553: "or set the 'rcon_address' cvar\n"
554: "to issue rcon commands\n");
1.1.1.2 root 555:
1.1 root 556: return;
557: }
558: NET_StringToAdr (rcon_address->string, &to);
559: if (to.port == 0)
560: to.port = BigShort (PORT_SERVER);
561: }
562:
563: NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
564: }
1.1.1.2 root 565:
566:
1.1 root 567: /*
568: =====================
569: CL_ClearState
1.1.1.2 root 570:
1.1 root 571: =====================
572: */
573: void CL_ClearState (void)
574: {
575: S_StopAllSounds ();
576: CL_ClearEffects ();
577: CL_ClearTEnts ();
1.1.1.2 root 578:
1.1 root 579: // wipe the entire cl structure
580: memset (&cl, 0, sizeof(cl));
581: memset (&cl_entities, 0, sizeof(cl_entities));
1.1.1.2 root 582:
1.1 root 583: SZ_Clear (&cls.netchan.message);
1.1.1.2 root 584:
1.1 root 585: }
1.1.1.2 root 586:
1.1 root 587: /*
588: =====================
589: CL_Disconnect
1.1.1.2 root 590:
1.1 root 591: Goes from a connected state to full screen console state
592: Sends a disconnect message to the server
593: This is also called on Com_Error, so it shouldn't cause any errors
594: =====================
595: */
596: void CL_Disconnect (void)
597: {
598: byte final[32];
1.1.1.2 root 599:
1.1 root 600: if (cls.state == ca_disconnected)
601: return;
1.1.1.2 root 602:
1.1 root 603: if (cl_timedemo && cl_timedemo->value)
604: {
605: int time;
606:
607: time = Sys_Milliseconds () - cl.timedemo_start;
608: if (time > 0)
609: Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
610: time/1000.0, cl.timedemo_frames*1000.0 / time);
611: }
1.1.1.2 root 612:
1.1 root 613: VectorClear (cl.refdef.blend);
614: re.CinematicSetPalette(NULL);
615:
616: M_ForceMenuOff ();
1.1.1.2 root 617:
1.1 root 618: cls.connect_time = 0;
1.1.1.2 root 619:
1.1 root 620: SCR_StopCinematic ();
1.1.1.2 root 621:
1.1 root 622: if (cls.demorecording)
623: CL_Stop_f ();
1.1.1.2 root 624:
1.1 root 625: // send a disconnect message to the server
626: final[0] = clc_stringcmd;
627: strcpy ((char *)final+1, "disconnect");
628: Netchan_Transmit (&cls.netchan, strlen(final), final);
629: Netchan_Transmit (&cls.netchan, strlen(final), final);
630: Netchan_Transmit (&cls.netchan, strlen(final), final);
1.1.1.2 root 631:
1.1 root 632: CL_ClearState ();
1.1.1.2 root 633:
634: // stop download
635: if (cls.download) {
636: fclose(cls.download);
637: cls.download = NULL;
638: }
639:
1.1 root 640: cls.state = ca_disconnected;
641: }
1.1.1.2 root 642:
1.1 root 643: void CL_Disconnect_f (void)
644: {
645: Com_Error (ERR_DROP, "Disconnected from server");
646: }
1.1.1.2 root 647:
648:
1.1 root 649: /*
650: ====================
651: CL_Packet_f
1.1.1.2 root 652:
1.1 root 653: packet <destination> <contents>
1.1.1.2 root 654:
1.1 root 655: Contents allows \n escape character
656: ====================
657: */
658: void CL_Packet_f (void)
659: {
660: char send[2048];
661: int i, l;
662: char *in, *out;
663: netadr_t adr;
1.1.1.2 root 664:
1.1 root 665: if (Cmd_Argc() != 3)
666: {
667: Com_Printf ("packet <destination> <contents>\n");
668: return;
669: }
1.1.1.2 root 670:
1.1 root 671: NET_Config (true); // allow remote
1.1.1.2 root 672:
1.1 root 673: if (!NET_StringToAdr (Cmd_Argv(1), &adr))
674: {
675: Com_Printf ("Bad address\n");
676: return;
677: }
678: if (!adr.port)
679: adr.port = BigShort (PORT_SERVER);
1.1.1.2 root 680:
1.1 root 681: in = Cmd_Argv(2);
682: out = send+4;
683: send[0] = send[1] = send[2] = send[3] = (char)0xff;
1.1.1.2 root 684:
1.1 root 685: l = strlen (in);
686: for (i=0 ; i<l ; i++)
687: {
688: if (in[i] == '\\' && in[i+1] == 'n')
689: {
690: *out++ = '\n';
691: i++;
692: }
693: else
694: *out++ = in[i];
695: }
696: *out = 0;
1.1.1.2 root 697:
1.1 root 698: NET_SendPacket (NS_CLIENT, out-send, send, adr);
699: }
1.1.1.2 root 700:
1.1 root 701: /*
702: =================
703: CL_Changing_f
1.1.1.2 root 704:
1.1 root 705: Just sent as a hint to the client that they should
706: drop to full console
707: =================
708: */
709: void CL_Changing_f (void)
710: {
1.1.1.2 root 711: //ZOID
712: //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
713: if (cls.download)
714: return;
715:
1.1 root 716: SCR_BeginLoadingPlaque ();
717: cls.state = ca_connected; // not active anymore, but not disconnected
718: Com_Printf ("\nChanging map...\n");
719: }
1.1.1.2 root 720:
721:
1.1 root 722: /*
723: =================
724: CL_Reconnect_f
1.1.1.2 root 725:
1.1 root 726: The server is changing levels
727: =================
728: */
729: void CL_Reconnect_f (void)
730: {
1.1.1.2 root 731: //ZOID
732: //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
733: if (cls.download)
734: return;
735:
1.1 root 736: S_StopAllSounds ();
1.1.1.2 root 737: if (cls.state == ca_connected) {
738: Com_Printf ("reconnecting...\n");
739: cls.state = ca_connected;
740: MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
741: MSG_WriteString (&cls.netchan.message, "new");
742: return;
743: }
744:
745: if (*cls.servername) {
746: if (cls.state >= ca_connected) {
747: CL_Disconnect();
748: cls.connect_time = cls.realtime - 1500;
749: } else
750: cls.connect_time = -99999; // fire immediately
751:
752: cls.state = ca_connecting;
753: Com_Printf ("reconnecting...\n");
754: }
1.1 root 755: }
1.1.1.2 root 756:
1.1 root 757: /*
758: =================
759: CL_ParseStatusMessage
1.1.1.2 root 760:
1.1 root 761: Handle a reply from a ping
762: =================
763: */
764: void CL_ParseStatusMessage (void)
765: {
766: char *s;
767:
768: s = MSG_ReadString(&net_message);
1.1.1.2 root 769:
1.1 root 770: Com_Printf ("%s\n", s);
771: M_AddToServerList (net_from, s);
772: }
1.1.1.2 root 773:
774:
1.1 root 775: /*
776: =================
777: CL_PingServers_f
778: =================
779: */
780: void CL_PingServers_f (void)
781: {
782: int i;
783: netadr_t adr;
784: char name[32];
785: char *adrstring;
786: cvar_t *noudp;
787: cvar_t *noipx;
1.1.1.2 root 788:
1.1 root 789: NET_Config (true); // allow remote
1.1.1.2 root 790:
1.1 root 791: // send a broadcast packet
792: Com_Printf ("pinging broadcast...\n");
793:
794: noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
795: if (!noudp->value)
796: {
797: adr.type = NA_BROADCAST;
798: adr.port = BigShort(PORT_SERVER);
799: Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
800: }
801:
802: noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
803: if (!noipx->value)
804: {
805: adr.type = NA_BROADCAST_IPX;
806: adr.port = BigShort(PORT_SERVER);
807: Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
808: }
1.1.1.2 root 809:
1.1 root 810: // send a packet to each address book entry
811: for (i=0 ; i<16 ; i++)
812: {
813: Com_sprintf (name, sizeof(name), "adr%i", i);
814: adrstring = Cvar_VariableString (name);
815: if (!adrstring || !adrstring[0])
816: continue;
1.1.1.2 root 817:
1.1 root 818: Com_Printf ("pinging %s...\n", adrstring);
819: if (!NET_StringToAdr (adrstring, &adr))
820: {
821: Com_Printf ("Bad address: %s\n", adrstring);
822: continue;
823: }
824: if (!adr.port)
825: adr.port = BigShort(PORT_SERVER);
826: Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
827: }
828: }
829:
1.1.1.2 root 830:
1.1 root 831: /*
832: =================
833: CL_Skins_f
834:
835: Load or download any custom player skins and models
836: =================
837: */
838: void CL_Skins_f (void)
839: {
840: int i;
841:
842: for (i=0 ; i<MAX_CLIENTS ; i++)
843: {
844: if (!cl.configstrings[CS_PLAYERSKINS+i][0])
845: continue;
846: Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]);
847: SCR_UpdateScreen ();
848: Sys_SendKeyEvents (); // pump message loop
849: CL_ParseClientinfo (i);
850: }
851: }
852:
1.1.1.2 root 853:
1.1 root 854: /*
855: =================
856: CL_ConnectionlessPacket
1.1.1.2 root 857:
1.1 root 858: Responses to broadcasts, etc
859: =================
860: */
861: void CL_ConnectionlessPacket (void)
862: {
863: char *s;
864: char *c;
865:
866: MSG_BeginReading (&net_message);
867: MSG_ReadLong (&net_message); // skip the -1
1.1.1.2 root 868:
1.1 root 869: s = MSG_ReadStringLine (&net_message);
1.1.1.2 root 870:
1.1 root 871: Cmd_TokenizeString (s, false);
1.1.1.2 root 872:
1.1 root 873: c = Cmd_Argv(0);
1.1.1.2 root 874:
1.1 root 875: Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
1.1.1.2 root 876:
1.1 root 877: // server connection
878: if (!strcmp(c, "client_connect"))
879: {
880: if (cls.state == ca_connected)
881: {
882: Com_Printf ("Dup connect received. Ignored.\n");
883: return;
884: }
885: Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
886: MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
887: MSG_WriteString (&cls.netchan.message, "new");
888: cls.state = ca_connected;
889: return;
890: }
1.1.1.2 root 891:
1.1 root 892: // server responding to a status broadcast
893: if (!strcmp(c, "info"))
894: {
895: CL_ParseStatusMessage ();
896: return;
897: }
1.1.1.2 root 898:
1.1 root 899: // remote command from gui front end
900: if (!strcmp(c, "cmd"))
901: {
902: if (!NET_IsLocalAddress(net_from))
903: {
904: Com_Printf ("Command packet from remote host. Ignored.\n");
905: return;
906: }
907: Sys_AppActivate ();
908: s = MSG_ReadString (&net_message);
909: Cbuf_AddText (s);
910: Cbuf_AddText ("\n");
911: return;
912: }
913: // print command from somewhere
914: if (!strcmp(c, "print"))
915: {
916: s = MSG_ReadString (&net_message);
1.1.1.3 ! root 917: Com_Printf ("%s", s);
1.1 root 918: return;
919: }
1.1.1.2 root 920:
1.1 root 921: // ping from somewhere
922: if (!strcmp(c, "ping"))
923: {
924: Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
925: return;
926: }
927:
928: // challenge from the server we are connecting to
929: if (!strcmp(c, "challenge"))
930: {
931: cls.challenge = atoi(Cmd_Argv(1));
932: CL_SendConnectPacket ();
933: return;
934: }
935:
936: // echo request from server
937: if (!strcmp(c, "echo"))
938: {
939: Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
940: return;
941: }
942:
943: Com_Printf ("Unknown command.\n");
944: }
1.1.1.2 root 945:
946:
1.1 root 947: /*
948: =================
949: CL_DumpPackets
950:
951: A vain attempt to help bad TCP stacks that cause problems
952: when they overflow
953: =================
954: */
955: void CL_DumpPackets (void)
956: {
957: while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
958: {
959: Com_Printf ("dumnping a packet\n");
960: }
961: }
1.1.1.2 root 962:
1.1 root 963: /*
964: =================
965: CL_ReadPackets
966: =================
967: */
968: void CL_ReadPackets (void)
969: {
970: while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
971: {
972: // Com_Printf ("packet\n");
973: //
974: // remote command packet
975: //
976: if (*(int *)net_message.data == -1)
977: {
978: CL_ConnectionlessPacket ();
979: continue;
980: }
1.1.1.2 root 981:
1.1 root 982: if (cls.state == ca_disconnected || cls.state == ca_connecting)
983: continue; // dump it if not connected
1.1.1.2 root 984:
1.1 root 985: if (net_message.cursize < 8)
986: {
987: Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
988: continue;
989: }
1.1.1.2 root 990:
1.1 root 991: //
992: // packet from server
993: //
994: if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
995: {
996: Com_DPrintf ("%s:sequenced packet without connection\n"
997: ,NET_AdrToString(net_from));
998: continue;
999: }
1000: if (!Netchan_Process(&cls.netchan, &net_message))
1001: continue; // wasn't accepted for some reason
1002: CL_ParseServerMessage ();
1003: }
1.1.1.2 root 1004:
1.1 root 1005: //
1006: // check timeout
1007: //
1008: if (cls.state >= ca_connected
1009: && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
1010: {
1011: if (++cl.timeoutcount > 5) // timeoutcount saves debugger
1012: {
1013: Com_Printf ("\nServer connection timed out.\n");
1014: CL_Disconnect ();
1015: return;
1016: }
1017: }
1018: else
1019: cl.timeoutcount = 0;
1020:
1021: }
1.1.1.2 root 1022:
1023:
1.1 root 1024: //=============================================================================
1.1.1.2 root 1025:
1026: /*
1027: ==============
1028: CL_FixUpGender_f
1029: ==============
1030: */
1031: void CL_FixUpGender(void)
1032: {
1033: char *p;
1034: char sk[80];
1035:
1036: if (gender_auto->value) {
1037:
1038: if (gender->modified) {
1039: // was set directly, don't override the user
1040: gender->modified = false;
1041: return;
1042: }
1043:
1044: strncpy(sk, skin->string, sizeof(sk) - 1);
1045: if ((p = strchr(sk, '/')) != NULL)
1046: *p = 0;
1047: if (Q_stricmp(sk, "male") == 0 || Q_stricmp(sk, "cyborg") == 0)
1048: Cvar_Set ("gender", "male");
1049: else if (Q_stricmp(sk, "female") == 0 || Q_stricmp(sk, "crackhor") == 0)
1050: Cvar_Set ("gender", "female");
1051: else
1052: Cvar_Set ("gender", "none");
1053: gender->modified = false;
1054: }
1055: }
1056:
1.1 root 1057: /*
1058: ==============
1059: CL_Userinfo_f
1060: ==============
1061: */
1062: void CL_Userinfo_f (void)
1063: {
1064: Com_Printf ("User info settings:\n");
1065: Info_Print (Cvar_Userinfo());
1066: }
1.1.1.2 root 1067:
1.1 root 1068: /*
1069: =================
1070: CL_Snd_Restart_f
1.1.1.2 root 1071:
1.1 root 1072: Restart the sound subsystem so it can pick up
1073: new parameters and flush all sounds
1074: =================
1075: */
1076: void CL_Snd_Restart_f (void)
1077: {
1078: S_Shutdown ();
1079: S_Init ();
1080: CL_RegisterSounds ();
1081: }
1.1.1.2 root 1082:
1083: int precache_check; // for autodownload of precache items
1084: int precache_spawncount;
1085: int precache_tex;
1086: int precache_model_skin;
1087:
1088: byte *precache_model; // used for skin checking in alias models
1089:
1090: #define PLAYER_MULT 5
1091:
1.1.1.3 ! root 1092: // ENV_CNT is map load, ENV_CNT+1 is first env map
! 1093: #define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
! 1094: #define TEXTURE_CNT (ENV_CNT+13)
! 1095:
! 1096: static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
1.1.1.2 root 1097:
1098: void CL_RequestNextDownload (void)
1099: {
1100: unsigned map_checksum; // for detecting cheater maps
1101: char fn[MAX_OSPATH];
1102: dmdl_t *pheader;
1103:
1104: if (cls.state != ca_connected)
1105: return;
1106:
1.1.1.3 ! root 1107: if (!allow_download->value && precache_check < ENV_CNT)
! 1108: precache_check = ENV_CNT;
1.1.1.2 root 1109:
1110: //ZOID
1111: if (precache_check == CS_MODELS) { // confirm map
1112: precache_check = CS_MODELS+2; // 0 isn't used
1113: if (allow_download_maps->value)
1114: if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
1115: return; // started a download
1116: }
1117: if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
1118: if (allow_download_models->value) {
1119: while (precache_check < CS_MODELS+MAX_MODELS &&
1120: cl.configstrings[precache_check][0]) {
1121: if (cl.configstrings[precache_check][0] == '*' ||
1122: cl.configstrings[precache_check][0] == '#') {
1123: precache_check++;
1124: continue;
1125: }
1126: if (precache_model_skin == 0) {
1127: if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
1128: precache_model_skin = 1;
1129: return; // started a download
1130: }
1131: precache_model_skin = 1;
1132: }
1133:
1134: // checking for skins in the model
1135: if (!precache_model) {
1136:
1137: FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
1138: if (!precache_model) {
1139: precache_model_skin = 0;
1140: precache_check++;
1141: continue; // couldn't load it
1142: }
1143: if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
1144: // not an alias model
1145: FS_FreeFile(precache_model);
1146: precache_model = 0;
1147: precache_model_skin = 0;
1148: precache_check++;
1149: continue;
1150: }
1151: pheader = (dmdl_t *)precache_model;
1152: if (LittleLong (pheader->version) != ALIAS_VERSION) {
1153: precache_check++;
1154: precache_model_skin = 0;
1155: continue; // couldn't load it
1156: }
1157: }
1158:
1159: pheader = (dmdl_t *)precache_model;
1160:
1161: while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
1162: if (!CL_CheckOrDownloadFile((char *)precache_model +
1163: LittleLong(pheader->ofs_skins) +
1164: (precache_model_skin - 1)*MAX_SKINNAME)) {
1165: precache_model_skin++;
1166: return; // started a download
1167: }
1168: precache_model_skin++;
1169: }
1170: if (precache_model) {
1171: FS_FreeFile(precache_model);
1172: precache_model = 0;
1173: }
1174: precache_model_skin = 0;
1175: precache_check++;
1176: }
1177: }
1178: precache_check = CS_SOUNDS;
1179: }
1180: if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) {
1181: if (allow_download_sounds->value) {
1182: if (precache_check == CS_SOUNDS)
1183: precache_check++; // zero is blank
1184: while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
1185: cl.configstrings[precache_check][0]) {
1186: if (cl.configstrings[precache_check][0] == '*') {
1187: precache_check++;
1188: continue;
1189: }
1190: Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
1191: if (!CL_CheckOrDownloadFile(fn))
1192: return; // started a download
1193: }
1194: }
1195: precache_check = CS_IMAGES;
1196: }
1197: if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) {
1198: if (precache_check == CS_IMAGES)
1199: precache_check++; // zero is blank
1200: while (precache_check < CS_IMAGES+MAX_IMAGES &&
1201: cl.configstrings[precache_check][0]) {
1202: Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
1203: if (!CL_CheckOrDownloadFile(fn))
1204: return; // started a download
1205: }
1206: precache_check = CS_PLAYERSKINS;
1207: }
1208: // skins are special, since a player has three things to download:
1209: // model, weapon model and skin
1210: // so precache_check is now *3
1211: if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
1212: if (allow_download_players->value) {
1213: while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
1214: int i, n;
1215: char model[MAX_QPATH], skin[MAX_QPATH], *p;
1216:
1217: i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
1218: n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
1219:
1220: if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
1221: precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
1222: continue;
1223: }
1224:
1225: if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
1226: p++;
1227: else
1228: p = cl.configstrings[CS_PLAYERSKINS+i];
1229: strcpy(model, p);
1230: p = strchr(model, '/');
1231: if (!p)
1232: p = strchr(model, '\\');
1233: if (p) {
1234: *p++ = 0;
1235: strcpy(skin, p);
1236: } else
1237: *skin = 0;
1238:
1239: switch (n) {
1240: case 0: // model
1241: Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
1242: if (!CL_CheckOrDownloadFile(fn)) {
1243: precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
1244: return; // started a download
1245: }
1246: n++;
1247: /*FALL THROUGH*/
1248:
1249: case 1: // weapon model
1250: Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
1251: if (!CL_CheckOrDownloadFile(fn)) {
1252: precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
1253: return; // started a download
1254: }
1255: n++;
1256: /*FALL THROUGH*/
1257:
1258: case 2: // weapon skin
1259: Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
1260: if (!CL_CheckOrDownloadFile(fn)) {
1261: precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
1262: return; // started a download
1263: }
1264: n++;
1265: /*FALL THROUGH*/
1266:
1267: case 3: // skin
1268: Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
1269: if (!CL_CheckOrDownloadFile(fn)) {
1270: precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
1271: return; // started a download
1272: }
1273: n++;
1274: /*FALL THROUGH*/
1275:
1276: case 4: // skin_i
1277: Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
1278: if (!CL_CheckOrDownloadFile(fn)) {
1279: precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
1280: return; // started a download
1281: }
1282: // move on to next model
1283: precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
1284: }
1285: }
1286: }
1287: // precache phase completed
1.1.1.3 ! root 1288: precache_check = ENV_CNT;
1.1.1.2 root 1289: }
1290:
1.1.1.3 ! root 1291: if (precache_check == ENV_CNT) {
! 1292: precache_check = ENV_CNT + 1;
1.1.1.2 root 1293:
1294: CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
1295:
1.1.1.3 ! root 1296: if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
1.1.1.2 root 1297: Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
1.1.1.3 ! root 1298: map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
! 1299: return;
! 1300: }
! 1301: }
! 1302:
! 1303: if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
! 1304: if (allow_download->value && allow_download_maps->value) {
! 1305: while (precache_check < TEXTURE_CNT) {
! 1306: int n = precache_check++ - ENV_CNT - 1;
! 1307:
! 1308: if (n & 1)
! 1309: Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx",
! 1310: cl.configstrings[CS_SKY], env_suf[n/2]);
! 1311: else
! 1312: Com_sprintf(fn, sizeof(fn), "env/%s%s.tga",
! 1313: cl.configstrings[CS_SKY], env_suf[n/2]);
! 1314: if (!CL_CheckOrDownloadFile(fn))
! 1315: return; // started a download
! 1316: }
! 1317: }
! 1318: precache_check = TEXTURE_CNT;
! 1319: }
! 1320:
! 1321: if (precache_check == TEXTURE_CNT) {
! 1322: precache_check = TEXTURE_CNT+1;
! 1323: precache_tex = 0;
1.1.1.2 root 1324: }
1325:
1326: // confirm existance of textures, download any that don't exist
1327: if (precache_check == TEXTURE_CNT+1) {
1328: // from qcommon/cmodel.c
1329: extern int numtexinfo;
1330: extern mapsurface_t map_surfaces[];
1331:
1332: if (allow_download->value && allow_download_maps->value) {
1333: while (precache_tex < numtexinfo) {
1334: char fn[MAX_OSPATH];
1335:
1336: sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
1337: if (!CL_CheckOrDownloadFile(fn))
1338: return; // started a download
1339: }
1340: }
1341: precache_check = TEXTURE_CNT+999;
1342: }
1343:
1344: //ZOID
1345: CL_RegisterSounds ();
1346: CL_PrepRefresh ();
1347:
1348: MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
1349: MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
1350: }
1351:
1.1 root 1352: /*
1353: =================
1354: CL_Precache_f
1.1.1.2 root 1355:
1.1 root 1356: The server will send this command right
1357: before allowing the client into the server
1358: =================
1359: */
1360: void CL_Precache_f (void)
1361: {
1.1.1.2 root 1362: //Yet another hack to let old demos work
1363: //the old precache sequence
1364: if (Cmd_Argc() < 2) {
1365: unsigned map_checksum; // for detecting cheater maps
1.1 root 1366:
1.1.1.2 root 1367: CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
1368: CL_RegisterSounds ();
1369: CL_PrepRefresh ();
1370: return;
1371: }
1.1 root 1372:
1.1.1.2 root 1373: precache_check = CS_MODELS;
1374: precache_spawncount = atoi(Cmd_Argv(1));
1375: precache_model = 0;
1376: precache_model_skin = 0;
1377:
1378: CL_RequestNextDownload();
1.1 root 1379: }
1.1.1.2 root 1380:
1381:
1.1 root 1382: /*
1383: =================
1384: CL_InitLocal
1385: =================
1386: */
1387: void CL_InitLocal (void)
1388: {
1389: cls.state = ca_disconnected;
1390: cls.realtime = Sys_Milliseconds ();
1.1.1.2 root 1391:
1.1 root 1392: CL_InitInput ();
1393:
1394: adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
1395: adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
1396: adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
1397: adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
1398: adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
1399: adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
1400: adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
1401: adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
1402: adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
1.1.1.2 root 1403:
1.1 root 1404: //
1405: // register our variables
1406: //
1407: cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
1408: cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
1409:
1410: cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
1411: cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
1412: cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
1413: cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
1414: cl_gun = Cvar_Get ("cl_gun", "1", 0);
1415: cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
1416: cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
1417: cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
1418: cl_predict = Cvar_Get ("cl_predict", "1", 0);
1.1.1.2 root 1419: // cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
1.1 root 1420: cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
1.1.1.2 root 1421:
1.1 root 1422: cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
1423: cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
1424: cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
1425: cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
1426: cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
1427: cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
1.1.1.2 root 1428:
1.1 root 1429: cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
1430: freelook = Cvar_Get( "freelook", "0", CVAR_ARCHIVE );
1431: lookspring = Cvar_Get ("lookspring", "0", CVAR_ARCHIVE);
1432: lookstrafe = Cvar_Get ("lookstrafe", "0", CVAR_ARCHIVE);
1433: sensitivity = Cvar_Get ("sensitivity", "3", CVAR_ARCHIVE);
1434:
1435: m_pitch = Cvar_Get ("m_pitch", "0.022", CVAR_ARCHIVE);
1436: m_yaw = Cvar_Get ("m_yaw", "0.022", 0);
1437: m_forward = Cvar_Get ("m_forward", "1", 0);
1438: m_side = Cvar_Get ("m_side", "1", 0);
1439:
1440: cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
1441: cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
1442: cl_showclamp = Cvar_Get ("showclamp", "0", 0);
1443: cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
1444: cl_paused = Cvar_Get ("paused", "0", 0);
1445: cl_timedemo = Cvar_Get ("timedemo", "0", 0);
1.1.1.2 root 1446:
1.1 root 1447: rcon_client_password = Cvar_Get ("rcon_password", "", 0);
1448: rcon_address = Cvar_Get ("rcon_address", "", 0);
1.1.1.2 root 1449:
1.1 root 1450: cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
1.1.1.2 root 1451:
1.1 root 1452: //
1453: // userinfo
1454: //
1455: info_password = Cvar_Get ("password", "", CVAR_USERINFO);
1.1.1.3 ! root 1456: info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
1.1 root 1457: name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
1458: skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
1459: rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE); // FIXME
1460: msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
1461: hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
1462: fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
1.1.1.2 root 1463: gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
1464: gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
1465: gender->modified = false; // clear this so we know when user sets it manually
1466:
1467: cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
1468:
1469:
1.1 root 1470: //
1471: // register our commands
1472: //
1473: Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
1474: Cmd_AddCommand ("pause", CL_Pause_f);
1475: Cmd_AddCommand ("pingservers", CL_PingServers_f);
1476: Cmd_AddCommand ("skins", CL_Skins_f);
1.1.1.2 root 1477:
1.1 root 1478: Cmd_AddCommand ("userinfo", CL_Userinfo_f);
1479: Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
1.1.1.2 root 1480:
1.1 root 1481: Cmd_AddCommand ("changing", CL_Changing_f);
1482: Cmd_AddCommand ("disconnect", CL_Disconnect_f);
1483: Cmd_AddCommand ("record", CL_Record_f);
1484: Cmd_AddCommand ("stop", CL_Stop_f);
1.1.1.2 root 1485:
1.1 root 1486: Cmd_AddCommand ("quit", CL_Quit_f);
1.1.1.2 root 1487:
1.1 root 1488: Cmd_AddCommand ("connect", CL_Connect_f);
1489: Cmd_AddCommand ("reconnect", CL_Reconnect_f);
1.1.1.2 root 1490:
1.1 root 1491: Cmd_AddCommand ("rcon", CL_Rcon_f);
1492:
1493: // Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
1.1.1.2 root 1494:
1.1 root 1495: Cmd_AddCommand ("setenv", CL_Setenv_f );
1.1.1.2 root 1496:
1.1 root 1497: Cmd_AddCommand ("precache", CL_Precache_f);
1.1.1.2 root 1498:
1499: Cmd_AddCommand ("download", CL_Download_f);
1500:
1.1 root 1501: //
1502: // forward to server commands
1503: //
1504: // the only thing this does is allow command completion
1505: // to work -- all unknown commands are automatically
1506: // forwarded to the server
1507: Cmd_AddCommand ("wave", NULL);
1508: Cmd_AddCommand ("inven", NULL);
1509: Cmd_AddCommand ("kill", NULL);
1510: Cmd_AddCommand ("use", NULL);
1511: Cmd_AddCommand ("drop", NULL);
1512: Cmd_AddCommand ("say", NULL);
1513: Cmd_AddCommand ("say_team", NULL);
1514: Cmd_AddCommand ("info", NULL);
1515: Cmd_AddCommand ("prog", NULL);
1516: Cmd_AddCommand ("give", NULL);
1517: Cmd_AddCommand ("god", NULL);
1518: Cmd_AddCommand ("notarget", NULL);
1519: Cmd_AddCommand ("noclip", NULL);
1520: Cmd_AddCommand ("invuse", NULL);
1521: Cmd_AddCommand ("invprev", NULL);
1522: Cmd_AddCommand ("invnext", NULL);
1523: Cmd_AddCommand ("invdrop", NULL);
1524: Cmd_AddCommand ("weapnext", NULL);
1525: Cmd_AddCommand ("weapprev", NULL);
1526: }
1.1.1.2 root 1527:
1528:
1529:
1.1 root 1530: /*
1531: ===============
1532: CL_WriteConfiguration
1.1.1.2 root 1533:
1.1 root 1534: Writes key bindings and archived cvars to config.cfg
1535: ===============
1536: */
1537: void CL_WriteConfiguration (void)
1538: {
1539: FILE *f;
1540: char path[MAX_QPATH];
1.1.1.2 root 1541:
1.1 root 1542: if (cls.state == ca_uninitialized)
1543: return;
1.1.1.2 root 1544:
1.1 root 1545: Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
1546: f = fopen (path, "w");
1547: if (!f)
1548: {
1549: Com_Printf ("Couldn't write config.cfg.\n");
1550: return;
1551: }
1.1.1.2 root 1552:
1.1 root 1553: fprintf (f, "// generated by quake, do not modify\n");
1554: Key_WriteBindings (f);
1555: fclose (f);
1.1.1.2 root 1556:
1.1 root 1557: Cvar_WriteVariables (path);
1558: }
1559:
1.1.1.2 root 1560:
1.1 root 1561: /*
1562: ==================
1563: CL_FixCvarCheats
1564:
1565: ==================
1566: */
1567:
1568: typedef struct
1569: {
1570: char *name;
1571: char *value;
1572: cvar_t *var;
1573: } cheatvar_t;
1574:
1575: cheatvar_t cheatvars[] = {
1576: {"timescale", "1"},
1577: {"timedemo", "0"},
1578: {"r_drawworld", "1"},
1579: {"cl_testlights", "0"},
1580: {"r_fullbright", "0"},
1581: {"r_drawflat", "0"},
1582: {"paused", "0"},
1583: {"fixedtime", "0"},
1.1.1.2 root 1584: {"sw_draworder", "0"},
1585: {"gl_lightmap", "0"},
1586: {"gl_saturatelighting", "0"},
1.1 root 1587: {NULL, NULL}
1588: };
1589:
1590: int numcheatvars;
1591:
1592: void CL_FixCvarCheats (void)
1593: {
1594: int i;
1595: cheatvar_t *var;
1596:
1597: if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1")
1598: || !cl.configstrings[CS_MAXCLIENTS][0] )
1599: return; // single player can cheat
1600:
1601: // find all the cvars if we haven't done it yet
1602: if (!numcheatvars)
1603: {
1604: while (cheatvars[numcheatvars].name)
1605: {
1606: cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
1607: cheatvars[numcheatvars].value, 0);
1608: numcheatvars++;
1609: }
1610: }
1611:
1612: // make sure they are all set to the proper values
1613: for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
1614: {
1615: if ( strcmp (var->var->string, var->value) )
1616: {
1617: Cvar_Set (var->name, var->value);
1618: }
1619: }
1620: }
1.1.1.2 root 1621:
1.1 root 1622: //============================================================================
1623:
1624: /*
1625: ==================
1626: CL_SendCommand
1627:
1628: ==================
1629: */
1630: void CL_SendCommand (void)
1631: {
1632: // get new key events
1633: Sys_SendKeyEvents ();
1634:
1635: // allow mice or other external controllers to add commands
1636: IN_Commands ();
1637:
1638: // process console commands
1639: Cbuf_Execute ();
1640:
1641: // fix any cheating cvars
1642: CL_FixCvarCheats ();
1643:
1644: // send intentions now
1645: CL_SendCmd ();
1646:
1647: // resend a connection request if necessary
1648: CL_CheckForResend ();
1649: }
1.1.1.2 root 1650:
1651:
1.1 root 1652: /*
1653: ==================
1654: CL_Frame
1.1.1.2 root 1655:
1.1 root 1656: ==================
1657: */
1658: void CL_Frame (int msec)
1659: {
1660: static int extratime;
1661: static int lasttimecalled;
1.1.1.2 root 1662:
1.1 root 1663: if (dedicated->value)
1664: return;
1.1.1.2 root 1665:
1.1 root 1666: extratime += msec;
1667:
1668: if (!cl_timedemo->value)
1669: {
1670: if (cls.state == ca_connected && extratime < 100)
1671: return; // don't flood packets out while connecting
1672: if (extratime < 1000/cl_maxfps->value)
1673: return; // framerate is too high
1674: }
1675:
1676: // let the mouse activate or deactivate
1677: IN_Frame ();
1.1.1.2 root 1678:
1.1 root 1679: // decide the simulation time
1680: cls.frametime = extratime/1000.0;
1681: cl.time += extratime;
1682: cls.realtime = curtime;
1.1.1.2 root 1683:
1.1 root 1684: extratime = 0;
1.1.1.2 root 1685: #if 0
1.1 root 1686: if (cls.frametime > (1.0 / cl_minfps->value))
1687: cls.frametime = (1.0 / cl_minfps->value);
1.1.1.2 root 1688: #else
1689: if (cls.frametime > (1.0 / 5))
1690: cls.frametime = (1.0 / 5);
1691: #endif
1692:
1.1 root 1693: // if in the debugger last frame, don't timeout
1694: if (msec > 5000)
1695: cls.netchan.last_received = Sys_Milliseconds ();
1696:
1697: // fetch results from server
1698: CL_ReadPackets ();
1699:
1700: // send a new command message to the server
1701: CL_SendCommand ();
1702:
1703: // predict all unacknowledged movements
1704: CL_PredictMovement ();
1.1.1.2 root 1705:
1.1 root 1706: // allow rendering DLL change
1707: VID_CheckChanges ();
1708: if (!cl.refresh_prepped && cls.state == ca_active)
1709: CL_PrepRefresh ();
1710:
1711: // update the screen
1712: if (host_speeds->value)
1713: time_before_ref = Sys_Milliseconds ();
1714: SCR_UpdateScreen ();
1715: if (host_speeds->value)
1716: time_after_ref = Sys_Milliseconds ();
1.1.1.2 root 1717:
1.1 root 1718: // update audio
1719: S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
1720:
1721: CDAudio_Update();
1722:
1723: // advance local effects for next frame
1724: CL_RunDLights ();
1725: CL_RunLightStyles ();
1726: SCR_RunCinematic ();
1727: SCR_RunConsole ();
1728:
1729: cls.framecount++;
1730:
1731: if ( log_stats->value )
1732: {
1733: if ( cls.state == ca_active )
1734: {
1735: if ( !lasttimecalled )
1736: {
1737: lasttimecalled = Sys_Milliseconds();
1738: if ( log_stats_file )
1739: fprintf( log_stats_file, "0\n" );
1740: }
1741: else
1742: {
1743: int now = Sys_Milliseconds();
1744:
1745: if ( log_stats_file )
1746: fprintf( log_stats_file, "%d\n", now - lasttimecalled );
1747: lasttimecalled = now;
1748: }
1749: }
1750: }
1751: }
1.1.1.2 root 1752:
1753:
1.1 root 1754: //============================================================================
1.1.1.2 root 1755:
1.1 root 1756: /*
1757: ====================
1758: CL_Init
1759: ====================
1760: */
1761: void CL_Init (void)
1762: {
1763: if (dedicated->value)
1764: return; // nothing running on the client
1.1.1.2 root 1765:
1.1 root 1766: // all archived variables will now be loaded
1.1.1.2 root 1767:
1.1 root 1768: Con_Init ();
1.1.1.2 root 1769: #if defined __linux__ || defined __sgi
1770: S_Init ();
1771: VID_Init ();
1772: #else
1.1 root 1773: VID_Init ();
1774: S_Init (); // sound must be initialized after window is created
1.1.1.2 root 1775: #endif
1.1 root 1776:
1777: V_Init ();
1778:
1779: net_message.data = net_message_buffer;
1780: net_message.maxsize = sizeof(net_message_buffer);
1.1.1.2 root 1781:
1.1 root 1782: M_Init ();
1783:
1784: SCR_Init ();
1785: cls.disable_screen = true; // don't draw yet
1.1.1.2 root 1786:
1.1 root 1787: CDAudio_Init ();
1788: CL_InitLocal ();
1789: IN_Init ();
1.1.1.2 root 1790:
1.1 root 1791: // Cbuf_AddText ("exec autoexec.cfg\n");
1792: FS_ExecAutoexec ();
1793: Cbuf_Execute ();
1.1.1.2 root 1794:
1.1 root 1795: }
1.1.1.2 root 1796:
1797:
1.1 root 1798: /*
1799: ===============
1800: CL_Shutdown
1.1.1.2 root 1801:
1.1 root 1802: FIXME: this is a callback from Sys_Quit and Com_Error. It would be better
1803: to run quit through here before the final handoff to the sys code.
1804: ===============
1805: */
1806: void CL_Shutdown(void)
1807: {
1808: static qboolean isdown = false;
1809:
1810: if (isdown)
1811: {
1812: printf ("recursive shutdown\n");
1813: return;
1814: }
1815: isdown = true;
1.1.1.2 root 1816:
1.1 root 1817: CL_WriteConfiguration ();
1.1.1.2 root 1818:
1.1 root 1819: CDAudio_Shutdown ();
1820: S_Shutdown();
1821: IN_Shutdown ();
1822: VID_Shutdown();
1823: }
1824:
1825:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.