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 "backgrnd.h"
20 #include "config.h"
21 #include "editship.h"
22 #include "episodes.h"
23 #include "file.h"
24 #include "fonthand.h"
25 #include "helptext.h"
26 #include "helptext.h"
27 #include "joystick.h"
28 #include "keyboard.h"
29 #include "lds_play.h"
30 #include "loudness.h"
31 #include "mainint.h"
32 #include "menus.h"
33 #include "mouse.h"
34 #include "mtrand.h"
35 #include "network.h"
36 #include "nortsong.h"
37 #include "nortvars.h"
38 #include "opentyr.h"
39 #include "palette.h"
40 #include "params.h"
41 #include "pcxmast.h"
42 #include "picload.h"
43 #include "player.h"
44 #include "setup.h"
45 #include "shots.h"
46 #include "sndmast.h"
47 #include "sprite.h"
48 #include "varz.h"
49 #include "vga256d.h"
50 #include "video.h"
51 
52 #include <assert.h>
53 #include <ctype.h>
54 
55 bool button[4];
56 
57 #define MAX_PAGE 8
58 #define TOPICS 6
59 const JE_byte topicStart[TOPICS] = { 0, 1, 2, 3, 7, 255 };
60 
61 JE_shortint constantLastX;
62 JE_word textErase;
63 JE_word upgradeCost;
64 JE_word downgradeCost;
65 JE_boolean performSave;
66 JE_boolean jumpSection;
67 JE_boolean useLastBank; /* See if I want to use the last 16 colors for DisplayText */
68 
69 bool pause_pressed = false, ingamemenu_pressed = false;
70 
71 /* Draws a message at the bottom text window on the playing screen */
JE_drawTextWindow(const char * text)72 void JE_drawTextWindow( const char *text )
73 {
74 	if (textErase > 0) // erase current text
75 		blit_sprite(VGAScreenSeg, 16, 189, OPTION_SHAPES, 36);  // in-game text area
76 
77 	textErase = 100;
78 	JE_outText(VGAScreenSeg, 20, 190, text, 0, 4);
79 }
80 
JE_outCharGlow(JE_word x,JE_word y,const char * s)81 void JE_outCharGlow( JE_word x, JE_word y, const char *s )
82 {
83 	JE_integer maxloc, loc, z;
84 	JE_shortint glowcol[60]; /* [1..60] */
85 	JE_shortint glowcolc[60]; /* [1..60] */
86 	JE_word textloc[60]; /* [1..60] */
87 	JE_byte bank;
88 
89 	setjasondelay2(1);
90 
91 	bank = (warningRed) ? 7 : ((useLastBank) ? 15 : 14);
92 
93 	if (s[0] == '\0')
94 		return;
95 
96 	if (frameCountMax == 0)
97 	{
98 		JE_textShade(VGAScreen, x, y, s, bank, 0, PART_SHADE);
99 		JE_showVGA();
100 	}
101 	else
102 	{
103 		maxloc = strlen(s);
104 		for (z = 0; z < 60; z++)
105 		{
106 			glowcol[z] = -8;
107 			glowcolc[z] = 1;
108 		}
109 
110 		loc = x;
111 		for (z = 0; z < maxloc; z++)
112 		{
113 			textloc[z] = loc;
114 
115 			int sprite_id = font_ascii[(unsigned char)s[z]];
116 
117 			if (s[z] == ' ')
118 				loc += 6;
119 			else if (sprite_id != -1)
120 				loc += sprite(TINY_FONT, sprite_id)->width + 1;
121 		}
122 
123 		for (loc = 0; (unsigned)loc < strlen(s) + 28; loc++)
124 		{
125 			if (!ESCPressed)
126 			{
127 				setjasondelay(frameCountMax);
128 
129 				NETWORK_KEEP_ALIVE();
130 
131 				int sprite_id = -1;
132 
133 				for (z = loc - 28; z <= loc; z++)
134 				{
135 					if (z >= 0 && z < maxloc)
136 					{
137 						sprite_id = font_ascii[(unsigned char)s[z]];
138 
139 						if (sprite_id != -1)
140 						{
141 							blit_sprite_hv(VGAScreen, textloc[z], y, TINY_FONT, sprite_id, bank, glowcol[z]);
142 
143 							glowcol[z] += glowcolc[z];
144 							if (glowcol[z] > 9)
145 								glowcolc[z] = -1;
146 						}
147 					}
148 				}
149 				if (sprite_id != -1 && --z < maxloc)
150 					blit_sprite_dark(VGAScreen, textloc[z] + 1, y + 1, TINY_FONT, sprite_id, true);
151 
152 				if (JE_anyButton())
153 					frameCountMax = 0;
154 
155 				do
156 				{
157 					if (levelWarningDisplay)
158 						JE_updateWarning(VGAScreen);
159 
160 					SDL_Delay(16);
161 				}
162 				while (!(delaycount() == 0 || ESCPressed));
163 
164 				JE_showVGA();
165 			}
166 		}
167 	}
168 }
169 
JE_drawPortConfigButtons(void)170 void JE_drawPortConfigButtons( void ) // rear weapon pattern indicator
171 {
172 	if (twoPlayerMode)
173 		return;
174 
175 	if (player[0].weapon_mode == 1)
176 	{
177 		blit_sprite(VGAScreenSeg, 285, 44, OPTION_SHAPES, 18);  // lit
178 		blit_sprite(VGAScreenSeg, 302, 44, OPTION_SHAPES, 19);  // unlit
179 	}
180 	else // == 2
181 	{
182 		blit_sprite(VGAScreenSeg, 285, 44, OPTION_SHAPES, 19);  // unlit
183 		blit_sprite(VGAScreenSeg, 302, 44, OPTION_SHAPES, 18);  // lit
184 	}
185 }
186 
JE_helpSystem(JE_byte startTopic)187 void JE_helpSystem( JE_byte startTopic )
188 {
189 	JE_integer page, lastPage = 0;
190 	JE_byte menu;
191 
192 	page = topicStart[startTopic-1];
193 
194 	fade_black(10);
195 	JE_loadPic(VGAScreen, 2, false);
196 
197 	play_song(SONG_MAPVIEW);
198 
199 	JE_showVGA();
200 	fade_palette(colors, 10, 0, 255);
201 
202 	memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
203 
204 	do
205 	{
206 		memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
207 
208 		temp2 = 0;
209 
210 		for (temp = 0; temp < TOPICS; temp++)
211 		{
212 			if (topicStart[temp] <= page)
213 			{
214 				temp2 = temp;
215 			}
216 		}
217 
218 		if (page > 0)
219 		{
220 			JE_char buf[128];
221 
222 			sprintf(buf, "%s %d", miscText[24], page-topicStart[temp2]+1);
223 			JE_outText(VGAScreen, 10, 192, buf, 13, 5);
224 
225 			sprintf(buf, "%s %d of %d", miscText[25], page, MAX_PAGE);
226 			JE_outText(VGAScreen, 220, 192, buf, 13, 5);
227 
228 			JE_dString(VGAScreen, JE_fontCenter(topicName[temp2], SMALL_FONT_SHAPES), 1, topicName[temp2], SMALL_FONT_SHAPES);
229 		}
230 
231 		menu = 0;
232 
233 		helpBoxBrightness = 3;
234 		verticalHeight = 8;
235 
236 		switch (page)
237 		{
238 			case 0:
239 				menu = 2;
240 				if (lastPage == MAX_PAGE)
241 				{
242 					menu = TOPICS;
243 				}
244 				JE_dString(VGAScreen, JE_fontCenter(topicName[0], FONT_SHAPES), 30, topicName[0], FONT_SHAPES);
245 
246 				do
247 				{
248 					for (temp = 1; temp <= TOPICS; temp++)
249 					{
250 						char buf[21+1];
251 
252 						if (temp == menu-1)
253 						{
254 							strcpy(buf+1, topicName[temp]);
255 							buf[0] = '~';
256 						} else {
257 							strcpy(buf, topicName[temp]);
258 						}
259 
260 						JE_dString(VGAScreen, JE_fontCenter(topicName[temp], SMALL_FONT_SHAPES), temp * 20 + 40, buf, SMALL_FONT_SHAPES);
261 					}
262 
263 					//JE_waitRetrace();  didn't do anything anyway?
264 					JE_showVGA();
265 
266 					tempW = 0;
267 					JE_textMenuWait(&tempW, false);
268 					if (newkey)
269 					{
270 						switch (lastkey_sym)
271 						{
272 							case SDLK_UP:
273 								menu--;
274 								if (menu < 2)
275 								{
276 									menu = TOPICS;
277 								}
278 								JE_playSampleNum(S_CURSOR);
279 								break;
280 							case SDLK_DOWN:
281 								menu++;
282 								if (menu > TOPICS)
283 								{
284 									menu = 2;
285 								}
286 								JE_playSampleNum(S_CURSOR);
287 								break;
288 							default:
289 								break;
290 						}
291 					}
292 				} while (!(lastkey_sym == SDLK_ESCAPE || lastkey_sym == SDLK_RETURN));
293 
294 				if (lastkey_sym == SDLK_RETURN)
295 				{
296 					page = topicStart[menu-1];
297 					JE_playSampleNum(S_CLICK);
298 				}
299 
300 				break;
301 			case 1: /* One-Player Menu */
302 				JE_HBox(VGAScreen, 10,  20,  2, 60);
303 				JE_HBox(VGAScreen, 10,  50,  5, 60);
304 				JE_HBox(VGAScreen, 10,  80, 21, 60);
305 				JE_HBox(VGAScreen, 10, 110,  1, 60);
306 				JE_HBox(VGAScreen, 10, 140, 28, 60);
307 				break;
308 			case 2: /* Two-Player Menu */
309 				JE_HBox(VGAScreen, 10,  20,  1, 60);
310 				JE_HBox(VGAScreen, 10,  60,  2, 60);
311 				JE_HBox(VGAScreen, 10, 100, 21, 60);
312 				JE_HBox(VGAScreen, 10, 140, 28, 60);
313 				break;
314 			case 3: /* Upgrade Ship */
315 				JE_HBox(VGAScreen, 10,  20,  5, 60);
316 				JE_HBox(VGAScreen, 10,  70,  6, 60);
317 				JE_HBox(VGAScreen, 10, 110,  7, 60);
318 				break;
319 			case 4:
320 				JE_HBox(VGAScreen, 10,  20,  8, 60);
321 				JE_HBox(VGAScreen, 10,  55,  9, 60);
322 				JE_HBox(VGAScreen, 10,  87, 10, 60);
323 				JE_HBox(VGAScreen, 10, 120, 11, 60);
324 				JE_HBox(VGAScreen, 10, 170, 13, 60);
325 				break;
326 			case 5:
327 				JE_HBox(VGAScreen, 10,  20, 14, 60);
328 				JE_HBox(VGAScreen, 10,  80, 15, 60);
329 				JE_HBox(VGAScreen, 10, 120, 16, 60);
330 				break;
331 			case 6:
332 				JE_HBox(VGAScreen, 10,  20, 17, 60);
333 				JE_HBox(VGAScreen, 10,  40, 18, 60);
334 				JE_HBox(VGAScreen, 10, 130, 20, 60);
335 				break;
336 			case 7: /* Options */
337 				JE_HBox(VGAScreen, 10,  20, 21, 60);
338 				JE_HBox(VGAScreen, 10,  70, 22, 60);
339 				JE_HBox(VGAScreen, 10, 110, 23, 60);
340 				JE_HBox(VGAScreen, 10, 140, 24, 60);
341 				break;
342 			case 8:
343 				JE_HBox(VGAScreen, 10,  20, 25, 60);
344 				JE_HBox(VGAScreen, 10,  60, 26, 60);
345 				JE_HBox(VGAScreen, 10, 100, 27, 60);
346 				JE_HBox(VGAScreen, 10, 140, 28, 60);
347 				JE_HBox(VGAScreen, 10, 170, 29, 60);
348 				break;
349 		}
350 
351 		helpBoxBrightness = 1;
352 		verticalHeight = 7;
353 
354 		lastPage = page;
355 
356 		if (menu == 0)
357 		{
358 			do {
359 				setjasondelay(3);
360 
361 				push_joysticks_as_keyboard();
362 				service_SDL_events(true);
363 
364 				JE_showVGA();
365 
366 				wait_delay();
367 			} while (!newkey && !newmouse);
368 
369 			wait_noinput(false, true, false);
370 
371 			if (newmouse)
372 			{
373 				switch (lastmouse_but)
374 				{
375 					case SDL_BUTTON_LEFT:
376 						lastkey_sym = SDLK_RIGHT;
377 						break;
378 					case SDL_BUTTON_RIGHT:
379 						lastkey_sym = SDLK_LEFT;
380 						break;
381 					case SDL_BUTTON_MIDDLE:
382 						lastkey_sym = SDLK_ESCAPE;
383 						break;
384 				}
385 				do
386 				{
387 					service_SDL_events(false);
388 				} while (mousedown);
389 				newkey = true;
390 			}
391 
392 			if (newkey)
393 			{
394 				switch (lastkey_sym)
395 				{
396 					case SDLK_LEFT:
397 					case SDLK_UP:
398 					case SDLK_PAGEUP:
399 						page--;
400 						JE_playSampleNum(S_CURSOR);
401 						break;
402 					case SDLK_RIGHT:
403 					case SDLK_DOWN:
404 					case SDLK_PAGEDOWN:
405 					case SDLK_RETURN:
406 					case SDLK_SPACE:
407 						if (page == MAX_PAGE)
408 						{
409 							page = 0;
410 						} else {
411 							page++;
412 						}
413 						JE_playSampleNum(S_CURSOR);
414 						break;
415 					case SDLK_F1:
416 						page = 0;
417 						JE_playSampleNum(S_CURSOR);
418 						break;
419 					default:
420 						break;
421 				}
422 			}
423 		}
424 
425 		if (page == 255)
426 		{
427 			lastkey_sym = SDLK_ESCAPE;
428 		}
429 	} while (lastkey_sym != SDLK_ESCAPE);
430 }
431 
432 // cost to upgrade a weapon power from power-1 (where power == 0 indicates an unupgraded weapon)
weapon_upgrade_cost(long base_cost,unsigned int power)433 long weapon_upgrade_cost( long base_cost, unsigned int power )
434 {
435 	assert(power <= 11);
436 
437 	unsigned int temp = 0;
438 
439 	// 0 1 3 6 10 15 21 29 ...
440 	for (; power > 0; power--)
441 		temp += power;
442 
443 	return base_cost * temp;
444 }
445 
JE_getCost(JE_byte itemType,JE_word itemNum)446 ulong JE_getCost( JE_byte itemType, JE_word itemNum )
447 {
448 	long cost = 0;
449 
450 	switch (itemType)
451 	{
452 	case 2:
453 		cost = (itemNum > 90) ? 100 : ships[itemNum].cost;
454 		break;
455 	case 3:
456 	case 4:
457 		cost = weaponPort[itemNum].cost;
458 
459 		const uint port = itemType - 3,
460 		           item_power = player[0].items.weapon[port].power - 1;
461 
462 		downgradeCost = weapon_upgrade_cost(cost, item_power);
463 		upgradeCost = weapon_upgrade_cost(cost, item_power + 1);
464 		break;
465 	case 5:
466 		cost = shields[itemNum].cost;
467 		break;
468 	case 6:
469 		cost = powerSys[itemNum].cost;
470 		break;
471 	case 7:
472 	case 8:
473 		cost = options[itemNum].cost;
474 		break;
475 	}
476 
477 	return cost;
478 }
479 
JE_loadScreen(void)480 void JE_loadScreen( void )
481 {
482 	JE_boolean quit;
483 	JE_byte sel, screen, min = 0, max = 0;
484 	char *tempstr;
485 	char *tempstr2;
486 	JE_boolean mal_str = false;
487 	int len;
488 
489 	tempstr = NULL;
490 
491 	free_sprite2s(&shapes6);
492 	JE_loadCompShapes(&shapes6, '1');  // need arrow sprites
493 
494 	fade_black(10);
495 	JE_loadPic(VGAScreen, 2, false);
496 	JE_showVGA();
497 	fade_palette(colors, 10, 0, 255);
498 
499 	screen = 1;
500 	sel = 1;
501 	quit = false;
502 
503 	memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
504 
505 	do
506 	{
507 		while (mousedown)
508 		{
509 			service_SDL_events(false);
510 			tempX = mouse_x;
511 			tempY = mouse_y;
512 		}
513 
514 		memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
515 
516 		JE_dString(VGAScreen, JE_fontCenter(miscText[38 + screen - 1], FONT_SHAPES), 5, miscText[38 + screen - 1], FONT_SHAPES);
517 
518 		switch (screen)
519 		{
520 		case 1:
521 			min = 1;
522 			max = 12;
523 			break;
524 		case 2:
525 			min = 12;
526 			max = 23;
527 		}
528 
529 		/* SYN: Go through text line by line */
530 		for (x = min; x <= max; x++)
531 		{
532 			tempY = 30 + (x - min) * 13;
533 
534 			if (x == max)
535 			{
536 				/* Last line is return to main menu, not a save game */
537 				if (mal_str)
538 				{
539 					free(tempstr);
540 					mal_str = false;
541 				}
542 				tempstr = miscText[34 - 1];
543 
544 				if (x == sel) /* Highlight if selected */
545 				{
546 					temp2 = 254;
547 				} else {
548 					temp2 = 250;
549 				}
550 			} else {
551 				if (x == sel) /* Highlight if selected */
552 				{
553 					temp2 = 254;
554 				} else {
555 					temp2 = 250 - ((saveFiles[x - 1].level == 0) << 1);
556 				}
557 
558 				if (saveFiles[x - 1].level == 0) /* I think this means the save file is unused */
559 				{
560 					if (mal_str)
561 					{
562 						free(tempstr);
563 						mal_str = false;
564 					}
565 					tempstr = miscText[3 - 1];
566 				} else {
567 					if (mal_str)
568 					{
569 						free(tempstr);
570 						mal_str = false;
571 					}
572 					tempstr = saveFiles[x - 1].name;
573 				}
574 			}
575 
576 			/* Write first column text */
577 			JE_textShade(VGAScreen, 10, tempY, tempstr, 13, (temp2 % 16) - 8, FULL_SHADE);
578 
579 			if (x < max) /* Write additional columns for all but the last row */
580 			{
581 				if (saveFiles[x - 1].level == 0)
582 				{
583 					if (mal_str)
584 					{
585 						free(tempstr);
586 					}
587 					tempstr = malloc(7);
588 					mal_str = true;
589 					strcpy(tempstr, "-----"); /* Unused save slot */
590 				} else {
591 					tempstr = saveFiles[x - 1].levelName;
592 					tempstr2 = malloc(5 + strlen(miscTextB[2-1]));
593 					sprintf(tempstr2, "%s %d", miscTextB[2-1], saveFiles[x - 1].episode);
594 					JE_textShade(VGAScreen, 250, tempY, tempstr2, 5, (temp2 % 16) - 8, FULL_SHADE);
595 					free(tempstr2);
596 				}
597 
598 				len = strlen(miscTextB[3-1]) + 2 + strlen(tempstr);
599 				tempstr2 = malloc(len);
600 				sprintf(tempstr2, "%s %s", miscTextB[3 - 1], tempstr);
601 				JE_textShade(VGAScreen, 120, tempY, tempstr2, 5, (temp2 % 16) - 8, FULL_SHADE);
602 				free(tempstr2);
603 			}
604 
605 		}
606 
607 		if (screen == 2)
608 		{
609 			blit_sprite2x2(VGAScreen, 90, 180, shapes6, 279);
610 		}
611 		if (screen == 1)
612 		{
613 			blit_sprite2x2(VGAScreen, 220, 180, shapes6, 281);
614 		}
615 
616 		helpBoxColor = 15;
617 		JE_helpBox(VGAScreen, 110, 182, miscText[56-1], 25);
618 
619 		JE_showVGA();
620 
621 		tempW = 0;
622 		JE_textMenuWait(&tempW, false);
623 
624 
625 		if (newkey)
626 		{
627 			switch (lastkey_sym)
628 			{
629 			case SDLK_UP:
630 				sel--;
631 				if (sel < min)
632 				{
633 					sel = max;
634 				}
635 				JE_playSampleNum(S_CURSOR);
636 				break;
637 			case SDLK_DOWN:
638 				sel++;
639 				if (sel > max)
640 				{
641 					sel = min;
642 				}
643 				JE_playSampleNum(S_CURSOR);
644 				break;
645 			case SDLK_LEFT:
646 			case SDLK_RIGHT:
647 				if (screen == 1)
648 				{
649 					screen = 2;
650 					sel += 11;
651 				} else {
652 					screen = 1;
653 					sel -= 11;
654 				}
655 				break;
656 			case SDLK_RETURN:
657 				if (sel < max)
658 				{
659 					if (saveFiles[sel - 1].level > 0)
660 					{
661 						JE_playSampleNum (S_SELECT);
662 						performSave = false;
663 						JE_operation(sel);
664 						quit = true;
665 					} else {
666 						JE_playSampleNum (S_CLINK);
667 					}
668 				} else {
669 					quit = true;
670 				}
671 
672 
673 				break;
674 			case SDLK_ESCAPE:
675 				quit = true;
676 				break;
677 			default:
678 				break;
679 			}
680 
681 		}
682 	} while (!quit);
683 }
684 
JE_totalScore(const Player * this_player)685 ulong JE_totalScore( const Player *this_player )
686 {
687 	ulong temp = this_player->cash;
688 
689 	temp += JE_getValue(2, this_player->items.ship);
690 	temp += JE_getValue(3, this_player->items.weapon[FRONT_WEAPON].id);
691 	temp += JE_getValue(4, this_player->items.weapon[REAR_WEAPON].id);
692 	temp += JE_getValue(5, this_player->items.shield);
693 	temp += JE_getValue(6, this_player->items.generator);
694 	temp += JE_getValue(7, this_player->items.sidekick[LEFT_SIDEKICK]);
695 	temp += JE_getValue(8, this_player->items.sidekick[RIGHT_SIDEKICK]);
696 
697 	return temp;
698 }
699 
JE_getValue(JE_byte itemType,JE_word itemNum)700 JE_longint JE_getValue( JE_byte itemType, JE_word itemNum )
701 {
702 	long value = 0;
703 
704 	switch (itemType)
705 	{
706 	case 2:
707 		value = ships[itemNum].cost;
708 		break;
709 	case 3:
710 	case 4:;
711 		const long base_value = weaponPort[itemNum].cost;
712 
713 		// if two-player, use first player's front and second player's rear weapon
714 		const uint port = itemType - 3;
715 		const uint item_power = player[twoPlayerMode ? port : 0].items.weapon[port].power - 1;
716 
717 		value = base_value;
718 		for (unsigned int i = 1; i <= item_power; ++i)
719 			value += weapon_upgrade_cost(base_value, i);
720 		break;
721 	case 5:
722 		value = shields[itemNum].cost;
723 		break;
724 	case 6:
725 		value = powerSys[itemNum].cost;
726 		break;
727 	case 7:
728 	case 8:
729 		value = options[itemNum].cost;
730 		break;
731 	}
732 
733 	return value;
734 }
735 
JE_nextEpisode(void)736 void JE_nextEpisode( void )
737 {
738 	strcpy(lastLevelName, "Completed");
739 
740 	if (episodeNum == initial_episode_num && !gameHasRepeated && episodeNum != EPISODE_AVAILABLE &&
741 	    !isNetworkGame && !constantPlay)
742 	{
743 		JE_highScoreCheck();
744 	}
745 
746 	unsigned int newEpisode = JE_findNextEpisode();
747 
748 	if (jumpBackToEpisode1)
749 	{
750 		// shareware version check
751 		if (episodeNum == 1 &&
752 			!isNetworkGame && !constantPlay)
753 		{
754 			// JE_loadOrderingInfo();
755 		}
756 
757 		if (episodeNum > 2 &&
758 			!constantPlay)
759 		{
760 			JE_playCredits();
761 		}
762 
763 		// randomly give player the SuperCarrot
764 		if ((mt_rand() % 6) == 0)
765 		{
766 			player[0].items.ship = 2;                      // SuperCarrot
767 			player[0].items.weapon[FRONT_WEAPON].id = 23;  // Banana Blast
768 			player[0].items.weapon[REAR_WEAPON].id = 24;   // Banana Blast Rear
769 
770 			for (uint i = 0; i < COUNTOF(player[0].items.weapon); ++i)
771 				player[0].items.weapon[i].power = 1;
772 
773 			player[1].items.weapon[REAR_WEAPON].id = 24;   // Banana Blast Rear
774 
775 			player[0].last_items = player[0].items;
776 		}
777 	}
778 
779 	if (newEpisode != episodeNum)
780 		JE_initEpisode(newEpisode);
781 
782 	gameLoaded = true;
783 	mainLevel = FIRST_LEVEL;
784 	saveLevel = FIRST_LEVEL;
785 
786 	play_song(26);
787 
788 	JE_clr256(VGAScreen);
789 	memcpy(colors, palettes[6-1], sizeof(colors));
790 
791 	JE_dString(VGAScreen, JE_fontCenter(episode_name[episodeNum], SMALL_FONT_SHAPES), 130, episode_name[episodeNum], SMALL_FONT_SHAPES);
792 	JE_dString(VGAScreen, JE_fontCenter(miscText[5-1], SMALL_FONT_SHAPES), 185, miscText[5-1], SMALL_FONT_SHAPES);
793 
794 	JE_showVGA();
795 	fade_palette(colors, 15, 0, 255);
796 
797 	JE_wipeKey();
798 	if (!constantPlay)
799 	{
800 		do
801 		{
802 			NETWORK_KEEP_ALIVE();
803 
804 			SDL_Delay(16);
805 		} while (!JE_anyButton());
806 	}
807 
808 	fade_black(15);
809 }
810 
JE_initPlayerData(void)811 void JE_initPlayerData( void )
812 {
813 	/* JE: New Game Items/Data */
814 
815 	player[0].items.ship = 1;                     // USP Talon
816 	player[0].items.weapon[FRONT_WEAPON].id = 1;  // Pulse Cannon
817 	player[0].items.weapon[REAR_WEAPON].id = 0;   // None
818 	player[0].items.shield = 4;                   // Gencore High Energy Shield
819 	player[0].items.generator = 2;                // Advanced MR-12
820 	for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i)
821 		player[0].items.sidekick[i] = 0;          // None
822 	player[0].items.special = 0;                  // None
823 
824 	player[0].last_items = player[0].items;
825 
826 	player[1].items = player[0].items;
827 	player[1].items.weapon[REAR_WEAPON].id = 15;  // Vulcan Cannon
828 	player[1].items.sidekick_level = 101;         // 101, 102, 103
829 	player[1].items.sidekick_series = 0;          // None
830 
831 	gameHasRepeated = false;
832 	onePlayerAction = false;
833 	superArcadeMode = SA_NONE;
834 	superTyrian = false;
835 	twoPlayerMode = false;
836 
837 	secretHint = (mt_rand() % 3) + 1;
838 
839 	for (uint p = 0; p < COUNTOF(player); ++p)
840 	{
841 		for (uint i = 0; i < COUNTOF(player->items.weapon); ++i)
842 		{
843 			player[p].items.weapon[i].power = 1;
844 		}
845 
846 		player[p].weapon_mode = 1;
847 		player[p].armor = ships[player[p].items.ship].dmg;
848 
849 		player[p].is_dragonwing = (p == 1);
850 		player[p].lives = &player[p].items.weapon[p].power;
851 
852 	}
853 
854 	mainLevel = FIRST_LEVEL;
855 	saveLevel = FIRST_LEVEL;
856 
857 	strcpy(lastLevelName, miscText[19]);
858 }
859 
JE_sortHighScores(void)860 void JE_sortHighScores( void )
861 {
862 	JE_byte x;
863 
864 	temp = 0;
865 	for (x = 0; x < 6; x++)
866 	{
867 		JE_sort();
868 		temp += 3;
869 	}
870 }
871 
JE_highScoreScreen(void)872 void JE_highScoreScreen( void )
873 {
874 	int min = 1;
875 	int max = 3;
876 
877 	int x, z;
878 	short int chg;
879 	int quit;
880 	char scoretemp[32];
881 
882 	free_sprite2s(&shapes6);
883 	JE_loadCompShapes(&shapes6, '1');  // need arrow sprites
884 
885 	fade_black(10);
886 	JE_loadPic(VGAScreen, 2, false);
887 	JE_showVGA();
888 	fade_palette(colors, 10, 0, 255);
889 
890 	quit = false;
891 	x = 1;
892 	chg = 1;
893 
894 	memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
895 
896 	do
897 	{
898 		if (episodeAvail[x-1])
899 		{
900 			memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
901 
902 			JE_dString(VGAScreen, JE_fontCenter(miscText[51 - 1], FONT_SHAPES), 03, miscText[51 - 1], FONT_SHAPES);
903 			JE_dString(VGAScreen, JE_fontCenter(episode_name[x], SMALL_FONT_SHAPES), 30, episode_name[x], SMALL_FONT_SHAPES);
904 
905 			/* Player 1 */
906 			temp = (x * 6) - 6;
907 
908 			JE_dString(VGAScreen, JE_fontCenter(miscText[47 - 1], SMALL_FONT_SHAPES), 55, miscText[47 - 1], SMALL_FONT_SHAPES);
909 
910 			for (z = 0; z < 3; z++)
911 			{
912 				int difficulty = saveFiles[temp + z].highScoreDiff;
913 				if (difficulty > 9)
914 				{
915 					saveFiles[temp + z].highScoreDiff = 0;
916 					difficulty = 0;
917 				}
918 				sprintf(scoretemp, "~#%d:~ %d", z + 1, saveFiles[temp+z].highScore1);
919 				JE_textShade(VGAScreen, 250, ((z+1) * 10) + 65 , difficultyNameB[difficulty], 15, difficulty + (difficulty == 0 ? 0 : -1), FULL_SHADE);
920 				JE_textShade(VGAScreen, 20, ((z+1) * 10) + 65 , scoretemp, 15, 0, FULL_SHADE);
921 				JE_textShade(VGAScreen, 110, ((z+1) * 10) + 65 , saveFiles[temp + z].highScoreName, 15, 2, FULL_SHADE);
922 			}
923 
924 			/* Player 2 */
925 			temp += 3;
926 
927 			JE_dString(VGAScreen, JE_fontCenter( miscText[48 - 1], SMALL_FONT_SHAPES), 120, miscText[48 - 1], SMALL_FONT_SHAPES);
928 
929 			/*{        textshade(20,125,misctext[49],15,3,_FullShade);
930 			  textshade(80,125,misctext[50],15,3,_FullShade);}*/
931 
932 			for (z = 0; z < 3; z++)
933 			{
934 				int difficulty = saveFiles[temp + z].highScoreDiff;
935 				if (difficulty > 9)
936 				{
937 					saveFiles[temp + z].highScoreDiff = 0;
938 					difficulty = 0;
939 				}
940 				sprintf(scoretemp, "~#%d:~ %d", z + 1, saveFiles[temp+z].highScore1); /* Not .highScore2 for some reason */
941 				JE_textShade(VGAScreen, 250, ((z+1) * 10) + 125 , difficultyNameB[difficulty], 15, difficulty + (difficulty == 0 ? 0 : -1), FULL_SHADE);
942 				JE_textShade(VGAScreen, 20, ((z+1) * 10) + 125 , scoretemp, 15, 0, FULL_SHADE);
943 				JE_textShade(VGAScreen, 110, ((z+1) * 10) + 125 , saveFiles[temp + z].highScoreName, 15, 2, FULL_SHADE);
944 			}
945 
946 			if (x > 1)
947 			{
948 				blit_sprite2x2(VGAScreen,  90, 180, shapes6, 279);
949 			}
950 
951 			if ( ( (x < 2) && episodeAvail[2-1] ) || ( (x < 3) && episodeAvail[3-1] ) )
952 			{
953 				blit_sprite2x2(VGAScreen,  220, 180, shapes6, 281);
954 			}
955 
956 			helpBoxColor = 15;
957 			JE_helpBox(VGAScreen, 110, 182, miscText[57 - 1], 25);
958 
959 			/* {Dstring(fontcenter(misctext[57],_SmallFontShapes),190,misctext[57],_SmallFontShapes);} */
960 
961 			JE_showVGA();
962 
963 			tempW = 0;
964 			JE_textMenuWait(&tempW, false);
965 
966 			if (newkey)
967 			{
968 				switch (lastkey_sym)
969 				{
970 				case SDLK_LEFT:
971 					x--;
972 					chg = -1;
973 					break;
974 				case SDLK_RIGHT:
975 					x++;
976 					chg = 1;
977 					break;
978 				default:
979 					break;
980 				}
981 			}
982 
983 		} else {
984 			x += chg;
985 		}
986 
987 		x = ( x < min ) ? max : ( x > max ) ? min : x;
988 
989 		if (newkey)
990 		{
991 			switch (lastkey_sym)
992 			{
993 			case SDLK_RETURN:
994 			case SDLK_ESCAPE:
995 				quit = true;
996 				break;
997 			default:
998 				break;
999 			}
1000 		}
1001 
1002 	} while (!quit);
1003 
1004 }
1005 
JE_gammaCorrect_func(JE_byte * col,JE_real r)1006 void JE_gammaCorrect_func( JE_byte *col, JE_real r )
1007 {
1008 	int temp = roundf(*col * r);
1009 	if (temp > 255)
1010 	{
1011 		temp = 255;
1012 	}
1013 	*col = temp;
1014 }
1015 
JE_gammaCorrect(Palette * colorBuffer,JE_byte gamma)1016 void JE_gammaCorrect( Palette *colorBuffer, JE_byte gamma )
1017 {
1018 	int x;
1019 	JE_real r = 1 + (JE_real)gamma / 10;
1020 
1021 	for (x = 0; x < 256; x++)
1022 	{
1023 		JE_gammaCorrect_func(&(*colorBuffer)[x].r, r);
1024 		JE_gammaCorrect_func(&(*colorBuffer)[x].g, r);
1025 		JE_gammaCorrect_func(&(*colorBuffer)[x].b, r);
1026 	}
1027 }
1028 
JE_gammaCheck(void)1029 JE_boolean JE_gammaCheck( void )
1030 {
1031 	bool temp = keysactive[SDLK_F11] != 0;
1032 	if (temp)
1033 	{
1034 		keysactive[SDLK_F11] = false;
1035 		newkey = false;
1036 		gammaCorrection = (gammaCorrection + 1) % 4;
1037 		memcpy(colors, palettes[pcxpal[3-1]], sizeof(colors));
1038 		JE_gammaCorrect(&colors, gammaCorrection);
1039 		set_palette(colors, 0, 255);
1040 	}
1041 	return temp;
1042 }
1043 
JE_doInGameSetup(void)1044 void JE_doInGameSetup( void )
1045 {
1046 	haltGame = false;
1047 
1048 #ifdef WITH_NETWORK
1049 	if (isNetworkGame)
1050 	{
1051 		network_prepare(PACKET_GAME_MENU);
1052 		network_send(4);  // PACKET_GAME_MENU
1053 
1054 		while (true)
1055 		{
1056 			service_SDL_events(false);
1057 
1058 			if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_GAME_MENU)
1059 			{
1060 				network_update();
1061 				break;
1062 			}
1063 
1064 			network_update();
1065 			network_check();
1066 
1067 			SDL_Delay(16);
1068 		}
1069 	}
1070 #endif
1071 
1072 	if (yourInGameMenuRequest)
1073 	{
1074 		if (JE_inGameSetup())
1075 		{
1076 			reallyEndLevel = true;
1077 			playerEndLevel = true;
1078 		}
1079 		quitRequested = false;
1080 
1081 		keysactive[SDLK_ESCAPE] = false;
1082 
1083 #ifdef WITH_NETWORK
1084 		if (isNetworkGame)
1085 		{
1086 			if (!playerEndLevel)
1087 			{
1088 				network_prepare(PACKET_WAITING);
1089 				network_send(4);  // PACKET_WAITING
1090 			} else {
1091 				network_prepare(PACKET_GAME_QUIT);
1092 				network_send(4);  // PACKET_GAMEQUIT
1093 			}
1094 		}
1095 #endif
1096 	}
1097 
1098 #ifdef WITH_NETWORK
1099 	if (isNetworkGame)
1100 	{
1101 		SDL_Surface *temp_surface = VGAScreen;
1102 		VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
1103 
1104 		if (!yourInGameMenuRequest)
1105 		{
1106 			JE_barShade(VGAScreen, 3, 60, 257, 80); /*Help Box*/
1107 			JE_barShade(VGAScreen, 5, 62, 255, 78);
1108 			JE_dString(VGAScreen, 10, 65, "Other player in options menu.", SMALL_FONT_SHAPES);
1109 			JE_showVGA();
1110 
1111 			while (true)
1112 			{
1113 				service_SDL_events(false);
1114 				JE_showVGA();
1115 
1116 				if (packet_in[0])
1117 				{
1118 					if (SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_WAITING)
1119 					{
1120 						network_check();
1121 						break;
1122 					} else if (SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_GAME_QUIT) {
1123 						reallyEndLevel = true;
1124 						playerEndLevel = true;
1125 
1126 						network_check();
1127 						break;
1128 					}
1129 				}
1130 
1131 				network_update();
1132 				network_check();
1133 
1134 				SDL_Delay(16);
1135 			}
1136 		} else {
1137 			/*
1138 			JE_barShade(3, 160, 257, 180); /-*Help Box*-/
1139 			JE_barShade(5, 162, 255, 178);
1140 			tempScreenSeg = VGAScreen;
1141 			JE_dString(VGAScreen, 10, 165, "Waiting for other player.", SMALL_FONT_SHAPES);
1142 			JE_showVGA();
1143 			*/
1144 		}
1145 
1146 		while (!network_is_sync())
1147 		{
1148 			service_SDL_events(false);
1149 
1150 			network_check();
1151 			SDL_Delay(16);
1152 		}
1153 
1154 		VGAScreen = temp_surface; /* side-effect of game_screen */
1155 	}
1156 #endif
1157 
1158 	yourInGameMenuRequest = false;
1159 
1160 	//skipStarShowVGA = true;
1161 }
1162 
JE_inGameSetup(void)1163 JE_boolean JE_inGameSetup( void )
1164 {
1165 	SDL_Surface *temp_surface = VGAScreen;
1166 	VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
1167 
1168 	JE_boolean returnvalue = false;
1169 
1170 	const JE_byte help[6] /* [1..6] */ = {15, 15, 28, 29, 26, 27};
1171 	JE_byte  sel;
1172 	JE_boolean quit;
1173 
1174 	bool first = true;
1175 
1176 	//tempScreenSeg = VGAScreenSeg; /* <MXD> ? should work as VGAScreen */
1177 
1178 	quit = false;
1179 	sel = 1;
1180 
1181 	JE_barShade(VGAScreen, 3, 13, 217, 137); /*Main Box*/
1182 	JE_barShade(VGAScreen, 5, 15, 215, 135);
1183 
1184 	JE_barShade(VGAScreen, 3, 143, 257, 157); /*Help Box*/
1185 	JE_barShade(VGAScreen, 5, 145, 255, 155);
1186 	memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
1187 
1188 	do
1189 	{
1190 		memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
1191 
1192 		for (x = 0; x < 6; x++)
1193 		{
1194 			JE_outTextAdjust(VGAScreen, 10, (x + 1) * 20, inGameText[x], 15, ((sel == x+1) << 1) - 4, SMALL_FONT_SHAPES, true);
1195 		}
1196 
1197 		JE_outTextAdjust(VGAScreen, 120, 3 * 20, detailLevel[processorType-1], 15, ((sel == 3) << 1) - 4, SMALL_FONT_SHAPES, true);
1198 		JE_outTextAdjust(VGAScreen, 120, 4 * 20, gameSpeedText[gameSpeed-1],   15, ((sel == 4) << 1) - 4, SMALL_FONT_SHAPES, true);
1199 
1200 		JE_outTextAdjust(VGAScreen, 10, 147, mainMenuHelp[help[sel-1]-1], 14, 6, TINY_FONT, true);
1201 
1202 		JE_barDrawShadow(VGAScreen, 120, 20, 1, music_disabled ? 12 : 16, tyrMusicVolume / 12, 3, 13);
1203 		JE_barDrawShadow(VGAScreen, 120, 40, 1, samples_disabled ? 12 : 16, fxVolume / 12, 3, 13);
1204 
1205 		JE_showVGA();
1206 
1207 		if (first)
1208 		{
1209 			first = false;
1210 			wait_noinput(false, false, true); // TODO: should up the joystick repeat temporarily instead
1211 		}
1212 
1213 		tempW = 0;
1214 		JE_textMenuWait(&tempW, true);
1215 
1216 		if (inputDetected)
1217 		{
1218 			switch (lastkey_sym)
1219 			{
1220 				case SDLK_RETURN:
1221 					JE_playSampleNum(S_SELECT);
1222 					switch (sel)
1223 					{
1224 						case 1:
1225 							music_disabled = !music_disabled;
1226 							break;
1227 						case 2:
1228 							samples_disabled = !samples_disabled;
1229 							break;
1230 						case 3:
1231 						case 4:
1232 							sel = 5;
1233 							break;
1234 						case 5:
1235 							quit = true;
1236 							break;
1237 						case 6:
1238 							returnvalue = true;
1239 							quit = true;
1240 							if (constantPlay)
1241 							{
1242 								JE_tyrianHalt(0);
1243 							}
1244 
1245 							if (isNetworkGame)
1246 							{ /*Tell other computer to exit*/
1247 								haltGame = true;
1248 								playerEndLevel = true;
1249 							}
1250 							break;
1251 					}
1252 					break;
1253 				case SDLK_ESCAPE:
1254 					quit = true;
1255 					JE_playSampleNum(S_SPRING);
1256 					break;
1257 				case SDLK_UP:
1258 					if (--sel < 1)
1259 					{
1260 						sel = 6;
1261 					}
1262 					JE_playSampleNum(S_CURSOR);
1263 					break;
1264 				case SDLK_DOWN:
1265 					if (++sel > 6)
1266 					{
1267 						sel = 1;
1268 					}
1269 					JE_playSampleNum(S_CURSOR);
1270 					break;
1271 				case SDLK_LEFT:
1272 					switch (sel)
1273 					{
1274 						case 1:
1275 							JE_changeVolume(&tyrMusicVolume, -12, &fxVolume, 0);
1276 							if (music_disabled)
1277 							{
1278 								music_disabled = false;
1279 								restart_song();
1280 							}
1281 							break;
1282 						case 2:
1283 							JE_changeVolume(&tyrMusicVolume, 0, &fxVolume, -12);
1284 							samples_disabled = false;
1285 							break;
1286 						case 3:
1287 							if (--processorType < 1)
1288 							{
1289 								processorType = 4;
1290 							}
1291 							JE_initProcessorType();
1292 							JE_setNewGameSpeed();
1293 							break;
1294 						case 4:
1295 							if (--gameSpeed < 1)
1296 							{
1297 								gameSpeed = 5;
1298 							}
1299 							JE_initProcessorType();
1300 							JE_setNewGameSpeed();
1301 							break;
1302 					}
1303 					if (sel < 5)
1304 					{
1305 						JE_playSampleNum(S_CURSOR);
1306 					}
1307 					break;
1308 				case SDLK_RIGHT:
1309 					switch (sel)
1310 					{
1311 						case 1:
1312 							JE_changeVolume(&tyrMusicVolume, 12, &fxVolume, 0);
1313 							if (music_disabled)
1314 							{
1315 								music_disabled = false;
1316 								restart_song();
1317 							}
1318 							break;
1319 						case 2:
1320 							JE_changeVolume(&tyrMusicVolume, 0, &fxVolume, 12);
1321 							samples_disabled = false;
1322 							break;
1323 						case 3:
1324 							if (++processorType > 4)
1325 							{
1326 								processorType = 1;
1327 							}
1328 							JE_initProcessorType();
1329 							JE_setNewGameSpeed();
1330 							break;
1331 						case 4:
1332 							if (++gameSpeed > 5)
1333 							{
1334 								gameSpeed = 1;
1335 							}
1336 							JE_initProcessorType();
1337 							JE_setNewGameSpeed();
1338 							break;
1339 					}
1340 					if (sel < 5)
1341 					{
1342 						JE_playSampleNum(S_CURSOR);
1343 					}
1344 					break;
1345 				case SDLK_w:
1346 					if (sel == 3)
1347 					{
1348 						processorType = 6;
1349 						JE_initProcessorType();
1350 					}
1351 				default:
1352 					break;
1353 			}
1354 		}
1355 
1356 	} while (!(quit || haltGame));
1357 
1358 	VGAScreen = temp_surface; /* side-effect of game_screen */
1359 
1360 	return returnvalue;
1361 }
1362 
JE_inGameHelp(void)1363 void JE_inGameHelp( void )
1364 {
1365 	SDL_Surface *temp_surface = VGAScreen;
1366 	VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
1367 
1368 	//tempScreenSeg = VGAScreenSeg;
1369 
1370 	JE_clearKeyboard();
1371 	JE_wipeKey();
1372 
1373 	JE_barShade(VGAScreen, 1, 1, 262, 182); /*Main Box*/
1374 	JE_barShade(VGAScreen, 3, 3, 260, 180);
1375 	JE_barShade(VGAScreen, 5, 5, 258, 178);
1376 	JE_barShade(VGAScreen, 7, 7, 256, 176);
1377 	fill_rectangle_xy(VGAScreen, 9, 9, 254, 174, 0);
1378 
1379 	if (twoPlayerMode)  // Two-Player Help
1380 	{
1381 		helpBoxColor = 3;
1382 		helpBoxBrightness = 3;
1383 		JE_HBox(VGAScreen, 20,  4, 36, 50);
1384 
1385 		// weapon help
1386 		blit_sprite(VGAScreenSeg, 2, 21, OPTION_SHAPES, 43);
1387 		helpBoxColor = 5;
1388 		helpBoxBrightness = 3;
1389 		JE_HBox(VGAScreen, 55, 20, 37, 40);
1390 
1391 		// sidekick help
1392 		blit_sprite(VGAScreenSeg, 5, 36, OPTION_SHAPES, 41);
1393 		helpBoxColor = 5;
1394 		helpBoxBrightness = 3;
1395 		JE_HBox(VGAScreen, 40, 43, 34, 44);
1396 
1397 		// sheild/armor help
1398 		blit_sprite(VGAScreenSeg, 2, 79, OPTION_SHAPES, 42);
1399 		helpBoxColor = 5;
1400 		helpBoxBrightness = 3;
1401 		JE_HBox(VGAScreen, 54, 84, 35, 40);
1402 
1403 		helpBoxColor = 5;
1404 		helpBoxBrightness = 3;
1405 		JE_HBox(VGAScreen, 5, 126, 38, 55);
1406 		helpBoxColor = 5;
1407 		helpBoxBrightness = 3;
1408 		JE_HBox(VGAScreen, 5, 160, 39, 55);
1409 	}
1410 	else
1411 	{
1412 		// power bar help
1413 		blit_sprite(VGAScreenSeg, 15, 5, OPTION_SHAPES, 40);
1414 		helpBoxColor = 5;
1415 		helpBoxBrightness = 3;
1416 		JE_HBox(VGAScreen, 40, 10, 31, 45);
1417 
1418 		// weapon help
1419 		blit_sprite(VGAScreenSeg, 5, 37, OPTION_SHAPES, 39);
1420 		helpBoxColor = 5;
1421 		helpBoxBrightness = 3;
1422 		JE_HBox(VGAScreen, 40, 40, 32, 44);
1423 		helpBoxColor = 5;
1424 		helpBoxBrightness = 3;
1425 		JE_HBox(VGAScreen, 40, 60, 33, 44);
1426 
1427 		// sidekick help
1428 		blit_sprite(VGAScreenSeg, 5, 98, OPTION_SHAPES, 41);
1429 		helpBoxColor = 5;
1430 		helpBoxBrightness = 3;
1431 		JE_HBox(VGAScreen, 40, 103, 34, 44);
1432 
1433 		// shield/armor help
1434 		blit_sprite(VGAScreenSeg, 2, 138, OPTION_SHAPES, 42);
1435 		helpBoxColor = 5;
1436 		helpBoxBrightness = 3;
1437 		JE_HBox(VGAScreen, 54, 143, 35, 40);
1438 	}
1439 
1440 	// "press a key"
1441 	blit_sprite(VGAScreenSeg, 16, 189, OPTION_SHAPES, 36);  // in-game text area
1442 	JE_outText(VGAScreenSeg, 120 - JE_textWidth(miscText[5-1], TINY_FONT) / 2 + 20, 190, miscText[5-1], 0, 4);
1443 
1444 	JE_showVGA();
1445 
1446 	do
1447 	{
1448 		tempW = 0;
1449 		JE_textMenuWait(&tempW, true);
1450 	}
1451 	while (!inputDetected);
1452 
1453 	textErase = 1;
1454 
1455 	VGAScreen = temp_surface;
1456 }
1457 
JE_highScoreCheck(void)1458 void JE_highScoreCheck( void )
1459 {
1460 	free_sprite2s(&shapes6);
1461 	JE_loadCompShapes(&shapes6, '1');  // need mouse cursor sprite
1462 
1463 	Sint32 temp_score;
1464 
1465 	for (int temp_p = 0; temp_p < (twoPlayerMode ? 2 : 1); ++temp_p)
1466 	{
1467 		JE_sortHighScores();
1468 
1469 		int p = temp_p;
1470 
1471 		if (twoPlayerMode)
1472 		{
1473 			// ask for the highest scorer first
1474 			if (player[0].cash < player[1].cash)
1475 				p = (temp_p == 0) ? 1 : 0;
1476 
1477 			temp_score = (p == 0) ? player[0].cash : player[1].cash;
1478 		}
1479 		else
1480 		{
1481 			// single player highscore includes cost of upgrades
1482 			temp_score = JE_totalScore(&player[0]);
1483 		}
1484 
1485 		int slot;
1486 		const int first_slot = (initial_episode_num - 1) * 6 + (twoPlayerMode ? 3 : 0),
1487 		          slot_limit = first_slot + 3;
1488 
1489 		for (slot = first_slot; slot < slot_limit; ++slot)
1490 		{
1491 			if (temp_score > saveFiles[slot].highScore1)
1492 				break;
1493 		}
1494 
1495 		// did you get a high score?
1496 		if (slot < slot_limit)
1497 		{
1498 			// shift down old scores
1499 			for (int i = slot_limit - 1; i > slot; --i)
1500 			{
1501 				saveFiles[i].highScore1 = saveFiles[i - 1].highScore1;
1502 				strcpy(saveFiles[i].highScoreName, saveFiles[i - 1].highScoreName);
1503 			}
1504 
1505 			wait_noinput(false, true, false);
1506 
1507 			JE_clr256(VGAScreen);
1508 			JE_showVGA();
1509 			memcpy(colors, palettes[0], sizeof(colors));
1510 
1511 			play_song(33);
1512 
1513 			{
1514 				/* Enter Thy name */
1515 
1516 				JE_byte flash = 8 * 16 + 10;
1517 				JE_boolean fadein = true;
1518 				JE_boolean quit = false, cancel = false;
1519 				char stemp[30], tempstr[30];
1520 				char buffer[256];
1521 
1522 				strcpy(stemp, "                             ");
1523 				temp = 0;
1524 
1525 				JE_barShade(VGAScreen, 65, 55, 255, 155);
1526 
1527 				do
1528 				{
1529 					service_SDL_events(true);
1530 
1531 					JE_dString(VGAScreen, JE_fontCenter(miscText[51], FONT_SHAPES), 3, miscText[51], FONT_SHAPES);
1532 
1533 					temp3 = twoPlayerMode ? 58 + p : 53;
1534 
1535 					JE_dString(VGAScreen, JE_fontCenter(miscText[temp3-1], SMALL_FONT_SHAPES), 30, miscText[temp3-1], SMALL_FONT_SHAPES);
1536 
1537 					blit_sprite(VGAScreenSeg, 50, 50, OPTION_SHAPES, 35);  // message box
1538 
1539 					if (twoPlayerMode)
1540 					{
1541 						sprintf(buffer, "%s %s", miscText[48 + p], miscText[53]);
1542 						JE_textShade(VGAScreen, 60, 55, buffer, 11, 4, FULL_SHADE);
1543 					}
1544 					else
1545 					{
1546 						JE_textShade(VGAScreen, 60, 55, miscText[53], 11, 4, FULL_SHADE);
1547 					}
1548 
1549 					sprintf(buffer, "%s %d", miscText[37], temp_score);
1550 					JE_textShade(VGAScreen, 70, 70, buffer, 11, 4, FULL_SHADE);
1551 
1552 					do
1553 					{
1554 						flash = (flash == 8 * 16 + 10) ? 8 * 16 + 2 : 8 * 16 + 10;
1555 						temp3 = (temp3 == 6) ? 2 : 6;
1556 
1557 						strncpy(tempstr, stemp, temp);
1558 						tempstr[temp] = '\0';
1559 						JE_outText(VGAScreen, 65, 89, tempstr, 8, 3);
1560 						tempW = 65 + JE_textWidth(tempstr, TINY_FONT);
1561 						JE_barShade(VGAScreen, tempW + 2, 90, tempW + 6, 95);
1562 						fill_rectangle_xy(VGAScreen, tempW + 1, 89, tempW + 5, 94, flash);
1563 
1564 						for (int i = 0; i < 14; i++)
1565 						{
1566 							setjasondelay(1);
1567 
1568 							JE_mouseStart();
1569 							JE_showVGA();
1570 							if (fadein)
1571 							{
1572 								fade_palette(colors, 15, 0, 255);
1573 								fadein = false;
1574 							}
1575 							JE_mouseReplace();
1576 
1577 							push_joysticks_as_keyboard();
1578 							service_wait_delay();
1579 
1580 							if (newkey || newmouse)
1581 								break;
1582 						}
1583 
1584 					} while (!newkey && !newmouse);
1585 
1586 					if (!playing)
1587 						play_song(31);
1588 
1589 					if (mouseButton > 0)
1590 					{
1591 						if (mouseX > 56 && mouseX < 142 && mouseY > 123 && mouseY < 149)
1592 						{
1593 							quit = true;
1594 						}
1595 						else if (mouseX > 151 && mouseX < 237 && mouseY > 123 && mouseY < 149)
1596 						{
1597 							quit = true;
1598 							cancel = true;
1599 						}
1600 					}
1601 					else if (newkey)
1602 					{
1603 						bool validkey = false;
1604 						lastkey_char = toupper(lastkey_char);
1605 						switch(lastkey_char)
1606 						{
1607 							case ' ':
1608 							case '-':
1609 							case '.':
1610 							case ',':
1611 							case ':':
1612 							case '!':
1613 							case '?':
1614 							case '#':
1615 							case '@':
1616 							case '$':
1617 							case '%':
1618 							case '*':
1619 							case '(':
1620 							case ')':
1621 							case '/':
1622 							case '=':
1623 							case '+':
1624 							case '<':
1625 							case '>':
1626 							case ';':
1627 							case '"':
1628 							case '\'':
1629 								validkey = true;
1630 							default:
1631 								if (temp < 28 && (validkey || (lastkey_char >= 'A' && lastkey_char <= 'Z') || (lastkey_char >= '0' && lastkey_char <= '9')))
1632 								{
1633 									stemp[temp] = lastkey_char;
1634 									temp++;
1635 								}
1636 								break;
1637 							case SDLK_BACKSPACE:
1638 							case SDLK_DELETE:
1639 								if (temp)
1640 								{
1641 									temp--;
1642 									stemp[temp] = ' ';
1643 								}
1644 								break;
1645 							case SDLK_ESCAPE:
1646 								quit = true;
1647 								cancel = true;
1648 								break;
1649 							case SDLK_RETURN:
1650 								quit = true;
1651 								break;
1652 						}
1653 					}
1654 				}
1655 				while (!quit);
1656 
1657 				if (!cancel)
1658 				{
1659 					saveFiles[slot].highScore1 = temp_score;
1660 					strcpy(saveFiles[slot].highScoreName, stemp);
1661 					saveFiles[slot].highScoreDiff = difficultyLevel;
1662 				}
1663 
1664 				fade_black(15);
1665 				JE_loadPic(VGAScreen, 2, false);
1666 
1667 				JE_dString(VGAScreen, JE_fontCenter(miscText[50], FONT_SHAPES), 10, miscText[50], FONT_SHAPES);
1668 				JE_dString(VGAScreen, JE_fontCenter(episode_name[episodeNum], SMALL_FONT_SHAPES), 35, episode_name[episodeNum], SMALL_FONT_SHAPES);
1669 
1670 				for (int i = first_slot; i < slot_limit; ++i)
1671 				{
1672 					if (i != slot)
1673 					{
1674 						sprintf(buffer, "~#%d:~  %d", (i - first_slot + 1), saveFiles[i].highScore1);
1675 						JE_textShade(VGAScreen,  20, ((i - first_slot + 1) * 12) + 65, buffer, 15, 0, FULL_SHADE);
1676 						JE_textShade(VGAScreen, 150, ((i - first_slot + 1) * 12) + 65, saveFiles[i].highScoreName, 15, 2, FULL_SHADE);
1677 					}
1678 				}
1679 
1680 				JE_showVGA();
1681 
1682 				fade_palette(colors, 15, 0, 255);
1683 
1684 				sprintf(buffer, "~#%d:~  %d", (slot - first_slot + 1), saveFiles[slot].highScore1);
1685 
1686 				frameCountMax = 6;
1687 				textGlowFont = TINY_FONT;
1688 
1689 				textGlowBrightness = 10;
1690 				JE_outTextGlow(VGAScreenSeg,  20, (slot - first_slot + 1) * 12 + 65, buffer);
1691 				textGlowBrightness = 10;
1692 				JE_outTextGlow(VGAScreenSeg, 150, (slot - first_slot + 1) * 12 + 65, saveFiles[slot].highScoreName);
1693 				textGlowBrightness = 10;
1694 				JE_outTextGlow(VGAScreenSeg, JE_fontCenter(miscText[4], TINY_FONT), 180, miscText[4]);
1695 
1696 				JE_showVGA();
1697 
1698 				if (frameCountMax != 0)
1699 					wait_input(true, true, true);
1700 
1701 				fade_black(15);
1702 			}
1703 
1704 		}
1705 	}
1706 }
1707 
1708 // increases game difficulty based on player's total score / total of players' scores
adjust_difficulty(void)1709 void adjust_difficulty( void )
1710 {
1711 	const float score_multiplier[10] =
1712 	{
1713 		0,     // Wimp  (doesn't exist)
1714 		0.4f,  // Easy
1715 		0.8f,  // Normal
1716 		1.3f,  // Hard
1717 		1.6f,  // Impossible
1718 		2,     // Insanity
1719 		2,     // Suicide
1720 		3,     // Maniacal
1721 		3,     // Zinglon
1722 		3,     // Nortaneous
1723 	};
1724 
1725 	assert(initialDifficulty > 0 && initialDifficulty < 10);
1726 
1727 	const ulong score = twoPlayerMode ? (player[0].cash + player[1].cash) : JE_totalScore(&player[0]),
1728 	            adjusted_score = roundf(score * score_multiplier[initialDifficulty]);
1729 
1730 	uint new_difficulty = 0;
1731 
1732 	if (twoPlayerMode)
1733 	{
1734 		if (adjusted_score < 10000)
1735 			new_difficulty = 1;  // Easy
1736 		else if (adjusted_score < 20000)
1737 			new_difficulty = 2;  // Normal
1738 		else if (adjusted_score < 50000)
1739 			new_difficulty = 3;  // Hard
1740 		else if (adjusted_score < 80000)
1741 			new_difficulty = 4;  // Impossible
1742 		else if (adjusted_score < 125000)
1743 			new_difficulty = 5;  // Insanity
1744 		else if (adjusted_score < 200000)
1745 			new_difficulty = 6;  // Suicide
1746 		else if (adjusted_score < 400000)
1747 			new_difficulty = 7;  // Maniacal
1748 		else if (adjusted_score < 600000)
1749 			new_difficulty = 8;  // Zinglon
1750 		else
1751 			new_difficulty = 9;  // Nortaneous
1752 	}
1753 	else
1754 	{
1755 		if (adjusted_score < 40000)
1756 			new_difficulty = 1;  // Easy
1757 		else if (adjusted_score < 70000)
1758 			new_difficulty = 2;  // Normal
1759 		else if (adjusted_score < 150000)
1760 			new_difficulty = 3;  // Hard
1761 		else if (adjusted_score < 300000)
1762 			new_difficulty = 4;  // Impossible
1763 		else if (adjusted_score < 600000)
1764 			new_difficulty = 5;  // Insanity
1765 		else if (adjusted_score < 1000000)
1766 			new_difficulty = 6;  // Suicide
1767 		else if (adjusted_score < 2000000)
1768 			new_difficulty = 7;  // Maniacal
1769 		else if (adjusted_score < 3000000)
1770 			new_difficulty = 8;  // Zinglon
1771 		else
1772 			new_difficulty = 9;  // Nortaneous
1773 	}
1774 
1775 	difficultyLevel = MAX((unsigned)difficultyLevel, new_difficulty);
1776 }
1777 
load_next_demo(void)1778 bool load_next_demo( void )
1779 {
1780 	if (++demo_num > 5)
1781 		demo_num = 1;
1782 
1783 	char demo_filename[9];
1784 	snprintf(demo_filename, sizeof(demo_filename), "demo.%d", demo_num);
1785 	demo_file = dir_fopen_die(data_dir(), demo_filename, "rb"); // TODO: only play demos from existing file (instead of dying)
1786 
1787 	difficultyLevel = 2;
1788 	bonusLevelCurrent = false;
1789 
1790 	Uint8 temp = fgetc(demo_file);
1791 	JE_initEpisode(temp);
1792 	efread(levelName, 1, 10, demo_file); levelName[10] = '\0';
1793 	lvlFileNum = fgetc(demo_file);
1794 
1795 	player[0].items.weapon[FRONT_WEAPON].id  = fgetc(demo_file);
1796 	player[0].items.weapon[REAR_WEAPON].id   = fgetc(demo_file);
1797 	player[0].items.super_arcade_mode        = fgetc(demo_file);
1798 	player[0].items.sidekick[LEFT_SIDEKICK]  = fgetc(demo_file);
1799 	player[0].items.sidekick[RIGHT_SIDEKICK] = fgetc(demo_file);
1800 	player[0].items.generator                = fgetc(demo_file);
1801 
1802 	player[0].items.sidekick_level           = fgetc(demo_file); // could probably ignore
1803 	player[0].items.sidekick_series          = fgetc(demo_file); // could probably ignore
1804 
1805 	initial_episode_num                      = fgetc(demo_file); // could probably ignore
1806 
1807 	player[0].items.shield                   = fgetc(demo_file);
1808 	player[0].items.special                  = fgetc(demo_file);
1809 	player[0].items.ship                     = fgetc(demo_file);
1810 
1811 	for (uint i = 0; i < 2; ++i)
1812 		player[0].items.weapon[i].power = fgetc(demo_file);
1813 
1814 	fseek(demo_file, 3, SEEK_CUR);
1815 
1816 	levelSong = fgetc(demo_file);
1817 
1818 	demo_keys_wait = 0;
1819 	demo_keys = next_demo_keys = 0;
1820 
1821 	printf("loaded demo '%s'\n", demo_filename);
1822 
1823 	return true;
1824 }
1825 
replay_demo_keys(void)1826 bool replay_demo_keys( void )
1827 {
1828 	if (demo_keys_wait == 0)
1829 		if (read_demo_keys() == false)
1830 			return false; // no more keys
1831 
1832 	if (demo_keys_wait > 0)
1833 		demo_keys_wait--;
1834 
1835 	if (demo_keys & (1 << 0))
1836 		player[0].y -= CURRENT_KEY_SPEED;
1837 	if (demo_keys & (1 << 1))
1838 		player[0].y += CURRENT_KEY_SPEED;
1839 
1840 	if (demo_keys & (1 << 2))
1841 		player[0].x -= CURRENT_KEY_SPEED;
1842 	if (demo_keys & (1 << 3))
1843 		player[0].x += CURRENT_KEY_SPEED;
1844 
1845 	button[0] = (bool)(demo_keys & (1 << 4));
1846 	button[3] = (bool)(demo_keys & (1 << 5));
1847 	button[1] = (bool)(demo_keys & (1 << 6));
1848 	button[2] = (bool)(demo_keys & (1 << 7));
1849 
1850 	return true;
1851 }
1852 
read_demo_keys(void)1853 bool read_demo_keys( void )
1854 {
1855 	demo_keys = next_demo_keys;
1856 
1857 	efread(&demo_keys_wait, sizeof(Uint16), 1, demo_file);
1858 	demo_keys_wait = SDL_Swap16(demo_keys_wait);
1859 
1860 	next_demo_keys = getc(demo_file);
1861 
1862 	return !feof(demo_file);
1863 }
1864 
1865 /*Street Fighter codes*/
JE_SFCodes(JE_byte playerNum_,JE_integer PX_,JE_integer PY_,JE_integer mouseX_,JE_integer mouseY_)1866 void JE_SFCodes( JE_byte playerNum_, JE_integer PX_, JE_integer PY_, JE_integer mouseX_, JE_integer mouseY_ )
1867 {
1868 	JE_byte temp, temp2, temp3, temp4, temp5;
1869 
1870 	uint ship = player[playerNum_-1].items.ship;
1871 
1872 	/*Get direction*/
1873 	if (playerNum_ == 2 && ship < 15)
1874 	{
1875 		ship = 0;
1876 	}
1877 
1878 	if (ship < 15)
1879 	{
1880 
1881 		temp2 = (mouseY_ > PY_) +    /*UP*/
1882 		        (mouseY_ < PY_) +    /*DOWN*/
1883 		        (PX_ < mouseX_) +    /*LEFT*/
1884 		        (PX_ > mouseX_);     /*RIGHT*/
1885 		temp = (mouseY_ > PY_) * 1 + /*UP*/
1886 		       (mouseY_ < PY_) * 2 + /*DOWN*/
1887 		       (PX_ < mouseX_) * 3 + /*LEFT*/
1888 		       (PX_ > mouseX_) * 4;  /*RIGHT*/
1889 
1890 		if (temp == 0) // no direction being pressed
1891 		{
1892 			if (!button[0]) // if fire button is released
1893 			{
1894 				temp = 9;
1895 				temp2 = 1;
1896 			} else {
1897 				temp2 = 0;
1898 				temp = 99;
1899 			}
1900 		}
1901 
1902 		if (temp2 == 1) // if exactly one direction pressed or firebutton is released
1903 		{
1904 			temp += button[0] * 4;
1905 
1906 			temp3 = superTyrian ? 21 : 3;
1907 			for (temp2 = 0; temp2 < temp3; temp2++)
1908 			{
1909 
1910 				/*Use SuperTyrian ShipCombos or not?*/
1911 				temp5 = superTyrian ? shipCombosB[temp2] : shipCombos[ship][temp2];
1912 
1913 				// temp5 == selected combo in ship
1914 				if (temp5 == 0) /* combo doesn't exists */
1915 				{
1916 					// mark twiddles as cancelled/finished
1917 					SFCurrentCode[playerNum_-1][temp2] = 0;
1918 				} else {
1919 					// get next combo key
1920 					temp4 = keyboardCombos[temp5-1][SFCurrentCode[playerNum_-1][temp2]];
1921 
1922 					// correct key
1923 					if (temp4 == temp)
1924 					{
1925 						SFCurrentCode[playerNum_-1][temp2]++;
1926 
1927 						temp4 = keyboardCombos[temp5-1][SFCurrentCode[playerNum_-1][temp2]];
1928 						if (temp4 > 100 && temp4 <= 100 + SPECIAL_NUM)
1929 						{
1930 							SFCurrentCode[playerNum_-1][temp2] = 0;
1931 							SFExecuted[playerNum_-1] = temp4 - 100;
1932 						}
1933 					} else {
1934 						if ((temp != 9) &&
1935 						    (temp4 - 1) % 4 != (temp - 1) % 4 &&
1936 						    (SFCurrentCode[playerNum_-1][temp2] == 0 ||
1937 						     keyboardCombos[temp5-1][SFCurrentCode[playerNum_-1][temp2]-1] != temp))
1938 						{
1939 							SFCurrentCode[playerNum_-1][temp2] = 0;
1940 						}
1941 					}
1942 				}
1943 			}
1944 		}
1945 
1946 	}
1947 }
1948 
JE_sort(void)1949 void JE_sort( void )
1950 {
1951 	JE_byte a, b;
1952 
1953 	for (a = 0; a < 2; a++)
1954 	{
1955 		for (b = a + 1; b < 3; b++)
1956 		{
1957 			if (saveFiles[temp + a].highScore1 < saveFiles[temp + b].highScore1)
1958 			{
1959 				JE_longint tempLI;
1960 				char tempStr[30];
1961 				JE_byte tempByte;
1962 
1963 				tempLI = saveFiles[temp + a].highScore1;
1964 				saveFiles[temp + a].highScore1 = saveFiles[temp + b].highScore1;
1965 				saveFiles[temp + b].highScore1 = tempLI;
1966 
1967 				strcpy(tempStr, saveFiles[temp + a].highScoreName);
1968 				strcpy(saveFiles[temp + a].highScoreName, saveFiles[temp + b].highScoreName);
1969 				strcpy(saveFiles[temp + b].highScoreName, tempStr);
1970 
1971 				tempByte = saveFiles[temp + a].highScoreDiff;
1972 				saveFiles[temp + a].highScoreDiff = saveFiles[temp + b].highScoreDiff;
1973 				saveFiles[temp + b].highScoreDiff = tempByte;
1974 			}
1975 		}
1976 	}
1977 }
1978 
JE_playCredits(void)1979 void JE_playCredits( void )
1980 {
1981 	const int lines_max = 132;
1982 	const int line_max_length = 65;
1983 
1984 	char credstr[lines_max][line_max_length + 1];
1985 
1986 	int lines = 0;
1987 
1988 	JE_byte currentpic = 0, fade = 0;
1989 	JE_shortint fadechg = 1;
1990 	JE_byte currentship = 0;
1991 	JE_integer shipx = 0, shipxwait = 0;
1992 	JE_shortint shipxc = 0, shipxca = 0;
1993 
1994 	load_sprites_file(EXTRA_SHAPES, "estsc.shp");
1995 
1996 	setjasondelay2(1000);
1997 
1998 	play_song(8);
1999 
2000 	// load credits text
2001 	FILE *f = dir_fopen_die(data_dir(), "tyrian.cdt", "rb");
2002 	for (lines = 0; !feof(f) && lines < lines_max; ++lines)
2003 	{
2004 		read_encrypted_pascal_string(credstr[lines], sizeof(credstr[lines]), f);
2005 	}
2006 	if (lines == lines_max)
2007 		--lines;
2008 	fclose(f);
2009 
2010 	memcpy(colors, palettes[6-1], sizeof(colors));
2011 	JE_clr256(VGAScreen);
2012 	JE_showVGA();
2013 	fade_palette(colors, 2, 0, 255);
2014 
2015 	//tempScreenSeg = VGAScreenSeg;
2016 
2017 	const int ticks_max = lines * 20 * 3;
2018 	for (int ticks = 0; ticks < ticks_max; ++ticks)
2019 	{
2020 		setjasondelay(1);
2021 		JE_clr256(VGAScreen);
2022 
2023 		blit_sprite_hv(VGAScreenSeg, 319 - sprite(EXTRA_SHAPES, currentpic)->width, 100 - (sprite(EXTRA_SHAPES, currentpic)->height / 2), EXTRA_SHAPES, currentpic, 0x0, fade - 15);
2024 
2025 		fade += fadechg;
2026 		if (fade == 0 && fadechg == -1)
2027 		{
2028 			fadechg = 1;
2029 			++currentpic;
2030 			if (currentpic >= sprite_table[EXTRA_SHAPES].count)
2031 				currentpic = 0;
2032 		}
2033 		if (fade == 15)
2034 			fadechg = 0;
2035 
2036 		if (delaycount2() == 0)
2037 		{
2038 			fadechg = -1;
2039 			setjasondelay2(900);
2040 		}
2041 
2042 		if (ticks % 200 == 0)
2043 		{
2044 			currentship = (mt_rand() % 11) + 1;
2045 			shipxwait = (mt_rand() % 80) + 10;
2046 			if ((mt_rand() % 2) == 1)
2047 			{
2048 				shipx = 1;
2049 				shipxc = 0;
2050 				shipxca = 1;
2051 			}
2052 			else
2053 			{
2054 				shipx = 900;
2055 				shipxc = 0;
2056 				shipxca = -1;
2057 			}
2058 		}
2059 
2060 		shipxwait--;
2061 		if (shipxwait == 0)
2062 		{
2063 			if (shipx == 1 || shipx == 900)
2064 				shipxc = 0;
2065 			shipxca = -shipxca;
2066 			shipxwait = (mt_rand() % 40) + 15;
2067 		}
2068 		shipxc += shipxca;
2069 		shipx += shipxc;
2070 		if (shipx < 1)
2071 		{
2072 			shipx = 1;
2073 			shipxwait = 1;
2074 		}
2075 		if (shipx > 900)
2076 		{
2077 			shipx = 900;
2078 			shipxwait = 1;
2079 		}
2080       	int tmp_unknown = shipxc * shipxc;
2081 		if (450 + tmp_unknown < 0 || 450 + tmp_unknown > 900)
2082 		{
2083 			if (shipxca < 0 && shipxc < 0)
2084 				shipxwait = 1;
2085 			if (shipxca > 0 && shipxc > 0)
2086 				shipxwait = 1;
2087 		}
2088 
2089 		uint ship_sprite = ships[currentship].shipgraphic;
2090 		if (shipxc < -10)
2091 			ship_sprite -= (shipxc < -20) ? 4 : 2;
2092 		else if (shipxc > 10)
2093 			ship_sprite += (shipxc > 20) ? 4 : 2;
2094 
2095 		blit_sprite2x2(VGAScreen, shipx / 40, 184 - (ticks % 200), shapes9, ship_sprite);
2096 
2097 		const int bottom_line = (ticks / 3) / 20;
2098 		int y = 20 - ((ticks / 3) % 20);
2099 
2100 		for (int line = bottom_line - 10; line < bottom_line; ++line)
2101 		{
2102 			if (line >= 0 && line < lines_max)
2103 			{
2104 				if (strcmp(&credstr[line][0], ".") != 0 && strlen(credstr[line]))
2105 				{
2106 					const Uint8 color = credstr[line][0] - 65;
2107 					const char *text = &credstr[line][1];
2108 
2109 					const int x = 110 - JE_textWidth(text, SMALL_FONT_SHAPES) / 2;
2110 
2111 					JE_outTextAdjust(VGAScreen, x + abs((y / 18) % 4 - 2) - 1, y - 1, text, color, -8, SMALL_FONT_SHAPES, false);
2112 					JE_outTextAdjust(VGAScreen, x,                             y,     text, color, -2, SMALL_FONT_SHAPES, false);
2113 				}
2114 			}
2115 
2116 			y += 20;
2117 		}
2118 
2119 		fill_rectangle_xy(VGAScreen, 0,  0, 319, 10, 0);
2120 		fill_rectangle_xy(VGAScreen, 0, 190, 319, 199, 0);
2121 
2122 		if (currentpic == sprite_table[EXTRA_SHAPES].count - 1)
2123 			JE_outTextAdjust(VGAScreen, 5, 180, miscText[54], 2, -2, SMALL_FONT_SHAPES, false);  // levels-in-episode
2124 
2125 		if (bottom_line == lines_max - 8)
2126 			fade_song();
2127 
2128 		if (ticks == ticks_max - 1)
2129 		{
2130 			--ticks;
2131 			play_song(9);
2132 		}
2133 
2134 		NETWORK_KEEP_ALIVE();
2135 
2136 		JE_showVGA();
2137 
2138 		wait_delay();
2139 
2140 		if (JE_anyButton())
2141 			break;
2142 	}
2143 
2144 	fade_black(10);
2145 
2146 	free_sprites(EXTRA_SHAPES);
2147 }
2148 
JE_endLevelAni(void)2149 void JE_endLevelAni( void )
2150 {
2151 	JE_word x, y;
2152 	JE_byte temp;
2153 	char tempStr[256];
2154 
2155 	Sint8 i;
2156 
2157 	if (!constantPlay)
2158 	{
2159 		// grant shipedit privileges
2160 
2161 		// special
2162 		if (player[0].items.special < 21)
2163 			saveTemp[SAVE_FILES_SIZE + 81 + player[0].items.special] = 1;
2164 
2165 		for (uint p = 0; p < COUNTOF(player); ++p)
2166 		{
2167 			// front, rear
2168 			for (uint i = 0; i < COUNTOF(player[p].items.weapon); ++i)
2169 				saveTemp[SAVE_FILES_SIZE + player[p].items.weapon[i].id] = 1;
2170 
2171 			// options
2172 			for (uint i = 0; i < COUNTOF(player[p].items.sidekick); ++i)
2173 				saveTemp[SAVE_FILES_SIZE + 51 + player[p].items.sidekick[i]] = 1;
2174 		}
2175 	}
2176 
2177 	adjust_difficulty();
2178 
2179 	player[0].last_items = player[0].items;
2180 	strcpy(lastLevelName, levelName);
2181 
2182 	JE_wipeKey();
2183 	frameCountMax = 4;
2184 	textGlowFont = SMALL_FONT_SHAPES;
2185 
2186 	SDL_Color white = { 255, 255, 255 };
2187 	set_colors(white, 254, 254);
2188 
2189 	if (!levelTimer || levelTimerCountdown > 0 || !(episodeNum == 4))
2190 		JE_playSampleNum(V_LEVEL_END);
2191 	else
2192 		play_song(21);
2193 
2194 	if (bonusLevel)
2195 	{
2196 		JE_outTextGlow(VGAScreenSeg, 20, 20, miscText[17-1]);
2197 	}
2198 	else if (all_players_alive())
2199 	{
2200 		sprintf(tempStr, "%s %s", miscText[27-1], levelName); // "Completed"
2201 		JE_outTextGlow(VGAScreenSeg, 20, 20, tempStr);
2202 	}
2203 	else
2204 	{
2205 		sprintf(tempStr, "%s %s", miscText[62-1], levelName); // "Exiting"
2206 		JE_outTextGlow(VGAScreenSeg, 20, 20, tempStr);
2207 	}
2208 
2209 	if (twoPlayerMode)
2210 	{
2211 		for (uint i = 0; i < 2; ++i)
2212 		{
2213 			snprintf(tempStr, sizeof(tempStr), "%s %lu", miscText[40 + i], player[i].cash);
2214 			JE_outTextGlow(VGAScreenSeg, 30, 50 + 20 * i, tempStr);
2215 		}
2216 	}
2217 	else
2218 	{
2219 		sprintf(tempStr, "%s %lu", miscText[28-1], player[0].cash);
2220 		JE_outTextGlow(VGAScreenSeg, 30, 50, tempStr);
2221 	}
2222 
2223 	temp = (totalEnemy == 0) ? 0 : roundf(enemyKilled * 100 / totalEnemy);
2224 	sprintf(tempStr, "%s %d%%", miscText[63-1], temp);
2225 	JE_outTextGlow(VGAScreenSeg, 40, 90, tempStr);
2226 
2227 	if (!constantPlay)
2228 		editorLevel += temp / 5;
2229 
2230 	if (!onePlayerAction && !twoPlayerMode)
2231 	{
2232 		JE_outTextGlow(VGAScreenSeg, 30, 120, miscText[4-1]);   /*Cubes*/
2233 
2234 		if (cubeMax > 0)
2235 		{
2236 			if (cubeMax > 4)
2237 				cubeMax = 4;
2238 
2239 			if (frameCountMax != 0)
2240 				frameCountMax = 1;
2241 
2242 			for (temp = 1; temp <= cubeMax; temp++)
2243 			{
2244 				NETWORK_KEEP_ALIVE();
2245 
2246 				JE_playSampleNum(18);
2247 				x = 20 + 30 * temp;
2248 				y = 135;
2249 				JE_drawCube(VGAScreenSeg, x, y, 9, 0);
2250 				JE_showVGA();
2251 
2252 				for (i = -15; i <= 10; i++)
2253 				{
2254 					setjasondelay(frameCountMax);
2255 
2256 					blit_sprite_hv(VGAScreenSeg, x, y, OPTION_SHAPES, 25, 0x9, i);
2257 
2258 					if (JE_anyButton())
2259 						frameCountMax = 0;
2260 
2261 					JE_showVGA();
2262 
2263 					wait_delay();
2264 				}
2265 				for (i = 10; i >= 0; i--)
2266 				{
2267 					setjasondelay(frameCountMax);
2268 
2269 					blit_sprite_hv(VGAScreenSeg, x, y, OPTION_SHAPES, 25, 0x9, i);
2270 
2271 					if (JE_anyButton())
2272 						frameCountMax = 0;
2273 
2274 					JE_showVGA();
2275 
2276 					wait_delay();
2277 				}
2278 			}
2279 		}
2280 		else
2281 		{
2282 			JE_outTextGlow(VGAScreenSeg, 50, 135, miscText[15-1]);
2283 		}
2284 
2285 	}
2286 
2287 	if (frameCountMax != 0)
2288 	{
2289 		frameCountMax = 6;
2290 		temp = 1;
2291 	} else {
2292 		temp = 0;
2293 	}
2294 	temp2 = twoPlayerMode ? 150 : 160;
2295 	JE_outTextGlow(VGAScreenSeg, 90, temp2, miscText[5-1]);
2296 
2297 	if (!constantPlay)
2298 	{
2299 		do
2300 		{
2301 			setjasondelay(1);
2302 
2303 			NETWORK_KEEP_ALIVE();
2304 
2305 			wait_delay();
2306 		} while (!(JE_anyButton() || (frameCountMax == 0 && temp == 1)));
2307 	}
2308 
2309 	wait_noinput(false, false, true); // TODO: should up the joystick repeat temporarily instead
2310 
2311 	fade_black(15);
2312 	JE_clr256(VGAScreen);
2313 }
2314 
JE_drawCube(SDL_Surface * screen,JE_word x,JE_word y,JE_byte filter,JE_byte brightness)2315 void JE_drawCube( SDL_Surface * screen, JE_word x, JE_word y, JE_byte filter, JE_byte brightness )
2316 {
2317 	blit_sprite_dark(screen, x + 4, y + 4, OPTION_SHAPES, 25, false);
2318 	blit_sprite_dark(screen, x + 3, y + 3, OPTION_SHAPES, 25, false);
2319 	blit_sprite_hv(screen, x, y, OPTION_SHAPES, 25, filter, brightness);
2320 }
2321 
JE_handleChat(void)2322 void JE_handleChat( void )
2323 {
2324 	// STUB(); Annoying piece of crap =P
2325 }
2326 
str_pop_int(char * str,int * val)2327 bool str_pop_int( char *str, int *val )
2328 {
2329 	bool success = false;
2330 
2331 	char buf[256];
2332 	assert(strlen(str) < sizeof(buf));
2333 
2334 	// grab the value from str
2335 	char *end;
2336 	*val = strtol(str, &end, 10);
2337 
2338 	if (end != str)
2339 	{
2340 		success = true;
2341 
2342 		// shift the rest to the beginning
2343 		strcpy(buf, end);
2344 		strcpy(str, buf);
2345 	}
2346 
2347 	return success;
2348 }
2349 
JE_operation(JE_byte slot)2350 void JE_operation( JE_byte slot )
2351 {
2352 	JE_byte flash;
2353 	char stemp[21];
2354 	char tempStr[51];
2355 
2356 	if (!performSave)
2357 	{
2358 		if (saveFiles[slot-1].level > 0)
2359 		{
2360 			gameJustLoaded = true;
2361 			JE_loadGame(slot);
2362 			gameLoaded = true;
2363 		}
2364 	}
2365 	else if (slot % 11 != 0)
2366 	{
2367 		strcpy(stemp, "              ");
2368 		memcpy(stemp, saveFiles[slot-1].name, strlen(saveFiles[slot-1].name));
2369 		temp = strlen(stemp);
2370 		while (stemp[temp-1] == ' ' && --temp);
2371 
2372 		flash = 8 * 16 + 10;
2373 
2374 		wait_noinput(false, true, false);
2375 
2376 		JE_barShade(VGAScreen, 65, 55, 255, 155);
2377 
2378 		bool quit = false;
2379 		while (!quit)
2380 		{
2381 			service_SDL_events(true);
2382 
2383 			blit_sprite(VGAScreen, 50, 50, OPTION_SHAPES, 35);  // message box
2384 
2385 			JE_textShade(VGAScreen, 60, 55, miscText[1-1], 11, 4, DARKEN);
2386 			JE_textShade(VGAScreen, 70, 70, levelName, 11, 4, DARKEN);
2387 
2388 			do
2389 			{
2390 				flash = (flash == 8 * 16 + 10) ? 8 * 16 + 2 : 8 * 16 + 10;
2391 				temp3 = (temp3 == 6) ? 2 : 6;
2392 
2393 				strcpy(tempStr, miscText[2-1]);
2394 				strncat(tempStr, stemp, temp);
2395 				JE_outText(VGAScreen, 65, 89, tempStr, 8, 3);
2396 				tempW = 65 + JE_textWidth(tempStr, TINY_FONT);
2397 				JE_barShade(VGAScreen, tempW + 2, 90, tempW + 6, 95);
2398 				fill_rectangle_xy(VGAScreen, tempW + 1, 89, tempW + 5, 94, flash);
2399 
2400 				for (int i = 0; i < 14; i++)
2401 				{
2402 					setjasondelay(1);
2403 
2404 					JE_mouseStart();
2405 					JE_showVGA();
2406 					JE_mouseReplace();
2407 
2408 					push_joysticks_as_keyboard();
2409 					service_wait_delay();
2410 
2411 					if (newkey || newmouse)
2412 						break;
2413 				}
2414 
2415 			}
2416 			while (!newkey && !newmouse);
2417 
2418 			if (mouseButton > 0)
2419 			{
2420 				if (mouseX > 56 && mouseX < 142 && mouseY > 123 && mouseY < 149)
2421 				{
2422 					quit = true;
2423 					JE_saveGame(slot, stemp);
2424 					JE_playSampleNum(S_SELECT);
2425 				}
2426 				else if (mouseX > 151 && mouseX < 237 && mouseY > 123 && mouseY < 149)
2427 				{
2428 					quit = true;
2429 					JE_playSampleNum(S_SPRING);
2430 				}
2431 			}
2432 			else if (newkey)
2433 			{
2434 				bool validkey = false;
2435 				lastkey_char = toupper(lastkey_char);
2436 				switch (lastkey_char)
2437 				{
2438 					case ' ':
2439 					case '-':
2440 					case '.':
2441 					case ',':
2442 					case ':':
2443 					case '!':
2444 					case '?':
2445 					case '#':
2446 					case '@':
2447 					case '$':
2448 					case '%':
2449 					case '*':
2450 					case '(':
2451 					case ')':
2452 					case '/':
2453 					case '=':
2454 					case '+':
2455 					case '<':
2456 					case '>':
2457 					case ';':
2458 					case '"':
2459 					case '\'':
2460 						validkey = true;
2461 					default:
2462 						if (temp < 14 && (validkey || (lastkey_char >= 'A' && lastkey_char <= 'Z') || (lastkey_char >= '0' && lastkey_char <= '9')))
2463 						{
2464 							JE_playSampleNum(S_CURSOR);
2465 							stemp[temp] = lastkey_char;
2466 							temp++;
2467 						}
2468 						break;
2469 					case SDLK_BACKSPACE:
2470 					case SDLK_DELETE:
2471 						if (temp)
2472 						{
2473 							temp--;
2474 							stemp[temp] = ' ';
2475 							JE_playSampleNum(S_CLICK);
2476 						}
2477 						break;
2478 					case SDLK_ESCAPE:
2479 						quit = true;
2480 						JE_playSampleNum(S_SPRING);
2481 						break;
2482 					case SDLK_RETURN:
2483 						quit = true;
2484 						JE_saveGame(slot, stemp);
2485 						JE_playSampleNum(S_SELECT);
2486 						break;
2487 				}
2488 
2489 			}
2490 		}
2491 	}
2492 
2493 	wait_noinput(false, true, false);
2494 }
2495 
JE_inGameDisplays(void)2496 void JE_inGameDisplays( void )
2497 {
2498 	char stemp[21];
2499 	char tempstr[256];
2500 
2501 	for (uint i = 0; i < ((twoPlayerMode && !galagaMode) ? 2 : 1); ++i)
2502 	{
2503 		snprintf(tempstr, sizeof(tempstr), "%lu", player[i].cash);
2504 		JE_textShade(VGAScreen, 30 + 200 * i, 175, tempstr, 2, 4, FULL_SHADE);
2505 	}
2506 
2507 	/*Special Weapon?*/
2508 	if (player[0].items.special > 0)
2509 		blit_sprite2x2(VGAScreen, 25, 1, eShapes[5], special[player[0].items.special].itemgraphic);
2510 
2511 	/*Lives Left*/
2512 	if (onePlayerAction || twoPlayerMode)
2513 	{
2514 		for (int temp = 0; temp < (onePlayerAction ? 1 : 2); temp++)
2515 		{
2516 			const uint extra_lives = *player[temp].lives - 1;
2517 
2518 			int y = (temp == 0 && player[0].items.special > 0) ? 35 : 15;
2519 			tempW = (temp == 0) ? 30: 270;
2520 
2521 			if (extra_lives >= 5)
2522 			{
2523 				blit_sprite2(VGAScreen, tempW, y, shapes9, 285);
2524 				tempW = (temp == 0) ? 45 : 250;
2525 				sprintf(tempstr, "%d", extra_lives);
2526 				JE_textShade(VGAScreen, tempW, y + 3, tempstr, 15, 1, FULL_SHADE);
2527 			}
2528 			else if (extra_lives >= 1)
2529 			{
2530 				for (uint i = 0; i < extra_lives; ++i)
2531 				{
2532 					blit_sprite2(VGAScreen, tempW, y, shapes9, 285);
2533 
2534 					tempW += (temp == 0) ? 12 : -12;
2535 				}
2536 			}
2537 
2538 			strcpy(stemp, (temp == 0) ? miscText[49-1] : miscText[50-1]);
2539 			if (isNetworkGame)
2540 			{
2541 				strcpy(stemp, JE_getName(temp+1));
2542 			}
2543 
2544 			tempW = (temp == 0) ? 28 : (285 - JE_textWidth(stemp, TINY_FONT));
2545 			JE_textShade(VGAScreen, tempW, y - 7, stemp, 2, 6, FULL_SHADE);
2546 		}
2547 	}
2548 
2549 	/*Super Bombs!!*/
2550 	for (uint i = 0; i < COUNTOF(player); ++i)
2551 	{
2552 		int x = (i == 0) ? 30 : 270;
2553 
2554 		for (uint j = player[i].superbombs; j > 0; --j)
2555 		{
2556 			blit_sprite2(VGAScreen, x, 160, shapes9, 304);
2557 			x += (i == 0) ? 12 : -12;
2558 		}
2559 	}
2560 
2561 	if (youAreCheating)
2562 	{
2563 		JE_outText(VGAScreen, 90, 170, "Cheaters always prosper.", 3, 4);
2564 	}
2565 }
2566 
JE_mainKeyboardInput(void)2567 void JE_mainKeyboardInput( void )
2568 {
2569 	JE_gammaCheck();
2570 
2571 	/* { Network Request Commands } */
2572 
2573 	if (!isNetworkGame)
2574 	{
2575 		/* { Edited Ships } for Player 1 */
2576 		if (extraAvail && keysactive[SDLK_TAB] && !isNetworkGame && !superTyrian)
2577 		{
2578 			for (x = SDLK_0; x <= SDLK_9; x++)
2579 			{
2580 				if (keysactive[x])
2581 				{
2582 					int z = x == SDLK_0 ? 10 : x - SDLK_0;
2583 					player[0].items.ship = 90 + z;                     /*Ships*/
2584 					z = (z - 1) * 15;
2585 					player[0].items.weapon[FRONT_WEAPON].id = extraShips[z + 1];
2586 					player[0].items.weapon[REAR_WEAPON].id = extraShips[z + 2];
2587 					player[0].items.special = extraShips[z + 3];
2588 					player[0].items.sidekick[LEFT_SIDEKICK] = extraShips[z + 4];
2589 					player[0].items.sidekick[RIGHT_SIDEKICK] = extraShips[z + 5];
2590 					player[0].items.generator = extraShips[z + 6];
2591 					/*Armor*/
2592 					player[0].items.shield = extraShips[z + 8];
2593 					memset(shotMultiPos, 0, sizeof(shotMultiPos));
2594 
2595 					if (player[0].weapon_mode > JE_portConfigs())
2596 						player[0].weapon_mode = 1;
2597 
2598 					tempW = player[0].armor;
2599 					JE_getShipInfo();
2600 					if (player[0].armor > tempW && editShip1)
2601 						player[0].armor = tempW;
2602 					else
2603 						editShip1 = true;
2604 
2605 					SDL_Surface *temp_surface = VGAScreen;
2606 					VGAScreen = VGAScreenSeg;
2607 					JE_wipeShieldArmorBars();
2608 					JE_drawArmor();
2609 					JE_drawShield();
2610 					VGAScreen = temp_surface;
2611 					JE_drawOptions();
2612 
2613 					keysactive[x] = false;
2614 				}
2615 			}
2616 		}
2617 
2618 		/* for Player 2 */
2619 		if (extraAvail && keysactive[SDLK_CAPSLOCK] && !isNetworkGame && !superTyrian)
2620 		{
2621 			for (x = SDLK_0; x <= SDLK_9; x++)
2622 			{
2623 				if (keysactive[x])
2624 				{
2625 					int z = x == SDLK_0 ? 10 : x - SDLK_0;
2626 					player[1].items.ship = 90 + z;
2627 					z = (z - 1) * 15;
2628 					player[1].items.weapon[FRONT_WEAPON].id = extraShips[z + 1];
2629 					player[1].items.weapon[REAR_WEAPON].id = extraShips[z + 2];
2630 					player[1].items.special = extraShips[z + 3];
2631 					player[1].items.sidekick[LEFT_SIDEKICK] = extraShips[z + 4];
2632 					player[1].items.sidekick[RIGHT_SIDEKICK] = extraShips[z + 5];
2633 					player[1].items.generator = extraShips[z + 6];
2634 					/*Armor*/
2635 					player[1].items.shield = extraShips[z + 8];
2636 					memset(shotMultiPos, 0, sizeof(shotMultiPos));
2637 
2638 					if (player[1].weapon_mode > JE_portConfigs())
2639 						player[1].weapon_mode = 1;
2640 
2641 					tempW = player[1].armor;
2642 					JE_getShipInfo();
2643 					if (player[1].armor > tempW && editShip2)
2644 						player[1].armor = tempW;
2645 					else
2646 						editShip2 = true;
2647 
2648 					SDL_Surface *temp_surface = VGAScreen;
2649 					VGAScreen = VGAScreenSeg;
2650 					JE_wipeShieldArmorBars();
2651 					JE_drawArmor();
2652 					JE_drawShield();
2653 					VGAScreen = temp_surface;
2654 					JE_drawOptions();
2655 
2656 					keysactive[x] = false;
2657 				}
2658 			}
2659 		}
2660 	}
2661 
2662 	/* { In-Game Help } */
2663 	if (keysactive[SDLK_F1])
2664 	{
2665 		if (isNetworkGame)
2666 		{
2667 			helpRequest = true;
2668 		} else {
2669 			JE_inGameHelp();
2670 			skipStarShowVGA = true;
2671 		}
2672 	}
2673 
2674 	/* {!Activate Nort Ship!} */
2675 	if (keysactive[SDLK_F2] && keysactive[SDLK_F4] && keysactive[SDLK_F6] && keysactive[SDLK_F7] &&
2676 	    keysactive[SDLK_F9] && keysactive[SDLK_BACKSLASH] && keysactive[SDLK_SLASH])
2677 	{
2678 		if (isNetworkGame)
2679 		{
2680 			nortShipRequest = true;
2681 		}
2682 		else
2683 		{
2684 			player[0].items.ship = 12;                     // Nort Ship
2685 			player[0].items.special = 13;                  // Astral Zone
2686 			player[0].items.weapon[FRONT_WEAPON].id = 36;  // NortShip Super Pulse
2687 			player[0].items.weapon[REAR_WEAPON].id = 37;   // NortShip Spreader
2688 			shipGr = 1;
2689 		}
2690 	}
2691 
2692 	/* {Cheating} */
2693 	if (!isNetworkGame && !twoPlayerMode && !superTyrian && superArcadeMode == SA_NONE)
2694 	{
2695 		if (keysactive[SDLK_F2] && keysactive[SDLK_F3] && keysactive[SDLK_F6])
2696 		{
2697 			youAreCheating = !youAreCheating;
2698 			keysactive[SDLK_F2] = false;
2699 		}
2700 
2701 		if (keysactive[SDLK_F2] && keysactive[SDLK_F3] && (keysactive[SDLK_F4] || keysactive[SDLK_F5]))
2702 		{
2703 			for (uint i = 0; i < COUNTOF(player); ++i)
2704 				player[i].armor = 0;
2705 
2706 			youAreCheating = !youAreCheating;
2707 			JE_drawTextWindow(miscText[63-1]);
2708 		}
2709 
2710 		if (constantPlay && keysactive[SDLK_c])
2711 		{
2712 			youAreCheating = !youAreCheating;
2713 			keysactive[SDLK_c] = false;
2714 		}
2715 	}
2716 
2717 	if (superTyrian)
2718 	{
2719 		youAreCheating = false;
2720 	}
2721 
2722 	/* {Personal Commands} */
2723 
2724 	/* {DEBUG} */
2725 	if (keysactive[SDLK_F10] && keysactive[SDLK_BACKSPACE])
2726 	{
2727 		keysactive[SDLK_F10] = false;
2728 		debug = !debug;
2729 
2730 		debugHist = 1;
2731 		debugHistCount = 1;
2732 
2733 		/* YKS: clock ticks since midnight replaced by SDL_GetTicks */
2734 		lastDebugTime = SDL_GetTicks();
2735 	}
2736 
2737 	/* {CHEAT-SKIP LEVEL} */
2738 	if (keysactive[SDLK_F2] && keysactive[SDLK_F6] && (keysactive[SDLK_F7] || keysactive[SDLK_F8]) && !keysactive[SDLK_F9]
2739 	    && !superTyrian && superArcadeMode == SA_NONE)
2740 	{
2741 		if (isNetworkGame)
2742 		{
2743 			skipLevelRequest = true;
2744 		} else {
2745 			levelTimer = true;
2746 			levelTimerCountdown = 0;
2747 			endLevel = true;
2748 			levelEnd = 40;
2749 		}
2750 	}
2751 
2752 	/* pause game */
2753 	pause_pressed = pause_pressed || keysactive[SDLK_p];
2754 
2755 	/* in-game setup */
2756 	ingamemenu_pressed = ingamemenu_pressed || keysactive[SDLK_ESCAPE];
2757 
2758 	if (keysactive[SDLK_BACKSPACE])
2759 	{
2760 		/* toggle screenshot pause */
2761 		if (keysactive[SDLK_NUMLOCK])
2762 		{
2763 			superPause = !superPause;
2764 		}
2765 
2766 		/* {SMOOTHIES} */
2767 		if (keysactive[SDLK_F12] && keysactive[SDLK_SCROLLOCK])
2768 		{
2769 			for (temp = SDLK_2; temp <= SDLK_9; temp++)
2770 			{
2771 				if (keysactive[temp])
2772 				{
2773 					smoothies[temp-SDLK_2] = !smoothies[temp-SDLK_2];
2774 				}
2775 			}
2776 			if (keysactive[SDLK_0])
2777 			{
2778 				smoothies[8] = !smoothies[8];
2779 			}
2780 		} else
2781 
2782 		/* {CYCLE THROUGH FILTER COLORS} */
2783 		if (keysactive[SDLK_MINUS])
2784 		{
2785 			if (levelFilter == -99)
2786 			{
2787 				levelFilter = 0;
2788 			} else {
2789 				levelFilter++;
2790 				if (levelFilter == 16)
2791 				{
2792 					levelFilter = -99;
2793 				}
2794 			}
2795 		} else
2796 
2797 		/* {HYPER-SPEED} */
2798 		if (keysactive[SDLK_1])
2799 		{
2800 			fastPlay++;
2801 			if (fastPlay > 2)
2802 			{
2803 				fastPlay = 0;
2804 			}
2805 			keysactive[SDLK_1] = false;
2806 			JE_setNewGameSpeed();
2807 		}
2808 
2809 		/* {IN-GAME RANDOM MUSIC SELECTION} */
2810 		if (keysactive[SDLK_SCROLLOCK])
2811 		{
2812 			play_song(mt_rand() % MUSIC_NUM);
2813 		}
2814 	}
2815 }
2816 
JE_pauseGame(void)2817 void JE_pauseGame( void )
2818 {
2819 	JE_boolean done = false;
2820 	JE_word mouseX, mouseY;
2821 
2822 	//tempScreenSeg = VGAScreenSeg; // sega000
2823 	if (!superPause)
2824 	{
2825 		JE_dString(VGAScreenSeg, 120, 90, miscText[22], FONT_SHAPES);
2826 
2827 		VGAScreen = VGAScreenSeg;
2828 		JE_showVGA();
2829 	}
2830 
2831 	set_volume(tyrMusicVolume / 2, fxVolume);
2832 
2833 #ifdef WITH_NETWORK
2834 	if (isNetworkGame)
2835 	{
2836 		network_prepare(PACKET_GAME_PAUSE);
2837 		network_send(4);  // PACKET_GAME_PAUSE
2838 
2839 		while (true)
2840 		{
2841 			service_SDL_events(false);
2842 
2843 			if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_GAME_PAUSE)
2844 			{
2845 				network_update();
2846 				break;
2847 			}
2848 
2849 			network_update();
2850 			network_check();
2851 
2852 			SDL_Delay(16);
2853 		}
2854 	}
2855 #endif
2856 
2857 	wait_noinput(false, false, true); // TODO: should up the joystick repeat temporarily instead
2858 
2859 	do
2860 	{
2861 		setjasondelay(2);
2862 
2863 		push_joysticks_as_keyboard();
2864 		service_SDL_events(true);
2865 
2866 		if ((newkey && lastkey_sym != SDLK_LCTRL && lastkey_sym != SDLK_RCTRL && lastkey_sym != SDLK_LALT && lastkey_sym != SDLK_RALT)
2867 		    || JE_mousePosition(&mouseX, &mouseY) > 0)
2868 		{
2869 #ifdef WITH_NETWORK
2870 			if (isNetworkGame)
2871 			{
2872 				network_prepare(PACKET_WAITING);
2873 				network_send(4);  // PACKET_WAITING
2874 			}
2875 #endif
2876 			done = true;
2877 		}
2878 
2879 #ifdef WITH_NETWORK
2880 		if (isNetworkGame)
2881 		{
2882 			network_check();
2883 
2884 			if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_WAITING)
2885 			{
2886 				network_check();
2887 
2888 				done = true;
2889 			}
2890 		}
2891 #endif
2892 
2893 		wait_delay();
2894 	} while (!done);
2895 
2896 #ifdef WITH_NETWORK
2897 	if (isNetworkGame)
2898 	{
2899 		while (!network_is_sync())
2900 		{
2901 			service_SDL_events(false);
2902 
2903 			network_check();
2904 			SDL_Delay(16);
2905 		}
2906 	}
2907 #endif
2908 
2909 	set_volume(tyrMusicVolume, fxVolume);
2910 
2911 	//skipStarShowVGA = true;
2912 }
2913 
JE_playerMovement(Player * this_player,JE_byte inputDevice,JE_byte playerNum_,JE_word shipGr_,Sprite2_array * shapes9ptr_,JE_word * mouseX_,JE_word * mouseY_)2914 void JE_playerMovement( Player *this_player,
2915                         JE_byte inputDevice,
2916                         JE_byte playerNum_,
2917                         JE_word shipGr_,
2918                         Sprite2_array *shapes9ptr_,
2919                         JE_word *mouseX_, JE_word *mouseY_ )
2920 {
2921 	JE_integer mouseXC, mouseYC;
2922 	JE_integer accelXC, accelYC;
2923 
2924 	if (playerNum_ == 2 || !twoPlayerMode)
2925 	{
2926 		tempW = weaponPort[this_player->items.weapon[REAR_WEAPON].id].opnum;
2927 
2928 		if (this_player->weapon_mode > tempW)
2929 			this_player->weapon_mode = 1;
2930 	}
2931 
2932 #ifdef WITH_NETWORK
2933 	if (isNetworkGame && thisPlayerNum == playerNum_)
2934 	{
2935 		network_state_prepare();
2936 		memset(&packet_state_out[0]->data[4], 0, 10);
2937 	}
2938 #endif
2939 
2940 redo:
2941 
2942 	if (isNetworkGame)
2943 	{
2944 		inputDevice = 0;
2945 	}
2946 
2947 	mouseXC = 0;
2948 	mouseYC = 0;
2949 	accelXC = 0;
2950 	accelYC = 0;
2951 
2952 	bool link_gun_analog = false;
2953 	float link_gun_angle = 0;
2954 
2955 	/* Draw Player */
2956 	if (!this_player->is_alive)
2957 	{
2958 		if (this_player->exploding_ticks > 0)
2959 		{
2960 			--this_player->exploding_ticks;
2961 
2962 			if (levelEndFxWait > 0)
2963 			{
2964 				levelEndFxWait--;
2965 			}
2966 			else
2967 			{
2968 				levelEndFxWait = (mt_rand() % 6) + 3;
2969 				if ((mt_rand() % 3) == 1)
2970 					soundQueue[6] = S_EXPLOSION_9;
2971 				else
2972 					soundQueue[5] = S_EXPLOSION_11;
2973 			}
2974 
2975 			int explosion_x = this_player->x + (mt_rand() % 32) - 16;
2976 			int explosion_y = this_player->y + (mt_rand() % 32) - 16;
2977 			JE_setupExplosionLarge(false, 0, explosion_x, explosion_y + 7);
2978 			JE_setupExplosionLarge(false, 0, this_player->x, this_player->y + 7);
2979 
2980 			if (levelEnd > 0)
2981 				levelEnd--;
2982 		}
2983 		else
2984 		{
2985 			if (twoPlayerMode || onePlayerAction)  // if arcade mode
2986 			{
2987 				if (*this_player->lives > 1)  // respawn if any extra lives
2988 				{
2989 					--(*this_player->lives);
2990 
2991 					reallyEndLevel = false;
2992 					shotMultiPos[playerNum_-1] = 0;
2993 					calc_purple_balls_needed(this_player);
2994 					twoPlayerLinked = false;
2995 					if (galagaMode)
2996 						twoPlayerMode = false;
2997 					this_player->y = 160;
2998 					this_player->invulnerable_ticks = 100;
2999 					this_player->is_alive = true;
3000 					endLevel = false;
3001 
3002 					if (galagaMode || episodeNum == 4)
3003 						this_player->armor = this_player->initial_armor;
3004 					else
3005 						this_player->armor = this_player->initial_armor / 2;
3006 
3007 					if (galagaMode)
3008 						this_player->shield = 0;
3009 					else
3010 						this_player->shield = this_player->shield_max / 2;
3011 
3012 					VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
3013 					JE_drawArmor();
3014 					JE_drawShield();
3015 					VGAScreen = game_screen; /* side-effect of game_screen */
3016 					goto redo;
3017 				}
3018 				else
3019 				{
3020 					if (galagaMode)
3021 						twoPlayerMode = false;
3022 					if (allPlayersGone && isNetworkGame)
3023 						reallyEndLevel = true;
3024 				}
3025 
3026 			}
3027 		}
3028 	}
3029 	else if (constantDie)
3030 	{
3031 		// finished exploding?  start dying again
3032 		if (this_player->exploding_ticks == 0)
3033 		{
3034 			this_player->shield = 0;
3035 
3036 			if (this_player->armor > 0)
3037 			{
3038 				--this_player->armor;
3039 			}
3040 			else
3041 			{
3042 				this_player->is_alive = false;
3043 				this_player->exploding_ticks = 60;
3044 				levelEnd = 40;
3045 			}
3046 
3047 			JE_wipeShieldArmorBars();
3048 			VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
3049 			JE_drawArmor();
3050 			VGAScreen = game_screen; /* side-effect of game_screen */
3051 
3052 			// as if instant death weren't enough, player also gets infinite lives in order to enjoy an infinite number of deaths -_-
3053 			if (*player[0].lives < 11)
3054 				++(*player[0].lives);
3055 		}
3056 	}
3057 
3058 
3059 	if (!this_player->is_alive)
3060 	{
3061 		explosionFollowAmountX = explosionFollowAmountY = 0;
3062 		return;
3063 	}
3064 
3065 	if (!endLevel)
3066 	{
3067 		*mouseX_ = this_player->x;
3068 		*mouseY_ = this_player->y;
3069 		button[1-1] = false;
3070 		button[2-1] = false;
3071 		button[3-1] = false;
3072 		button[4-1] = false;
3073 
3074 		/* --- Movement Routine Beginning --- */
3075 
3076 		if (!isNetworkGame || playerNum_ == thisPlayerNum)
3077 		{
3078 			if (endLevel)
3079 			{
3080 				this_player->y -= 2;
3081 			}
3082 			else
3083 			{
3084 				if (record_demo || play_demo)
3085 					inputDevice = 1;  // keyboard is required device for demo recording
3086 
3087 				// demo playback input
3088 				if (play_demo)
3089 				{
3090 					if (!replay_demo_keys())
3091 					{
3092 						endLevel = true;
3093 						levelEnd = 40;
3094 					}
3095 				}
3096 
3097 				/* joystick input */
3098 				if ((inputDevice == 0 || inputDevice >= 3) && joysticks > 0)
3099 				{
3100 					int j = inputDevice  == 0 ? 0 : inputDevice - 3;
3101 					int j_max = inputDevice == 0 ? joysticks : inputDevice - 3 + 1;
3102 					for (; j < j_max; j++)
3103 					{
3104 						poll_joystick(j);
3105 
3106 						if (joystick[j].analog)
3107 						{
3108 							mouseXC += joystick_axis_reduce(j, joystick[j].x);
3109 							mouseYC += joystick_axis_reduce(j, joystick[j].y);
3110 
3111 							link_gun_analog = joystick_analog_angle(j, &link_gun_angle);
3112 						}
3113 						else
3114 						{
3115 							this_player->x += (joystick[j].direction[3] ? -CURRENT_KEY_SPEED : 0) + (joystick[j].direction[1] ? CURRENT_KEY_SPEED : 0);
3116 							this_player->y += (joystick[j].direction[0] ? -CURRENT_KEY_SPEED : 0) + (joystick[j].direction[2] ? CURRENT_KEY_SPEED : 0);
3117 						}
3118 
3119 						button[0] |= joystick[j].action[0];
3120 						button[1] |= joystick[j].action[2];
3121 						button[2] |= joystick[j].action[3];
3122 						button[3] |= joystick[j].action_pressed[1];
3123 
3124 						ingamemenu_pressed |= joystick[j].action_pressed[4];
3125 						pause_pressed |= joystick[j].action_pressed[5];
3126 					}
3127 				}
3128 
3129 				service_SDL_events(false);
3130 
3131 				/* mouse input */
3132 				if ((inputDevice == 0 || inputDevice == 2) && has_mouse)
3133 				{
3134 					button[0] |= mouse_pressed[0];
3135 					button[1] |= mouse_pressed[1];
3136 					button[2] |= mouse_has_three_buttons ? mouse_pressed[2] : mouse_pressed[1];
3137 
3138 					if (input_grab_enabled)
3139 					{
3140 						mouseXC += mouse_x - 159;
3141 						mouseYC += mouse_y - 100;
3142 					}
3143 
3144 					if ((!isNetworkGame || playerNum_ == thisPlayerNum)
3145 					    && (!galagaMode || (playerNum_ == 2 || !twoPlayerMode || player[1].exploding_ticks > 0)))
3146 					{
3147 						set_mouse_position(159, 100);
3148 					}
3149 				}
3150 
3151 				/* keyboard input */
3152 				if ((inputDevice == 0 || inputDevice == 1) && !play_demo)
3153 				{
3154 					if (keysactive[keySettings[0]])
3155 						this_player->y -= CURRENT_KEY_SPEED;
3156 					if (keysactive[keySettings[1]])
3157 						this_player->y += CURRENT_KEY_SPEED;
3158 
3159 					if (keysactive[keySettings[2]])
3160 						this_player->x -= CURRENT_KEY_SPEED;
3161 					if (keysactive[keySettings[3]])
3162 						this_player->x += CURRENT_KEY_SPEED;
3163 
3164 					button[0] = button[0] || keysactive[keySettings[4]];
3165 					button[3] = button[3] || keysactive[keySettings[5]];
3166 					button[1] = button[1] || keysactive[keySettings[6]];
3167 					button[2] = button[2] || keysactive[keySettings[7]];
3168 
3169 					if (constantPlay)
3170 					{
3171 						for (unsigned int i = 0; i < 4; i++)
3172 							button[i] = true;
3173 
3174 						++this_player->y;
3175 						this_player->x += constantLastX;
3176 					}
3177 
3178 					// TODO: check if demo recording still works
3179 					if (record_demo)
3180 					{
3181 						bool new_input = false;
3182 
3183 						for (unsigned int i = 0; i < 8; i++)
3184 						{
3185 							bool temp = demo_keys & (1 << i);
3186 							if (temp != keysactive[keySettings[i]])
3187 								new_input = true;
3188 						}
3189 
3190 						demo_keys_wait++;
3191 
3192 						if (new_input)
3193 						{
3194 							demo_keys_wait = SDL_Swap16(demo_keys_wait);
3195 							efwrite(&demo_keys_wait, sizeof(Uint16), 1, demo_file);
3196 
3197 							demo_keys = 0;
3198 							for (unsigned int i = 0; i < 8; i++)
3199 								demo_keys |= keysactive[keySettings[i]] ? (1 << i) : 0;
3200 
3201 							fputc(demo_keys, demo_file);
3202 
3203 							demo_keys_wait = 0;
3204 						}
3205 					}
3206 				}
3207 
3208 				if (smoothies[9-1])
3209 				{
3210 					*mouseY_ = this_player->y - (*mouseY_ - this_player->y);
3211 					mouseYC = -mouseYC;
3212 				}
3213 
3214 				accelXC += this_player->x - *mouseX_;
3215 				accelYC += this_player->y - *mouseY_;
3216 
3217 				if (mouseXC > 30)
3218 					mouseXC = 30;
3219 				else if (mouseXC < -30)
3220 					mouseXC = -30;
3221 				if (mouseYC > 30)
3222 					mouseYC = 30;
3223 				else if (mouseYC < -30)
3224 					mouseYC = -30;
3225 
3226 				if (mouseXC > 0)
3227 					this_player->x += (mouseXC + 3) / 4;
3228 				else if (mouseXC < 0)
3229 					this_player->x += (mouseXC - 3) / 4;
3230 				if (mouseYC > 0)
3231 					this_player->y += (mouseYC + 3) / 4;
3232 				else if (mouseYC < 0)
3233 					this_player->y += (mouseYC - 3) / 4;
3234 
3235 				if (mouseXC > 3)
3236 					accelXC++;
3237 				else if (mouseXC < -2)
3238 					accelXC--;
3239 				if (mouseYC > 2)
3240 					accelYC++;
3241 				else if (mouseYC < -2)
3242 					accelYC--;
3243 
3244 			}   /*endLevel*/
3245 
3246 #ifdef WITH_NETWORK
3247 			if (isNetworkGame && playerNum_ == thisPlayerNum)
3248 			{
3249 				Uint16 buttons = 0;
3250 				for (int i = 4 - 1; i >= 0; i--)
3251 				{
3252 					buttons <<= 1;
3253 					buttons |= button[i];
3254 				}
3255 
3256 				SDLNet_Write16(this_player->x - *mouseX_, &packet_state_out[0]->data[4]);
3257 				SDLNet_Write16(this_player->y - *mouseY_, &packet_state_out[0]->data[6]);
3258 				SDLNet_Write16(accelXC,                   &packet_state_out[0]->data[8]);
3259 				SDLNet_Write16(accelYC,                   &packet_state_out[0]->data[10]);
3260 				SDLNet_Write16(buttons,                   &packet_state_out[0]->data[12]);
3261 
3262 				this_player->x = *mouseX_;
3263 				this_player->y = *mouseY_;
3264 
3265 				button[0] = false;
3266 				button[1] = false;
3267 				button[2] = false;
3268 				button[3] = false;
3269 
3270 				accelXC = 0;
3271 				accelYC = 0;
3272 			}
3273 #endif
3274 		}  /*isNetworkGame*/
3275 
3276 		/* --- Movement Routine Ending --- */
3277 
3278 		moveOk = true;
3279 
3280 #ifdef WITH_NETWORK
3281 		if (isNetworkGame && !network_state_is_reset())
3282 		{
3283 			if (playerNum_ != thisPlayerNum)
3284 			{
3285 				if (thisPlayerNum == 2)
3286 					difficultyLevel = SDLNet_Read16(&packet_state_in[0]->data[16]);
3287 
3288 				Uint16 buttons = SDLNet_Read16(&packet_state_in[0]->data[12]);
3289 				for (int i = 0; i < 4; i++)
3290 				{
3291 					button[i] = buttons & 1;
3292 					buttons >>= 1;
3293 				}
3294 
3295 				this_player->x += (Sint16)SDLNet_Read16(&packet_state_in[0]->data[4]);
3296 				this_player->y += (Sint16)SDLNet_Read16(&packet_state_in[0]->data[6]);
3297 				accelXC = (Sint16)SDLNet_Read16(&packet_state_in[0]->data[8]);
3298 				accelYC = (Sint16)SDLNet_Read16(&packet_state_in[0]->data[10]);
3299 			}
3300 			else
3301 			{
3302 				Uint16 buttons = SDLNet_Read16(&packet_state_out[network_delay]->data[12]);
3303 				for (int i = 0; i < 4; i++)
3304 				{
3305 					button[i] = buttons & 1;
3306 					buttons >>= 1;
3307 				}
3308 
3309 				this_player->x += (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[4]);
3310 				this_player->y += (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[6]);
3311 				accelXC = (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[8]);
3312 				accelYC = (Sint16)SDLNet_Read16(&packet_state_out[network_delay]->data[10]);
3313 			}
3314 		}
3315 #endif
3316 
3317 		/*Street-Fighter codes*/
3318 		JE_SFCodes(playerNum_, this_player->x, this_player->y, *mouseX_, *mouseY_);
3319 
3320 		if (moveOk)
3321 		{
3322 			/* END OF MOVEMENT ROUTINES */
3323 
3324 			/*Linking Routines*/
3325 
3326 			if (twoPlayerMode && !twoPlayerLinked && this_player->x == *mouseX_ && this_player->y == *mouseY_
3327 			    && abs(player[0].x - player[1].x) < 8 && abs(player[0].y - player[1].y) < 8
3328 			    && player[0].is_alive && player[1].is_alive && !galagaMode)
3329 			{
3330 				twoPlayerLinked = true;
3331 			}
3332 
3333 			if (playerNum_ == 1 && (button[3-1] || button[2-1]) && !galagaMode)
3334 				twoPlayerLinked = false;
3335 
3336 			if (twoPlayerMode && twoPlayerLinked && playerNum_ == 2
3337 			    && (this_player->x != *mouseX_ || this_player->y != *mouseY_))
3338 			{
3339 				if (button[0])
3340 				{
3341 					if (link_gun_analog)
3342 					{
3343 						linkGunDirec = link_gun_angle;
3344 					}
3345 					else
3346 					{
3347 						JE_real tempR;
3348 
3349 						if (abs(this_player->x - *mouseX_) > abs(this_player->y - *mouseY_))
3350 							tempR = (this_player->x - *mouseX_ > 0) ? M_PI_2 : (M_PI + M_PI_2);
3351 						else
3352 							tempR = (this_player->y - *mouseY_ > 0) ? 0 : M_PI;
3353 
3354 						if (fabsf(linkGunDirec - tempR) < 0.3f)
3355 							linkGunDirec = tempR;
3356 						else if (linkGunDirec < tempR && linkGunDirec - tempR > -3.24f)
3357 							linkGunDirec += 0.2f;
3358 						else if (linkGunDirec - tempR < M_PI)
3359 							linkGunDirec -= 0.2f;
3360 						else
3361 							linkGunDirec += 0.2f;
3362 					}
3363 
3364 					if (linkGunDirec >= (2 * M_PI))
3365 						linkGunDirec -= (2 * M_PI);
3366 					else if (linkGunDirec < 0)
3367 						linkGunDirec += (2 * M_PI);
3368 				}
3369 				else if (!galagaMode)
3370 				{
3371 					twoPlayerLinked = false;
3372 				}
3373 			}
3374 		}
3375 	}
3376 
3377 	if (levelEnd > 0 && all_players_dead())
3378 		reallyEndLevel = true;
3379 
3380 	/* End Level Fade-Out */
3381 	if (this_player->is_alive && endLevel)
3382 	{
3383 		if (levelEnd == 0)
3384 		{
3385 			reallyEndLevel = true;
3386 		}
3387 		else
3388 		{
3389 			this_player->y -= levelEndWarp;
3390 			if (this_player->y < -200)
3391 				reallyEndLevel = true;
3392 
3393 			int trail_spacing = 1;
3394 			int trail_y = this_player->y;
3395 			int num_trails = abs(41 - levelEnd);
3396 			if (num_trails > 20)
3397 				num_trails = 20;
3398 
3399 			for (int i = 0; i < num_trails; i++)
3400 			{
3401 				trail_y += trail_spacing;
3402 				trail_spacing++;
3403 			}
3404 
3405 			for (int i = 1; i < num_trails; i++)
3406 			{
3407 				trail_y -= trail_spacing;
3408 				trail_spacing--;
3409 
3410 				if (trail_y > 0 && trail_y < 170)
3411 				{
3412 					if (shipGr_ == 0)
3413 					{
3414 						blit_sprite2x2(VGAScreen, this_player->x - 17, trail_y - 7, *shapes9ptr_, 13);
3415 						blit_sprite2x2(VGAScreen, this_player->x + 7 , trail_y - 7, *shapes9ptr_, 51);
3416 					}
3417 					else if (shipGr_ == 1)
3418 					{
3419 						blit_sprite2x2(VGAScreen, this_player->x - 17, trail_y - 7, *shapes9ptr_, 220);
3420 						blit_sprite2x2(VGAScreen, this_player->x + 7 , trail_y - 7, *shapes9ptr_, 222);
3421 					}
3422 					else
3423 					{
3424 						blit_sprite2x2(VGAScreen, this_player->x - 5, trail_y - 7, *shapes9ptr_, shipGr_);
3425 					}
3426 				}
3427 			}
3428 		}
3429 	}
3430 
3431 	if (play_demo)
3432 		JE_dString(VGAScreen, 115, 10, miscText[7], SMALL_FONT_SHAPES); // insert coin
3433 
3434 	if (this_player->is_alive && !endLevel)
3435 	{
3436 		if (!twoPlayerLinked || playerNum_ < 2)
3437 		{
3438 			if (!twoPlayerMode || shipGr2 != 0)  // if not dragonwing
3439 			{
3440 				if (this_player->sidekick[LEFT_SIDEKICK].style == 0)
3441 				{
3442 					this_player->sidekick[LEFT_SIDEKICK].x = *mouseX_ - 14;
3443 					this_player->sidekick[LEFT_SIDEKICK].y = *mouseY_;
3444 				}
3445 
3446 				if (this_player->sidekick[RIGHT_SIDEKICK].style == 0)
3447 				{
3448 					this_player->sidekick[RIGHT_SIDEKICK].x = *mouseX_ + 16;
3449 					this_player->sidekick[RIGHT_SIDEKICK].y = *mouseY_;
3450 				}
3451 			}
3452 
3453 			if (this_player->x_friction_ticks > 0)
3454 			{
3455 				--this_player->x_friction_ticks;
3456 			}
3457 			else
3458 			{
3459 				this_player->x_friction_ticks = 1;
3460 
3461 				if (this_player->x_velocity < 0)
3462 					++this_player->x_velocity;
3463 				else if (this_player->x_velocity > 0)
3464 					--this_player->x_velocity;
3465 			}
3466 
3467 			if (this_player->y_friction_ticks > 0)
3468 			{
3469 				--this_player->y_friction_ticks;
3470 			}
3471 			else
3472 			{
3473 				this_player->y_friction_ticks = 2;
3474 
3475 				if (this_player->y_velocity < 0)
3476 					++this_player->y_velocity;
3477 				else if (this_player->y_velocity > 0)
3478 					--this_player->y_velocity;
3479 			}
3480 
3481 			this_player->x_velocity += accelXC;
3482 			this_player->y_velocity += accelYC;
3483 
3484 			this_player->x_velocity = MIN(MAX(-4, this_player->x_velocity), 4);
3485 			this_player->y_velocity = MIN(MAX(-4, this_player->y_velocity), 4);
3486 
3487 			this_player->x += this_player->x_velocity;
3488 			this_player->y += this_player->y_velocity;
3489 
3490 			// if player moved, add new ship x, y history entry
3491 			if (this_player->x - *mouseX_ != 0 || this_player->y - *mouseY_ != 0)
3492 			{
3493 				for (uint i = 1; i < COUNTOF(player->old_x); ++i)
3494 				{
3495 					this_player->old_x[i - 1] = this_player->old_x[i];
3496 					this_player->old_y[i - 1] = this_player->old_y[i];
3497 				}
3498 				this_player->old_x[COUNTOF(player->old_x) - 1] = this_player->x;
3499 				this_player->old_y[COUNTOF(player->old_x) - 1] = this_player->y;
3500 			}
3501 		}
3502 		else  /*twoPlayerLinked*/
3503 		{
3504 			if (shipGr_ == 0)
3505 				this_player->x = player[0].x - 1;
3506 			else
3507 				this_player->x = player[0].x;
3508 			this_player->y = player[0].y + 8;
3509 
3510 			this_player->x_velocity = player[0].x_velocity;
3511 			this_player->y_velocity = 4;
3512 
3513 			// turret direction marker/shield
3514 			shotMultiPos[SHOT_MISC] = 0;
3515 			b = player_shot_create(0, SHOT_MISC, this_player->x + 1 + roundf(sinf(linkGunDirec + 0.2f) * 26), this_player->y + roundf(cosf(linkGunDirec + 0.2f) * 26), *mouseX_, *mouseY_, 148, playerNum_);
3516 			shotMultiPos[SHOT_MISC] = 0;
3517 			b = player_shot_create(0, SHOT_MISC, this_player->x + 1 + roundf(sinf(linkGunDirec - 0.2f) * 26), this_player->y + roundf(cosf(linkGunDirec - 0.2f) * 26), *mouseX_, *mouseY_, 148, playerNum_);
3518 			shotMultiPos[SHOT_MISC] = 0;
3519 			b = player_shot_create(0, SHOT_MISC, this_player->x + 1 + roundf(sinf(linkGunDirec) * 26), this_player->y + roundf(cosf(linkGunDirec) * 26), *mouseX_, *mouseY_, 147, playerNum_);
3520 
3521 			if (shotRepeat[SHOT_REAR] > 0)
3522 			{
3523 				--shotRepeat[SHOT_REAR];
3524 			}
3525 			else if (button[1-1])
3526 			{
3527 				shotMultiPos[SHOT_REAR] = 0;
3528 				b = player_shot_create(0, SHOT_REAR, this_player->x + 1 + roundf(sinf(linkGunDirec) * 20), this_player->y + roundf(cosf(linkGunDirec) * 20), *mouseX_, *mouseY_, linkGunWeapons[this_player->items.weapon[REAR_WEAPON].id-1], playerNum_);
3529 				player_shot_set_direction(b, this_player->items.weapon[REAR_WEAPON].id, linkGunDirec);
3530 			}
3531 		}
3532 	}
3533 
3534 	if (!endLevel)
3535 	{
3536 		if (this_player->x > 256)
3537 		{
3538 			this_player->x = 256;
3539 			constantLastX = -constantLastX;
3540 		}
3541 		if (this_player->x < 40)
3542 		{
3543 			this_player->x = 40;
3544 			constantLastX = -constantLastX;
3545 		}
3546 
3547 		if (isNetworkGame && playerNum_ == 1)
3548 		{
3549 			if (this_player->y > 154)
3550 				this_player->y = 154;
3551 		}
3552 		else
3553 		{
3554 			if (this_player->y > 160)
3555 				this_player->y = 160;
3556 		}
3557 
3558 		if (this_player->y < 10)
3559 			this_player->y = 10;
3560 
3561 		// Determines the ship banking sprite to display, depending on horizontal velocity and acceleration
3562 		int ship_banking = this_player->x_velocity / 2 + (this_player->x - *mouseX_) / 6;
3563 		ship_banking = MAX(-2, MIN(ship_banking, 2));
3564 
3565 		int ship_sprite = ship_banking * 2 + shipGr_;
3566 
3567 		explosionFollowAmountX = this_player->x - this_player->last_x_explosion_follow;
3568 		explosionFollowAmountY = this_player->y - this_player->last_y_explosion_follow;
3569 
3570 		if (explosionFollowAmountY < 0)
3571 			explosionFollowAmountY = 0;
3572 
3573 		this_player->last_x_explosion_follow = this_player->x;
3574 		this_player->last_y_explosion_follow = this_player->y;
3575 
3576 		if (shipGr_ == 0)
3577 		{
3578 			if (background2)
3579 			{
3580 				blit_sprite2x2_darken(VGAScreen, this_player->x - 17 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite + 13);
3581 				blit_sprite2x2_darken(VGAScreen, this_player->x + 7 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite + 51);
3582 				if (superWild)
3583 				{
3584 					blit_sprite2x2_darken(VGAScreen, this_player->x - 16 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite + 13);
3585 					blit_sprite2x2_darken(VGAScreen, this_player->x + 6 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite + 51);
3586 				}
3587 			}
3588 		}
3589 		else if (shipGr_ == 1)
3590 		{
3591 			if (background2)
3592 			{
3593 				blit_sprite2x2_darken(VGAScreen, this_player->x - 17 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, 220);
3594 				blit_sprite2x2_darken(VGAScreen, this_player->x + 7 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, 222);
3595 			}
3596 		}
3597 		else
3598 		{
3599 			if (background2)
3600 			{
3601 				blit_sprite2x2_darken(VGAScreen, this_player->x - 5 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite);
3602 				if (superWild)
3603 				{
3604 					blit_sprite2x2_darken(VGAScreen, this_player->x - 4 - mapX2Ofs + 30, this_player->y - 7 + shadowYDist, *shapes9ptr_, ship_sprite);
3605 				}
3606 			}
3607 		}
3608 
3609 		if (this_player->invulnerable_ticks > 0)
3610 		{
3611 			--this_player->invulnerable_ticks;
3612 
3613 			if (shipGr_ == 0)
3614 			{
3615 				blit_sprite2x2_blend(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, ship_sprite + 13);
3616 				blit_sprite2x2_blend(VGAScreen, this_player->x + 7 , this_player->y - 7, *shapes9ptr_, ship_sprite + 51);
3617 			}
3618 			else if (shipGr_ == 1)
3619 			{
3620 				blit_sprite2x2_blend(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, 220);
3621 				blit_sprite2x2_blend(VGAScreen, this_player->x + 7 , this_player->y - 7, *shapes9ptr_, 222);
3622 			}
3623 			else
3624 				blit_sprite2x2_blend(VGAScreen, this_player->x - 5, this_player->y - 7, *shapes9ptr_, ship_sprite);
3625 		}
3626 		else
3627 		{
3628 			if (shipGr_ == 0)
3629 			{
3630 				blit_sprite2x2(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, ship_sprite + 13);
3631 				blit_sprite2x2(VGAScreen, this_player->x + 7, this_player->y - 7, *shapes9ptr_, ship_sprite + 51);
3632 			}
3633 			else if (shipGr_ == 1)
3634 			{
3635 				blit_sprite2x2(VGAScreen, this_player->x - 17, this_player->y - 7, *shapes9ptr_, 220);
3636 				blit_sprite2x2(VGAScreen, this_player->x + 7, this_player->y - 7, *shapes9ptr_, 222);
3637 
3638 				int ship_banking;
3639 				switch (ship_sprite)
3640 				{
3641 				case 5:
3642 					blit_sprite2(VGAScreen, this_player->x - 17, this_player->y + 7, *shapes9ptr_, 40);
3643 					tempW = this_player->x - 7;
3644 					ship_banking = -2;
3645 					break;
3646 				case 3:
3647 					blit_sprite2(VGAScreen, this_player->x - 17, this_player->y + 7, *shapes9ptr_, 39);
3648 					tempW = this_player->x - 7;
3649 					ship_banking = -1;
3650 					break;
3651 				case 1:
3652 					ship_banking = 0;
3653 					break;
3654 				case -1:
3655 					blit_sprite2(VGAScreen, this_player->x + 19, this_player->y + 7, *shapes9ptr_, 58);
3656 					tempW = this_player->x + 9;
3657 					ship_banking = 1;
3658 					break;
3659 				case -3:
3660 					blit_sprite2(VGAScreen, this_player->x + 19, this_player->y + 7, *shapes9ptr_, 59);
3661 					tempW = this_player->x + 9;
3662 					ship_banking = 2;
3663 					break;
3664 				}
3665 				if (ship_banking != 0)  // NortSparks
3666 				{
3667 					if (shotRepeat[SHOT_NORTSPARKS] > 0)
3668 					{
3669 						--shotRepeat[SHOT_NORTSPARKS];
3670 					}
3671 					else
3672 					{
3673 						b = player_shot_create(0, SHOT_NORTSPARKS, tempW + (mt_rand() % 8) - 4, this_player->y + (mt_rand() % 8) - 4, *mouseX_, *mouseY_, 671, 1);
3674 						shotRepeat[SHOT_NORTSPARKS] = abs(ship_banking) - 1;
3675 					}
3676 				}
3677 			}
3678 			else
3679 			{
3680 				blit_sprite2x2(VGAScreen, this_player->x - 5, this_player->y - 7, *shapes9ptr_, ship_sprite);
3681 			}
3682 		}
3683 
3684 		/*Options Location*/
3685 		if (playerNum_ == 2 && shipGr_ == 0)  // if dragonwing
3686 		{
3687 			if (this_player->sidekick[LEFT_SIDEKICK].style == 0)
3688 			{
3689 				this_player->sidekick[LEFT_SIDEKICK].x = this_player->x - 14 + ship_banking * 2;
3690 				this_player->sidekick[LEFT_SIDEKICK].y = this_player->y;
3691 			}
3692 
3693 			if (this_player->sidekick[RIGHT_SIDEKICK].style == 0)
3694 			{
3695 				this_player->sidekick[RIGHT_SIDEKICK].x = this_player->x + 17 + ship_banking * 2;
3696 				this_player->sidekick[RIGHT_SIDEKICK].y = this_player->y;
3697 			}
3698 		}
3699 	}  // !endLevel
3700 
3701 	if (moveOk)
3702 	{
3703 		if (this_player->is_alive)
3704 		{
3705 			if (!endLevel)
3706 			{
3707 				this_player->delta_x_shot_move = this_player->x - this_player->last_x_shot_move;
3708 				this_player->delta_y_shot_move = this_player->y - this_player->last_y_shot_move;
3709 
3710 				/* PLAYER SHOT Change */
3711 				if (button[4-1])
3712 				{
3713 					portConfigChange = true;
3714 					if (portConfigDone)
3715 					{
3716 						shotMultiPos[SHOT_REAR] = 0;
3717 
3718 						if (superArcadeMode != SA_NONE && superArcadeMode <= SA_NORTSHIPZ)
3719 						{
3720 							shotMultiPos[SHOT_SPECIAL] = 0;
3721 							shotMultiPos[SHOT_SPECIAL2] = 0;
3722 							if (player[0].items.special == SASpecialWeapon[superArcadeMode-1])
3723 							{
3724 								player[0].items.special = SASpecialWeaponB[superArcadeMode-1];
3725 								this_player->weapon_mode = 2;
3726 							}
3727 							else
3728 							{
3729 								player[0].items.special = SASpecialWeapon[superArcadeMode-1];
3730 								this_player->weapon_mode = 1;
3731 							}
3732 						}
3733 						else if (++this_player->weapon_mode > JE_portConfigs())
3734 							this_player->weapon_mode = 1;
3735 
3736 						JE_drawPortConfigButtons();
3737 						portConfigDone = false;
3738 					}
3739 				}
3740 
3741 				/* PLAYER SHOT Creation */
3742 
3743 				/*SpecialShot*/
3744 				if (!galagaMode)
3745 					JE_doSpecialShot(playerNum_, &this_player->armor, &this_player->shield);
3746 
3747 				/*Normal Main Weapons*/
3748 				if (!(twoPlayerLinked && playerNum_ == 2))
3749 				{
3750 					int min, max;
3751 
3752 					if (!twoPlayerMode)
3753 						min = 1, max = 2;
3754 					else
3755 						min = max = playerNum_;
3756 
3757 					for (temp = min - 1; temp < max; temp++)
3758 					{
3759 						const uint item = this_player->items.weapon[temp].id;
3760 
3761 						if (item > 0)
3762 						{
3763 							if (shotRepeat[temp] > 0)
3764 							{
3765 								--shotRepeat[temp];
3766 							}
3767 							else if (button[1-1])
3768 							{
3769 								const uint item_power = galagaMode ? 0 : this_player->items.weapon[temp].power - 1,
3770 								           item_mode = (temp == REAR_WEAPON) ? this_player->weapon_mode - 1 : 0;
3771 
3772 								b = player_shot_create(item, temp, this_player->x, this_player->y, *mouseX_, *mouseY_, weaponPort[item].op[item_mode][item_power], playerNum_);
3773 							}
3774 						}
3775 					}
3776 				}
3777 
3778 				/*Super Charge Weapons*/
3779 				if (playerNum_ == 2)
3780 				{
3781 
3782 					if (!twoPlayerLinked)
3783 						blit_sprite2(VGAScreen, this_player->x + (shipGr_ == 0) + 1, this_player->y - 13, eShapes[5], 77 + chargeLevel + chargeGr * 19);
3784 
3785 					if (chargeGrWait > 0)
3786 					{
3787 						chargeGrWait--;
3788 					}
3789 					else
3790 					{
3791 						chargeGr++;
3792 						if (chargeGr == 4)
3793 							chargeGr = 0;
3794 						chargeGrWait = 3;
3795 					}
3796 
3797 					if (chargeLevel > 0)
3798 					{
3799 						fill_rectangle_xy(VGAScreenSeg, 269, 107 + (chargeLevel - 1) * 3, 275, 108 + (chargeLevel - 1) * 3, 193);
3800 					}
3801 
3802 					if (chargeWait > 0)
3803 					{
3804 						chargeWait--;
3805 					}
3806 					else
3807 					{
3808 						if (chargeLevel < chargeMax)
3809 							chargeLevel++;
3810 
3811 						chargeWait = 28 - this_player->items.weapon[REAR_WEAPON].power * 2;
3812 						if (difficultyLevel > 3)
3813 							chargeWait -= 5;
3814 					}
3815 
3816 					if (chargeLevel > 0)
3817 						fill_rectangle_xy(VGAScreenSeg, 269, 107 + (chargeLevel - 1) * 3, 275, 108 + (chargeLevel - 1) * 3, 204);
3818 
3819 					if (shotRepeat[SHOT_P2_CHARGE] > 0)
3820 					{
3821 						--shotRepeat[SHOT_P2_CHARGE];
3822 					}
3823 					else if (button[1-1] && (!twoPlayerLinked || chargeLevel > 0))
3824 					{
3825 						shotMultiPos[SHOT_P2_CHARGE] = 0;
3826 						b = player_shot_create(16, SHOT_P2_CHARGE, this_player->x, this_player->y, *mouseX_, *mouseY_, chargeGunWeapons[player[1].items.weapon[REAR_WEAPON].id-1] + chargeLevel, playerNum_);
3827 
3828 						if (chargeLevel > 0)
3829 							fill_rectangle_xy(VGAScreenSeg, 269, 107 + (chargeLevel - 1) * 3, 275, 108 + (chargeLevel - 1) * 3, 193);
3830 
3831 						chargeLevel = 0;
3832 						chargeWait = 30 - this_player->items.weapon[REAR_WEAPON].power * 2;
3833 					}
3834 				}
3835 
3836 				/*SUPER BOMB*/
3837 				temp = playerNum_;
3838 				if (temp == 0)
3839 					temp = 1;  /*Get whether player 1 or 2*/
3840 
3841 				if (player[temp-1].superbombs > 0)
3842 				{
3843 					if (shotRepeat[SHOT_P1_SUPERBOMB + temp-1] > 0)
3844 					{
3845 						--shotRepeat[SHOT_P1_SUPERBOMB + temp-1];
3846 					}
3847 					else if (button[3-1] || button[2-1])
3848 					{
3849 						--player[temp-1].superbombs;
3850 						shotMultiPos[SHOT_P1_SUPERBOMB + temp-1] = 0;
3851 						b = player_shot_create(16, SHOT_P1_SUPERBOMB + temp-1, this_player->x, this_player->y, *mouseX_, *mouseY_, 535, playerNum_);
3852 					}
3853 				}
3854 
3855 				// sidekicks
3856 
3857 				if (this_player->sidekick[LEFT_SIDEKICK].style == 4 && this_player->sidekick[RIGHT_SIDEKICK].style == 4)
3858 					optionSatelliteRotate += 0.2f;
3859 				else if (this_player->sidekick[LEFT_SIDEKICK].style == 4 || this_player->sidekick[RIGHT_SIDEKICK].style == 4)
3860 					optionSatelliteRotate += 0.15f;
3861 
3862 				switch (this_player->sidekick[LEFT_SIDEKICK].style)
3863 				{
3864 				case 1:  // trailing
3865 				case 3:
3866 					this_player->sidekick[LEFT_SIDEKICK].x = this_player->old_x[COUNTOF(player->old_x) / 2 - 1];
3867 					this_player->sidekick[LEFT_SIDEKICK].y = this_player->old_y[COUNTOF(player->old_x) / 2 - 1];
3868 					break;
3869 				case 2:  // front-mounted
3870 					this_player->sidekick[LEFT_SIDEKICK].x = this_player->x;
3871 					this_player->sidekick[LEFT_SIDEKICK].y = MAX(10, this_player->y - 20);
3872 					break;
3873 				case 4:  // orbitting
3874 					this_player->sidekick[LEFT_SIDEKICK].x = this_player->x + roundf(sinf(optionSatelliteRotate) * 20);
3875 					this_player->sidekick[LEFT_SIDEKICK].y = this_player->y + roundf(cosf(optionSatelliteRotate) * 20);
3876 					break;
3877 				}
3878 
3879 				switch (this_player->sidekick[RIGHT_SIDEKICK].style)
3880 				{
3881 				case 4:  // orbitting
3882 					this_player->sidekick[RIGHT_SIDEKICK].x = this_player->x - roundf(sinf(optionSatelliteRotate) * 20);
3883 					this_player->sidekick[RIGHT_SIDEKICK].y = this_player->y - roundf(cosf(optionSatelliteRotate) * 20);
3884 					break;
3885 				case 1:  // trailing
3886 				case 3:
3887 					this_player->sidekick[RIGHT_SIDEKICK].x = this_player->old_x[0];
3888 					this_player->sidekick[RIGHT_SIDEKICK].y = this_player->old_y[0];
3889 					break;
3890 				case 2:  // front-mounted
3891 					if (!optionAttachmentLinked)
3892 					{
3893 						this_player->sidekick[RIGHT_SIDEKICK].y += optionAttachmentMove / 2;
3894 						if (optionAttachmentMove >= -2)
3895 						{
3896 							if (optionAttachmentReturn)
3897 								temp = 2;
3898 							else
3899 								temp = 0;
3900 
3901 							if (this_player->sidekick[RIGHT_SIDEKICK].y > (this_player->y - 20) + 5)
3902 							{
3903 								temp = 2;
3904 								optionAttachmentMove -= 1 + optionAttachmentReturn;
3905 							}
3906 							else if (this_player->sidekick[RIGHT_SIDEKICK].y > (this_player->y - 20) - 0)
3907 							{
3908 								temp = 3;
3909 								if (optionAttachmentMove > 0)
3910 									optionAttachmentMove--;
3911 								else
3912 									optionAttachmentMove++;
3913 							}
3914 							else if (this_player->sidekick[RIGHT_SIDEKICK].y > (this_player->y - 20) - 5)
3915 							{
3916 								temp = 2;
3917 								optionAttachmentMove++;
3918 							}
3919 							else if (optionAttachmentMove < 2 + optionAttachmentReturn * 4)
3920 							{
3921 								optionAttachmentMove += 1 + optionAttachmentReturn;
3922 							}
3923 
3924 							if (optionAttachmentReturn)
3925 								temp = temp * 2;
3926 							if (abs(this_player->sidekick[RIGHT_SIDEKICK].x - this_player->x) < temp)
3927 								temp = 1;
3928 
3929 							if (this_player->sidekick[RIGHT_SIDEKICK].x > this_player->x)
3930 								this_player->sidekick[RIGHT_SIDEKICK].x -= temp;
3931 							else if (this_player->sidekick[RIGHT_SIDEKICK].x < this_player->x)
3932 								this_player->sidekick[RIGHT_SIDEKICK].x += temp;
3933 
3934 							if (abs(this_player->sidekick[RIGHT_SIDEKICK].y - (this_player->y - 20)) + abs(this_player->sidekick[RIGHT_SIDEKICK].x - this_player->x) < 8)
3935 							{
3936 								optionAttachmentLinked = true;
3937 								soundQueue[2] = S_CLINK;
3938 							}
3939 
3940 							if (button[3-1])
3941 								optionAttachmentReturn = true;
3942 						}
3943 						else  // sidekick needs to catch up to player
3944 						{
3945 							optionAttachmentMove += 1 + optionAttachmentReturn;
3946 							JE_setupExplosion(this_player->sidekick[RIGHT_SIDEKICK].x + 1, this_player->sidekick[RIGHT_SIDEKICK].y + 10, 0, 0, false, false);
3947 						}
3948 					}
3949 					else
3950 					{
3951 						this_player->sidekick[RIGHT_SIDEKICK].x = this_player->x;
3952 						this_player->sidekick[RIGHT_SIDEKICK].y = this_player->y - 20;
3953 						if (button[3-1])
3954 						{
3955 							optionAttachmentLinked = false;
3956 							optionAttachmentReturn = false;
3957 							optionAttachmentMove = -20;
3958 							soundQueue[3] = S_WEAPON_26;
3959 						}
3960 					}
3961 
3962 					if (this_player->sidekick[RIGHT_SIDEKICK].y < 10)
3963 						this_player->sidekick[RIGHT_SIDEKICK].y = 10;
3964 					break;
3965 				}
3966 
3967 				if (playerNum_ == 2 || !twoPlayerMode)  // if player has sidekicks
3968 				{
3969 					for (uint i = 0; i < COUNTOF(player->items.sidekick); ++i)
3970 					{
3971 						uint shot_i = (i == 0) ? SHOT_LEFT_SIDEKICK : SHOT_RIGHT_SIDEKICK;
3972 
3973 						JE_OptionType *this_option = &options[this_player->items.sidekick[i]];
3974 
3975 						// fire/refill sidekick
3976 						if (this_option->wport > 0)
3977 						{
3978 							if (shotRepeat[shot_i] > 0)
3979 							{
3980 								--shotRepeat[shot_i];
3981 							}
3982 							else
3983 							{
3984 								const int ammo_max = this_player->sidekick[i].ammo_max;
3985 
3986 								if (ammo_max > 0)  // sidekick has limited ammo
3987 								{
3988 									if (this_player->sidekick[i].ammo_refill_ticks > 0)
3989 									{
3990 										--this_player->sidekick[i].ammo_refill_ticks;
3991 									}
3992 									else  // refill one ammo
3993 									{
3994 										this_player->sidekick[i].ammo_refill_ticks = this_player->sidekick[i].ammo_refill_ticks_max;
3995 
3996 										if (this_player->sidekick[i].ammo < ammo_max)
3997 											++this_player->sidekick[i].ammo;
3998 
3999 										// draw sidekick refill ammo gauge
4000 										const int y = hud_sidekick_y[twoPlayerMode ? 1 : 0][i] + 13;
4001 										draw_segmented_gauge(VGAScreenSeg, 284, y, 112, 2, 2, MAX(1, ammo_max / 10), this_player->sidekick[i].ammo);
4002 									}
4003 
4004 									if (button[1 + i] && this_player->sidekick[i].ammo > 0)
4005 									{
4006 										b = player_shot_create(this_option->wport, shot_i, this_player->sidekick[i].x, this_player->sidekick[i].y, *mouseX_, *mouseY_, this_option->wpnum + this_player->sidekick[i].charge, playerNum_);
4007 
4008 										--this_player->sidekick[i].ammo;
4009 										if (this_player->sidekick[i].charge > 0)
4010 										{
4011 											shotMultiPos[shot_i] = 0;
4012 											this_player->sidekick[i].charge = 0;
4013 										}
4014 										this_player->sidekick[i].charge_ticks = 20;
4015 										this_player->sidekick[i].animation_enabled = true;
4016 
4017 										// draw sidekick discharge ammo gauge
4018 										const int y = hud_sidekick_y[twoPlayerMode ? 1 : 0][i] + 13;
4019 										fill_rectangle_xy(VGAScreenSeg, 284, y, 312, y + 2, 0);
4020 										draw_segmented_gauge(VGAScreenSeg, 284, y, 112, 2, 2, MAX(1, ammo_max / 10), this_player->sidekick[i].ammo);
4021 									}
4022 								}
4023 								else  // has infinite ammo
4024 								{
4025 									if (button[0] || button[1 + i])
4026 									{
4027 										b = player_shot_create(this_option->wport, shot_i, this_player->sidekick[i].x, this_player->sidekick[i].y, *mouseX_, *mouseY_, this_option->wpnum + this_player->sidekick[i].charge, playerNum_);
4028 
4029 										if (this_player->sidekick[i].charge > 0)
4030 										{
4031 											shotMultiPos[shot_i] = 0;
4032 											this_player->sidekick[i].charge = 0;
4033 										}
4034 										this_player->sidekick[i].charge_ticks = 20;
4035 										this_player->sidekick[i].animation_enabled = true;
4036 									}
4037 								}
4038 							}
4039 						}
4040 					}
4041 				}  // end of if player has sidekicks
4042 			}  // !endLevel
4043 		} // this_player->is_alive
4044 	} // moveOK
4045 
4046 	// draw sidekicks
4047 	if ((playerNum_ == 2 || !twoPlayerMode) && !endLevel)
4048 	{
4049 		for (uint i = 0; i < COUNTOF(this_player->sidekick); ++i)
4050 		{
4051 			JE_OptionType *this_option = &options[this_player->items.sidekick[i]];
4052 
4053 			if (this_option->option > 0)
4054 			{
4055 				if (this_player->sidekick[i].animation_enabled)
4056 				{
4057 					if (++this_player->sidekick[i].animation_frame >= this_option->ani)
4058 					{
4059 						this_player->sidekick[i].animation_frame = 0;
4060 						this_player->sidekick[i].animation_enabled = (this_option->option == 1);
4061 					}
4062 				}
4063 
4064 				const int x = this_player->sidekick[i].x,
4065 				          y = this_player->sidekick[i].y;
4066 				const uint sprite = this_option->gr[this_player->sidekick[i].animation_frame] + this_player->sidekick[i].charge;
4067 
4068 				if (this_player->sidekick[i].style == 1 || this_player->sidekick[i].style == 2)
4069 					blit_sprite2x2(VGAScreen, x - 6, y, eShapes[5], sprite);
4070 				else
4071 					blit_sprite2(VGAScreen, x, y, shapes9, sprite);
4072 			}
4073 
4074 			if (--this_player->sidekick[i].charge_ticks == 0)
4075 			{
4076 				if (this_player->sidekick[i].charge < this_option->pwr)
4077 					++this_player->sidekick[i].charge;
4078 				this_player->sidekick[i].charge_ticks = 20;
4079 			}
4080 		}
4081 	}
4082 }
4083 
JE_mainGamePlayerFunctions(void)4084 void JE_mainGamePlayerFunctions( void )
4085 {
4086 	/*PLAYER MOVEMENT/MOUSE ROUTINES*/
4087 
4088 	if (endLevel && levelEnd > 0)
4089 	{
4090 		levelEnd--;
4091 		levelEndWarp++;
4092 	}
4093 
4094 	/*Reset Street-Fighter commands*/
4095 	memset(SFExecuted, 0, sizeof(SFExecuted));
4096 
4097 	portConfigChange = false;
4098 
4099 	if (twoPlayerMode)
4100 	{
4101 		JE_playerMovement(&player[0],
4102 		                  !galagaMode ? inputDevice[0] : 0, 1, shipGr, shipGrPtr,
4103 		                  &mouseX, &mouseY);
4104 		JE_playerMovement(&player[1],
4105 		                  !galagaMode ? inputDevice[1] : 0, 2, shipGr2, shipGr2ptr,
4106 		                  &mouseXB, &mouseYB);
4107 	}
4108 	else
4109 	{
4110 		JE_playerMovement(&player[0],
4111 		                  0, 1, shipGr, shipGrPtr,
4112 		                  &mouseX, &mouseY);
4113 	}
4114 
4115 	/* == Parallax Map Scrolling == */
4116 	if (twoPlayerMode)
4117 	{
4118 		tempX = (player[0].x + player[1].x) / 2;
4119 	} else {
4120 		tempX = player[0].x;
4121 	}
4122 
4123 	tempW = floorf((260.0f - (tempX - 36.0f)) / (260.0f - 36.0f) * (24.0f * 3.0f) - 1.0f);
4124 	mapX3Ofs   = tempW;
4125 	mapX3Pos   = mapX3Ofs % 24;
4126 	mapX3bpPos = 1 - (mapX3Ofs / 24);
4127 
4128 	mapX2Ofs   = (tempW * 2) / 3;
4129 	mapX2Pos   = mapX2Ofs % 24;
4130 	mapX2bpPos = 1 - (mapX2Ofs / 24);
4131 
4132 	oldMapXOfs = mapXOfs;
4133 	mapXOfs    = mapX2Ofs / 2;
4134 	mapXPos    = mapXOfs % 24;
4135 	mapXbpPos  = 1 - (mapXOfs / 24);
4136 
4137 	if (background3x1)
4138 	{
4139 		mapX3Ofs = mapXOfs;
4140 		mapX3Pos = mapXPos;
4141 		mapX3bpPos = mapXbpPos - 1;
4142 	}
4143 }
4144 
JE_getName(JE_byte pnum)4145 const char *JE_getName( JE_byte pnum )
4146 {
4147 	if (pnum == thisPlayerNum && network_player_name[0] != '\0')
4148 		return network_player_name;
4149 	else if (network_opponent_name[0] != '\0')
4150 		return network_opponent_name;
4151 
4152 	return miscText[47 + pnum];
4153 }
4154 
JE_playerCollide(Player * this_player,JE_byte playerNum_)4155 void JE_playerCollide( Player *this_player, JE_byte playerNum_ )
4156 {
4157 	char tempStr[256];
4158 
4159 	for (int z = 0; z < 100; z++)
4160 	{
4161 		if (enemyAvail[z] != 1)
4162 		{
4163 			int enemy_screen_x = enemy[z].ex + enemy[z].mapoffset;
4164 
4165 			if (abs(this_player->x - enemy_screen_x) < 12 && abs(this_player->y - enemy[z].ey) < 14)
4166 			{   /*Collide*/
4167 				int evalue = enemy[z].evalue;
4168 				if (evalue > 29999)
4169 				{
4170 					if (evalue == 30000)  // spawn dragonwing in galaga mode, otherwise just a purple ball
4171 					{
4172 						this_player->cash += 100;
4173 
4174 						if (!galagaMode)
4175 						{
4176 							handle_got_purple_ball(this_player);
4177 						}
4178 						else
4179 						{
4180 							// spawn the dragonwing?
4181 							if (twoPlayerMode)
4182 								this_player->cash += 2400;
4183 							twoPlayerMode = true;
4184 							twoPlayerLinked = true;
4185 							player[1].items.weapon[REAR_WEAPON].power = 1;
4186 							player[1].armor = 10;
4187 							player[1].is_alive = true;
4188 						}
4189 						enemyAvail[z] = 1;
4190 						soundQueue[7] = S_POWERUP;
4191 					}
4192 					else if (superArcadeMode != SA_NONE && evalue > 30000)
4193 					{
4194 						shotMultiPos[SHOT_FRONT] = 0;
4195 						shotRepeat[SHOT_FRONT] = 10;
4196 
4197 						tempW = SAWeapon[superArcadeMode-1][evalue - 30000-1];
4198 
4199 						// if picked up already-owned weapon, power weapon up
4200 						if (tempW == player[0].items.weapon[FRONT_WEAPON].id)
4201 						{
4202 							this_player->cash += 1000;
4203 							power_up_weapon(this_player, FRONT_WEAPON);
4204 						}
4205 						// else weapon also gives purple ball
4206 						else
4207 						{
4208 							handle_got_purple_ball(this_player);
4209 						}
4210 
4211 						player[0].items.weapon[FRONT_WEAPON].id = tempW;
4212 						this_player->cash += 200;
4213 						soundQueue[7] = S_POWERUP;
4214 						enemyAvail[z] = 1;
4215 					}
4216 					else if (evalue > 32100)
4217 					{
4218 						if (playerNum_ == 1)
4219 						{
4220 							this_player->cash += 250;
4221 							player[0].items.special = evalue - 32100;
4222 							shotMultiPos[SHOT_SPECIAL] = 0;
4223 							shotRepeat[SHOT_SPECIAL] = 10;
4224 							shotMultiPos[SHOT_SPECIAL2] = 0;
4225 							shotRepeat[SHOT_SPECIAL2] = 0;
4226 
4227 							if (isNetworkGame)
4228 								sprintf(tempStr, "%s %s %s", JE_getName(1), miscTextB[4-1], special[evalue - 32100].name);
4229 							else if (twoPlayerMode)
4230 								sprintf(tempStr, "%s %s", miscText[43-1], special[evalue - 32100].name);
4231 							else
4232 								sprintf(tempStr, "%s %s", miscText[64-1], special[evalue - 32100].name);
4233 							JE_drawTextWindow(tempStr);
4234 							soundQueue[7] = S_POWERUP;
4235 							enemyAvail[z] = 1;
4236 						}
4237 					}
4238 					else if (evalue > 32000)
4239 					{
4240 						if (playerNum_ == 2)
4241 						{
4242 							enemyAvail[z] = 1;
4243 							if (isNetworkGame)
4244 								sprintf(tempStr, "%s %s %s", JE_getName(2), miscTextB[4-1], options[evalue - 32000].name);
4245 							else
4246 								sprintf(tempStr, "%s %s", miscText[44-1], options[evalue - 32000].name);
4247 							JE_drawTextWindow(tempStr);
4248 
4249 							// if picked up a different sidekick than player already has, then reset sidekicks to least powerful, else power them up
4250 							if (evalue - 32000u != player[1].items.sidekick_series)
4251 							{
4252 								player[1].items.sidekick_series = evalue - 32000;
4253 								player[1].items.sidekick_level = 101;
4254 							}
4255 							else if (player[1].items.sidekick_level < 103)
4256 							{
4257 								++player[1].items.sidekick_level;
4258 							}
4259 
4260 							uint temp = player[1].items.sidekick_level - 100 - 1;
4261 							for (uint i = 0; i < COUNTOF(player[1].items.sidekick); ++i)
4262 								player[1].items.sidekick[i] = optionSelect[player[1].items.sidekick_series][temp][i];
4263 
4264 
4265 							shotMultiPos[SHOT_LEFT_SIDEKICK] = 0;
4266 							shotMultiPos[SHOT_RIGHT_SIDEKICK] = 0;
4267 							JE_drawOptions();
4268 							soundQueue[7] = S_POWERUP;
4269 						}
4270 						else if (onePlayerAction)
4271 						{
4272 							enemyAvail[z] = 1;
4273 							sprintf(tempStr, "%s %s", miscText[64-1], options[evalue - 32000].name);
4274 							JE_drawTextWindow(tempStr);
4275 
4276 							for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i)
4277 								player[0].items.sidekick[i] = evalue - 32000;
4278 							shotMultiPos[SHOT_LEFT_SIDEKICK] = 0;
4279 							shotMultiPos[SHOT_RIGHT_SIDEKICK] = 0;
4280 
4281 							JE_drawOptions();
4282 							soundQueue[7] = S_POWERUP;
4283 						}
4284 						if (enemyAvail[z] == 1)
4285 							this_player->cash += 250;
4286 					}
4287 					else if (evalue > 31000)
4288 					{
4289 						this_player->cash += 250;
4290 						if (playerNum_ == 2)
4291 						{
4292 							if (isNetworkGame)
4293 								sprintf(tempStr, "%s %s %s", JE_getName(2), miscTextB[4-1], weaponPort[evalue - 31000].name);
4294 							else
4295 								sprintf(tempStr, "%s %s", miscText[44-1], weaponPort[evalue - 31000].name);
4296 							JE_drawTextWindow(tempStr);
4297 							player[1].items.weapon[REAR_WEAPON].id = evalue - 31000;
4298 							shotMultiPos[SHOT_REAR] = 0;
4299 							enemyAvail[z] = 1;
4300 							soundQueue[7] = S_POWERUP;
4301 						}
4302 						else if (onePlayerAction)
4303 						{
4304 							sprintf(tempStr, "%s %s", miscText[64-1], weaponPort[evalue - 31000].name);
4305 							JE_drawTextWindow(tempStr);
4306 							player[0].items.weapon[REAR_WEAPON].id = evalue - 31000;
4307 							shotMultiPos[SHOT_REAR] = 0;
4308 							enemyAvail[z] = 1;
4309 							soundQueue[7] = S_POWERUP;
4310 
4311 							if (player[0].items.weapon[REAR_WEAPON].power == 0)  // does this ever happen?
4312 								player[0].items.weapon[REAR_WEAPON].power = 1;
4313 						}
4314 					}
4315 					else if (evalue > 30000)
4316 					{
4317 						if (playerNum_ == 1 && twoPlayerMode)
4318 						{
4319 							if (isNetworkGame)
4320 								sprintf(tempStr, "%s %s %s", JE_getName(1), miscTextB[4-1], weaponPort[evalue - 30000].name);
4321 							else
4322 								sprintf(tempStr, "%s %s", miscText[43-1], weaponPort[evalue - 30000].name);
4323 							JE_drawTextWindow(tempStr);
4324 							player[0].items.weapon[FRONT_WEAPON].id = evalue - 30000;
4325 							shotMultiPos[SHOT_FRONT] = 0;
4326 							enemyAvail[z] = 1;
4327 							soundQueue[7] = S_POWERUP;
4328 						}
4329 						else if (onePlayerAction)
4330 						{
4331 							sprintf(tempStr, "%s %s", miscText[64-1], weaponPort[evalue - 30000].name);
4332 							JE_drawTextWindow(tempStr);
4333 							player[0].items.weapon[FRONT_WEAPON].id = evalue - 30000;
4334 							shotMultiPos[SHOT_FRONT] = 0;
4335 							enemyAvail[z] = 1;
4336 							soundQueue[7] = S_POWERUP;
4337 						}
4338 
4339 						if (enemyAvail[z] == 1)
4340 						{
4341 							player[0].items.special = specialArcadeWeapon[evalue - 30000-1];
4342 							if (player[0].items.special > 0)
4343 							{
4344 								shotMultiPos[SHOT_SPECIAL] = 0;
4345 								shotRepeat[SHOT_SPECIAL] = 0;
4346 								shotMultiPos[SHOT_SPECIAL2] = 0;
4347 								shotRepeat[SHOT_SPECIAL2] = 0;
4348 							}
4349 							this_player->cash += 250;
4350 						}
4351 
4352 					}
4353 				}
4354 				else if (evalue > 20000)
4355 				{
4356 					if (twoPlayerLinked)
4357 					{
4358 						// share the armor evenly between linked players
4359 						for (uint i = 0; i < COUNTOF(player); ++i)
4360 						{
4361 							player[i].armor += (evalue - 20000) / COUNTOF(player);
4362 							if (player[i].armor > 28)
4363 								player[i].armor = 28;
4364 						}
4365 					}
4366 					else
4367 					{
4368 						this_player->armor += evalue - 20000;
4369 						if (this_player->armor > 28)
4370 							this_player->armor = 28;
4371 					}
4372 					enemyAvail[z] = 1;
4373 					VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
4374 					JE_drawArmor();
4375 					VGAScreen = game_screen; /* side-effect of game_screen */
4376 					soundQueue[7] = S_POWERUP;
4377 				}
4378 				else if (evalue > 10000 && enemyAvail[z] == 2)
4379 				{
4380 					if (!bonusLevel)
4381 					{
4382 						play_song(30);  /*Zanac*/
4383 						bonusLevel = true;
4384 						nextLevel = evalue - 10000;
4385 						enemyAvail[z] = 1;
4386 						displayTime = 150;
4387 					}
4388 				}
4389 				else if (enemy[z].scoreitem)
4390 				{
4391 					enemyAvail[z] = 1;
4392 					soundQueue[7] = S_ITEM;
4393 					if (evalue == 1)
4394 					{
4395 						cubeMax++;
4396 						soundQueue[3] = V_DATA_CUBE;
4397 					}
4398 					else if (evalue == -1)  // got front weapon powerup
4399 					{
4400 						if (isNetworkGame)
4401 							sprintf(tempStr, "%s %s %s", JE_getName(1), miscTextB[4-1], miscText[45-1]);
4402 						else if (twoPlayerMode)
4403 							sprintf(tempStr, "%s %s", miscText[43-1], miscText[45-1]);
4404 						else
4405 							strcpy(tempStr, miscText[45-1]);
4406 						JE_drawTextWindow(tempStr);
4407 
4408 						power_up_weapon(&player[0], FRONT_WEAPON);
4409 						soundQueue[7] = S_POWERUP;
4410 					}
4411 					else if (evalue == -2)  // got rear weapon powerup
4412 					{
4413 						if (isNetworkGame)
4414 							sprintf(tempStr, "%s %s %s", JE_getName(2), miscTextB[4-1], miscText[46-1]);
4415 						else if (twoPlayerMode)
4416 							sprintf(tempStr, "%s %s", miscText[44-1], miscText[46-1]);
4417 						else
4418 							strcpy(tempStr, miscText[46-1]);
4419 						JE_drawTextWindow(tempStr);
4420 
4421 						power_up_weapon(twoPlayerMode ? &player[1] : &player[0], REAR_WEAPON);
4422 						soundQueue[7] = S_POWERUP;
4423 					}
4424 					else if (evalue == -3)
4425 					{
4426 						// picked up orbiting asteroid killer
4427 						shotMultiPos[SHOT_MISC] = 0;
4428 						b = player_shot_create(0, SHOT_MISC, this_player->x, this_player->y, mouseX, mouseY, 104, playerNum_);
4429 						shotAvail[z] = 0;
4430 					}
4431 					else if (evalue == -4)
4432 					{
4433 						if (player[playerNum_-1].superbombs < 10)
4434 							++player[playerNum_-1].superbombs;
4435 					}
4436 					else if (evalue == -5)
4437 					{
4438 						player[0].items.weapon[FRONT_WEAPON].id = 25;  // HOT DOG!
4439 						player[0].items.weapon[REAR_WEAPON].id = 26;
4440 						player[1].items.weapon[REAR_WEAPON].id = 26;
4441 
4442 						player[0].last_items = player[0].items;
4443 
4444 						for (uint i = 0; i < COUNTOF(player); ++i)
4445 							player[i].weapon_mode = 1;
4446 
4447 						memset(shotMultiPos, 0, sizeof(shotMultiPos));
4448 					}
4449 					else if (twoPlayerLinked)
4450 					{
4451 						// players get equal share of pick-up cash when linked
4452 						for (uint i = 0; i < COUNTOF(player); ++i)
4453 							player[i].cash += evalue / COUNTOF(player);
4454 					}
4455 					else
4456 					{
4457 						this_player->cash += evalue;
4458 					}
4459 					JE_setupExplosion(enemy_screen_x, enemy[z].ey, 0, enemyDat[enemy[z].enemytype].explosiontype, true, false);
4460 				}
4461 				else if (this_player->invulnerable_ticks == 0 && enemyAvail[z] == 0 &&
4462 				         (enemyDat[enemy[z].enemytype].explosiontype & 1) == 0) // explosiontype & 1 == 0: not ground enemy
4463 				{
4464 					int armorleft = enemy[z].armorleft;
4465 					if (armorleft > damageRate)
4466 						armorleft = damageRate;
4467 
4468 					JE_playerDamage(armorleft, this_player);
4469 
4470 					// player ship gets push-back from collision
4471 					if (enemy[z].armorleft > 0)
4472 					{
4473 						this_player->x_velocity += (enemy[z].exc * enemy[z].armorleft) / 2;
4474 						this_player->y_velocity += (enemy[z].eyc * enemy[z].armorleft) / 2;
4475 					}
4476 
4477 					int armorleft2 = enemy[z].armorleft;
4478 					if (armorleft2 == 255)
4479 						armorleft2 = 30000;
4480 
4481 					temp = enemy[z].linknum;
4482 					if (temp == 0)
4483 						temp = 255;
4484 
4485 					b = z;
4486 
4487 					if (armorleft2 > armorleft)
4488 					{
4489 						// damage enemy
4490 						if (enemy[z].armorleft != 255)
4491 							enemy[z].armorleft -= armorleft;
4492 						soundQueue[5] = S_ENEMY_HIT;
4493 					}
4494 					else
4495 					{
4496 						// kill enemy
4497 						for (temp2 = 0; temp2 < 100; temp2++)
4498 						{
4499 							if (enemyAvail[temp2] != 1)
4500 							{
4501 								temp3 = enemy[temp2].linknum;
4502 								if (temp2 == b ||
4503 									(temp != 255 &&
4504 									 (temp == temp3 || temp - 100 == temp3
4505 									  || (temp3 > 40 && temp3 / 20 == temp / 20 && temp3 <= temp))))
4506 								{
4507 									int enemy_screen_x = enemy[temp2].ex + enemy[temp2].mapoffset;
4508 
4509 									enemy[temp2].linknum = 0;
4510 
4511 									enemyAvail[temp2] = 1;
4512 
4513 									if (enemyDat[enemy[temp2].enemytype].esize == 1)
4514 									{
4515 										JE_setupExplosionLarge(enemy[temp2].enemyground, enemy[temp2].explonum, enemy_screen_x, enemy[temp2].ey);
4516 										soundQueue[6] = S_EXPLOSION_9;
4517 									}
4518 									else
4519 									{
4520 										JE_setupExplosion(enemy_screen_x, enemy[temp2].ey, 0, 1, false, false);
4521 										soundQueue[5] = S_EXPLOSION_4;
4522 									}
4523 								}
4524 							}
4525 						}
4526 						enemyAvail[z] = 1;
4527 					}
4528 				}
4529 			}
4530 
4531 		}
4532 	}
4533 }
4534 
4535