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