Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.  * OpenTyrian: A modern cross-platform port of Tyrian
  3.  * Copyright (C) 2007-2009  The OpenTyrian Development Team
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version 2
  8.  * of the License, or (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  18.  */
  19. #include "network.h"
  20.  
  21. #include "episodes.h"
  22. #include "fonthand.h"
  23. #include "helptext.h"
  24. #include "joystick.h"
  25. #include "keyboard.h"
  26. #include "mainint.h"
  27. #include "nortvars.h"
  28. #include "opentyr.h"
  29. #include "picload.h"
  30. #include "sprite.h"
  31. #include "varz.h"
  32. #include "video.h"
  33.  
  34. #include <assert.h>
  35.  
  36. /*                              HERE BE DRAGONS!
  37.  *
  38.  * When I wrote this code I thought it was wonderful... that thought was very
  39.  * wrong.  It works, but good luck understanding how... I don't anymore.
  40.  *
  41.  * Hopefully it'll be rewritten some day.
  42.  */
  43.  
  44. #define NET_VERSION       2            // increment whenever networking changes might create incompatability
  45. #define NET_PORT          1333         // UDP
  46.  
  47. #define NET_PACKET_SIZE   256
  48. #define NET_PACKET_QUEUE  16
  49.  
  50. #define NET_RETRY         640          // ticks to wait for packet acknowledgement before resending
  51. #define NET_RESEND        320          // ticks to wait before requesting unreceived game packet
  52. #define NET_KEEP_ALIVE    1600         // ticks to wait between keep-alive packets
  53. #define NET_TIME_OUT      16000        // ticks to wait before considering connection dead
  54.  
  55. bool isNetworkGame = false;
  56. int network_delay = 1 + 1;  // minimum is 1 + 0
  57.  
  58. char *network_opponent_host = NULL;
  59.  
  60. Uint16 network_player_port = NET_PORT,
  61.        network_opponent_port = NET_PORT;
  62.  
  63. static char empty_string[] = "";
  64. char *network_player_name = empty_string,
  65.      *network_opponent_name = empty_string;
  66.  
  67. #ifdef WITH_NETWORK
  68. static UDPsocket socket;
  69. static IPaddress ip;
  70.  
  71. UDPpacket *packet_out_temp;
  72. static UDPpacket *packet_temp;
  73.  
  74. UDPpacket *packet_in[NET_PACKET_QUEUE] = { NULL },
  75.           *packet_out[NET_PACKET_QUEUE] = { NULL };
  76.  
  77. static Uint16 last_out_sync = 0, queue_in_sync = 0, queue_out_sync = 0, last_ack_sync = 0;
  78. static Uint32 last_in_tick = 0, last_out_tick = 0;
  79.  
  80. UDPpacket *packet_state_in[NET_PACKET_QUEUE] = { NULL };
  81. static UDPpacket *packet_state_in_xor[NET_PACKET_QUEUE] = { NULL };
  82. UDPpacket *packet_state_out[NET_PACKET_QUEUE] = { NULL };
  83.  
  84. static Uint16 last_state_in_sync = 0, last_state_out_sync = 0;
  85. static Uint32 last_state_in_tick = 0;
  86.  
  87. static bool net_initialized = false;
  88. static bool connected = false, quit = false;
  89. #endif
  90.  
  91. uint thisPlayerNum = 0;  /* Player number on this PC (1 or 2) */
  92.  
  93. JE_boolean haltGame = false;
  94.  
  95. JE_boolean moveOk;
  96.  
  97. /* Special Requests */
  98. JE_boolean pauseRequest, skipLevelRequest, helpRequest, nortShipRequest;
  99. JE_boolean yourInGameMenuRequest, inGameMenuRequest;
  100.  
  101. #ifdef WITH_NETWORK
  102. static void packet_copy( UDPpacket *dst, UDPpacket *src )
  103. {
  104.         void *temp = dst->data;
  105.         memcpy(dst, src, sizeof(*dst));
  106.         dst->data = temp;
  107.         memcpy(dst->data, src->data, src->len);
  108. }
  109.  
  110. static void packets_shift_up( UDPpacket **packet, int max_packets )
  111. {
  112.                 if (packet[0])
  113.                 {
  114.                         SDLNet_FreePacket(packet[0]);
  115.                 }
  116.                 for (int i = 0; i < max_packets - 1; i++)
  117.                 {
  118.                         packet[i] = packet[i + 1];
  119.                 }
  120.                 packet[max_packets - 1] = NULL;
  121. }
  122.  
  123. static void packets_shift_down( UDPpacket **packet, int max_packets )
  124. {
  125.         if (packet[max_packets - 1])
  126.         {
  127.                 SDLNet_FreePacket(packet[max_packets - 1]);
  128.         }
  129.         for (int i = max_packets - 1; i > 0; i--)
  130.         {
  131.                 packet[i] = packet[i - 1];
  132.         }
  133.         packet[0] = NULL;
  134. }
  135.  
  136. // prepare new packet for sending
  137. void network_prepare( Uint16 type )
  138. {
  139.         SDLNet_Write16(type,          &packet_out_temp->data[0]);
  140.         SDLNet_Write16(last_out_sync, &packet_out_temp->data[2]);
  141. }
  142.  
  143. // send packet but don't expect acknoledgment of delivery
  144. static bool network_send_no_ack( int len )
  145. {
  146.         packet_out_temp->len = len;
  147.  
  148.         if (!SDLNet_UDP_Send(socket, 0, packet_out_temp))
  149.         {
  150.                 printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
  151.                 return false;
  152.         }
  153.  
  154.         return true;
  155. }
  156.  
  157. // send packet and place it in queue to be acknowledged
  158. bool network_send( int len )
  159. {
  160.         bool temp = network_send_no_ack(len);
  161.  
  162.         Uint16 i = last_out_sync - queue_out_sync;
  163.         if (i < NET_PACKET_QUEUE)
  164.         {
  165.                 packet_out[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
  166.                 packet_copy(packet_out[i], packet_out_temp);
  167.         } else {
  168.                 // connection is probably bad now
  169.                 fprintf(stderr, "warning: outbound packet queue overflow\n");
  170.                 return false;
  171.         }
  172.  
  173.         last_out_sync++;
  174.  
  175.         if (network_is_sync())
  176.                 last_out_tick = SDL_GetTicks();
  177.  
  178.         return temp;
  179. }
  180.  
  181. // send acknowledgement packet
  182. static int network_acknowledge( Uint16 sync )
  183. {
  184.         SDLNet_Write16(PACKET_ACKNOWLEDGE, &packet_out_temp->data[0]);
  185.         SDLNet_Write16(sync,               &packet_out_temp->data[2]);
  186.         network_send_no_ack(4);
  187.  
  188.         return 0;
  189. }
  190.  
  191. // activity lately?
  192. static bool network_is_alive( void )
  193. {
  194.         return (SDL_GetTicks() - last_in_tick < NET_TIME_OUT || SDL_GetTicks() - last_state_in_tick < NET_TIME_OUT);
  195. }
  196.  
  197. // poll for new packets received, check that connection is alive, resend queued packets if necessary
  198. int network_check( void )
  199. {
  200.         if (!net_initialized)
  201.                 return -1;
  202.  
  203.         if (connected)
  204.         {
  205.                 // timeout
  206.                 if (!network_is_alive())
  207.                 {
  208.                         if (!quit)
  209.                                 network_tyrian_halt(2, false);
  210.                 }
  211.  
  212.                 // keep-alive
  213.                 static Uint32 keep_alive_tick = 0;
  214.                 if (SDL_GetTicks() - keep_alive_tick > NET_KEEP_ALIVE)
  215.                 {
  216.                         network_prepare(PACKET_KEEP_ALIVE);
  217.                         network_send_no_ack(4);
  218.  
  219.                         keep_alive_tick = SDL_GetTicks();
  220.                 }
  221.         }
  222.  
  223.         // retry
  224.         if (packet_out[0] && SDL_GetTicks() - last_out_tick > NET_RETRY)
  225.         {
  226.                 if (!SDLNet_UDP_Send(socket, 0, packet_out[0]))
  227.                 {
  228.                         printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
  229.                         return -1;
  230.                 }
  231.  
  232.                 last_out_tick = SDL_GetTicks();
  233.         }
  234.  
  235.         switch (SDLNet_UDP_Recv(socket, packet_temp))
  236.         {
  237.                 case -1:
  238.                         printf("SDLNet_UDP_Recv: %s\n", SDL_GetError());
  239.                         return -1;
  240.                         break;
  241.                 case 0:
  242.                         break;
  243.                 default:
  244.                         if (packet_temp->channel == 0 && packet_temp->len >= 4)
  245.                         {
  246.                                 switch (SDLNet_Read16(&packet_temp->data[0]))
  247.                                 {
  248.                                         case PACKET_ACKNOWLEDGE:
  249.                                                 if ((Uint16)(SDLNet_Read16(&packet_temp->data[2]) - last_ack_sync) < NET_PACKET_QUEUE)
  250.                                                 {
  251.                                                         last_ack_sync = SDLNet_Read16(&packet_temp->data[2]);
  252.                                                 }
  253.  
  254.                                                 {
  255.                                                         Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - queue_out_sync;
  256.                                                         if (i < NET_PACKET_QUEUE)
  257.                                                         {
  258.                                                                 if (packet_out[i])
  259.                                                                 {
  260.                                                                         SDLNet_FreePacket(packet_out[i]);
  261.                                                                         packet_out[i] = NULL;
  262.                                                                 }
  263.                                                         }
  264.                                                 }
  265.  
  266.                                                 // remove acknowledged packets from queue
  267.                                                 while (packet_out[0] == NULL && (Uint16)(last_ack_sync - queue_out_sync) < NET_PACKET_QUEUE)
  268.                                                 {
  269.                                                         packets_shift_up(packet_out, NET_PACKET_QUEUE);
  270.  
  271.                                                         queue_out_sync++;
  272.                                                 }
  273.  
  274.                                                 last_in_tick = SDL_GetTicks();
  275.                                                 break;
  276.  
  277.                                         case PACKET_CONNECT:
  278.                                                 queue_in_sync = SDLNet_Read16(&packet_temp->data[2]);
  279.  
  280.                                                 for (int i = 0; i < NET_PACKET_QUEUE; i++)
  281.                                                 {
  282.                                                         if (packet_in[i])
  283.                                                         {
  284.                                                                 SDLNet_FreePacket(packet_in[i]);
  285.                                                                 packet_in[i] = NULL;
  286.                                                         }
  287.                                                 }
  288.                                                 // fall through
  289.  
  290.                                         case PACKET_DETAILS:
  291.                                         case PACKET_WAITING:
  292.                                         case PACKET_BUSY:
  293.                                         case PACKET_GAME_QUIT:
  294.                                         case PACKET_GAME_PAUSE:
  295.                                         case PACKET_GAME_MENU:
  296.                                                 {
  297.                                                         Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - queue_in_sync;
  298.                                                         if (i < NET_PACKET_QUEUE)
  299.                                                         {
  300.                                                                 if (packet_in[i] == NULL)
  301.                                                                         packet_in[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
  302.                                                                 packet_copy(packet_in[i], packet_temp);
  303.                                                         } else {
  304.                                                                 // inbound packet queue overflow/underflow
  305.                                                                 // under normal circumstances, this is okay
  306.                                                         }
  307.                                                 }
  308.  
  309.                                                 network_acknowledge(SDLNet_Read16(&packet_temp->data[2]));
  310.                                                 // fall through
  311.  
  312.                                         case PACKET_KEEP_ALIVE:
  313.                                                 last_in_tick = SDL_GetTicks();
  314.                                                 break;
  315.  
  316.                                         case PACKET_QUIT:
  317.                                                 if (!quit)
  318.                                                 {
  319.                                                         network_prepare(PACKET_QUIT);
  320.                                                         network_send(4);  // PACKET_QUIT
  321.                                                 }
  322.  
  323.                                                 network_acknowledge(SDLNet_Read16(&packet_temp->data[2]));
  324.  
  325.                                                 if (!quit)
  326.                                                         network_tyrian_halt(1, true);
  327.                                                 break;
  328.  
  329.                                         case PACKET_STATE:
  330.                                                 // place packet in queue if within limits
  331.                                                 {
  332.                                                         Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - last_state_in_sync + 1;
  333.                                                         if (i < NET_PACKET_QUEUE)
  334.                                                         {
  335.                                                                 if (packet_state_in[i] == NULL)
  336.                                                                         packet_state_in[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
  337.                                                                 packet_copy(packet_state_in[i], packet_temp);
  338.                                                         }
  339.                                                 }
  340.                                                 break;
  341.  
  342.                                         case PACKET_STATE_XOR:
  343.                                                 // place packet in queue if within limits
  344.                                                 {
  345.                                                         Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - last_state_in_sync + 1;
  346.                                                         if (i < NET_PACKET_QUEUE)
  347.                                                         {
  348.                                                                 if (packet_state_in_xor[i] == NULL)
  349.                                                                 {
  350.                                                                         packet_state_in_xor[i] = SDLNet_AllocPacket(NET_PACKET_SIZE);
  351.                                                                         packet_copy(packet_state_in_xor[i], packet_temp);
  352.                                                                 } else if (SDLNet_Read16(&packet_state_in_xor[i]->data[0]) != PACKET_STATE_XOR) {
  353.                                                                         for (int j = 4; j < packet_state_in_xor[i]->len; j++)
  354.                                                                                 packet_state_in_xor[i]->data[j] ^= packet_temp->data[j];
  355.                                                                         SDLNet_Write16(PACKET_STATE_XOR, &packet_state_in_xor[i]->data[0]);
  356.                                                                 }
  357.                                                         }
  358.                                                 }
  359.                                                 break;
  360.  
  361.                                         case PACKET_STATE_RESEND:
  362.                                                 // resend requested state packet if still available
  363.                                                 {
  364.                                                         Uint16 i = last_state_out_sync - SDLNet_Read16(&packet_temp->data[2]);
  365.                                                         if (i > 0 && i < NET_PACKET_QUEUE)
  366.                                                         {
  367.                                                                 if (packet_state_out[i])
  368.                                                                 {
  369.                                                                         if (!SDLNet_UDP_Send(socket, 0, packet_state_out[i]))
  370.                                                                         {
  371.                                                                                 printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
  372.                                                                                 return -1;
  373.                                                                         }
  374.                                                                 }
  375.                                                         }
  376.                                                 }
  377.                                                 break;
  378.  
  379.                                         default:
  380.                                                 fprintf(stderr, "warning: bad packet %d received\n", SDLNet_Read16(&packet_temp->data[0]));
  381.                                                 return 0;
  382.                                                 break;
  383.                                 }
  384.  
  385.                                 return 1;
  386.                         }
  387.                         break;
  388.         }
  389.  
  390.         return 0;
  391. }
  392.  
  393. // discard working packet, now processing next packet in queue
  394. bool network_update( void )
  395. {
  396.         if (packet_in[0])
  397.         {
  398.                 packets_shift_up(packet_in, NET_PACKET_QUEUE);
  399.  
  400.                 queue_in_sync++;
  401.  
  402.                 return true;
  403.         }
  404.  
  405.         return false;
  406. }
  407.  
  408. // has opponent gotten all the packets we've sent?
  409. bool network_is_sync( void )
  410. {
  411.         return (queue_out_sync - last_ack_sync == 1);
  412. }
  413.  
  414.  
  415. // prepare new state for sending
  416. void network_state_prepare( void )
  417. {
  418.         if (packet_state_out[0])
  419.         {
  420.                 fprintf(stderr, "warning: state packet overwritten (previous packet remains unsent)\n");
  421.         } else {
  422.                 packet_state_out[0] = SDLNet_AllocPacket(NET_PACKET_SIZE);
  423.                 packet_state_out[0]->len = 28;
  424.         }
  425.  
  426.         SDLNet_Write16(PACKET_STATE, &packet_state_out[0]->data[0]);
  427.         SDLNet_Write16(last_state_out_sync, &packet_state_out[0]->data[2]);
  428.         memset(&packet_state_out[0]->data[4], 0, 28 - 4);
  429. }
  430.  
  431. // send state packet, xor packet if applicable
  432. int network_state_send( void )
  433. {
  434.         if (!SDLNet_UDP_Send(socket, 0, packet_state_out[0]))
  435.         {
  436.                 printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
  437.                 return -1;
  438.         }
  439.  
  440.         // send xor of last network_delay packets
  441.         if (network_delay > 1 && (last_state_out_sync + 1) % network_delay == 0 && packet_state_out[network_delay - 1] != NULL)
  442.         {
  443.                 packet_copy(packet_temp, packet_state_out[0]);
  444.                 SDLNet_Write16(PACKET_STATE_XOR, &packet_temp->data[0]);
  445.                 for (int i = 1; i < network_delay; i++)
  446.                         for (int j = 4; j < packet_temp->len; j++)
  447.                                 packet_temp->data[j] ^= packet_state_out[i]->data[j];
  448.  
  449.                 if (!SDLNet_UDP_Send(socket, 0, packet_temp))
  450.                 {
  451.                         printf("SDLNet_UDP_Send: %s\n", SDL_GetError());
  452.                         return -1;
  453.                 }
  454.         }
  455.  
  456.         packets_shift_down(packet_state_out, NET_PACKET_QUEUE);
  457.  
  458.         last_state_out_sync++;
  459.  
  460.         return 0;
  461. }
  462.  
  463. // receive state packet, wait until received
  464. bool network_state_update( void )
  465. {
  466.         if (network_state_is_reset())
  467.         {
  468.                 return 0;
  469.         } else {
  470.                 packets_shift_up(packet_state_in, NET_PACKET_QUEUE);
  471.  
  472.                 packets_shift_up(packet_state_in_xor, NET_PACKET_QUEUE);
  473.  
  474.                 last_state_in_sync++;
  475.  
  476.                 // current xor packet index
  477.                 int x = network_delay - (last_state_in_sync - 1) % network_delay - 1;
  478.  
  479.                 // loop until needed packet is available
  480.                 while (!packet_state_in[0])
  481.                 {
  482.                         // xor the packet from thin air, if possible
  483.                         if (packet_state_in_xor[x] && SDLNet_Read16(&packet_state_in_xor[x]->data[0]) == PACKET_STATE_XOR)
  484.                         {
  485.                                 // check for all other required packets
  486.                                 bool okay = true;
  487.                                 for (int i = 1; i <= x; i++)
  488.                                 {
  489.                                         if (packet_state_in[i] == NULL)
  490.                                         {
  491.                                                 okay = false;
  492.                                                 break;
  493.                                         }
  494.                                 }
  495.                                 if (okay)
  496.                                 {
  497.                                         packet_state_in[0] = SDLNet_AllocPacket(NET_PACKET_SIZE);
  498.                                         packet_copy(packet_state_in[0], packet_state_in_xor[x]);
  499.                                         for (int i = 1; i <= x; i++)
  500.                                                 for (int j = 4; j < packet_state_in[0]->len; j++)
  501.                                                         packet_state_in[0]->data[j] ^= packet_state_in[i]->data[j];
  502.                                         break;
  503.                                 }
  504.                         }
  505.  
  506.                         static Uint32 resend_tick = 0;
  507.                         if (SDL_GetTicks() - last_state_in_tick > NET_RESEND && SDL_GetTicks() - resend_tick > NET_RESEND)
  508.                         {
  509.                                 SDLNet_Write16(PACKET_STATE_RESEND,    &packet_out_temp->data[0]);
  510.                                 SDLNet_Write16(last_state_in_sync - 1, &packet_out_temp->data[2]);
  511.                                 network_send_no_ack(4);  // PACKET_RESEND
  512.  
  513.                                 resend_tick = SDL_GetTicks();
  514.                         }
  515.  
  516.                         if (network_check() == 0)
  517.                                 uSDL_Delay(1);
  518.                 }
  519.  
  520.                 if (network_delay > 1)
  521.                 {
  522.                         // process the current in packet against the xor queue
  523.                         if (packet_state_in_xor[x] == NULL)
  524.                         {
  525.                                 packet_state_in_xor[x] = SDLNet_AllocPacket(NET_PACKET_SIZE);
  526.                                 packet_copy(packet_state_in_xor[x], packet_state_in[0]);
  527.                                 packet_state_in_xor[x]->status = 0;
  528.                         } else {
  529.                                 for (int j = 4; j < packet_state_in_xor[x]->len; j++)
  530.                                         packet_state_in_xor[x]->data[j] ^= packet_state_in[0]->data[j];
  531.                         }
  532.                 }
  533.  
  534.                 last_state_in_tick = SDL_GetTicks();
  535.         }
  536.  
  537.         return 1;
  538. }
  539.  
  540. // ignore first network_delay states of level
  541. bool network_state_is_reset( void )
  542. {
  543.         return (last_state_out_sync < network_delay);
  544. }
  545.  
  546. // reset queues for new level
  547. void network_state_reset( void )
  548. {
  549.         last_state_in_sync = last_state_out_sync = 0;
  550.  
  551.         for (int i = 0; i < NET_PACKET_QUEUE; i++)
  552.         {
  553.                 if (packet_state_in[i])
  554.                 {
  555.                         SDLNet_FreePacket(packet_state_in[i]);
  556.                         packet_state_in[i] = NULL;
  557.                 }
  558.         }
  559.         for (int i = 0; i < NET_PACKET_QUEUE; i++)
  560.         {
  561.                 if (packet_state_in_xor[i])
  562.                 {
  563.                         SDLNet_FreePacket(packet_state_in_xor[i]);
  564.                         packet_state_in_xor[i] = NULL;
  565.                 }
  566.         }
  567.         for (int i = 0; i < NET_PACKET_QUEUE; i++)
  568.         {
  569.                 if (packet_state_out[i])
  570.                 {
  571.                         SDLNet_FreePacket(packet_state_out[i]);
  572.                         packet_state_out[i] = NULL;
  573.                 }
  574.         }
  575.  
  576.         last_state_in_tick = SDL_GetTicks();
  577. }
  578.  
  579.  
  580. // attempt to punch through firewall by firing off UDP packets at the opponent
  581. // exchange game information
  582. int network_connect( void )
  583. {
  584.         SDLNet_ResolveHost(&ip, network_opponent_host, network_opponent_port);
  585.  
  586.         SDLNet_UDP_Bind(socket, 0, &ip);
  587.  
  588.         Uint16 episodes = 0, episodes_local = 0;
  589.         assert(EPISODE_MAX <= 16);
  590.         for (int i = EPISODE_MAX - 1; i >= 0; i--)
  591.         {
  592.                 episodes <<= 1;
  593.                 episodes |= (episodeAvail[i] != 0);
  594.         }
  595.         episodes_local = episodes;
  596.  
  597.         assert(NET_PACKET_SIZE - 12 >= 20 + 1);
  598.         if (strlen(network_player_name) > 20)
  599.                 network_player_name[20] = '\0';
  600.  
  601. connect_reset:
  602.         network_prepare(PACKET_CONNECT);
  603.         SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]);
  604.         SDLNet_Write16(network_delay,   &packet_out_temp->data[6]);
  605.         SDLNet_Write16(episodes_local,  &packet_out_temp->data[8]);
  606.         SDLNet_Write16(thisPlayerNum,   &packet_out_temp->data[10]);
  607.         strcpy((char *)&packet_out_temp->data[12], network_player_name);
  608.         network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT
  609.  
  610.         // until opponent sends connect packet
  611.         while (true)
  612.         {
  613.                 push_joysticks_as_keyboard();
  614.                 service_SDL_events(false);
  615.  
  616.                 if (newkey && lastkey_sym == SDLK_ESCAPE)
  617.                         network_tyrian_halt(0, false);
  618.  
  619.                 // never timeout
  620.                 last_in_tick = SDL_GetTicks();
  621.  
  622.                 if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT)
  623.                         break;
  624.  
  625.                 network_update();
  626.                 network_check();
  627.  
  628.                 uSDL_Delay(16);
  629.         }
  630.  
  631. connect_again:
  632.         if (SDLNet_Read16(&packet_in[0]->data[4]) != NET_VERSION)
  633.         {
  634.                 fprintf(stderr, "error: network version did not match opponent's\n");
  635.                 network_tyrian_halt(4, true);
  636.         }
  637.         if (SDLNet_Read16(&packet_in[0]->data[6]) != network_delay)
  638.         {
  639.                 fprintf(stderr, "error: network delay did not match opponent's\n");
  640.                 network_tyrian_halt(5, true);
  641.         }
  642.         if (SDLNet_Read16(&packet_in[0]->data[10]) == thisPlayerNum)
  643.         {
  644.                 fprintf(stderr, "error: player number conflicts with opponent's\n");
  645.                 network_tyrian_halt(6, true);
  646.         }
  647.  
  648.         episodes = SDLNet_Read16(&packet_in[0]->data[8]);
  649.         for (int i = 0; i < EPISODE_MAX; i++) {
  650.                 episodeAvail[i] &= (episodes & 1);
  651.                 episodes >>= 1;
  652.         }
  653.  
  654.         network_opponent_name = malloc(packet_in[0]->len - 12 + 1);
  655.         strcpy(network_opponent_name, (char *)&packet_in[0]->data[12]);
  656.  
  657.         network_update();
  658.  
  659.         // until opponent has acknowledged
  660.         while (!network_is_sync())
  661.         {
  662.                 service_SDL_events(false);
  663.  
  664.                 // got a duplicate packet; process it again (but why?)
  665.                 if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT)
  666.                         goto connect_again;
  667.  
  668.                 network_check();
  669.  
  670.                 // maybe opponent didn't get our packet
  671.                 if (SDL_GetTicks() - last_out_tick > NET_RETRY)
  672.                         goto connect_reset;
  673.  
  674.                 uSDL_Delay(16);
  675.         }
  676.  
  677.         // send another packet since sometimes the network syncs without both connect packets exchanged
  678.         // there should be a better way to handle this
  679.         network_prepare(PACKET_CONNECT);
  680.         SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]);
  681.         SDLNet_Write16(network_delay,   &packet_out_temp->data[6]);
  682.         SDLNet_Write16(episodes_local,  &packet_out_temp->data[8]);
  683.         SDLNet_Write16(thisPlayerNum,   &packet_out_temp->data[10]);
  684.         strcpy((char *)&packet_out_temp->data[12], network_player_name);
  685.         network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT
  686.  
  687.         connected = true;
  688.  
  689.         return 0;
  690. }
  691.  
  692. // something has gone wrong :(
  693. void network_tyrian_halt( unsigned int err, bool attempt_sync )
  694. {
  695.         const char *err_msg[] = {
  696.                 "Quitting...",
  697.                 "Other player quit the game.",
  698.                 "Network connection was lost.",
  699.                 "Network connection failed.",
  700.                 "Network version mismatch.",
  701.                 "Network delay mismatch.",
  702.                 "Network player number conflict.",
  703.         };
  704.  
  705.         quit = true;
  706.  
  707.         if (err >= COUNTOF(err_msg))
  708.                 err = 0;
  709.  
  710.         fade_black(10);
  711.  
  712.         VGAScreen = VGAScreenSeg;
  713.  
  714.         JE_loadPic(VGAScreen, 2, false);
  715.         JE_dString(VGAScreen, JE_fontCenter(err_msg[err], SMALL_FONT_SHAPES), 140, err_msg[err], SMALL_FONT_SHAPES);
  716.  
  717.         JE_showVGA();
  718.         fade_palette(colors, 10, 0, 255);
  719.  
  720.         if (attempt_sync)
  721.         {
  722.                 while (!network_is_sync() && network_is_alive())
  723.                 {
  724.                         service_SDL_events(false);
  725.  
  726.                         network_check();
  727.                         uSDL_Delay(16);
  728.                 }
  729.         }
  730.  
  731.         if (err)
  732.         {
  733.                 while (!JE_anyButton())
  734.                         uSDL_Delay(16);
  735.         }
  736.  
  737.         fade_black(10);
  738.  
  739.         SDLNet_Quit();
  740.  
  741.         JE_tyrianHalt(5);
  742. }
  743.  
  744. int network_init( void )
  745. {
  746.         printf("Initializing network...\n");
  747.  
  748.         if (network_delay * 2 > NET_PACKET_QUEUE - 2)
  749.         {
  750.                 fprintf(stderr, "error: network delay would overflow packet queue\n");
  751.                 return -4;
  752.         }
  753.  
  754.         if (SDLNet_Init() == -1)
  755.         {
  756.                 fprintf(stderr, "error: SDLNet_Init: %s\n", SDLNet_GetError());
  757.                 return -1;
  758.         }
  759.  
  760.         socket = SDLNet_UDP_Open(network_player_port);
  761.         if (!socket)
  762.         {
  763.                 fprintf(stderr, "error: SDLNet_UDP_Open: %s\n", SDLNet_GetError());
  764.                 return -2;
  765.         }
  766.  
  767.         packet_temp = SDLNet_AllocPacket(NET_PACKET_SIZE);
  768.         packet_out_temp = SDLNet_AllocPacket(NET_PACKET_SIZE);
  769.  
  770.         if (!packet_temp || !packet_out_temp)
  771.         {
  772.                 printf("SDLNet_AllocPacket: %s\n", SDLNet_GetError());
  773.                 return -3;
  774.         }
  775.  
  776.         net_initialized = true;
  777.  
  778.         return 0;
  779. }
  780.  
  781. #endif
  782.  
  783. void JE_clearSpecialRequests( void )
  784. {
  785.         pauseRequest = false;
  786.         inGameMenuRequest = false;
  787.         skipLevelRequest = false;
  788.         helpRequest = false;
  789.         nortShipRequest = false;
  790. }
  791.  
  792.