home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / ourcom.c < prev    next >
Text File  |  1998-06-08  |  18KB  |  840 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/main/rcs/ourcom.c $
  15.  * $Revision: 2.0 $
  16.  * $Author: john $
  17.  * $Date: 1995/02/27 11:27:36 $
  18.  * 
  19.  * Modem support code
  20.  * 
  21.  * $Log: ourcom.c $
  22.  * Revision 2.0  1995/02/27  11:27:36  john
  23.  * New version 2.0, which has no anonymous unions, builds with
  24.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  25.  * 
  26.  * Revision 1.1  1994/10/09  22:29:00  rob
  27.  * Initial revision
  28.  * 
  29.  * Revision 1.7  1994/09/27  15:05:54  rob
  30.  * Last checkin had error.
  31.  * 
  32.  * Revision 1.6  1994/09/27  15:03:12  rob
  33.  * Null modem basic routines working.  Sending DEAD messages and
  34.  * missiles still need to be done.
  35.  * 
  36.  * Revision 1.5  1994/09/24  16:52:20  rob
  37.  * Added stubbed funcs for startup and stop of serial games.
  38.  * 
  39.  * Revision 1.4  1994/09/24  15:10:21  rob
  40.  * Removed some compiler warnings.
  41.  * 
  42.  * Revision 1.3  1994/09/24  14:40:34  rob
  43.  * Sending shortpos structures.  9600 baud max.
  44.  * 
  45.  * Revision 1.2  1994/09/22  17:53:11  rob
  46.  * First revision.  Not functional yet.
  47.  * 
  48.  * Revision 1.1  1994/09/21  13:23:25  rob
  49.  * Initial revision
  50.  * 
  51.  * 
  52.  */
  53.  
  54.  
  55. #pragma off (unreferenced)
  56. static char rcsid[] = "$Id: ourcom.c 2.0 1995/02/27 11:27:36 john Exp $";
  57. #pragma on (unreferenced)
  58.  
  59. #include <stdio.h>
  60. #include <stdlib.h>
  61. #include <dos.h>
  62. #include <conio.h>
  63. #include <string.h>
  64. #include <time.h>
  65.  
  66. #include "game.h"
  67. #include "modem.h"
  68. #include "object.h"
  69. #include "player.h"
  70. #include "laser.h"
  71. #include "error.h"
  72. #include "network.h"
  73. #include "mono.h"
  74. #include "gauges.h"
  75. #include "newmenu.h"
  76. #include "gamesave.h"
  77. #include "netmisc.h"
  78. #include "dpmi.h"
  79. #include "commlib.h"
  80.  
  81. /*
  82.     Code to support modem/null-modem play
  83.  */
  84.  
  85. extern int Spreadfire_toggle;
  86.  
  87. static long com_port;
  88. long serial_active;
  89. long com_port_num;
  90. long com_speed;
  91. long sync_time;
  92. long com_open = 0;
  93. static long com_vect;
  94. static long com_type; /* What type of UART is available */
  95. static char syncbuffer[MAX_SER_MSG_LEN+1];
  96. static long synccnt;
  97. static long synclen;
  98. volatile char inbuf[SERIAL_BUFFER_SIZE];  // Serial input buffer
  99. volatile char outbuf[SERIAL_BUFFER_SIZE]; // Serial output buffer
  100. volatile long inbufplc, inbufend, outbufplc, outbufend;
  101. volatile char line_stat, modem_stat;
  102. volatile char modem_alert;
  103. long comi;  // counter used in ISR
  104. int Other_player; // Player num for modem opponent
  105.  
  106. long MyObjnum, OtherObjnum;
  107.  
  108. void (__interrupt __far *oldcomhandler)();
  109. void __interrupt __far comhandler(void);
  110.                                                                              
  111.  
  112. void reset_player_object(void); // In object.c but not in object.h
  113.  
  114. /* Function prototypes for functions not exported through modem.h */
  115.  
  116. void serial_param_setup(void);
  117. void serial_link_start(void);
  118. void modem_dialout(void);
  119. void modem_answer(void);
  120. long serial_get_sync_packet(void);
  121. void com_do_sync(int nitem, newmenu_item *menus, int *key, int citem);
  122.  
  123.     
  124. com_enable () // Detect and enable the COM port selected by the user
  125. {
  126.     // com_port_num and com_speed should be set before calling this func
  127.  
  128.     long divisor;
  129.     short *ptr;
  130.  
  131.     if (com_open)
  132.         return 0;
  133.  
  134.     /* Set the variables for the selected com port */
  135.     if ( (com_port_num < 1) || (com_port_num > 4) )
  136.         return -1;
  137.  
  138.     com_vect = 0xb+(com_port_num & 1); // Interrupt vector
  139.  
  140.     ptr = (short *) (0x400L+(long)((com_port_num-1)<<1));
  141.     com_port = (long)(*ptr); // COM I/O Port Addr
  142.     if (com_port == 0) return -1;
  143.  
  144.     /* Set the speed of the COM port UART, saving the old value */
  145.     if ( (com_speed <= 0) || (com_speed > 115200) )
  146.          return -1;
  147.     
  148.     // Enable the interrupts for the COM port 
  149.  
  150.     _disable();
  151.  
  152.     outp(com_port+3, 0x080); /* Enable access to the baud divider regs */
  153.     divisor = 115200/com_speed;
  154.     outp(com_port+0, divisor&255); /* Plug in our new baud rate */
  155.     outp(com_port+1, divisor>>8);
  156.     outp(com_port+3, 0x03);   /* 8,N,1, also turns off divisor access */
  157.  
  158.     // Check UART type, enable FIFO if 16550
  159.  
  160.     outp(com_port+2, 0x81);  /* Enable FIFO with trigger level of 8 */
  161.     if ((inp(com_port+2) & 0xf8) == 0xc0)
  162.     {
  163.         com_type = 16550;
  164.         mprintf(0,"16550 uart found.\n"); // debug
  165.     }    
  166.     else 
  167.     {
  168.         com_type = 16450;
  169.         mprintf(0,"16450 uart found.\n"); // debug
  170.     }
  171.     
  172.     /* register new com interrupt handler */
  173.  
  174.     oldcomhandler = _dos_getvect(com_vect);
  175.     _dos_setvect(com_vect, serial_isr);
  176.  
  177.     /* Enable UART generation of interrupts, but select none for now */
  178.     
  179.     outp(com_port+4, 0x0b);
  180.     outp(com_port+1, 0);       
  181.     
  182.     
  183.     /* Unmask vector in PIC */
  184.     outp(0x21, inp(0x21)&(255-(1 << (com_vect&7))));
  185.  
  186.     line_stat = inp(com_port+5);
  187.     modem_stat = inp(com_port+6);
  188.  
  189.     inp(com_port+0); /* eat any pending char */
  190.     inp(com_port+2); /* ignore any existing interrupts */
  191.     
  192.     /* Enable specific UART interrupts */
  193.     
  194.     outp(com_port+1, 0x03); /* RxRDY and TBE are enabled */
  195.  
  196.     atexit(com_disable);
  197.  
  198.     _enable();
  199.  
  200.     mprintf(0, "Com port opened.\n");
  201.     com_open = 1;
  202.  
  203.     return 0;
  204. }
  205.  
  206. void
  207. com_disable()
  208. {
  209.     if (!com_open) 
  210.         return;
  211.  
  212.     if ((inp(com_port+5)&0x20) > 0)
  213.     {
  214.         if (outbufplc != outbufend)
  215.         {
  216.             outp(com_port, outbuf[outbufplc]);
  217.             outbufplc = ((outbufplc+1)&(SERIAL_BUFFER_SIZE-1));
  218.         }
  219.     }
  220.         
  221.     while (outbufplc != outbufend) ; // wait for buffer to drain
  222.  
  223.     _disable();
  224.     outp(0x21,inp(0x21)|(1<<(com_vect&7)));          //Mask vector
  225.     outp(com_port+1,0);
  226.     outp(com_port+4,0);
  227.     _dos_setvect(com_vect, oldcomhandler);
  228.     _enable();
  229.     mprintf(0, "Com port released.");
  230.     com_open = 0;
  231. }
  232.  
  233. com_reset_buffers(void)
  234. {
  235.     inbufend = inbufplc = 0;
  236. }
  237.  
  238.  
  239. com_send(long dat, long numbytes)
  240. {
  241.     long i;
  242.  
  243.     i = 0;
  244.     while (numbytes > 0)
  245.     {
  246.         outbuf[outbufend] = (char)((dat>>i)&255);
  247.         outbufend = ((outbufend+1)&(SERIAL_BUFFER_SIZE-1));
  248.  
  249.         numbytes--;
  250.         i += 8;
  251.     }
  252.  
  253.     if ((inp(com_port+5)&0x20) > 0)
  254.     {
  255.         if (outbufplc != outbufend)
  256.         {
  257.             outp(com_port,outbuf[outbufplc]);
  258.             outbufplc = ((outbufplc+1)&(SERIAL_BUFFER_SIZE-1));
  259.         }
  260.     }
  261.     return ;
  262. }
  263.  
  264. com_send_ptr(char *ptr, long len)
  265. {
  266.     long i = 0;
  267.  
  268.     while (i < len)
  269.     {
  270.         outbuf[outbufend] = (char)ptr[i];
  271.         outbufend = ((outbufend+1)&(SERIAL_BUFFER_SIZE-1));
  272.         if (outbufend == outbufplc)
  273.             mprintf(0, "possible buffer wraparound\n");
  274.         i++;
  275.     }
  276.  
  277.     if ((inp(com_port+5)&0x20) > 0)
  278.     {
  279.         if (outbufplc != outbufend)
  280.         {
  281.             outp(com_port, outbuf[outbufplc]);
  282.             outbufplc = ((outbufplc+1)&(SERIAL_BUFFER_SIZE-1));
  283.         }
  284.     }
  285.     return ;
  286. }
  287.  
  288.         
  289.                   
  290. com_send_string(char *string, int len)
  291. {
  292.     long i;
  293.  
  294.     i = 0;
  295.     while (i < len)
  296.     {
  297.         outbuf[outbufend] = string[i];
  298.         outbufend = ((outbufend+1)&(SERIAL_BUFFER_SIZE-1));
  299.         i++;
  300.     }
  301.     if ((inp(com_port+5)&0x20) > 0)
  302.     {
  303.         if (outbufplc != outbufend)
  304.         {
  305.             outp(com_port,outbuf[outbufplc]);
  306.             outbufplc = ((outbufplc+1)&(SERIAL_BUFFER_SIZE-1));
  307.         }
  308.     }
  309.     return ;
  310. }
  311.  
  312. comgetchar()
  313. {
  314.     short i;
  315.  
  316.     i = -1;
  317.     if (inbufplc != inbufend)
  318.     {
  319.         i = (short)inbuf[inbufplc];
  320.         inbufplc = ((inbufplc+1)&(SERIAL_BUFFER_SIZE-1));
  321.     }
  322.     return(i);
  323. }
  324.  
  325. comgetchar_timed(long count)
  326. {
  327.     short i;
  328.  
  329.     i = -1;
  330.  
  331.     Assert(count > -1);
  332.  
  333.     while ((inbufplc == inbufend) && count--) ;
  334.  
  335.     if (inbufplc != inbufend)
  336.     {
  337.         i = (short)inbuf[inbufplc];
  338.         inbufplc = ((inbufplc+1)&(SERIAL_BUFFER_SIZE-1));
  339.     }
  340.     return(i);
  341. }
  342.  
  343. comwaitfor(char string[81]) // Wait for reply on serial (smartmodem control)
  344. {
  345.     short dat;
  346.     long i;
  347.  
  348.     i = 0;
  349.     while ((string[i] != 0) && (kbhit() == 0))
  350.     {
  351.         if ((dat = comgetchar()) >= 0)
  352.         {
  353.             printf("%c",dat);
  354.             if (((char)dat) == string[i])
  355.                 i++;
  356.         }
  357.     }
  358.     return(0);
  359. }
  360.  
  361. void __interrupt __far serial_isr(void)
  362. {
  363.     while (1)
  364.     {
  365.         switch(inp(com_port+2)&7)
  366.         {
  367.             case 4: // receive empty
  368.              do
  369.              {
  370.                  inbuf[inbufend] = inp(com_port);
  371.                  inbufend = ((inbufend+1)&(SERIAL_BUFFER_SIZE-1));
  372.              } while (com_type==16550 && (inp(com_port+5)&1));
  373.              break;
  374.             case 2: /* X-mit buffer empty */
  375.              if (outbufplc != outbufend)
  376.              {
  377.                  if (com_type == 16550)
  378.                      comi = 16;
  379.                  else
  380.                      comi = 1;
  381.                  do
  382.                 {
  383.                      outp(com_port,outbuf[outbufplc]);
  384.                      outbufplc = ((outbufplc+1)&(SERIAL_BUFFER_SIZE-1));
  385.                 } while ((--comi) && (outbufplc != outbufend));
  386.              }
  387.              break;
  388.             case 6:
  389.              line_stat = inp(com_port+5);
  390.              modem_alert = 1;
  391.              break;
  392.             case 0: /* RS-232 status change */
  393.              modem_stat = inp(com_port+6); 
  394.              modem_alert = 1;
  395.              break;
  396.             default:
  397.              outp(0x20, 0x20); // Clear interrupt
  398.              return;
  399.         }            
  400.     }
  401. }
  402.  
  403. com_get_fire(void)
  404. {
  405.     ushort check;
  406.  
  407.     mprintf(0, "Entered com_get_fire.\n");
  408.  
  409.     // Check checksum
  410.     check = netmisc_calc_checksum(syncbuffer, 5);
  411.     if (check != *(ushort *)(syncbuffer+5))
  412.     {
  413.         // Checksum failure
  414.         synccnt = 0;
  415.         mprintf(0, "Bad checksum on fire.\n");
  416.         return;
  417.     }
  418.  
  419.     // Act out the actual shooting
  420.     
  421.     do_laser_firing(OtherObjnum, (int)syncbuffer[2], (int)syncbuffer[3], (int)syncbuffer[4]);
  422. }
  423.  
  424. void
  425. com_get_ppos(void)
  426. {        
  427.     ushort check;
  428.  
  429.     // Check checksum
  430.     check = netmisc_calc_checksum(syncbuffer, 18);
  431.     if (check != *(ushort *)(syncbuffer+18))
  432.     {
  433.         // Checksum failure
  434.         synccnt = 0;
  435.         mprintf(0, "Bad checksum on ppos.\n");
  436.         return;
  437.     }
  438.     
  439.     extract_shortpos(Objects+OtherObjnum, (shortpos *)(syncbuffer+1));
  440.     obj_relink(OtherObjnum, Objects[OtherObjnum].segnum);
  441. }
  442.  
  443. void
  444. com_process_input(void)
  445. {
  446.     // Read all complete messages from the serial buffer and process
  447.     // the contents.
  448.  
  449.     short dat;
  450.     char temp_char;
  451.  
  452.     while ( (dat = comgetchar()) >= 0) // Returns -1 when serial pipe empty
  453.     {
  454.         syncbuffer[synccnt++] = dat;
  455.         if (synccnt == 1)
  456.         {
  457.             switch(dat)
  458.             {
  459.                 case SER_PPOS: synclen = 20; break;
  460.                 case SER_FIRE: synclen = 7;  break;
  461.                 case SER_MESS: synclen = MAX_MESSAGE_LEN+1; break;
  462.                 case SER_KILL: synclen = 2;  break;
  463.                 case SER_QUIT: synclen = 1;  break; 
  464.                 default: mprintf(0,"%c", dat);
  465.                     synccnt = 0;
  466.                     synclen = 1;
  467.                     break;
  468.             }
  469.         }
  470.         if (synccnt == synclen)
  471.         {
  472.             switch(syncbuffer[0])
  473.             {
  474.                 case SER_PPOS: // Player position
  475.                     com_get_ppos();
  476.                     break;
  477.                 case SER_FIRE:
  478.                     com_get_fire();
  479.                     break;
  480.                 case SER_MESS:  // Message sending
  481.                     HUD_init_message("%s says '%s'", Players[temp_char].callsign,
  482.                         (char *)syncbuffer+2);                    
  483.                     break;
  484.                 case SER_KILL:  // 'I got killed' message
  485.                     temp_char= (char)syncbuffer[2];     // who killed him
  486.                     if (temp_char != Player_num) 
  487.                     {  // Not suicide
  488.                         Players[temp_char].net_kills_total++;
  489.                         Players[temp_char].net_kills_level++;
  490.                         HUD_init_message("%s killed %s!",
  491.                             (temp_char == Player_num) ? "you" : Players[temp_char].callsign,
  492.                             Players[temp_char].callsign);
  493.                     }
  494.                     else
  495.                     {
  496.                         HUD_init_message("%s comitted suicide!", Players[temp_char].callsign);
  497.                     }
  498.                     break;
  499.                 case SER_QUIT: // Other player has left the game!
  500.                     temp_char = (char)syncbuffer[1];     // size 1, player id
  501.                     // More is needed here
  502.                     HUD_init_message("%s has left the game!", Players[temp_char].callsign);
  503.                     break;
  504.  
  505.             }
  506.             synccnt = 0;
  507.         }
  508.     }
  509.  
  510.     com_send_status();
  511.     return ;
  512. }
  513.  
  514.  
  515. com_send_fire(void)
  516. {
  517.     static char buf[20];
  518.  
  519.     buf[0] = (char)SER_FIRE;
  520.     buf[1] = (char)Network_laser_fired;
  521.     buf[2] = (char)Network_laser_gun;
  522.     buf[3] = (char)Network_laser_level;
  523.     buf[4] = (char)Network_laser_flags;
  524.     *(ushort *)(buf+5) = netmisc_calc_checksum(buf, 5);
  525.     com_send_ptr(buf, 7);
  526. }
  527.  
  528. com_send_mypos(void)
  529. {
  530.     char buf[20];
  531.  
  532.     buf[0] = (char)SER_PPOS;
  533.     create_shortpos((shortpos *)(buf+1), Objects+MyObjnum); // size 17
  534.     *(short *)(buf+18)=netmisc_calc_checksum(buf, 18);
  535.     com_send_ptr(buf, 20);
  536. }
  537.  
  538. com_send_status(void)
  539. {
  540.  
  541.  
  542.     static fix last_comm_time = 0;
  543.  
  544.     last_comm_time += FrameTime;
  545.  
  546.     if ((last_comm_time < MIN_COMM_GAP) && !Network_laser_fired)
  547.          return;
  548.  
  549.     last_comm_time = 0;
  550.  
  551.     // Send the data for my current position through the serial 
  552.  
  553.     com_send_mypos();
  554.  
  555.     // If we fired this frame, send FIRE messages
  556.     
  557.     if (Network_laser_fired)
  558.     {
  559.         com_send_fire();
  560.         Network_laser_fired = 0;
  561.     }
  562.  
  563.  
  564.     // Send network messages, if any were sent this frame
  565.  
  566.     if (Network_message_reciever != -1) 
  567.     {
  568.         Network_message_reciever = -1;
  569.         com_send((long)SER_MESS, 1);
  570.         com_send((long)Player_num, 1);
  571.         com_send_string(Network_message, MAX_MESSAGE_LEN);
  572.     }
  573.  
  574.     // No other message types are sent here.  SER_KILL messages are sent
  575.     // at time of 'termination'.  SER_QUIT messages are sent when leaving.    
  576.  
  577.     return;
  578. }
  579.  
  580.  
  581. // Stubs for future functions
  582.  
  583. void
  584. modem_stop_serial(void)
  585. {
  586.     
  587. }
  588.  
  589. void
  590. modem_stop_modem(void)
  591. {
  592.  
  593. }
  594.  
  595. #define ADD_ITEM(t,value,key)  do { m[num_options].type=NM_TYPE_MENU; m[num_options].text=t; menu_choice[num_options]=value;num_options++; } while (0)
  596.  
  597. #define MENU_SERIAL_SETUP             0
  598. #define MENU_SERIAL_LINK_START     1
  599. #define MENU_MODEM_CALL                2
  600. #define MENU_MODEM_ANSWER            3
  601. #define MENU_RETURN_TO_MAIN         4
  602.  
  603. #define SER_SYNC_LEN 35
  604.  
  605. void
  606. modem_start_game(void)
  607. {
  608.     newmenu_item m[10];
  609.     int menu_choice[10];
  610.     int num_options = 0;
  611.     int choice;
  612.  
  613.  
  614.     ADD_ITEM("Setup serial parameters...", MENU_SERIAL_SETUP, -1);
  615.     ADD_ITEM("Start serial game...", MENU_SERIAL_LINK_START, -1);
  616.     ADD_ITEM("Dial remote modem...", MENU_MODEM_CALL, -1);
  617.     ADD_ITEM("Answer modem call...", MENU_MODEM_ANSWER, -1);
  618.  
  619.     ADD_ITEM("Return to game...", MENU_RETURN_TO_MAIN, -1);
  620.  
  621.     choice = newmenu_do("SERIAL OPTIONS", NULL, num_options, m, NULL);
  622.  
  623.     if (choice > -1) 
  624.     {
  625.         switch (choice)
  626.         {
  627.             case MENU_SERIAL_SETUP:
  628.                  serial_param_setup();
  629.                 break;
  630.             case MENU_SERIAL_LINK_START:
  631.                 serial_link_start();
  632.                 break;
  633.             case MENU_MODEM_CALL:
  634.                 modem_dialout();
  635.                 break;
  636.             case MENU_MODEM_ANSWER:
  637.                 modem_answer();
  638.                 break;
  639.             default: 
  640.                 return;
  641.         }
  642.     }
  643. }
  644.  
  645. void serial_param_setup(void)
  646. {
  647.  
  648. }
  649.  
  650. // Handshaking to start a serial game, 2 players only
  651.  
  652. void com_do_sync(int nitems, newmenu_item *menus, int *key, int citem)
  653. {
  654.  
  655.     int result;    
  656.  
  657.     menus = menus;
  658.     nitems = nitems;
  659.     citem = citem;
  660.     
  661.     serial_send_my_sync_packet();
  662.         
  663.     result = serial_get_sync_packet();
  664.  
  665.     if (result == -1)
  666.         return;
  667.  
  668.     *key = -2;
  669.  
  670.     mprintf(0, "Got sync packet.\n");
  671.  
  672.     serial_send_my_sync_packet();  // One last time for good measure
  673.  
  674.     com_reset_buffers();
  675.  
  676.     Game_mode |= GM_SERIAL;
  677.  
  678. }
  679.  
  680. void serial_link_start(void)
  681. {
  682.     int i, j;
  683.     int choice;
  684.     newmenu_item m[2];
  685.  
  686.     if (!serial_active) return;
  687.  
  688.     sync_time = (long)time(0);
  689.  
  690.     com_enable(); // Open COM port as configured
  691.  
  692.     N_players = 2;
  693.  
  694.     m[0].type=NM_TYPE_MENU;
  695.     m[0].text="Cancel";
  696.     choice = newmenu_do("WAIT", "Waiting for opponent...", 1, m, com_do_sync);
  697.     if (choice !=-2) {
  698.         Game_mode = GM_NORMAL;
  699.         N_players = 0;
  700.         return;
  701.     }
  702.  
  703.     Assert(Game_mode & GM_SERIAL);
  704.  
  705.     // Setup the serial game
  706.  
  707.     load_game(Gamesave_current_filename);
  708.  
  709.     network_delete_extra_objects(); // Removes monsters from level
  710.     
  711.     j = 0;
  712.     for (i = 0; i < 2; i++)
  713.     {
  714.         while (Objects[j].type != OBJ_PLAYER)
  715.         {
  716.             j++;
  717.             Assert( j < MAX_OBJECTS);
  718.         }
  719.         Players[i].objnum = j;
  720.         mprintf(0,"Player %d is object %d.\n", i, j);
  721.         j++;
  722.     }
  723.         
  724.     MyObjnum = Players[Player_num].objnum;
  725.     OtherObjnum = Players[Other_player].objnum;
  726.  
  727.     mprintf(0, "I am object number %d.\n", MyObjnum);
  728.     mprintf(0, "Other guy is obj   %d.\n", OtherObjnum);
  729.     mprintf(0, "Other Player num   %d.\n", Other_player);
  730.  
  731.     init_player_stats_game();
  732.  
  733.     gameseq_remove_unused_players();
  734.  
  735.     Viewer = ConsoleObject = &Objects[MyObjnum];
  736.  
  737.     ConsoleObject->control_type = CT_FLYING;
  738.  
  739.     reset_player_object();
  740.  
  741.     Objects[OtherObjnum].control_type = CT_NONE;
  742.     Objects[OtherObjnum].movement_type = MT_PHYSICS;
  743.  
  744. }
  745.  
  746.  
  747. void
  748. serial_send_my_sync_packet(void)
  749. {
  750.     char buf[SER_SYNC_LEN];
  751.  
  752.     // Build my sync packet
  753.  
  754.     buf[0] = (char)SER_SYNC;
  755.     *(long *)(buf+1) = (long)sync_time;
  756.     strcpy(buf+5, network_get_callsign());
  757.     strcpy(buf+17, Gamesave_current_filename); // 16 bytes
  758.     // add a checksum, 16-bit CRC
  759.     *(ushort *)(buf+33) = netmisc_calc_checksum(buf, 33);
  760.     com_send_ptr(buf, SER_SYNC_LEN);
  761. }
  762.  
  763. long
  764. serial_get_sync_packet(void)
  765. {
  766.     char syncbuf[80];
  767.     static long loc_synccnt = 0;
  768.     long other_sync_time;
  769.     ushort checksum;
  770.     short dat;
  771.     
  772.      while ( (dat = comgetchar_timed(1000000L)) >= 0) // returns -1 when timed out
  773.      {
  774.          syncbuf[loc_synccnt++] = dat;
  775.          if (loc_synccnt == 1) 
  776.          {
  777.              if (dat != SER_SYNC)
  778.              {
  779.                  loc_synccnt = 0;
  780.                      
  781.              }
  782.          }
  783.          if (loc_synccnt == SER_SYNC_LEN)
  784.          {
  785.             // Check the checksum before we act on this packet
  786.             checksum = netmisc_calc_checksum(syncbuf, 33);
  787.             if (checksum != *(ushort *)(syncbuf+33))
  788.             {
  789.                 // Checksum error
  790.                 mprintf(0, "Checksum failure on SYNC.  %d!=%d.\n",
  791.                     checksum, *(ushort *)(syncbuf+33));
  792.  
  793.                 loc_synccnt = 0;
  794.                 continue;
  795.             }
  796.  
  797.             other_sync_time = *(long *)(syncbuf+1);
  798.             if (other_sync_time > sync_time) 
  799.             {
  800.                 // I am the master
  801.                 Player_num = 0;
  802.                 Other_player = 1;
  803.             }
  804.             else if (other_sync_time < sync_time)
  805.             {                                                                                       
  806.                 // I am the slave
  807.                 Player_num = 1;
  808.                 Other_player = 0;
  809.                 strcpy(Gamesave_current_filename, (char *)syncbuf+17);
  810.             }
  811.             else 
  812.             {
  813.                 // Time times were equal!
  814.                 sync_time = (long)time(0);
  815.                 loc_synccnt = 0;
  816.                 return -1;
  817.             }
  818.             
  819.             // Fill in opponent's Player structure
  820.             strcpy(Players[Other_player].callsign, (char *)syncbuf+5);
  821.             mprintf(0, "Opponent is named %s.\n", Players[Other_player].callsign);
  822.  
  823.             return (0);            
  824.         }
  825.     }
  826.     return (-1);
  827. }
  828.  
  829. void modem_dialout(void)
  830. {
  831.  
  832. }
  833.  
  834. void modem_answer(void)
  835. {
  836.  
  837. }
  838.  
  839. 
  840.