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