home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Hexen Source / D_NET.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-25  |  20.3 KB  |  928 lines

  1.  
  2. //**************************************************************************
  3. //**
  4. //** d_net.c : Heretic 2 : Raven Software, Corp.
  5. //**
  6. //** $RCSfile: d_net.c,v $
  7. //** $Revision: 1.16 $
  8. //** $Date: 96/01/01 03:39:44 $
  9. //** $Author: bgokey $
  10. //**
  11. //** This version has the fixed ticdup code.
  12. //**
  13. //**************************************************************************
  14.  
  15. #include "h2def.h"
  16. #include "p_local.h"
  17. #include <stdlib.h> // for atoi()
  18.  
  19. #define NCMD_EXIT               0x80000000
  20. #define NCMD_RETRANSMIT 0x40000000
  21. #define NCMD_SETUP              0x20000000
  22. #define NCMD_KILL               0x10000000              // kill game
  23. #define NCMD_CHECKSUM   0x0fffffff
  24.  
  25.  
  26. doomcom_t               *doomcom;
  27. doomdata_t              *netbuffer;             // points inside doomcom
  28.  
  29.  
  30. /*
  31. ==============================================================================
  32.  
  33.                             NETWORKING
  34.  
  35. gametic is the tic about to (or currently being) run
  36. maketic is the tick that hasn't had control made for it yet
  37. nettics[] has the maketics for all players
  38.  
  39. a gametic cannot be run until nettics[] > gametic for all players
  40.  
  41. ==============================================================================
  42. */
  43.  
  44. #define RESENDCOUNT     10
  45. #define PL_DRONE        0x80                            // bit flag in doomdata->player
  46.  
  47. ticcmd_t                localcmds[BACKUPTICS];
  48.  
  49. ticcmd_t        netcmds[MAXPLAYERS][BACKUPTICS];
  50. int             nettics[MAXNETNODES];
  51. boolean                 nodeingame[MAXNETNODES];        // set false as nodes leave game
  52. boolean                 remoteresend[MAXNETNODES];      // set when local needs tics
  53. int                             resendto[MAXNETNODES];                  // set when remote needs tics
  54. int                             resendcount[MAXNETNODES];
  55.  
  56. int                             nodeforplayer[MAXPLAYERS];
  57.  
  58. int             maketic;
  59. int                             lastnettic, skiptics;
  60. int                             ticdup;
  61. int                             maxsend;        // BACKUPTICS/(2*ticdup)-1
  62.  
  63. void H2_ProcessEvents (void);
  64. void G_BuildTiccmd (ticcmd_t *cmd);
  65. void H2_DoAdvanceDemo (void);
  66. extern void ST_NetProgress(void);
  67. extern void ST_NetDone(void);
  68.  
  69. boolean                 reboundpacket;
  70. doomdata_t              reboundstore;
  71.  
  72.  
  73. int     NetbufferSize (void)
  74. {
  75.     return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
  76. }
  77.  
  78. unsigned NetbufferChecksum (void)
  79. {
  80.     unsigned                c;
  81.     int             i,l;
  82.  
  83.     c = 0x1234567;
  84.  
  85. #if defined(NeXT) || defined(NORMALUNIX)
  86.     return 0;                       // byte order problems
  87. #endif
  88.  
  89.     l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
  90.     for (i=0 ; i<l ; i++)
  91.         c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
  92.  
  93.     return c & NCMD_CHECKSUM;
  94. }
  95.  
  96. int ExpandTics (int low)
  97. {
  98.     int     delta;
  99.  
  100.     delta = low - (maketic&0xff);
  101.  
  102.     if (delta >= -64 && delta <= 64)
  103.         return (maketic&~0xff) + low;
  104.     if (delta > 64)
  105.         return (maketic&~0xff) - 256 + low;
  106.     if (delta < -64)
  107.         return (maketic&~0xff) + 256 + low;
  108.  
  109.     I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
  110.     return 0;
  111. }
  112.  
  113.  
  114. //============================================================================
  115.  
  116.  
  117. /*
  118. ==============
  119. =
  120. = HSendPacket
  121. =
  122. ==============
  123. */
  124.  
  125. void HSendPacket (int node, int flags)
  126. {
  127.     netbuffer->checksum = NetbufferChecksum () | flags;
  128.  
  129.     if (!node)
  130.     {
  131.         reboundstore = *netbuffer;
  132.         reboundpacket = true;
  133.         return;
  134.     }
  135.  
  136.     if (demoplayback)
  137.         return;
  138.  
  139.     if (!netgame)
  140.         I_Error ("Tried to transmit to another node");
  141.  
  142.     doomcom->command = CMD_SEND;
  143.     doomcom->remotenode = node;
  144.     doomcom->datalength = NetbufferSize ();
  145.  
  146. if (debugfile)
  147. {
  148.     int             i;
  149.     int             realretrans;
  150.     if (netbuffer->checksum & NCMD_RETRANSMIT)
  151.         realretrans = ExpandTics (netbuffer->retransmitfrom);
  152.     else
  153.         realretrans = -1;
  154.     fprintf (debugfile,"send (%i + %i, R %i) [%i] "
  155.     ,ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
  156.     for (i=0 ; i<doomcom->datalength ; i++)
  157.         fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
  158.     fprintf (debugfile,"\n");
  159. }
  160.  
  161.     I_NetCmd ();
  162. }
  163.  
  164. //==========================================================================
  165. //
  166. // NET_SendFrags
  167. //
  168. //==========================================================================
  169.  
  170. void NET_SendFrags(player_t *player)
  171. {
  172.     int i;
  173.     int frags;
  174.  
  175.     netbuffer->checksum = NetbufferChecksum();
  176.  
  177.     if (demoplayback)
  178.     {
  179.         return;
  180.     }
  181.     if (!netgame)
  182.     {
  183.         I_Error ("Tried to transmit to another node");
  184.     }
  185.  
  186.     frags = 0;
  187.     for(i = 0; i < MAXPLAYERS; i++)
  188.     {
  189.         frags += player->frags[i];
  190.     }
  191.     doomcom->command = CMD_FRAG;
  192.     doomcom->remotenode = frags;
  193.     doomcom->datalength = NetbufferSize ();
  194.  
  195.     I_NetCmd ();
  196. }
  197.  
  198. /*
  199. ==============
  200. =
  201. = HGetPacket
  202. =
  203. = Returns false if no packet is waiting
  204. =
  205. ==============
  206. */
  207.  
  208. boolean HGetPacket (void)
  209. {
  210.     if (reboundpacket)
  211.     {
  212.         *netbuffer = reboundstore;
  213.         doomcom->remotenode = 0;
  214.         reboundpacket = false;
  215.         return true;
  216.     }
  217.  
  218.     if (!netgame)
  219.         return false;
  220.     if (demoplayback)
  221.         return false;
  222.  
  223.     doomcom->command = CMD_GET;
  224.     I_NetCmd ();
  225.     if (doomcom->remotenode == -1)
  226.         return false;
  227.  
  228.     if (doomcom->datalength != NetbufferSize ())
  229.     {
  230.         if (debugfile)
  231.             fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
  232.         return false;
  233.     }
  234.  
  235.     if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
  236.     {
  237.         if (debugfile)
  238.             fprintf (debugfile,"bad packet checksum\n");
  239.         return false;
  240.     }
  241.  
  242. if (debugfile)
  243. {
  244.     int             realretrans;
  245.             int     i;
  246.  
  247.     if (netbuffer->checksum & NCMD_SETUP)
  248.         fprintf (debugfile,"setup packet\n");
  249.     else
  250.     {
  251.         if (netbuffer->checksum & NCMD_RETRANSMIT)
  252.             realretrans = ExpandTics (netbuffer->retransmitfrom);
  253.         else
  254.             realretrans = -1;
  255.         fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",doomcom->remotenode,
  256.         ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
  257.         for (i=0 ; i<doomcom->datalength ; i++)
  258.             fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
  259.         fprintf (debugfile,"\n");
  260.     }
  261. }
  262.     return true;
  263. }
  264.  
  265.  
  266. /*
  267. ===================
  268. =
  269. = GetPackets
  270. =
  271. ===================
  272. */
  273.  
  274. char    exitmsg[80];
  275.  
  276. void GetPackets (void)
  277. {
  278.     int             netconsole;
  279.     int             netnode;
  280.     ticcmd_t        *src, *dest;
  281.     int             realend;
  282.     int             realstart;
  283.  
  284.     while (HGetPacket ())
  285.     {
  286.         if (netbuffer->checksum & NCMD_SETUP)
  287.             continue;               // extra setup packet
  288.  
  289.         netconsole = netbuffer->player & ~PL_DRONE;
  290.         netnode = doomcom->remotenode;
  291.         //
  292.         // to save bytes, only the low byte of tic numbers are sent
  293.         // Figure out what the rest of the bytes are
  294.         //
  295.         realstart = ExpandTics (netbuffer->starttic);
  296.         realend = (realstart+netbuffer->numtics);
  297.  
  298.         //
  299.         // check for exiting the game
  300.         //
  301.         if (netbuffer->checksum & NCMD_EXIT)
  302.         {
  303.             if (!nodeingame[netnode])
  304.                 continue;
  305.             nodeingame[netnode] = false;
  306.             playeringame[netconsole] = false;
  307.             strcpy (exitmsg, "PLAYER 1 LEFT THE GAME");
  308.             exitmsg[7] += netconsole;
  309.             P_SetMessage(&players[consoleplayer], exitmsg, true);
  310.             S_StartSound(NULL, SFX_CHAT);
  311. //            players[consoleplayer].message = exitmsg;
  312. //                      if (demorecording)
  313. //                              G_CheckDemoStatus ();
  314.             continue;
  315.         }
  316.  
  317.         //
  318.         // check for a remote game kill
  319.         //
  320.         if (netbuffer->checksum & NCMD_KILL)
  321.             I_Error ("Killed by network driver");
  322.  
  323.         nodeforplayer[netconsole] = netnode;
  324.  
  325.         //
  326.         // check for retransmit request
  327.         //
  328.         if ( resendcount[netnode] <= 0
  329.         && (netbuffer->checksum & NCMD_RETRANSMIT) )
  330.         {
  331.             resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
  332. if (debugfile)
  333. fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
  334.             resendcount[netnode] = RESENDCOUNT;
  335.         }
  336.         else
  337.             resendcount[netnode]--;
  338.  
  339.         //
  340.         // check for out of order / duplicated packet
  341.         //
  342.         if (realend == nettics[netnode])
  343.             continue;
  344.  
  345.         if (realend < nettics[netnode])
  346.         {
  347. if (debugfile)
  348. fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
  349.             continue;
  350.         }
  351.  
  352.         //
  353.         // check for a missed packet
  354.         //
  355.         if (realstart > nettics[netnode])
  356.         {
  357.         // stop processing until the other system resends the missed tics
  358. if (debugfile)
  359. fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, realstart, nettics[netnode]);
  360.             remoteresend[netnode] = true;
  361.             continue;
  362.         }
  363.  
  364. //
  365. // update command store from the packet
  366. //
  367. {
  368.     int             start;
  369.  
  370.         remoteresend[netnode] = false;
  371.  
  372.         start = nettics[netnode] - realstart;
  373.         src = &netbuffer->cmds[start];
  374.  
  375.         while (nettics[netnode] < realend)
  376.         {
  377.             dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
  378.             nettics[netnode]++;
  379.             *dest = *src;
  380.             src++;
  381.         }
  382.     }
  383. }
  384.  
  385. }
  386.  
  387. /*
  388. =============
  389. =
  390. = NetUpdate
  391. =
  392. = Builds ticcmds for console player
  393. = sends out a packet
  394. =============
  395. */
  396.  
  397. int      gametime;
  398.  
  399. void NetUpdate (void)
  400. {
  401.     int             nowtime;
  402.     int             newtics;
  403.     int                             i,j;
  404.     int                             realstart;
  405.     int                             gameticdiv;
  406.  
  407. //
  408. // check time
  409. //
  410.     nowtime = I_GetTime ()/ticdup;
  411.     newtics = nowtime - gametime;
  412.     gametime = nowtime;
  413.  
  414.     if (newtics <= 0)                       // nothing new to update
  415.         goto listen;
  416.  
  417.     if (skiptics <= newtics)
  418.     {
  419.         newtics -= skiptics;
  420.         skiptics = 0;
  421.     }
  422.     else
  423.     {
  424.         skiptics -= newtics;
  425.         newtics = 0;
  426.     }
  427.  
  428.  
  429.     netbuffer->player = consoleplayer;
  430.  
  431. //
  432. // build new ticcmds for console player
  433. //
  434.     gameticdiv = gametic/ticdup;
  435.     for (i=0 ; i<newtics ; i++)
  436.     {
  437.         I_StartTic ();
  438.         H2_ProcessEvents ();
  439.         if (maketic - gameticdiv >= BACKUPTICS/2-1)
  440.             break;          // can't hold any more
  441. //printf ("mk:%i ",maketic);
  442.         G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
  443.         maketic++;
  444.     }
  445.  
  446.  
  447.     if (singletics)
  448.         return;         // singletic update is syncronous
  449.  
  450. //
  451. // send the packet to the other nodes
  452. //
  453.     for (i=0 ; i<doomcom->numnodes ; i++)
  454.         if (nodeingame[i])
  455.         {
  456.             netbuffer->starttic = realstart = resendto[i];
  457.             netbuffer->numtics = maketic - realstart;
  458.             if (netbuffer->numtics > BACKUPTICS)
  459.                 I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
  460.  
  461.             resendto[i] = maketic - doomcom->extratics;
  462.  
  463.             for (j=0 ; j< netbuffer->numtics ; j++)
  464.                 netbuffer->cmds[j] =
  465.                     localcmds[(realstart+j)%BACKUPTICS];
  466.  
  467.             if (remoteresend[i])
  468.             {
  469.                 netbuffer->retransmitfrom = nettics[i];
  470.                 HSendPacket (i, NCMD_RETRANSMIT);
  471.             }
  472.             else
  473.             {
  474.                 netbuffer->retransmitfrom = 0;
  475.                 HSendPacket (i, 0);
  476.             }
  477.         }
  478.  
  479. //
  480. // listen for other packets
  481. //
  482. listen:
  483.  
  484.     GetPackets ();
  485. }
  486.  
  487.  
  488. /*
  489. =====================
  490. =
  491. = CheckAbort
  492. =
  493. =====================
  494. */
  495.  
  496. void CheckAbort (void)
  497. {
  498.     event_t *ev;
  499.     int             stoptic;
  500.  
  501.     stoptic = I_GetTime () + 2;
  502.     while (I_GetTime() < stoptic)
  503.         I_StartTic ();
  504.  
  505.     I_StartTic ();
  506.     for ( ; eventtail != eventhead
  507.     ; eventtail = (++eventtail)&(MAXEVENTS-1) )
  508.     {
  509.         ev = &events[eventtail];
  510.         if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
  511.             I_Error ("Network game synchronization aborted.");
  512.     }
  513. }
  514.  
  515. /*
  516. =====================
  517. =
  518. = D_ArbitrateNetStart
  519. =
  520. =====================
  521. */
  522.  
  523. void D_ArbitrateNetStart (void)
  524. {
  525.     int             i;
  526.     boolean gotinfo[MAXNETNODES];
  527.     boolean gotClass[MAXNETNODES];
  528. #ifdef __WATCOMC__
  529.     int nextTic;
  530.     extern volatile int ticcount;
  531.  
  532.     nextTic = ticcount+8;
  533. #endif
  534.  
  535.     autostart = true;
  536.  
  537.     memset (gotClass,0,sizeof(gotClass));
  538.     memset (gotinfo,0,sizeof(gotinfo));
  539.     gotClass[doomcom->consoleplayer] = true;
  540.     do
  541.     {
  542.         i = 0;
  543.  
  544.         CheckAbort();
  545.         while(HGetPacket())
  546.         { // Check for any incoming packets
  547.             if(netbuffer->checksum&NCMD_SETUP && netbuffer->starttic >= 64)
  548.             {
  549.                 
  550.                 PlayerClass[netbuffer->player] = netbuffer->starttic&0x3f;
  551.                 if(!gotClass[netbuffer->player])
  552.                 {
  553.                     gotClass[netbuffer->player] = true;
  554.                     ST_NetProgress();
  555.                     ST_Message("\n");
  556.                 }
  557.                 if(netbuffer->retransmitfrom)
  558.                 { // that node has received info from all other nodes
  559.                     gotinfo[netbuffer->player] = true;
  560.                 }
  561.             }
  562.         }
  563. #ifdef __WATCOMC__
  564.         if(ticcount <= nextTic)
  565.         { // only send packets every half second
  566.             continue;
  567.         }
  568.         nextTic = ticcount+8;
  569. #endif
  570.         // Keep sending out packets containing the console class
  571.         for(i = 0; i < doomcom->numnodes; i++)
  572.         {
  573.             netbuffer->player = doomcom->consoleplayer;
  574.             netbuffer->starttic = PlayerClass[doomcom->consoleplayer]+64;
  575.             netbuffer->retransmitfrom = gotinfo[doomcom->consoleplayer];
  576.             netbuffer->numtics = 0;
  577.             HSendPacket(i, NCMD_SETUP);
  578.         }
  579.         for(i = 0; i < doomcom->numnodes; i++)
  580.         { // Make sure that all nodes have sent class info
  581.             if (!gotClass[i])
  582.             {
  583.                 ST_Message(".");
  584.                 break;
  585.             }
  586.         }
  587.         if(i < doomcom->numnodes)
  588.         {
  589.             continue;
  590.         }
  591.         else
  592.         { // consoleplayer has received all player classes
  593.             if(gotinfo[doomcom->consoleplayer])
  594.             {
  595.                 CheckAbort();
  596.             }
  597.             else
  598.             {
  599.                 gotinfo[doomcom->consoleplayer] = true;
  600.                 ST_Message("All player classes received, ready to proceed\n");
  601.                 ST_NetDone();
  602.             }
  603.         }
  604.         for (i = 0; i < doomcom->numnodes; i++)
  605.         { // Make sure that all nodes are ready to proceed
  606.             if (!gotinfo[i])
  607.             {
  608.                 break;
  609.             }
  610.         }
  611.     } while(i < doomcom->numnodes);
  612.  
  613.     memset (gotinfo,0,sizeof(gotinfo));
  614.  
  615.     if (doomcom->consoleplayer)
  616.     {       // listen for setup info from key player
  617. //              ST_Message ("listening for network start info...\n");
  618.         while (1)
  619.         {
  620.             CheckAbort ();
  621.             if (!HGetPacket ())
  622.                 continue;
  623.             if(netbuffer->checksum & NCMD_SETUP && netbuffer->starttic < 64)
  624.             {
  625.                 if (netbuffer->player != VERSION)
  626.                     I_Error ("Different HEXEN versions cannot play a net game!");
  627.                 startskill = netbuffer->retransmitfrom & 15;
  628.                 deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
  629.                 nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
  630.                 respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
  631.                 startmap = netbuffer->starttic & 0x3f;
  632.                 startepisode = 1;
  633.                 return;
  634.             }
  635.         }
  636.     }
  637.     else
  638.     {       // key player, send the setup info
  639. //              ST_Message ("sending network start info...\n");
  640.         do
  641.         {
  642.             CheckAbort ();
  643.             for (i=0 ; i<doomcom->numnodes ; i++)
  644.             {
  645.                 netbuffer->retransmitfrom = startskill;
  646.                 if (deathmatch)
  647.                     netbuffer->retransmitfrom |= (deathmatch<<6);
  648.                 if (nomonsters)
  649.                     netbuffer->retransmitfrom |= 0x20;
  650.                 if (respawnparm)
  651.                     netbuffer->retransmitfrom |= 0x10;
  652.                 netbuffer->starttic = startmap&0x3f;
  653.                 netbuffer->player = VERSION;
  654.                 netbuffer->numtics = 0;
  655.                 HSendPacket (i, NCMD_SETUP);
  656.             }
  657.  
  658. #if 1
  659.             for(i = 10 ; i  &&  HGetPacket(); --i)
  660.             {
  661.  if((netbuffer->player&0x7f) < MAXNETNODES)
  662.                 gotinfo[netbuffer->player&0x7f] = true;
  663.             }
  664. #else
  665.             while (HGetPacket ())
  666.             {
  667.                 gotinfo[netbuffer->player&0x7f] = true;
  668.             }
  669. #endif
  670.  
  671.             for (i=1 ; i<doomcom->numnodes ; i++)
  672.                 if (!gotinfo[i])
  673.                     break;
  674.         } while (i < doomcom->numnodes);
  675.     }
  676. }
  677.  
  678. /*
  679. ===================
  680. =
  681. = D_CheckNetGame
  682. =
  683. = Works out player numbers among the net participants
  684. ===================
  685. */
  686.  
  687. extern  int                     viewangleoffset;
  688.  
  689. void D_CheckNetGame (void)
  690. {
  691.     int             i;
  692.     int pClass;
  693.  
  694.     for (i=0 ; i<MAXNETNODES ; i++)
  695.     {
  696.         nodeingame[i] = false;
  697.         nettics[i] = 0;
  698.         remoteresend[i] = false;        // set when local needs tics
  699.         resendto[i] = 0;                        // which tic to start sending
  700.     }
  701.  
  702. // I_InitNetwork sets doomcom and netgame
  703.     I_InitNetwork ();
  704.     if (doomcom->id != DOOMCOM_ID)
  705.         I_Error ("Doomcom buffer invalid!");
  706.     netbuffer = &doomcom->data;
  707.     consoleplayer = displayplayer = doomcom->consoleplayer;
  708.     pClass = PCLASS_FIGHTER;
  709.     if(i = M_CheckParm("-class"))
  710.     {
  711.         pClass = atoi(myargv[i+1]);
  712.         if(pClass > PCLASS_MAGE || pClass < PCLASS_FIGHTER)
  713.         {
  714.             I_Error("Invalid player class: %d\n", pClass);
  715.         }
  716.         ST_Message("\nPlayer Class: %d\n", pClass);
  717.     }
  718.     PlayerClass[consoleplayer] = pClass;
  719.     if (netgame)
  720.         D_ArbitrateNetStart ();
  721. //ST_Message ("startskill %i  deathmatch: %i  startmap: %i  startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
  722.  
  723. // read values out of doomcom
  724.     ticdup = doomcom->ticdup;
  725.     maxsend = BACKUPTICS/(2*ticdup)-1;
  726.     if (maxsend<1)
  727.         maxsend = 1;
  728.  
  729.     for (i=0 ; i<doomcom->numplayers ; i++)
  730.         playeringame[i] = true;
  731.     for (i=0 ; i<doomcom->numnodes ; i++)
  732.         nodeingame[i] = true;
  733.  
  734. //ST_Message ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
  735.  
  736. }
  737.  
  738. /*
  739. ==================
  740. =
  741. = D_QuitNetGame
  742. =
  743. = Called before quitting to leave a net game without hanging the
  744. = other players
  745. =
  746. ==================
  747. */
  748.  
  749. void D_QuitNetGame (void)
  750. {
  751.     int             i, j;
  752.  
  753.     if (debugfile)
  754.         fclose (debugfile);
  755.  
  756.     if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
  757.         return;
  758.  
  759. // send a bunch of packets for security
  760.     netbuffer->player = consoleplayer;
  761.     netbuffer->numtics = 0;
  762.     for (i=0 ; i<4 ; i++)
  763.     {
  764.         for (j=1 ; j<doomcom->numnodes ; j++)
  765.             if (nodeingame[j])
  766.                 HSendPacket (j, NCMD_EXIT);
  767.         I_WaitVBL (1);
  768.     }
  769. }
  770.  
  771.  
  772.  
  773. /*
  774. ===============
  775. =
  776. = TryRunTics
  777. =
  778. ===============
  779. */
  780.  
  781. int     frametics[4], frameon;
  782. int     frameskip[4];
  783. int             oldnettics;
  784. extern  boolean advancedemo;
  785.  
  786. void TryRunTics (void)
  787. {
  788.     int             i;
  789.     int             lowtic;
  790.     int             entertic;
  791.     static int              oldentertics;
  792.     int                             realtics, availabletics;
  793.     int                             counts;
  794.     int                             numplaying;
  795.  
  796. //
  797. // get real tics
  798. //
  799.     entertic = I_GetTime ()/ticdup;
  800.     realtics = entertic - oldentertics;
  801.     oldentertics = entertic;
  802.  
  803. //
  804. // get available tics
  805. //
  806.     NetUpdate ();
  807.  
  808.     lowtic = MAXINT;
  809.     numplaying = 0;
  810.     for (i=0 ; i<doomcom->numnodes ; i++)
  811.         if (nodeingame[i])
  812.         {
  813.             numplaying++;
  814.             if (nettics[i] < lowtic)
  815.                 lowtic = nettics[i];
  816.         }
  817.     availabletics = lowtic - gametic/ticdup;
  818.  
  819.  
  820. //
  821. // decide how many tics to run
  822. //
  823.     if (realtics < availabletics-1)
  824.         counts = realtics+1;
  825.     else if (realtics < availabletics)
  826.         counts = realtics;
  827.     else
  828.         counts = availabletics;
  829.     if (counts < 1)
  830.         counts = 1;
  831.  
  832.     frameon++;
  833.  
  834. if (debugfile)
  835.     fprintf (debugfile,"=======real: %i  avail: %i  game: %i\n",realtics, availabletics,counts);
  836.  
  837.     if (!demoplayback)
  838.     {
  839.     //=============================================================================
  840.     //
  841.     //      ideally nettics[0] should be 1 - 3 tics above lowtic
  842.     //      if we are consistantly slower, speed up time
  843.     //
  844.         for (i=0 ; i<MAXPLAYERS ; i++)
  845.             if (playeringame[i])
  846.                 break;
  847.         if (consoleplayer == i)
  848.         {       // the key player does not adapt
  849.         }
  850.         else
  851.         {
  852.             if (nettics[0] <= nettics[nodeforplayer[i]])
  853.             {
  854.                 gametime--;
  855.     //                      printf ("-");
  856.             }
  857.             frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
  858.             oldnettics = nettics[0];
  859.             if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
  860.             {
  861.                 skiptics = 1;
  862.     //                      printf ("+");
  863.             }
  864.         }
  865.     //=============================================================================
  866.     }       // demoplayback
  867.  
  868.     //
  869.     // wait for new tics if needed
  870.     //
  871.         while (lowtic < gametic/ticdup + counts)
  872.         {
  873.  
  874.             NetUpdate ();
  875.             lowtic = MAXINT;
  876.  
  877.             for (i=0 ; i<doomcom->numnodes ; i++)
  878.                 if (nodeingame[i] && nettics[i] < lowtic)
  879.                     lowtic = nettics[i];
  880.  
  881.             if (lowtic < gametic/ticdup)
  882.                 I_Error ("TryRunTics: lowtic < gametic");
  883.  
  884.             // don't stay in here forever -- give the menu a chance to work
  885.             if (I_GetTime ()/ticdup - entertic >= 20)
  886.             {
  887.                 MN_Ticker ();
  888.                 return;
  889.             }
  890.         }
  891.  
  892. //
  893. // run the count * ticdup dics
  894. //
  895.     while (counts--)
  896.     {
  897.         for (i=0 ; i<ticdup ; i++)
  898.         {
  899.             if (gametic/ticdup > lowtic)
  900.                 I_Error ("gametic>lowtic");
  901.             if (advancedemo)
  902.                 H2_DoAdvanceDemo ();
  903.             MN_Ticker ();
  904.             G_Ticker ();
  905.             gametic++;
  906.             //
  907.             // modify command for duplicated tics
  908.             //
  909.             if (i != ticdup-1)
  910.             {
  911.                 ticcmd_t        *cmd;
  912.                 int                     buf;
  913.                 int                     j;
  914.  
  915.                 buf = (gametic/ticdup)%BACKUPTICS;
  916.                 for (j=0 ; j<MAXPLAYERS ; j++)
  917.                 {
  918.                     cmd = &netcmds[j][buf];
  919.                     cmd->chatchar = 0;
  920.                     if (cmd->buttons & BT_SPECIAL)
  921.                         cmd->buttons = 0;
  922.                 }
  923.             }
  924.         }
  925.         NetUpdate ();                                   // check for new console commands
  926.     }
  927. }
  928.