home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / client / cl_main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-21  |  30.9 KB  |  1,536 lines

  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_main.c  -- client main loop
  21.  
  22. #include "quakedef.h"
  23. #include "winquake.h"
  24. #ifdef _WIN32
  25. #include "winsock.h"
  26. #else
  27. #include <netinet/in.h>
  28. #endif
  29.  
  30.  
  31. // we need to declare some mouse variables here, because the menu system
  32. // references them even when on a unix system.
  33.  
  34. qboolean    noclip_anglehack;        // remnant from old quake
  35.  
  36.  
  37. cvar_t    rcon_password = {"rcon_password", "", false};
  38.  
  39. cvar_t    rcon_address = {"rcon_address", ""};
  40.  
  41. cvar_t    cl_timeout = {"cl_timeout", "60"};
  42.  
  43. cvar_t    cl_shownet = {"cl_shownet","0"};    // can be 0, 1, or 2
  44.  
  45. cvar_t    cl_sbar        = {"cl_sbar", "0", true};
  46. cvar_t    cl_hudswap    = {"cl_hudswap", "0", true};
  47. cvar_t    cl_maxfps    = {"cl_maxfps", "0", true};
  48.  
  49. cvar_t    lookspring = {"lookspring","0", true};
  50. cvar_t    lookstrafe = {"lookstrafe","0", true};
  51. cvar_t    sensitivity = {"sensitivity","3", true};
  52.  
  53. cvar_t    m_pitch = {"m_pitch","0.022", true};
  54. cvar_t    m_yaw = {"m_yaw","0.022"};
  55. cvar_t    m_forward = {"m_forward","1"};
  56. cvar_t    m_side = {"m_side","0.8"};
  57.  
  58. cvar_t    entlatency = {"entlatency", "20"};
  59. cvar_t    cl_predict_players = {"cl_predict_players", "1"};
  60. cvar_t    cl_predict_players2 = {"cl_predict_players2", "1"};
  61. cvar_t    cl_solid_players = {"cl_solid_players", "1"};
  62.  
  63. cvar_t  localid = {"localid", ""};
  64.  
  65. static qboolean allowremotecmd = true;
  66.  
  67. //
  68. // info mirrors
  69. //
  70. cvar_t    password = {"password", "", false, true};
  71. cvar_t    spectator = {"spectator", "", false, true};
  72. cvar_t    name = {"name","unnamed", true, true};
  73. cvar_t    team = {"team","", true, true};
  74. cvar_t    skin = {"skin","", true, true};
  75. cvar_t    topcolor = {"topcolor","0", true, true};
  76. cvar_t    bottomcolor = {"bottomcolor","0", true, true};
  77. cvar_t    rate = {"rate","2500", true, true};
  78. cvar_t    noaim = {"noaim","0", true, true};
  79. cvar_t    msg = {"msg","1", true, true};
  80.  
  81. extern cvar_t cl_hightrack;
  82.  
  83.  
  84. client_static_t    cls;
  85. client_state_t    cl;
  86.  
  87. entity_state_t    cl_baselines[MAX_EDICTS];
  88. efrag_t            cl_efrags[MAX_EFRAGS];
  89. entity_t        cl_static_entities[MAX_STATIC_ENTITIES];
  90. lightstyle_t    cl_lightstyle[MAX_LIGHTSTYLES];
  91. dlight_t        cl_dlights[MAX_DLIGHTS];
  92.  
  93. // refresh list
  94. // this is double buffered so the last frame
  95. // can be scanned for oldorigins of trailing objects
  96. int                cl_numvisedicts, cl_oldnumvisedicts;
  97. entity_t        *cl_visedicts, *cl_oldvisedicts;
  98. entity_t        cl_visedicts_list[2][MAX_VISEDICTS];
  99.  
  100. double            connect_time = -1;        // for connection retransmits
  101.  
  102. quakeparms_t host_parms;
  103.  
  104. qboolean    host_initialized;        // true if into command execution
  105. qboolean    nomaster;
  106.  
  107. double        host_frametime;
  108. double        realtime;                // without any filtering or bounding
  109. double        oldrealtime;            // last frame run
  110. int            host_framecount;
  111.  
  112. int            host_hunklevel;
  113.  
  114. byte        *host_basepal;
  115. byte        *host_colormap;
  116.  
  117. netadr_t    master_adr;                // address of the master server
  118.  
  119. cvar_t    host_speeds = {"host_speeds","0"};            // set for running times
  120. cvar_t    show_fps = {"show_fps","0"};            // set for running times
  121. cvar_t    developer = {"developer","0"};
  122.  
  123. int            fps_count;
  124.  
  125. jmp_buf     host_abort;
  126.  
  127. void Master_Connect_f (void);
  128.  
  129. float    server_version = 0;    // version of server we connected to
  130.  
  131. char emodel_name[] = 
  132.     { 'e' ^ 0xff, 'm' ^ 0xff, 'o' ^ 0xff, 'd' ^ 0xff, 'e' ^ 0xff, 'l' ^ 0xff, 0 };
  133. char pmodel_name[] = 
  134.     { 'p' ^ 0xff, 'm' ^ 0xff, 'o' ^ 0xff, 'd' ^ 0xff, 'e' ^ 0xff, 'l' ^ 0xff, 0 };
  135. char prespawn_name[] = 
  136.     { 'p'^0xff, 'r'^0xff, 'e'^0xff, 's'^0xff, 'p'^0xff, 'a'^0xff, 'w'^0xff, 'n'^0xff,
  137.         ' '^0xff, '%'^0xff, 'i'^0xff, ' '^0xff, '0'^0xff, ' '^0xff, '%'^0xff, 'i'^0xff, 0 };
  138. char modellist_name[] = 
  139.     { 'm'^0xff, 'o'^0xff, 'd'^0xff, 'e'^0xff, 'l'^0xff, 'l'^0xff, 'i'^0xff, 's'^0xff, 't'^0xff, 
  140.         ' '^0xff, '%'^0xff, 'i'^0xff, ' '^0xff, '%'^0xff, 'i'^0xff, 0 };
  141. char soundlist_name[] = 
  142.     { 's'^0xff, 'o'^0xff, 'u'^0xff, 'n'^0xff, 'd'^0xff, 'l'^0xff, 'i'^0xff, 's'^0xff, 't'^0xff, 
  143.         ' '^0xff, '%'^0xff, 'i'^0xff, ' '^0xff, '%'^0xff, 'i'^0xff, 0 };
  144.  
  145. /*
  146. ==================
  147. CL_Quit_f
  148. ==================
  149. */
  150. void CL_Quit_f (void)
  151. {
  152.     if (1 /* key_dest != key_console */ /* && cls.state != ca_dedicated */)
  153.     {
  154.         M_Menu_Quit_f ();
  155.         return;
  156.     }
  157.     CL_Disconnect ();
  158.     Sys_Quit ();
  159. }
  160.  
  161. /*
  162. =======================
  163. CL_Version_f
  164. ======================
  165. */
  166. void CL_Version_f (void)
  167. {
  168.     Con_Printf ("Version %4.2f\n", VERSION);
  169.     Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
  170. }
  171.  
  172.  
  173. /*
  174. =======================
  175. CL_SendConnectPacket
  176.  
  177. called by CL_Connect_f and CL_CheckResend
  178. ======================
  179. */
  180. void CL_SendConnectPacket (void)
  181. {
  182.     netadr_t    adr;
  183.     char    data[2048];
  184.     double t1, t2;
  185. // JACK: Fixed bug where DNS lookups would cause two connects real fast
  186. //       Now, adds lookup time to the connect time.
  187. //         Should I add it to realtime instead?!?!
  188.  
  189.     if (cls.state != ca_disconnected)
  190.         return;
  191.  
  192.     t1 = Sys_DoubleTime ();
  193.  
  194.     if (!NET_StringToAdr (cls.servername, &adr))
  195.     {
  196.         Con_Printf ("Bad server address\n");
  197.         connect_time = -1;
  198.         return;
  199.     }
  200.  
  201.     if (!NET_IsClientLegal(&adr))
  202.     {
  203.         Con_Printf ("Illegal server address\n");
  204.         connect_time = -1;
  205.         return;
  206.     }
  207.  
  208.     if (adr.port == 0)
  209.         adr.port = BigShort (27500);
  210.     t2 = Sys_DoubleTime ();
  211.  
  212.     connect_time = realtime+t2-t1;    // for retransmit requests
  213.  
  214.     cls.qport = Cvar_VariableValue("qport");
  215.  
  216.     Info_SetValueForStarKey (cls.userinfo, "*ip", NET_AdrToString(adr), MAX_INFO_STRING);
  217.  
  218. //    Con_Printf ("Connecting to %s...\n", cls.servername);
  219.     sprintf (data, "%c%c%c%cconnect %i %i %i \"%s\"\n",
  220.         255, 255, 255, 255,    PROTOCOL_VERSION, cls.qport, cls.challenge, cls.userinfo);
  221.     NET_SendPacket (strlen(data), data, adr);
  222. }
  223.  
  224. /*
  225. =================
  226. CL_CheckForResend
  227.  
  228. Resend a connect message if the last one has timed out
  229.  
  230. =================
  231. */
  232. void CL_CheckForResend (void)
  233. {
  234.     netadr_t    adr;
  235.     char    data[2048];
  236.     double t1, t2;
  237.  
  238.     if (connect_time == -1)
  239.         return;
  240.     if (cls.state != ca_disconnected)
  241.         return;
  242.     if (connect_time && realtime - connect_time < 5.0)
  243.         return;
  244.  
  245.     t1 = Sys_DoubleTime ();
  246.     if (!NET_StringToAdr (cls.servername, &adr))
  247.     {
  248.         Con_Printf ("Bad server address\n");
  249.         connect_time = -1;
  250.         return;
  251.     }
  252.     if (!NET_IsClientLegal(&adr))
  253.     {
  254.         Con_Printf ("Illegal server address\n");
  255.         connect_time = -1;
  256.         return;
  257.     }
  258.  
  259.     if (adr.port == 0)
  260.         adr.port = BigShort (27500);
  261.     t2 = Sys_DoubleTime ();
  262.  
  263.     connect_time = realtime+t2-t1;    // for retransmit requests
  264.  
  265.     Con_Printf ("Connecting to %s...\n", cls.servername);
  266.     sprintf (data, "%c%c%c%cgetchallenge\n", 255, 255, 255, 255);
  267.     NET_SendPacket (strlen(data), data, adr);
  268. }
  269.  
  270. void CL_BeginServerConnect(void)
  271. {
  272.     connect_time = 0;
  273.     CL_CheckForResend();
  274. }
  275.  
  276. /*
  277. ================
  278. CL_Connect_f
  279.  
  280. ================
  281. */
  282. void CL_Connect_f (void)
  283. {
  284.     char    *server;
  285.  
  286.     if (Cmd_Argc() != 2)
  287.     {
  288.         Con_Printf ("usage: connect <server>\n");
  289.         return;    
  290.     }
  291.     
  292.     server = Cmd_Argv (1);
  293.  
  294.     CL_Disconnect ();
  295.  
  296.     strncpy (cls.servername, server, sizeof(cls.servername)-1);
  297.     CL_BeginServerConnect();
  298. }
  299.  
  300.  
  301. /*
  302. =====================
  303. CL_Rcon_f
  304.  
  305.   Send the rest of the command line over as
  306.   an unconnected command.
  307. =====================
  308. */
  309. void CL_Rcon_f (void)
  310. {
  311.     char    message[1024];
  312.     int        i;
  313.     netadr_t    to;
  314.  
  315.     if (!rcon_password.string)
  316.     {
  317.         Con_Printf ("You must set 'rcon_password' before\n"
  318.                     "issuing an rcon command.\n");
  319.         return;
  320.     }
  321.  
  322.     message[0] = 255;
  323.     message[1] = 255;
  324.     message[2] = 255;
  325.     message[3] = 255;
  326.     message[4] = 0;
  327.  
  328.     strcat (message, "rcon ");
  329.  
  330.     strcat (message, rcon_password.string);
  331.     strcat (message, " ");
  332.  
  333.     for (i=1 ; i<Cmd_Argc() ; i++)
  334.     {
  335.         strcat (message, Cmd_Argv(i));
  336.         strcat (message, " ");
  337.     }
  338.  
  339.     if (cls.state >= ca_connected)
  340.         to = cls.netchan.remote_address;
  341.     else
  342.     {
  343.         if (!strlen(rcon_address.string))
  344.         {
  345.             Con_Printf ("You must either be connected,\n"
  346.                         "or set the 'rcon_address' cvar\n"
  347.                         "to issue rcon commands\n");
  348.  
  349.             return;
  350.         }
  351.         NET_StringToAdr (rcon_address.string, &to);
  352.     }
  353.     
  354.     NET_SendPacket (strlen(message)+1, message
  355.         , to);
  356. }
  357.  
  358.  
  359. /*
  360. =====================
  361. CL_ClearState
  362.  
  363. =====================
  364. */
  365. void CL_ClearState (void)
  366. {
  367.     int            i;
  368.  
  369.     S_StopAllSounds (true);
  370.  
  371.     Con_DPrintf ("Clearing memory\n");
  372.     D_FlushCaches ();
  373.     Mod_ClearAll ();
  374.     if (host_hunklevel)    // FIXME: check this...
  375.         Hunk_FreeToLowMark (host_hunklevel);
  376.  
  377.     CL_ClearTEnts ();
  378.  
  379. // wipe the entire cl structure
  380.     memset (&cl, 0, sizeof(cl));
  381.  
  382.     SZ_Clear (&cls.netchan.message);
  383.  
  384. // clear other arrays    
  385.     memset (cl_efrags, 0, sizeof(cl_efrags));
  386.     memset (cl_dlights, 0, sizeof(cl_dlights));
  387.     memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
  388.  
  389. //
  390. // allocate the efrags and chain together into a free list
  391. //
  392.     cl.free_efrags = cl_efrags;
  393.     for (i=0 ; i<MAX_EFRAGS-1 ; i++)
  394.         cl.free_efrags[i].entnext = &cl.free_efrags[i+1];
  395.     cl.free_efrags[i].entnext = NULL;
  396. }
  397.  
  398. /*
  399. =====================
  400. CL_Disconnect
  401.  
  402. Sends a disconnect message to the server
  403. This is also called on Host_Error, so it shouldn't cause any errors
  404. =====================
  405. */
  406. void CL_Disconnect (void)
  407. {
  408.     byte    final[10];
  409.  
  410.     connect_time = -1;
  411.  
  412. #ifdef _WIN32
  413.     SetWindowText (mainwindow, "QuakeWorld: disconnected");
  414. #endif
  415.  
  416. // stop sounds (especially looping!)
  417.     S_StopAllSounds (true);
  418.     
  419. // if running a local server, shut it down
  420.     if (cls.demoplayback)
  421.         CL_StopPlayback ();
  422.     else if (cls.state != ca_disconnected)
  423.     {
  424.         if (cls.demorecording)
  425.             CL_Stop_f ();
  426.  
  427.         final[0] = clc_stringcmd;
  428.         strcpy (final+1, "drop");
  429.         Netchan_Transmit (&cls.netchan, 6, final);
  430.         Netchan_Transmit (&cls.netchan, 6, final);
  431.         Netchan_Transmit (&cls.netchan, 6, final);
  432.  
  433.         cls.state = ca_disconnected;
  434.  
  435.         cls.demoplayback = cls.demorecording = cls.timedemo = false;
  436.     }
  437.     Cam_Reset();
  438.  
  439.     if (cls.download) {
  440.         fclose(cls.download);
  441.         cls.download = NULL;
  442.     }
  443.  
  444.     CL_StopUpload();
  445.  
  446. }
  447.  
  448. void CL_Disconnect_f (void)
  449. {
  450.     CL_Disconnect ();
  451. }
  452.  
  453. /*
  454. ====================
  455. CL_User_f
  456.  
  457. user <name or userid>
  458.  
  459. Dump userdata / masterdata for a user
  460. ====================
  461. */
  462. void CL_User_f (void)
  463. {
  464.     int        uid;
  465.     int        i;
  466.  
  467.     if (Cmd_Argc() != 2)
  468.     {
  469.         Con_Printf ("Usage: user <username / userid>\n");
  470.         return;
  471.     }
  472.  
  473.     uid = atoi(Cmd_Argv(1));
  474.  
  475.     for (i=0 ; i<MAX_CLIENTS ; i++)
  476.     {
  477.         if (!cl.players[i].name[0])
  478.             continue;
  479.         if (cl.players[i].userid == uid
  480.         || !strcmp(cl.players[i].name, Cmd_Argv(1)) )
  481.         {
  482.             Info_Print (cl.players[i].userinfo);
  483.             return;
  484.         }
  485.     }
  486.     Con_Printf ("User not in server.\n");
  487. }
  488.  
  489. /*
  490. ====================
  491. CL_Users_f
  492.  
  493. Dump userids for all current players
  494. ====================
  495. */
  496. void CL_Users_f (void)
  497. {
  498.     int        i;
  499.     int        c;
  500.  
  501.     c = 0;
  502.     Con_Printf ("userid frags name\n");
  503.     Con_Printf ("------ ----- ----\n");
  504.     for (i=0 ; i<MAX_CLIENTS ; i++)
  505.     {
  506.         if (cl.players[i].name[0])
  507.         {
  508.             Con_Printf ("%6i %4i %s\n", cl.players[i].userid, cl.players[i].frags, cl.players[i].name);
  509.             c++;
  510.         }
  511.     }
  512.  
  513.     Con_Printf ("%i total users\n", c);
  514. }
  515.  
  516. void CL_Color_f (void)
  517. {
  518.     // just for quake compatability...
  519.     int        top, bottom;
  520.     char    num[16];
  521.  
  522.     if (Cmd_Argc() == 1)
  523.     {
  524.         Con_Printf ("\"color\" is \"%s %s\"\n",
  525.             Info_ValueForKey (cls.userinfo, "topcolor"),
  526.             Info_ValueForKey (cls.userinfo, "bottomcolor") );
  527.         Con_Printf ("color <0-13> [0-13]\n");
  528.         return;
  529.     }
  530.  
  531.     if (Cmd_Argc() == 2)
  532.         top = bottom = atoi(Cmd_Argv(1));
  533.     else
  534.     {
  535.         top = atoi(Cmd_Argv(1));
  536.         bottom = atoi(Cmd_Argv(2));
  537.     }
  538.     
  539.     top &= 15;
  540.     if (top > 13)
  541.         top = 13;
  542.     bottom &= 15;
  543.     if (bottom > 13)
  544.         bottom = 13;
  545.     
  546.     sprintf (num, "%i", top);
  547.     Cvar_Set ("topcolor", num);
  548.     sprintf (num, "%i", bottom);
  549.     Cvar_Set ("bottomcolor", num);
  550. }
  551.  
  552. /*
  553. ==================
  554. CL_FullServerinfo_f
  555.  
  556. Sent by server when serverinfo changes
  557. ==================
  558. */
  559. void CL_FullServerinfo_f (void)
  560. {
  561.     char *p;
  562.     float v;
  563.  
  564.     if (Cmd_Argc() != 2)
  565.     {
  566.         Con_Printf ("usage: fullserverinfo <complete info string>\n");
  567.         return;
  568.     }
  569.  
  570.     strcpy (cl.serverinfo, Cmd_Argv(1));
  571.  
  572.     if ((p = Info_ValueForKey(cl.serverinfo, "*vesion")) && *p) {
  573.         v = Q_atof(p);
  574.         if (v) {
  575.             if (!server_version)
  576.                 Con_Printf("Version %1.2f Server\n", v);
  577.             server_version = v;
  578.         }
  579.     }
  580. }
  581.  
  582. /*
  583. ==================
  584. CL_FullInfo_f
  585.  
  586. Allow clients to change userinfo
  587. ==================
  588. Casey was here :)
  589. */
  590. void CL_FullInfo_f (void)
  591. {
  592.     char    key[512];
  593.     char    value[512];
  594.     char    *o;
  595.     char    *s;
  596.  
  597.     if (Cmd_Argc() != 2)
  598.     {
  599.         Con_Printf ("fullinfo <complete info string>\n");
  600.         return;
  601.     }
  602.  
  603.     s = Cmd_Argv(1);
  604.     if (*s == '\\')
  605.         s++;
  606.     while (*s)
  607.     {
  608.         o = key;
  609.         while (*s && *s != '\\')
  610.             *o++ = *s++;
  611.         *o = 0;
  612.  
  613.         if (!*s)
  614.         {
  615.             Con_Printf ("MISSING VALUE\n");
  616.             return;
  617.         }
  618.  
  619.         o = value;
  620.         s++;
  621.         while (*s && *s != '\\')
  622.             *o++ = *s++;
  623.         *o = 0;
  624.  
  625.         if (*s)
  626.             s++;
  627.  
  628.         if (!stricmp(key, pmodel_name) || !stricmp(key, emodel_name))
  629.             continue;
  630.  
  631.         Info_SetValueForKey (cls.userinfo, key, value, MAX_INFO_STRING);
  632.     }
  633. }
  634.  
  635. /*
  636. ==================
  637. CL_SetInfo_f
  638.  
  639. Allow clients to change userinfo
  640. ==================
  641. */
  642. void CL_SetInfo_f (void)
  643. {
  644.     if (Cmd_Argc() == 1)
  645.     {
  646.         Info_Print (cls.userinfo);
  647.         return;
  648.     }
  649.     if (Cmd_Argc() != 3)
  650.     {
  651.         Con_Printf ("usage: setinfo [ <key> <value> ]\n");
  652.         return;
  653.     }
  654.     if (!stricmp(Cmd_Argv(1), pmodel_name) || !strcmp(Cmd_Argv(1), emodel_name))
  655.         return;
  656.  
  657.     Info_SetValueForKey (cls.userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING);
  658.     if (cls.state >= ca_connected)
  659.         Cmd_ForwardToServer ();
  660. }
  661.  
  662. /*
  663. ====================
  664. CL_Packet_f
  665.  
  666. packet <destination> <contents>
  667.  
  668. Contents allows \n escape character
  669. ====================
  670. */
  671. void CL_Packet_f (void)
  672. {
  673.     char    send[2048];
  674.     int        i, l;
  675.     char    *in, *out;
  676.     netadr_t    adr;
  677.  
  678.     if (Cmd_Argc() != 3)
  679.     {
  680.         Con_Printf ("packet <destination> <contents>\n");
  681.         return;
  682.     }
  683.  
  684.     if (!NET_StringToAdr (Cmd_Argv(1), &adr))
  685.     {
  686.         Con_Printf ("Bad address\n");
  687.         return;
  688.     }
  689.  
  690.     in = Cmd_Argv(2);
  691.     out = send+4;
  692.     send[0] = send[1] = send[2] = send[3] = 0xff;
  693.  
  694.     l = strlen (in);
  695.     for (i=0 ; i<l ; i++)
  696.     {
  697.         if (in[i] == '\\' && in[i+1] == 'n')
  698.         {
  699.             *out++ = '\n';
  700.             i++;
  701.         }
  702.         else
  703.             *out++ = in[i];
  704.     }
  705.     *out = 0;
  706.  
  707.     NET_SendPacket (out-send, send, adr);
  708. }
  709.  
  710.  
  711. /*
  712. =====================
  713. CL_NextDemo
  714.  
  715. Called to play the next demo in the demo loop
  716. =====================
  717. */
  718. void CL_NextDemo (void)
  719. {
  720.     char    str[1024];
  721.  
  722.     if (cls.demonum == -1)
  723.         return;        // don't play demos
  724.  
  725.     if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
  726.     {
  727.         cls.demonum = 0;
  728.         if (!cls.demos[cls.demonum][0])
  729.         {
  730. //            Con_Printf ("No demos listed with startdemos\n");
  731.             cls.demonum = -1;
  732.             return;
  733.         }
  734.     }
  735.  
  736.     sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
  737.     Cbuf_InsertText (str);
  738.     cls.demonum++;
  739. }
  740.  
  741.  
  742. /*
  743. =================
  744. CL_Changing_f
  745.  
  746. Just sent as a hint to the client that they should
  747. drop to full console
  748. =================
  749. */
  750. void CL_Changing_f (void)
  751. {
  752.     if (cls.download)  // don't change when downloading
  753.         return;
  754.  
  755.     S_StopAllSounds (true);
  756.     cl.intermission = 0;
  757.     cls.state = ca_connected;    // not active anymore, but not disconnected
  758.     Con_Printf ("\nChanging map...\n");
  759. }
  760.  
  761.  
  762. /*
  763. =================
  764. CL_Reconnect_f
  765.  
  766. The server is changing levels
  767. =================
  768. */
  769. void CL_Reconnect_f (void)
  770. {
  771.     if (cls.download)  // don't change when downloading
  772.         return;
  773.  
  774.     S_StopAllSounds (true);
  775.  
  776.     if (cls.state == ca_connected) {
  777.         Con_Printf ("reconnecting...\n");
  778.         MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
  779.         MSG_WriteString (&cls.netchan.message, "new");
  780.         return;
  781.     }
  782.  
  783.     if (!*cls.servername) {
  784.         Con_Printf("No server to reconnect to...\n");
  785.         return;
  786.     }
  787.  
  788.     CL_Disconnect();
  789.     CL_BeginServerConnect();
  790. }
  791.  
  792. /*
  793. =================
  794. CL_ConnectionlessPacket
  795.  
  796. Responses to broadcasts, etc
  797. =================
  798. */
  799. void CL_ConnectionlessPacket (void)
  800. {
  801.     char    *s;
  802.     int        c;
  803.  
  804.     MSG_BeginReading ();
  805.     MSG_ReadLong ();        // skip the -1
  806.  
  807.     c = MSG_ReadByte ();
  808.     if (!cls.demoplayback)
  809.         Con_Printf ("%s: ", NET_AdrToString (net_from));
  810. //    Con_DPrintf ("%s", net_message.data + 5);
  811.     if (c == S2C_CONNECTION)
  812.     {
  813.         Con_Printf ("connection\n");
  814.         if (cls.state >= ca_connected)
  815.         {
  816.             if (!cls.demoplayback)
  817.                 Con_Printf ("Dup connect received.  Ignored.\n");
  818.             return;
  819.         }
  820.         Netchan_Setup (&cls.netchan, net_from, cls.qport);
  821.         MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
  822.         MSG_WriteString (&cls.netchan.message, "new");    
  823.         cls.state = ca_connected;
  824.         Con_Printf ("Connected.\n");
  825.         allowremotecmd = false; // localid required now for remote cmds
  826.         return;
  827.     }
  828.     // remote command from gui front end
  829.     if (c == A2C_CLIENT_COMMAND)
  830.     {
  831.         char    cmdtext[2048];
  832.  
  833.         Con_Printf ("client command\n");
  834.  
  835.         if ((*(unsigned *)net_from.ip != *(unsigned *)net_local_adr.ip
  836.             && *(unsigned *)net_from.ip != htonl(INADDR_LOOPBACK)) )
  837.         {
  838.             Con_Printf ("Command packet from remote host.  Ignored.\n");
  839.             return;
  840.         }
  841. #ifdef _WIN32
  842.         ShowWindow (mainwindow, SW_RESTORE);
  843.         SetForegroundWindow (mainwindow);
  844. #endif
  845.         s = MSG_ReadString ();
  846.  
  847.         strncpy(cmdtext, s, sizeof(cmdtext) - 1);
  848.         cmdtext[sizeof(cmdtext) - 1] = 0;
  849.  
  850.         s = MSG_ReadString ();
  851.  
  852.         while (*s && isspace(*s))
  853.             s++;
  854.         while (*s && isspace(s[strlen(s) - 1]))
  855.             s[strlen(s) - 1] = 0;
  856.  
  857.         if (!allowremotecmd && (!*localid.string || strcmp(localid.string, s))) {
  858.             if (!*localid.string) {
  859.                 Con_Printf("===========================\n");
  860.                 Con_Printf("Command packet received from local host, but no "
  861.                     "localid has been set.  You may need to upgrade your server "
  862.                     "browser.\n");
  863.                 Con_Printf("===========================\n");
  864.                 return;
  865.             }
  866.             Con_Printf("===========================\n");
  867.             Con_Printf("Invalid localid on command packet received from local host. "
  868.                 "\n|%s| != |%s|\n"
  869.                 "You may need to reload your server browser and QuakeWorld.\n",
  870.                 s, localid.string);
  871.             Con_Printf("===========================\n");
  872.             Cvar_Set("localid", "");
  873.             return;
  874.         }
  875.  
  876.         Cbuf_AddText (cmdtext);
  877.         allowremotecmd = false;
  878.         return;
  879.     }
  880.     // print command from somewhere
  881.     if (c == A2C_PRINT)
  882.     {
  883.         Con_Printf ("print\n");
  884.  
  885.         s = MSG_ReadString ();
  886.         Con_Print (s);
  887.         return;
  888.     }
  889.  
  890.     // ping from somewhere
  891.     if (c == A2A_PING)
  892.     {
  893.         char    data[6];
  894.  
  895.         Con_Printf ("ping\n");
  896.  
  897.         data[0] = 0xff;
  898.         data[1] = 0xff;
  899.         data[2] = 0xff;
  900.         data[3] = 0xff;
  901.         data[4] = A2A_ACK;
  902.         data[5] = 0;
  903.         
  904.         NET_SendPacket (6, &data, net_from);
  905.         return;
  906.     }
  907.  
  908.     if (c == S2C_CHALLENGE) {
  909.         Con_Printf ("challenge\n");
  910.  
  911.         s = MSG_ReadString ();
  912.         cls.challenge = atoi(s);
  913.         CL_SendConnectPacket ();
  914.         return;
  915.     }
  916.  
  917. #if 0
  918.     if (c == svc_disconnect) {
  919.         Con_Printf ("disconnect\n");
  920.  
  921.         Host_EndGame ("Server disconnected");
  922.         return;
  923.     }
  924. #endif
  925.  
  926.     Con_Printf ("unknown:  %c\n", c);
  927. }
  928.  
  929.  
  930. /*
  931. =================
  932. CL_ReadPackets
  933. =================
  934. */
  935. void CL_ReadPackets (void)
  936. {
  937. //    while (NET_GetPacket ())
  938.     while (CL_GetMessage())
  939.     {
  940.         //
  941.         // remote command packet
  942.         //
  943.         if (*(int *)net_message.data == -1)
  944.         {
  945.             CL_ConnectionlessPacket ();
  946.             continue;
  947.         }
  948.  
  949.         if (net_message.cursize < 8)
  950.         {
  951.             Con_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
  952.             continue;
  953.         }
  954.  
  955.         //
  956.         // packet from server
  957.         //
  958.         if (!cls.demoplayback && 
  959.             !NET_CompareAdr (net_from, cls.netchan.remote_address))
  960.         {
  961.             Con_DPrintf ("%s:sequenced packet without connection\n"
  962.                 ,NET_AdrToString(net_from));
  963.             continue;
  964.         }
  965.         if (!Netchan_Process(&cls.netchan))
  966.             continue;        // wasn't accepted for some reason
  967.         CL_ParseServerMessage ();
  968.  
  969. //        if (cls.demoplayback && cls.state >= ca_active && !CL_DemoBehind())
  970. //            return;
  971.     }
  972.  
  973.     //
  974.     // check timeout
  975.     //
  976.     if (cls.state >= ca_connected
  977.      && realtime - cls.netchan.last_received > cl_timeout.value)
  978.     {
  979.         Con_Printf ("\nServer connection timed out.\n");
  980.         CL_Disconnect ();
  981.         return;
  982.     }
  983.     
  984. }
  985.  
  986. //=============================================================================
  987.  
  988. /*
  989. =====================
  990. CL_Download_f
  991. =====================
  992. */
  993. void CL_Download_f (void)
  994. {
  995.     char *p, *q;
  996.  
  997.     if (cls.state == ca_disconnected)
  998.     {
  999.         Con_Printf ("Must be connected.\n");
  1000.         return;
  1001.     }
  1002.  
  1003.     if (Cmd_Argc() != 2)
  1004.     {
  1005.         Con_Printf ("Usage: download <datafile>\n");
  1006.         return;
  1007.     }
  1008.  
  1009.     sprintf (cls.downloadname, "%s/%s", com_gamedir, Cmd_Argv(1));
  1010.  
  1011.     p = cls.downloadname;
  1012.     for (;;) {
  1013.         if ((q = strchr(p, '/')) != NULL) {
  1014.             *q = 0;
  1015.             Sys_mkdir(cls.downloadname);
  1016.             *q = '/';
  1017.             p = q + 1;
  1018.         } else
  1019.             break;
  1020.     }
  1021.  
  1022.     strcpy(cls.downloadtempname, cls.downloadname);
  1023.     cls.download = fopen (cls.downloadname, "wb");
  1024.     cls.downloadtype = dl_single;
  1025.  
  1026.     MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  1027.     SZ_Print (&cls.netchan.message, va("download %s\n",Cmd_Argv(1)));
  1028. }
  1029.  
  1030. #ifdef _WINDOWS
  1031. #include <windows.h>
  1032. /*
  1033. =================
  1034. CL_Minimize_f
  1035. =================
  1036. */
  1037. void CL_Windows_f (void) {
  1038. //    if (modestate == MS_WINDOWED)
  1039. //        ShowWindow(mainwindow, SW_MINIMIZE);
  1040. //    else
  1041.         SendMessage(mainwindow, WM_SYSKEYUP, VK_TAB, 1 | (0x0F << 16) | (1<<29));
  1042. }
  1043. #endif
  1044.  
  1045. /*
  1046. =================
  1047. CL_Init
  1048. =================
  1049. */
  1050. void CL_Init (void)
  1051. {
  1052.     extern    cvar_t        baseskin;
  1053.     extern    cvar_t        noskins;
  1054.     char st[80];
  1055.  
  1056.     cls.state = ca_disconnected;
  1057.  
  1058.     Info_SetValueForKey (cls.userinfo, "name", "unnamed", MAX_INFO_STRING);
  1059.     Info_SetValueForKey (cls.userinfo, "topcolor", "0", MAX_INFO_STRING);
  1060.     Info_SetValueForKey (cls.userinfo, "bottomcolor", "0", MAX_INFO_STRING);
  1061.     Info_SetValueForKey (cls.userinfo, "rate", "2500", MAX_INFO_STRING);
  1062.     Info_SetValueForKey (cls.userinfo, "msg", "1", MAX_INFO_STRING);
  1063.     sprintf (st, "%4.2f-%04d", VERSION, build_number());
  1064.     Info_SetValueForStarKey (cls.userinfo, "*ver", st, MAX_INFO_STRING);
  1065.  
  1066.     CL_InitInput ();
  1067.     CL_InitTEnts ();
  1068.     CL_InitPrediction ();
  1069.     CL_InitCam ();
  1070.     Pmove_Init ();
  1071.     
  1072. //
  1073. // register our commands
  1074. //
  1075.     Cvar_RegisterVariable (&show_fps);
  1076.     Cvar_RegisterVariable (&host_speeds);
  1077.     Cvar_RegisterVariable (&developer);
  1078.  
  1079.     Cvar_RegisterVariable (&cl_warncmd);
  1080.     Cvar_RegisterVariable (&cl_upspeed);
  1081.     Cvar_RegisterVariable (&cl_forwardspeed);
  1082.     Cvar_RegisterVariable (&cl_backspeed);
  1083.     Cvar_RegisterVariable (&cl_sidespeed);
  1084.     Cvar_RegisterVariable (&cl_movespeedkey);
  1085.     Cvar_RegisterVariable (&cl_yawspeed);
  1086.     Cvar_RegisterVariable (&cl_pitchspeed);
  1087.     Cvar_RegisterVariable (&cl_anglespeedkey);
  1088.     Cvar_RegisterVariable (&cl_shownet);
  1089.     Cvar_RegisterVariable (&cl_sbar);
  1090.     Cvar_RegisterVariable (&cl_hudswap);
  1091.     Cvar_RegisterVariable (&cl_maxfps);
  1092.     Cvar_RegisterVariable (&cl_timeout);
  1093.     Cvar_RegisterVariable (&lookspring);
  1094.     Cvar_RegisterVariable (&lookstrafe);
  1095.     Cvar_RegisterVariable (&sensitivity);
  1096.  
  1097.     Cvar_RegisterVariable (&m_pitch);
  1098.     Cvar_RegisterVariable (&m_yaw);
  1099.     Cvar_RegisterVariable (&m_forward);
  1100.     Cvar_RegisterVariable (&m_side);
  1101.  
  1102.     Cvar_RegisterVariable (&rcon_password);
  1103.     Cvar_RegisterVariable (&rcon_address);
  1104.  
  1105.     Cvar_RegisterVariable (&entlatency);
  1106.     Cvar_RegisterVariable (&cl_predict_players2);
  1107.     Cvar_RegisterVariable (&cl_predict_players);
  1108.     Cvar_RegisterVariable (&cl_solid_players);
  1109.  
  1110.     Cvar_RegisterVariable (&localid);
  1111.  
  1112.     Cvar_RegisterVariable (&baseskin);
  1113.     Cvar_RegisterVariable (&noskins);
  1114.  
  1115.     //
  1116.     // info mirrors
  1117.     //
  1118.     Cvar_RegisterVariable (&name);
  1119.     Cvar_RegisterVariable (&password);
  1120.     Cvar_RegisterVariable (&spectator);
  1121.     Cvar_RegisterVariable (&skin);
  1122.     Cvar_RegisterVariable (&team);
  1123.     Cvar_RegisterVariable (&topcolor);
  1124.     Cvar_RegisterVariable (&bottomcolor);
  1125.     Cvar_RegisterVariable (&rate);
  1126.     Cvar_RegisterVariable (&msg);
  1127.     Cvar_RegisterVariable (&noaim);
  1128.  
  1129.  
  1130.     Cmd_AddCommand ("version", CL_Version_f);
  1131.  
  1132.     Cmd_AddCommand ("changing", CL_Changing_f);
  1133.     Cmd_AddCommand ("disconnect", CL_Disconnect_f);
  1134.     Cmd_AddCommand ("record", CL_Record_f);
  1135.     Cmd_AddCommand ("rerecord", CL_ReRecord_f);
  1136.     Cmd_AddCommand ("stop", CL_Stop_f);
  1137.     Cmd_AddCommand ("playdemo", CL_PlayDemo_f);
  1138.     Cmd_AddCommand ("timedemo", CL_TimeDemo_f);
  1139.  
  1140.     Cmd_AddCommand ("skins", Skin_Skins_f);
  1141.     Cmd_AddCommand ("allskins", Skin_AllSkins_f);
  1142.  
  1143.     Cmd_AddCommand ("quit", CL_Quit_f);
  1144.  
  1145.     Cmd_AddCommand ("connect", CL_Connect_f);
  1146.     Cmd_AddCommand ("reconnect", CL_Reconnect_f);
  1147.  
  1148.     Cmd_AddCommand ("rcon", CL_Rcon_f);
  1149.     Cmd_AddCommand ("packet", CL_Packet_f);
  1150.     Cmd_AddCommand ("user", CL_User_f);
  1151.     Cmd_AddCommand ("users", CL_Users_f);
  1152.  
  1153.     Cmd_AddCommand ("setinfo", CL_SetInfo_f);
  1154.     Cmd_AddCommand ("fullinfo", CL_FullInfo_f);
  1155.     Cmd_AddCommand ("fullserverinfo", CL_FullServerinfo_f);
  1156.  
  1157.     Cmd_AddCommand ("color", CL_Color_f);
  1158.     Cmd_AddCommand ("download", CL_Download_f);
  1159.  
  1160.     Cmd_AddCommand ("nextul", CL_NextUpload);
  1161.     Cmd_AddCommand ("stopul", CL_StopUpload);
  1162.  
  1163. //
  1164. // forward to server commands
  1165. //
  1166.     Cmd_AddCommand ("kill", NULL);
  1167.     Cmd_AddCommand ("pause", NULL);
  1168.     Cmd_AddCommand ("say", NULL);
  1169.     Cmd_AddCommand ("say_team", NULL);
  1170.     Cmd_AddCommand ("serverinfo", NULL);
  1171.  
  1172. //
  1173. //  Windows commands
  1174. //
  1175. #ifdef _WINDOWS
  1176.     Cmd_AddCommand ("windows", CL_Windows_f);
  1177. #endif
  1178. }
  1179.  
  1180.  
  1181. /*
  1182. ================
  1183. Host_EndGame
  1184.  
  1185. Call this to drop to a console without exiting the qwcl
  1186. ================
  1187. */
  1188. void Host_EndGame (char *message, ...)
  1189. {
  1190.     va_list        argptr;
  1191.     char        string[1024];
  1192.     
  1193.     va_start (argptr,message);
  1194.     vsprintf (string,message,argptr);
  1195.     va_end (argptr);
  1196.     Con_Printf ("\n===========================\n");
  1197.     Con_Printf ("Host_EndGame: %s\n",string);
  1198.     Con_Printf ("===========================\n\n");
  1199.     
  1200.     CL_Disconnect ();
  1201.  
  1202.     longjmp (host_abort, 1);
  1203. }
  1204.  
  1205. /*
  1206. ================
  1207. Host_Error
  1208.  
  1209. This shuts down the client and exits qwcl
  1210. ================
  1211. */
  1212. void Host_Error (char *error, ...)
  1213. {
  1214.     va_list        argptr;
  1215.     char        string[1024];
  1216.     static    qboolean inerror = false;
  1217.     
  1218.     if (inerror)
  1219.         Sys_Error ("Host_Error: recursively entered");
  1220.     inerror = true;
  1221.     
  1222.     va_start (argptr,error);
  1223.     vsprintf (string,error,argptr);
  1224.     va_end (argptr);
  1225.     Con_Printf ("Host_Error: %s\n",string);
  1226.     
  1227.     CL_Disconnect ();
  1228.     cls.demonum = -1;
  1229.  
  1230.     inerror = false;
  1231.  
  1232. // FIXME
  1233.     Sys_Error ("Host_Error: %s\n",string);
  1234. }
  1235.  
  1236.  
  1237. /*
  1238. ===============
  1239. Host_WriteConfiguration
  1240.  
  1241. Writes key bindings and archived cvars to config.cfg
  1242. ===============
  1243. */
  1244. void Host_WriteConfiguration (void)
  1245. {
  1246.     FILE    *f;
  1247.  
  1248.     if (host_initialized)
  1249.     {
  1250.         f = fopen (va("%s/config.cfg",com_gamedir), "w");
  1251.         if (!f)
  1252.         {
  1253.             Con_Printf ("Couldn't write config.cfg.\n");
  1254.             return;
  1255.         }
  1256.         
  1257.         Key_WriteBindings (f);
  1258.         Cvar_WriteVariables (f);
  1259.  
  1260.         fclose (f);
  1261.     }
  1262. }
  1263.  
  1264.  
  1265. //============================================================================
  1266.  
  1267. #if 0
  1268. /*
  1269. ==================
  1270. Host_SimulationTime
  1271.  
  1272. This determines if enough time has passed to run a simulation frame
  1273. ==================
  1274. */
  1275. qboolean Host_SimulationTime(float time)
  1276. {
  1277.     float fps;
  1278.  
  1279.     if (oldrealtime > realtime)
  1280.         oldrealtime = 0;
  1281.  
  1282.     if (cl_maxfps.value)
  1283.         fps = max(30.0, min(cl_maxfps.value, 72.0));
  1284.     else
  1285.         fps = max(30.0, min(rate.value/80.0, 72.0));
  1286.  
  1287.     if (!cls.timedemo && (realtime + time) - oldrealtime < 1.0/fps)
  1288.         return false;            // framerate is too high
  1289.     return true;
  1290. }
  1291. #endif
  1292.  
  1293.  
  1294. /*
  1295. ==================
  1296. Host_Frame
  1297.  
  1298. Runs all active servers
  1299. ==================
  1300. */
  1301. int        nopacketcount;
  1302. void Host_Frame (float time)
  1303. {
  1304.     static double        time1 = 0;
  1305.     static double        time2 = 0;
  1306.     static double        time3 = 0;
  1307.     int            pass1, pass2, pass3;
  1308.     float fps;
  1309.     if (setjmp (host_abort) )
  1310.         return;            // something bad happened, or the server disconnected
  1311.  
  1312.     // decide the simulation time
  1313.     realtime += time;
  1314.     if (oldrealtime > realtime)
  1315.         oldrealtime = 0;
  1316.  
  1317.     if (cl_maxfps.value)
  1318.         fps = max(30.0, min(cl_maxfps.value, 72.0));
  1319.     else
  1320.         fps = max(30.0, min(rate.value/80.0, 72.0));
  1321.  
  1322.     if (!cls.timedemo && realtime - oldrealtime < 1.0/fps)
  1323.         return;            // framerate is too high
  1324.  
  1325.     host_frametime = realtime - oldrealtime;
  1326.     oldrealtime = realtime;
  1327.     if (host_frametime > 0.2)
  1328.         host_frametime = 0.2;
  1329.         
  1330.     // get new key events
  1331.     Sys_SendKeyEvents ();
  1332.  
  1333.     // allow mice or other external controllers to add commands
  1334.     IN_Commands ();
  1335.  
  1336.     // process console commands
  1337.     Cbuf_Execute ();
  1338.  
  1339.     // fetch results from server
  1340.     CL_ReadPackets ();
  1341.  
  1342.     // send intentions now
  1343.     // resend a connection request if necessary
  1344.     if (cls.state == ca_disconnected) {
  1345.         CL_CheckForResend ();
  1346.     } else
  1347.         CL_SendCmd ();
  1348.  
  1349.     // Set up prediction for other players
  1350.     CL_SetUpPlayerPrediction(false);
  1351.  
  1352.     // do client side motion prediction
  1353.     CL_PredictMove ();
  1354.  
  1355.     // Set up prediction for other players
  1356.     CL_SetUpPlayerPrediction(true);
  1357.  
  1358.     // build a refresh entity list
  1359.     CL_EmitEntities ();
  1360.  
  1361.     // update video
  1362.     if (host_speeds.value)
  1363.         time1 = Sys_DoubleTime ();
  1364.  
  1365.     SCR_UpdateScreen ();
  1366.  
  1367.     if (host_speeds.value)
  1368.         time2 = Sys_DoubleTime ();
  1369.         
  1370.     // update audio
  1371.     if (cls.state == ca_active)
  1372.     {
  1373.         S_Update (r_origin, vpn, vright, vup);
  1374.         CL_DecayLights ();
  1375.     }
  1376.     else
  1377.         S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin);
  1378.     
  1379.     CDAudio_Update();
  1380.  
  1381.     if (host_speeds.value)
  1382.     {
  1383.         pass1 = (time1 - time3)*1000;
  1384.         time3 = Sys_DoubleTime ();
  1385.         pass2 = (time2 - time1)*1000;
  1386.         pass3 = (time3 - time2)*1000;
  1387.         Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n",
  1388.                     pass1+pass2+pass3, pass1, pass2, pass3);
  1389.     }
  1390.  
  1391.     host_framecount++;
  1392.     fps_count++;
  1393. }
  1394.  
  1395. static void simple_crypt(char *buf, int len)
  1396. {
  1397.     while (len--)
  1398.         *buf++ ^= 0xff;
  1399. }
  1400.  
  1401. void Host_FixupModelNames(void)
  1402. {
  1403.     simple_crypt(emodel_name, sizeof(emodel_name) - 1);
  1404.     simple_crypt(pmodel_name, sizeof(pmodel_name) - 1);
  1405.     simple_crypt(prespawn_name,  sizeof(prespawn_name)  - 1);
  1406.     simple_crypt(modellist_name, sizeof(modellist_name) - 1);
  1407.     simple_crypt(soundlist_name, sizeof(soundlist_name) - 1);
  1408. }
  1409.  
  1410. //============================================================================
  1411.  
  1412. /*
  1413. ====================
  1414. Host_Init
  1415. ====================
  1416. */
  1417. void Host_Init (quakeparms_t *parms)
  1418. {
  1419.     COM_InitArgv (parms->argc, parms->argv);
  1420.     COM_AddParm ("-game");
  1421.     COM_AddParm ("qw");
  1422.  
  1423.     Sys_mkdir("qw");
  1424.  
  1425.     if (COM_CheckParm ("-minmemory"))
  1426.         parms->memsize = MINIMUM_MEMORY;
  1427.  
  1428.     host_parms = *parms;
  1429.  
  1430.     if (parms->memsize < MINIMUM_MEMORY)
  1431.         Sys_Error ("Only %4.1f megs of memory reported, can't execute game", parms->memsize / (float)0x100000);
  1432.  
  1433.     Memory_Init (parms->membase, parms->memsize);
  1434.     Cbuf_Init ();
  1435.     Cmd_Init ();
  1436.     V_Init ();
  1437.  
  1438.     COM_Init ();
  1439.  
  1440.     Host_FixupModelNames();
  1441.     
  1442.     NET_Init (PORT_CLIENT);
  1443.     Netchan_Init ();
  1444.  
  1445.     W_LoadWadFile ("gfx.wad");
  1446.     Key_Init ();
  1447.     Con_Init ();    
  1448.     M_Init ();    
  1449.     Mod_Init ();
  1450.     
  1451. //    Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
  1452.     Con_Printf ("%4.1f megs RAM used.\n",parms->memsize/ (1024*1024.0));
  1453.     
  1454.     R_InitTextures ();
  1455.  
  1456.     host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp");
  1457.     if (!host_basepal)
  1458.         Sys_Error ("Couldn't load gfx/palette.lmp");
  1459.     host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp");
  1460.     if (!host_colormap)
  1461.         Sys_Error ("Couldn't load gfx/colormap.lmp");
  1462. #ifdef __linux__
  1463.     IN_Init ();
  1464.     CDAudio_Init ();
  1465.     VID_Init (host_basepal);
  1466.     Draw_Init ();
  1467.     SCR_Init ();
  1468.     R_Init ();
  1469.  
  1470. //    S_Init ();        // S_Init is now done as part of VID. Sigh.
  1471.     
  1472.     cls.state = ca_disconnected;
  1473.     Sbar_Init ();
  1474.     CL_Init ();
  1475. #else
  1476.     VID_Init (host_basepal);
  1477.     Draw_Init ();
  1478.     SCR_Init ();
  1479.     R_Init ();
  1480. //    S_Init ();        // S_Init is now done as part of VID. Sigh.
  1481. #ifdef GLQUAKE
  1482.     S_Init();
  1483. #endif
  1484.  
  1485.     cls.state = ca_disconnected;
  1486.     CDAudio_Init ();
  1487.     Sbar_Init ();
  1488.     CL_Init ();
  1489.     IN_Init ();
  1490. #endif
  1491.  
  1492.     Cbuf_InsertText ("exec quake.rc\n");
  1493.     Cbuf_AddText ("echo Type connect <internet address> or use GameSpy to connect to a game.\n");
  1494.     Cbuf_AddText ("cl_warncmd 1\n");
  1495.  
  1496.     Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
  1497.     host_hunklevel = Hunk_LowMark ();
  1498.  
  1499.     host_initialized = true;
  1500.  
  1501.     Con_Printf ("\nClient Version %4.2f (Build %04d)\n\n", VERSION, build_number());
  1502.  
  1503.     Con_Printf ("€ QuakeWorld Initialized ‚\n");    
  1504. }
  1505.  
  1506.  
  1507. /*
  1508. ===============
  1509. Host_Shutdown
  1510.  
  1511. FIXME: this is a callback from Sys_Quit and Sys_Error.  It would be better
  1512. to run quit through here before the final handoff to the sys code.
  1513. ===============
  1514. */
  1515. void Host_Shutdown(void)
  1516. {
  1517.     static qboolean isdown = false;
  1518.     
  1519.     if (isdown)
  1520.     {
  1521.         printf ("recursive shutdown\n");
  1522.         return;
  1523.     }
  1524.     isdown = true;
  1525.  
  1526.     Host_WriteConfiguration (); 
  1527.         
  1528.     CDAudio_Shutdown ();
  1529.     NET_Shutdown ();
  1530.     S_Shutdown();
  1531.     IN_Shutdown ();
  1532.     if (host_basepal)
  1533.         VID_Shutdown();
  1534. }
  1535.  
  1536.