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 "animlib.h"
20 #include "backgrnd.h"
21 #include "episodes.h"
22 #include "file.h"
23 #include "font.h"
24 #include "fonthand.h"
25 #include "game_menu.h"
26 #include "joystick.h"
27 #include "keyboard.h"
28 #include "lds_play.h"
29 #include "loudness.h"
30 #include "lvllib.h"
31 #include "menus.h"
32 #include "mainint.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 "params.h"
40 #include "pcxload.h"
41 #include "pcxmast.h"
42 #include "picload.h"
43 #include "setup.h"
44 #include "shots.h"
45 #include "sprite.h"
46 #include "tyrian2.h"
47 #include "vga256d.h"
48 #include "video.h"
49 
50 #include <assert.h>
51 #include <ctype.h>
52 #include <math.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <stdint.h>
56 
57 inline static void blit_enemy( SDL_Surface *surface, unsigned int i, signed int x_offset, signed int y_offset, signed int sprite_offset );
58 
59 boss_bar_t boss_bar[2];
60 
61 /* Level Event Data */
62 JE_boolean quit, loadLevelOk;
63 
64 struct JE_EventRecType eventRec[EVENT_MAXIMUM]; /* [1..eventMaximum] */
65 JE_word levelEnemyMax;
66 JE_word levelEnemyFrequency;
67 JE_word levelEnemy[40]; /* [1..40] */
68 
69 char tempStr[31];
70 
71 /* Data used for ItemScreen procedure to indicate items available */
72 JE_byte itemAvail[9][10]; /* [1..9, 1..10] */
73 JE_byte itemAvailMax[9]; /* [1..9] */
74 
JE_starShowVGA(void)75 void JE_starShowVGA( void )
76 {
77 	JE_byte *src;
78 	Uint8 *s = NULL; /* screen pointer, 8-bit specific */
79 
80 	int x, y, lightx, lighty, lightdist;
81 
82 	if (!playerEndLevel && !skipStarShowVGA)
83 	{
84 
85 		s = VGAScreenSeg->pixels;
86 
87 		src = game_screen->pixels;
88 		src += 24;
89 
90 		if (smoothScroll != 0 /*&& thisPlayerNum != 2*/)
91 		{
92 			wait_delay();
93 			setjasondelay(frameCountMax);
94 		}
95 
96 		if (starShowVGASpecialCode == 1)
97 		{
98 			src += game_screen->pitch * 183;
99 			for (y = 0; y < 184; y++)
100 			{
101 				memmove(s, src, 264);
102 				s += VGAScreenSeg->pitch;
103 				src -= game_screen->pitch;
104 			}
105 		}
106 		else if (starShowVGASpecialCode == 2 && processorType >= 2)
107 		{
108 			lighty = 172 - player[0].y;
109 			lightx = 281 - player[0].x;
110 
111 			for (y = 184; y; y--)
112 			{
113 				if (lighty > y)
114 				{
115 					for (x = 320 - 56; x; x--)
116 					{
117 						*s = (*src & 0xf0) | ((*src >> 2) & 0x03);
118 						s++;
119 						src++;
120 					}
121 				}
122 				else
123 				{
124 					for (x = 320 - 56; x; x--)
125 					{
126 						lightdist = abs(lightx - x) + lighty;
127 						if (lightdist < y)
128 							*s = *src;
129 						else if (lightdist - y <= 5)
130 							*s = (*src & 0xf0) | (((*src & 0x0f) + (3 * (5 - (lightdist - y)))) / 4);
131 						else
132 							*s = (*src & 0xf0) | ((*src & 0x0f) >> 2);
133 						s++;
134 						src++;
135 					}
136 				}
137 				s += 56 + VGAScreenSeg->pitch - 320;
138 				src += 56 + VGAScreenSeg->pitch - 320;
139 			}
140 		}
141 		else
142 		{
143 			for (y = 0; y < 184; y++)
144 			{
145 				memmove(s, src, 264);
146 				s += VGAScreenSeg->pitch;
147 				src += game_screen->pitch;
148 			}
149 		}
150 		JE_showVGA();
151 	}
152 
153 	quitRequested = false;
154 	skipStarShowVGA = false;
155 }
156 
blit_enemy(SDL_Surface * surface,unsigned int i,signed int x_offset,signed int y_offset,signed int sprite_offset)157 inline static void blit_enemy( SDL_Surface *surface, unsigned int i, signed int x_offset, signed int y_offset, signed int sprite_offset )
158 {
159 	if (enemy[i].sprite2s == NULL)
160 	{
161 		fprintf(stderr, "warning: enemy %d sprite missing\n", i);
162 		return;
163 	}
164 
165 	const int x = enemy[i].ex + x_offset + tempMapXOfs,
166 	          y = enemy[i].ey + y_offset;
167 	const unsigned int index = enemy[i].egr[enemy[i].enemycycle - 1] + sprite_offset;
168 
169 	if (enemy[i].filter != 0)
170 		blit_sprite2_filter(surface, x, y, *enemy[i].sprite2s, index, enemy[i].filter);
171 	else
172 		blit_sprite2(surface, x, y, *enemy[i].sprite2s, index);
173 }
174 
JE_drawEnemy(int enemyOffset)175 void JE_drawEnemy( int enemyOffset ) // actually does a whole lot more than just drawing
176 {
177 	player[0].x -= 25;
178 
179 	for (int i = enemyOffset - 25; i < enemyOffset; i++)
180 	{
181 		if (enemyAvail[i] != 1)
182 		{
183 			enemy[i].mapoffset = tempMapXOfs;
184 
185 			if (enemy[i].xaccel && enemy[i].xaccel - 89u > mt_rand() % 11)
186 			{
187 				if (player[0].x > enemy[i].ex)
188 				{
189 					if (enemy[i].exc < enemy[i].xaccel - 89)
190 						enemy[i].exc++;
191 				}
192 				else
193 				{
194 					if (enemy[i].exc >= 0 || -enemy[i].exc < enemy[i].xaccel - 89)
195 						enemy[i].exc--;
196 				}
197 			}
198 
199 			if (enemy[i].yaccel && enemy[i].yaccel - 89u > mt_rand() % 11)
200 			{
201 				if (player[0].y > enemy[i].ey)
202 				{
203 					if (enemy[i].eyc < enemy[i].yaccel - 89)
204 						enemy[i].eyc++;
205 				}
206 				else
207 				{
208 					if (enemy[i].eyc >= 0 || -enemy[i].eyc < enemy[i].yaccel - 89)
209 						enemy[i].eyc--;
210 				}
211 			}
212 
213  			if (enemy[i].ex + tempMapXOfs > -29 && enemy[i].ex + tempMapXOfs < 300)
214 			{
215 				if (enemy[i].aniactive == 1)
216 				{
217 					enemy[i].enemycycle++;
218 
219 					if (enemy[i].enemycycle == enemy[i].animax)
220 						enemy[i].aniactive = enemy[i].aniwhenfire;
221 					else if (enemy[i].enemycycle > enemy[i].ani)
222 						enemy[i].enemycycle = enemy[i].animin;
223 				}
224 
225 				if (enemy[i].egr[enemy[i].enemycycle - 1] == 999)
226 					goto enemy_gone;
227 
228 				if (enemy[i].size == 1) // 2x2 enemy
229 				{
230 					if (enemy[i].ey > -13)
231 					{
232 						blit_enemy(VGAScreen, i, -6, -7, 0);
233 						blit_enemy(VGAScreen, i,  6, -7, 1);
234 					}
235 					if (enemy[i].ey > -26 && enemy[i].ey < 182)
236 					{
237 						blit_enemy(VGAScreen, i, -6,  7, 19);
238 						blit_enemy(VGAScreen, i,  6,  7, 20);
239 					}
240 				}
241 				else
242 				{
243 					if (enemy[i].ey > -13)
244 						blit_enemy(VGAScreen, i, 0, 0, 0);
245 				}
246 
247 				enemy[i].filter = 0;
248 			}
249 
250 			if (enemy[i].excc)
251 			{
252 				if (--enemy[i].exccw <= 0)
253 				{
254 					if (enemy[i].exc == enemy[i].exrev)
255 					{
256 						enemy[i].excc = -enemy[i].excc;
257 						enemy[i].exrev = -enemy[i].exrev;
258 						enemy[i].exccadd = -enemy[i].exccadd;
259 					}
260 					else
261 					{
262 						enemy[i].exc += enemy[i].exccadd;
263 						enemy[i].exccw = enemy[i].exccwmax;
264 						if (enemy[i].exc == enemy[i].exrev)
265 						{
266 							enemy[i].excc = -enemy[i].excc;
267 							enemy[i].exrev = -enemy[i].exrev;
268 							enemy[i].exccadd = -enemy[i].exccadd;
269 						}
270 					}
271 				}
272 			}
273 
274 			if (enemy[i].eycc)
275 			{
276 				if (--enemy[i].eyccw <= 0)
277 				{
278 					if (enemy[i].eyc == enemy[i].eyrev)
279 					{
280 						enemy[i].eycc = -enemy[i].eycc;
281 						enemy[i].eyrev = -enemy[i].eyrev;
282 						enemy[i].eyccadd = -enemy[i].eyccadd;
283 					}
284 					else
285 					{
286 						enemy[i].eyc += enemy[i].eyccadd;
287 						enemy[i].eyccw = enemy[i].eyccwmax;
288 						if (enemy[i].eyc == enemy[i].eyrev)
289 						{
290 							enemy[i].eycc = -enemy[i].eycc;
291 							enemy[i].eyrev = -enemy[i].eyrev;
292 							enemy[i].eyccadd = -enemy[i].eyccadd;
293 						}
294 					}
295 				}
296 			}
297 
298 			enemy[i].ey += enemy[i].fixedmovey;
299 
300 			enemy[i].ex += enemy[i].exc;
301 			if (enemy[i].ex < -80 || enemy[i].ex > 340)
302 				goto enemy_gone;
303 
304 			enemy[i].ey += enemy[i].eyc;
305 			if (enemy[i].ey < -112 || enemy[i].ey > 190)
306 				goto enemy_gone;
307 
308 			goto enemy_still_exists;
309 
310 enemy_gone:
311 			/* enemy[i].egr[10] &= 0x00ff; <MXD> madness? */
312 			enemyAvail[i] = 1;
313 			goto draw_enemy_end;
314 
315 enemy_still_exists:
316 
317 			/*X bounce*/
318 			if (enemy[i].ex <= enemy[i].xminbounce || enemy[i].ex >= enemy[i].xmaxbounce)
319 				enemy[i].exc = -enemy[i].exc;
320 
321 			/*Y bounce*/
322 			if (enemy[i].ey <= enemy[i].yminbounce || enemy[i].ey >= enemy[i].ymaxbounce)
323 				enemy[i].eyc = -enemy[i].eyc;
324 
325 			/* Evalue != 0 - score item at boundary */
326 			if (enemy[i].scoreitem)
327 			{
328 				if (enemy[i].ex < -5)
329 					enemy[i].ex++;
330 				if (enemy[i].ex > 245)
331 					enemy[i].ex--;
332 			}
333 
334 			enemy[i].ey += tempBackMove;
335 
336 			if (enemy[i].ex <= -24 || enemy[i].ex >= 296)
337 				goto draw_enemy_end;
338 
339 			tempX = enemy[i].ex;
340 			tempY = enemy[i].ey;
341 
342 			temp = enemy[i].enemytype;
343 
344 			/* Enemy Shots */
345 			if (enemy[i].edamaged == 1)
346 				goto draw_enemy_end;
347 
348 			enemyOnScreen++;
349 
350 			if (enemy[i].iced)
351 			{
352 				enemy[i].iced--;
353 				if (enemy[i].enemyground != 0)
354 				{
355 					enemy[i].filter = 0x09;
356 				}
357 				goto draw_enemy_end;
358 			}
359 
360 			for (int j = 3; j > 0; j--)
361 			{
362 				if (enemy[i].freq[j-1])
363 				{
364 					temp3 = enemy[i].tur[j-1];
365 
366 					if (--enemy[i].eshotwait[j-1] == 0 && temp3)
367 					{
368 						enemy[i].eshotwait[j-1] = enemy[i].freq[j-1];
369 						if (difficultyLevel > 2)
370 						{
371 							enemy[i].eshotwait[j-1] = (enemy[i].eshotwait[j-1] / 2) + 1;
372 							if (difficultyLevel > 7)
373 								enemy[i].eshotwait[j-1] = (enemy[i].eshotwait[j-1] / 2) + 1;
374 						}
375 
376 						if (galagaMode && (enemy[i].eyc == 0 || (mt_rand() % 400) >= galagaShotFreq))
377 							goto draw_enemy_end;
378 
379 						switch (temp3)
380 						{
381 						case 252: /* Savara Boss DualMissile */
382 							if (enemy[i].ey > 20)
383 							{
384 								JE_setupExplosion(tempX - 8 + tempMapXOfs, tempY - 20 - backMove * 8, -2, 6, false, false);
385 								JE_setupExplosion(tempX + 4 + tempMapXOfs, tempY - 20 - backMove * 8, -2, 6, false, false);
386 							}
387 							break;
388 						case 251:; /* Suck-O-Magnet */
389 							const int attractivity = 4 - (abs(player[0].x - tempX) + abs(player[0].y - tempY)) / 100;
390 							player[0].x_velocity += (player[0].x > tempX) ? -attractivity : attractivity;
391 							break;
392 						case 253: /* Left ShortRange Magnet */
393 							if (abs(player[0].x + 25 - 14 - tempX) < 24 && abs(player[0].y - tempY) < 28)
394 							{
395 								player[0].x_velocity += 2;
396 							}
397 							if (twoPlayerMode &&
398 							   (abs(player[1].x - 14 - tempX) < 24 && abs(player[1].y - tempY) < 28))
399 							{
400 								player[1].x_velocity += 2;
401 							}
402 							break;
403 						case 254: /* Left ShortRange Magnet */
404 							if (abs(player[0].x + 25 - 14 - tempX) < 24 && abs(player[0].y - tempY) < 28)
405 							{
406 								player[0].x_velocity -= 2;
407 							}
408 							if (twoPlayerMode &&
409 							   (abs(player[1].x - 14 - tempX) < 24 && abs(player[1].y - tempY) < 28))
410 							{
411 								player[1].x_velocity -= 2;
412 							}
413 							break;
414 						case 255: /* Magneto RePulse!! */
415 							if (difficultyLevel != 1) /*DIF*/
416 							{
417 								if (j == 3)
418 								{
419 									enemy[i].filter = 0x70;
420 								}
421 								else
422 								{
423 									const int repulsivity = 4 - (abs(player[0].x - tempX) + abs(player[0].y - tempY)) / 20;
424 									if (repulsivity > 0)
425 										player[0].x_velocity += (player[0].x > tempX) ? repulsivity : -repulsivity;
426 								}
427 							}
428 							break;
429 						default:
430 						/*Rot*/
431 							for (int tempCount = weapons[temp3].multi; tempCount > 0; tempCount--)
432 							{
433 								for (b = 0; b < ENEMY_SHOT_MAX; b++)
434 								{
435 									if (enemyShotAvail[b] == 1)
436 										break;
437 								}
438 								if (b == ENEMY_SHOT_MAX)
439 									goto draw_enemy_end;
440 
441 								enemyShotAvail[b] = !enemyShotAvail[b];
442 
443 								if (weapons[temp3].sound > 0)
444 								{
445 									do
446 										temp = mt_rand() % 8;
447 									while (temp == 3);
448 									soundQueue[temp] = weapons[temp3].sound;
449 								}
450 
451 								if (enemy[i].aniactive == 2)
452 									enemy[i].aniactive = 1;
453 
454 								if (++enemy[i].eshotmultipos[j-1] > weapons[temp3].max)
455 									enemy[i].eshotmultipos[j-1] = 1;
456 
457 								int tempPos = enemy[i].eshotmultipos[j-1] - 1;
458 
459 								if (j == 1)
460 									temp2 = 4;
461 
462 								enemyShot[b].sx = tempX + weapons[temp3].bx[tempPos] + tempMapXOfs;
463 								enemyShot[b].sy = tempY + weapons[temp3].by[tempPos];
464 								enemyShot[b].sdmg = weapons[temp3].attack[tempPos];
465 								enemyShot[b].tx = weapons[temp3].tx;
466 								enemyShot[b].ty = weapons[temp3].ty;
467 								enemyShot[b].duration = weapons[temp3].del[tempPos];
468 								enemyShot[b].animate = 0;
469 								enemyShot[b].animax = weapons[temp3].weapani;
470 
471 								enemyShot[b].sgr = weapons[temp3].sg[tempPos];
472 								switch (j)
473 								{
474 								case 1:
475 									enemyShot[b].syc = weapons[temp3].acceleration;
476 									enemyShot[b].sxc = weapons[temp3].accelerationx;
477 
478 									enemyShot[b].sxm = weapons[temp3].sx[tempPos];
479 									enemyShot[b].sym = weapons[temp3].sy[tempPos];
480 									break;
481 								case 3:
482 									enemyShot[b].sxc = -weapons[temp3].acceleration;
483 									enemyShot[b].syc = weapons[temp3].accelerationx;
484 
485 									enemyShot[b].sxm = -weapons[temp3].sy[tempPos];
486 									enemyShot[b].sym = -weapons[temp3].sx[tempPos];
487 									break;
488 								case 2:
489 									enemyShot[b].sxc = weapons[temp3].acceleration;
490 									enemyShot[b].syc = -weapons[temp3].acceleration;
491 
492 									enemyShot[b].sxm = weapons[temp3].sy[tempPos];
493 									enemyShot[b].sym = -weapons[temp3].sx[tempPos];
494 									break;
495 								}
496 
497 								if (weapons[temp3].aim > 0)
498 								{
499 									int aim = weapons[temp3].aim;
500 
501 									/*DIF*/
502 									if (difficultyLevel > 2)
503 									{
504 										aim += difficultyLevel - 2;
505 									}
506 
507 									JE_word target_x = player[0].x;
508 									JE_word target_y = player[0].y;
509 
510 									if (twoPlayerMode)
511 									{
512 										// fire at live player(s)
513 										if (player[0].is_alive && !player[1].is_alive)
514 											temp = 0;
515 										else if (player[1].is_alive && !player[0].is_alive)
516 											temp = 1;
517 										else
518 											temp = mt_rand() % 2;
519 
520 										if (temp == 1)
521 										{
522 											target_x = player[1].x - 25;
523 											target_y = player[1].y;
524 										}
525 									}
526 
527 									int relative_x = (target_x + 25) - tempX - tempMapXOfs - 4;
528 									if (relative_x == 0)
529 										relative_x = 1;
530 									int relative_y = target_y - tempY;
531 									if (relative_y == 0)
532 										relative_y = 1;
533 									const int longest_side = MAX(abs(relative_x), abs(relative_y));
534 									enemyShot[b].sxm = roundf((float)relative_x / longest_side * aim);
535 									enemyShot[b].sym = roundf((float)relative_y / longest_side * aim);
536 								}
537 							}
538 							break;
539 						}
540 					}
541 				}
542 			}
543 
544 			/* Enemy Launch Routine */
545 			if (enemy[i].launchfreq)
546 			{
547 				if (--enemy[i].launchwait == 0)
548 				{
549 					enemy[i].launchwait = enemy[i].launchfreq;
550 
551 					if (enemy[i].launchspecial != 0)
552 					{
553 						/*Type  1 : Must be inline with player*/
554 						if (abs(enemy[i].ey - player[0].y) > 5)
555 							goto draw_enemy_end;
556 					}
557 
558 					if (enemy[i].aniactive == 2)
559 					{
560 						enemy[i].aniactive = 1;
561 					}
562 
563 					if (enemy[i].launchtype == 0)
564 						goto draw_enemy_end;
565 
566 					tempW = enemy[i].launchtype;
567 					b = JE_newEnemy(enemyOffset == 50 ? 75 : enemyOffset - 25, tempW, 0);
568 
569 					/*Launch Enemy Placement*/
570 					if (b > 0)
571 					{
572 						struct JE_SingleEnemyType* e = &enemy[b-1];
573 
574 						e->ex = tempX;
575 						e->ey = tempY + enemyDat[e->enemytype].startyc;
576 						if (e->size == 0)
577 							e->ey -= 7;
578 
579 						if (e->launchtype > 0 && e->launchfreq == 0)
580 						{
581 							if (e->launchtype > 90)
582 							{
583 								e->ex += mt_rand() % ((e->launchtype - 90) * 4) - (e->launchtype - 90) * 2;
584 							}
585 							else
586 							{
587 								int target_x = (player[0].x + 25) - tempX - tempMapXOfs - 4;
588 								if (target_x == 0)
589 									target_x = 1;
590 								int tempI5 = player[0].y - tempY;
591 								if (tempI5 == 0)
592 									tempI5 = 1;
593 								const int longest_side = MAX(abs(target_x), abs(tempI5));
594 								e->exc = roundf(((float)target_x / longest_side) * e->launchtype);
595 								e->eyc = roundf(((float)tempI5 / longest_side) * e->launchtype);
596 							}
597 						}
598 
599 						do
600 							temp = mt_rand() % 8;
601 						while (temp == 3);
602 						soundQueue[temp] = randomEnemyLaunchSounds[(mt_rand() % 3)];
603 
604 						if (enemy[i].launchspecial == 1
605 						    && enemy[i].linknum < 100)
606 						{
607 							e->linknum = enemy[i].linknum;
608 						}
609 					}
610 				}
611 			}
612 		}
613 draw_enemy_end:
614 		;
615 	}
616 
617 	player[0].x += 25;
618 }
619 
JE_main(void)620 void JE_main( void )
621 {
622 	char buffer[256];
623 
624 	int lastEnemyOnScreen;
625 
626 	/* NOTE: BEGIN MAIN PROGRAM HERE AFTER LOADING A GAME OR STARTING A NEW ONE */
627 
628 	/* ----------- GAME ROUTINES ------------------------------------- */
629 	/* We need to jump to the beginning to make space for the routines */
630 	/* --------------------------------------------------------------- */
631 	goto start_level_first;
632 
633 
634 	/*------------------------------GAME LOOP-----------------------------------*/
635 
636 
637 	/* Startlevel is called after a previous level is over.  If the first level
638 	   is started for a gaming session, startlevelfirst is called instead and
639 	   this code is skipped.  The code here finishes the level and prepares for
640 	   the loadmap function. */
641 
642 start_level:
643 
644 	if (galagaMode)
645 		twoPlayerMode = false;
646 
647 	JE_clearKeyboard();
648 
649 	free_sprite2s(&eShapes[0]);
650 	free_sprite2s(&eShapes[1]);
651 	free_sprite2s(&eShapes[2]);
652 	free_sprite2s(&eShapes[3]);
653 
654 	/* Normal speed */
655 	if (fastPlay != 0)
656 	{
657 		smoothScroll = true;
658 		speed = 0x4300;
659 		JE_resetTimerInt();
660 		JE_setTimerInt();
661 	}
662 
663 	if (play_demo || record_demo)
664 	{
665 		if (demo_file)
666 		{
667 			fclose(demo_file);
668 			demo_file = NULL;
669 		}
670 
671 		if (play_demo)
672 		{
673 			stop_song();
674 			fade_black(10);
675 
676 			wait_noinput(true, true, true);
677 		}
678 	}
679 
680 	difficultyLevel = oldDifficultyLevel;   /*Return difficulty to normal*/
681 
682 	if (!play_demo)
683 	{
684 		if ((!all_players_dead() || normalBonusLevelCurrent || bonusLevelCurrent) && !playerEndLevel)
685 		{
686 			mainLevel = nextLevel;
687 			JE_endLevelAni();
688 
689 			fade_song();
690 		}
691 		else
692 		{
693 			fade_song();
694 			fade_black(10);
695 
696 			JE_loadGame(twoPlayerMode ? 22 : 11);
697 			if (doNotSaveBackup)
698 			{
699 				superTyrian = false;
700 				onePlayerAction = false;
701 				player[0].items.super_arcade_mode = SA_NONE;
702 			}
703 			if (bonusLevelCurrent && !playerEndLevel)
704 			{
705 				mainLevel = nextLevel;
706 			}
707 		}
708 	}
709 	doNotSaveBackup = false;
710 
711 	if (play_demo)
712 		return;
713 
714 start_level_first:
715 
716 	set_volume(tyrMusicVolume, fxVolume);
717 
718 	endLevel = false;
719 	reallyEndLevel = false;
720 	playerEndLevel = false;
721 	extraGame = false;
722 
723 	doNotSaveBackup = false;
724 	JE_loadMap();
725 
726 	if (mainLevel == 0)  // if quit itemscreen
727 		return;          // back to titlescreen
728 
729 	fade_song();
730 
731 	for (uint i = 0; i < COUNTOF(player); ++i)
732 		player[i].is_alive = true;
733 
734 	oldDifficultyLevel = difficultyLevel;
735 	if (episodeNum == EPISODE_AVAILABLE)
736 		difficultyLevel--;
737 	if (difficultyLevel < 1)
738 		difficultyLevel = 1;
739 
740 	player[0].x = 100;
741 	player[0].y = 180;
742 
743 	player[1].x = 190;
744 	player[1].y = 180;
745 
746 	assert(COUNTOF(player->old_x) == COUNTOF(player->old_y));
747 
748 	for (uint i = 0; i < COUNTOF(player); ++i)
749 	{
750 		for (uint j = 0; j < COUNTOF(player->old_x); ++j)
751 		{
752 			player[i].old_x[j] = player[i].x - (19 - j);
753 			player[i].old_y[j] = player[i].y - 18;
754 		}
755 
756 		player[i].last_x_shot_move = player[i].x;
757 		player[i].last_y_shot_move = player[i].y;
758 	}
759 
760 	JE_loadPic(VGAScreen, twoPlayerMode ? 6 : 3, false);
761 
762 	JE_drawOptions();
763 
764 	JE_outText(VGAScreen, 268, twoPlayerMode ? 76 : 118, levelName, 12, 4);
765 
766 	JE_showVGA();
767 	JE_gammaCorrect(&colors, gammaCorrection);
768 	fade_palette(colors, 50, 0, 255);
769 
770 	free_sprite2s(&shapes6);
771 	JE_loadCompShapes(&shapes6, '6'); // explosion sprites
772 
773 	/* MAPX will already be set correctly */
774 	mapY = 300 - 8;
775 	mapY2 = 600 - 8;
776 	mapY3 = 600 - 8;
777 	mapYPos = &megaData1.mainmap[mapY][0] - 1;
778 	mapY2Pos = &megaData2.mainmap[mapY2][0] - 1;
779 	mapY3Pos = &megaData3.mainmap[mapY3][0] - 1;
780 	mapXPos = 0;
781 	mapXOfs = 0;
782 	mapX2Pos = 0;
783 	mapX3Pos = 0;
784 	mapX3Ofs = 0;
785 	mapXbpPos = 0;
786 	mapX2bpPos = 0;
787 	mapX3bpPos = 0;
788 
789 	map1YDelay = 1;
790 	map1YDelayMax = 1;
791 	map2YDelay = 1;
792 	map2YDelayMax = 1;
793 
794 	musicFade = false;
795 
796 	backPos = 0;
797 	backPos2 = 0;
798 	backPos3 = 0;
799 	power = 0;
800 	starfield_speed = 1;
801 
802 	/* Setup player ship graphics */
803 	JE_getShipInfo();
804 
805 	for (uint i = 0; i < COUNTOF(player); ++i)
806 	{
807 		player[i].x_velocity = 0;
808 		player[i].y_velocity = 0;
809 
810 		player[i].invulnerable_ticks = 100;
811 	}
812 
813 	newkey = newmouse = false;
814 
815 	/* Initialize Level Data and Debug Mode */
816 	levelEnd = 255;
817 	levelEndWarp = -4;
818 	levelEndFxWait = 0;
819 	warningCol = 120;
820 	warningColChange = 1;
821 	warningSoundDelay = 0;
822 	armorShipDelay = 50;
823 
824 	bonusLevel = false;
825 	readyToEndLevel = false;
826 	firstGameOver = true;
827 	eventLoc = 1;
828 	curLoc = 0;
829 	backMove = 1;
830 	backMove2 = 2;
831 	backMove3 = 3;
832 	explodeMove = 2;
833 	enemiesActive = true;
834 	for(temp = 0; temp < 3; temp++)
835 	{
836 		button[temp] = false;
837 	}
838 	stopBackgrounds = false;
839 	stopBackgroundNum = 0;
840 	background3x1   = false;
841 	background3x1b  = false;
842 	background3over = 0;
843 	background2over = 1;
844 	topEnemyOver = false;
845 	skyEnemyOverAll = false;
846 	smallEnemyAdjust = false;
847 	starActive = true;
848 	enemyContinualDamage = false;
849 	levelEnemyFrequency = 96;
850 	quitRequested = false;
851 
852 	for (unsigned int i = 0; i < COUNTOF(boss_bar); i++)
853 		boss_bar[i].link_num = 0;
854 
855 	forceEvents = false;  /*Force events to continue if background movement = 0*/
856 
857 	superEnemy254Jump = 0;   /*When Enemy with PL 254 dies*/
858 
859 	/* Filter Status */
860 	filterActive = true;
861 	filterFade = true;
862 	filterFadeStart = false;
863 	levelFilter = -99;
864 	levelBrightness = -14;
865 	levelBrightnessChg = 1;
866 
867 	background2notTransparent = false;
868 
869 	uint old_weapon_bar[2] = { 0, 0 };  // only redrawn when they change
870 
871 	/* Initially erase power bars */
872 	lastPower = power / 10;
873 
874 	/* Initial Text */
875 	JE_drawTextWindow(miscText[20]);
876 
877 	/* Setup Armor/Shield Data */
878 	shieldWait = 1;
879 	shieldT    = shields[player[0].items.shield].tpwr * 20;
880 
881 	for (uint i = 0; i < COUNTOF(player); ++i)
882 	{
883 		player[i].shield     = shields[player[i].items.shield].mpwr;
884 		player[i].shield_max = player[i].shield * 2;
885 	}
886 
887 	JE_drawShield();
888 	JE_drawArmor();
889 
890 	for (uint i = 0; i < COUNTOF(player); ++i)
891 		player[i].superbombs = 0;
892 
893 	/* Set cubes to 0 */
894 	cubeMax = 0;
895 
896 	/* Secret Level Display */
897 	flash = 0;
898 	flashChange = 1;
899 	displayTime = 0;
900 
901 	play_song(levelSong - 1);
902 
903 	JE_drawPortConfigButtons();
904 
905 	/* --- MAIN LOOP --- */
906 
907 	newkey = false;
908 
909 #ifdef WITH_NETWORK
910 	if (isNetworkGame)
911 	{
912 		JE_clearSpecialRequests();
913 		mt_srand(32402394);
914 	}
915 #endif
916 
917 	initialize_starfield();
918 
919 	JE_setNewGameSpeed();
920 
921 	/* JE_setVol(tyrMusicVolume, fxPlayVol >> 2); NOTE: MXD killed this because it was broken */
922 
923 	/*Save backup game*/
924 	if (!play_demo && !doNotSaveBackup)
925 	{
926 		temp = twoPlayerMode ? 22 : 11;
927 		JE_saveGame(temp, "LAST LEVEL    ");
928 	}
929 
930 	if (!play_demo && record_demo)
931 	{
932 		Uint8 new_demo_num = 0;
933 
934 		do
935 		{
936 			sprintf(tempStr, "demorec.%d", new_demo_num++);
937 		}
938 		while (dir_file_exists(get_user_directory(), tempStr)); // until file doesn't exist
939 
940 		demo_file = dir_fopen_warn(get_user_directory(), tempStr, "wb");
941 		if (!demo_file)
942 			exit(1);
943 
944 		efwrite(&episodeNum, 1,  1, demo_file);
945 		efwrite(levelName,   1, 10, demo_file);
946 		efwrite(&lvlFileNum, 1,  1, demo_file);
947 
948 		fputc(player[0].items.weapon[FRONT_WEAPON].id,  demo_file);
949 		fputc(player[0].items.weapon[REAR_WEAPON].id,   demo_file);
950 		fputc(player[0].items.super_arcade_mode,        demo_file);
951 		fputc(player[0].items.sidekick[LEFT_SIDEKICK],  demo_file);
952 		fputc(player[0].items.sidekick[RIGHT_SIDEKICK], demo_file);
953 		fputc(player[0].items.generator,                demo_file);
954 
955 		fputc(player[0].items.sidekick_level,           demo_file);
956 		fputc(player[0].items.sidekick_series,          demo_file);
957 
958 		fputc(initial_episode_num,                      demo_file);
959 
960 		fputc(player[0].items.shield,                   demo_file);
961 		fputc(player[0].items.special,                  demo_file);
962 		fputc(player[0].items.ship,                     demo_file);
963 
964 		for (uint i = 0; i < 2; ++i)
965 			fputc(player[0].items.weapon[i].power, demo_file);
966 
967 		for (uint i = 0; i < 3; ++i)
968 			fputc(0, demo_file);
969 
970 		efwrite(&levelSong,  1,  1, demo_file);
971 
972 		demo_keys = 0;
973 		demo_keys_wait = 0;
974 	}
975 
976 	twoPlayerLinked = false;
977 	linkGunDirec = M_PI;
978 
979 	for (uint i = 0; i < COUNTOF(player); ++i)
980 		calc_purple_balls_needed(&player[i]);
981 
982 	damageRate = 2;  /*Normal Rate for Collision Damage*/
983 
984 	chargeWait   = 5;
985 	chargeLevel  = 0;
986 	chargeMax    = 5;
987 	chargeGr     = 0;
988 	chargeGrWait = 3;
989 
990 	portConfigChange = false;
991 
992 	/*Destruction Ratio*/
993 	totalEnemy = 0;
994 	enemyKilled = 0;
995 
996 	astralDuration = 0;
997 
998 	superArcadePowerUp = 1;
999 
1000 	yourInGameMenuRequest = false;
1001 
1002 	constantLastX = -1;
1003 
1004 	for (uint i = 0; i < COUNTOF(player); ++i)
1005 		player[i].exploding_ticks = 0;
1006 
1007 	if (isNetworkGame)
1008 	{
1009 		JE_loadItemDat();
1010 	}
1011 
1012 	memset(enemyAvail,       1, sizeof(enemyAvail));
1013 	for (uint i = 0; i < COUNTOF(enemyShotAvail); i++)
1014 		enemyShotAvail[i] = 1;
1015 
1016 	/*Initialize Shots*/
1017 	memset(playerShotData,   0, sizeof(playerShotData));
1018 	memset(shotAvail,        0, sizeof(shotAvail));
1019 	memset(shotMultiPos,     0, sizeof(shotMultiPos));
1020 	memset(shotRepeat,       1, sizeof(shotRepeat));
1021 
1022 	memset(button,           0, sizeof(button));
1023 
1024 	memset(globalFlags,      0, sizeof(globalFlags));
1025 
1026 	memset(explosions,       0, sizeof(explosions));
1027 	memset(rep_explosions,   0, sizeof(rep_explosions));
1028 
1029 	/* --- Clear Sound Queue --- */
1030 	memset(soundQueue,       0, sizeof(soundQueue));
1031 	soundQueue[3] = V_GOOD_LUCK;
1032 
1033 	memset(enemyShapeTables, 0, sizeof(enemyShapeTables));
1034 	memset(enemy,            0, sizeof(enemy));
1035 
1036 	memset(SFCurrentCode,    0, sizeof(SFCurrentCode));
1037 	memset(SFExecuted,       0, sizeof(SFExecuted));
1038 
1039 	zinglonDuration = 0;
1040 	specialWait = 0;
1041 	nextSpecialWait = 0;
1042 	optionAttachmentMove  = 0;    /*Launch the Attachments!*/
1043 	optionAttachmentLinked = true;
1044 
1045 	editShip1 = false;
1046 	editShip2 = false;
1047 
1048 	memset(smoothies, 0, sizeof(smoothies));
1049 
1050 	levelTimer = false;
1051 	randomExplosions = false;
1052 
1053 	last_superpixel = 0;
1054 	memset(superpixels, 0, sizeof(superpixels));
1055 
1056 	returnActive = false;
1057 
1058 	galagaShotFreq = 0;
1059 
1060 	if (galagaMode)
1061 	{
1062 		difficultyLevel = 2;
1063 	}
1064 	galagaLife = 10000;
1065 
1066 	JE_drawOptionLevel();
1067 
1068 	// keeps map from scrolling past the top
1069 	BKwrap1 = BKwrap1to = &megaData1.mainmap[1][0];
1070 	BKwrap2 = BKwrap2to = &megaData2.mainmap[1][0];
1071 	BKwrap3 = BKwrap3to = &megaData3.mainmap[1][0];
1072 
1073 level_loop:
1074 
1075 	//tempScreenSeg = game_screen; /* side-effect of game_screen */
1076 
1077 	if (isNetworkGame)
1078 	{
1079 		smoothies[9-1] = false;
1080 		smoothies[6-1] = false;
1081 	} else {
1082 		starShowVGASpecialCode = smoothies[9-1] + (smoothies[6-1] << 1);
1083 	}
1084 
1085 	/*Background Wrapping*/
1086 	if (mapYPos <= BKwrap1)
1087 	{
1088 		mapYPos = BKwrap1to;
1089 	}
1090 	if (mapY2Pos <= BKwrap2)
1091 	{
1092 		mapY2Pos = BKwrap2to;
1093 	}
1094 	if (mapY3Pos <= BKwrap3)
1095 	{
1096 		mapY3Pos = BKwrap3to;
1097 	}
1098 
1099 
1100 	allPlayersGone = all_players_dead() &&
1101 	                 ((*player[0].lives == 1 && player[0].exploding_ticks == 0) || (!onePlayerAction && !twoPlayerMode)) &&
1102 	                 ((*player[1].lives == 1 && player[1].exploding_ticks == 0) || !twoPlayerMode);
1103 
1104 
1105 	/*-----MUSIC FADE------*/
1106 	if (musicFade)
1107 	{
1108 		if (tempVolume > 10)
1109 		{
1110 			tempVolume--;
1111 			set_volume(tempVolume, fxVolume);
1112 		}
1113 		else
1114 		{
1115 			musicFade = false;
1116 		}
1117 	}
1118 
1119 	if (!allPlayersGone && levelEnd > 0 && endLevel)
1120 	{
1121 		play_song(9);
1122 		musicFade = false;
1123 	}
1124 	else if (!playing && firstGameOver)
1125 	{
1126 		play_song(levelSong - 1);
1127 	}
1128 
1129 
1130 	if (!endLevel) // draw HUD
1131 	{
1132 		VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
1133 
1134 		/*-----------------------Message Bar------------------------*/
1135 		if (textErase > 0 && --textErase == 0)
1136 			blit_sprite(VGAScreenSeg, 16, 189, OPTION_SHAPES, 36);  // in-game message area
1137 
1138 		/*------------------------Shield Gen-------------------------*/
1139 		if (galagaMode)
1140 		{
1141 			for (uint i = 0; i < COUNTOF(player); ++i)
1142 				player[i].shield = 0;
1143 
1144 			// spawned dragonwing died :(
1145 			if (*player[1].lives == 0 || player[1].armor == 0)
1146 				twoPlayerMode = false;
1147 
1148 			if (player[0].cash >= (unsigned)galagaLife)
1149 			{
1150 				soundQueue[6] = S_EXPLOSION_11;
1151 				soundQueue[7] = S_SOUL_OF_ZINGLON;
1152 
1153 				if (*player[0].lives < 11)
1154 					++(*player[0].lives);
1155 				else
1156 					player[0].cash += 1000;
1157 
1158 				if (galagaLife == 10000)
1159 					galagaLife = 20000;
1160 				else
1161 					galagaLife += 25000;
1162 			}
1163 		}
1164 		else // not galagaMode
1165 		{
1166 			if (twoPlayerMode)
1167 			{
1168 				if (--shieldWait == 0)
1169 				{
1170 					shieldWait = 15;
1171 
1172 					for (uint i = 0; i < COUNTOF(player); ++i)
1173 					{
1174 						if (player[i].shield < player[i].shield_max && player[i].is_alive)
1175 							++player[i].shield;
1176 					}
1177 
1178 					JE_drawShield();
1179 				}
1180 			}
1181 			else if (player[0].is_alive && player[0].shield < player[0].shield_max && power > shieldT)
1182 			{
1183 				if (--shieldWait == 0)
1184 				{
1185 					shieldWait = 15;
1186 
1187 					power -= shieldT;
1188 
1189 					++player[0].shield;
1190 					if (player[1].shield < player[0].shield_max)
1191 						++player[1].shield;
1192 
1193 					JE_drawShield();
1194 				}
1195 			}
1196 		}
1197 
1198 		/*---------------------Weapon Display-------------------------*/
1199 		for (uint i = 0; i < 2; ++i)
1200 		{
1201 			uint item_power = player[twoPlayerMode ? i : 0].items.weapon[i].power;
1202 
1203 			if (old_weapon_bar[i] != item_power)
1204 			{
1205 				old_weapon_bar[i] = item_power;
1206 
1207 				int x = twoPlayerMode ? 286 : 289,
1208 				    y = (i == 0) ? (twoPlayerMode ? 6 : 17) : (twoPlayerMode ? 100 : 38);
1209 
1210 				fill_rectangle_xy(VGAScreenSeg, x, y, x + 1 + 10 * 2, y + 2, 0);
1211 
1212 				for (uint j = 1; j <= item_power; ++j)
1213 				{
1214 					JE_rectangle(VGAScreen, x, y, x + 1, y + 2, 115 + j); /* SEGa000 */
1215 					x += 2;
1216 				}
1217 			}
1218 		}
1219 
1220 		/*------------------------Power Bar-------------------------*/
1221 		if (twoPlayerMode || onePlayerAction)
1222 		{
1223 			power = 900;
1224 		}
1225 		else
1226 		{
1227 			power += powerAdd;
1228 			if (power > 900)
1229 				power = 900;
1230 
1231 			temp = power / 10;
1232 
1233 			if (temp != lastPower)
1234 			{
1235 				if (temp > lastPower)
1236 					fill_rectangle_xy(VGAScreenSeg, 269, 113 - 11 - temp, 276, 114 - 11 - lastPower, 113 + temp / 7);
1237 				else
1238 					fill_rectangle_xy(VGAScreenSeg, 269, 113 - 11 - lastPower, 276, 114 - 11 - temp, 0);
1239 
1240 				lastPower = temp;
1241 			}
1242 		}
1243 
1244 		oldMapX3Ofs = mapX3Ofs;
1245 
1246 		enemyOnScreen = 0;
1247 	}
1248 
1249 	/* use game_screen for all the generic drawing functions */
1250 	VGAScreen = game_screen;
1251 
1252 	/*---------------------------EVENTS-------------------------*/
1253 	while (eventRec[eventLoc-1].eventtime <= curLoc && eventLoc <= maxEvent)
1254 		JE_eventSystem();
1255 
1256 	if (isNetworkGame && reallyEndLevel)
1257 		goto start_level;
1258 
1259 
1260 	/* SMOOTHIES! */
1261 	JE_checkSmoothies();
1262 	if (anySmoothies)
1263 		VGAScreen = VGAScreen2;  // this makes things complicated, but we do it anyway :(
1264 
1265 	/* --- BACKGROUNDS --- */
1266 	/* --- BACKGROUND 1 --- */
1267 
1268 	if (forceEvents && !backMove)
1269 		curLoc++;
1270 
1271 	if (map1YDelayMax > 1 && backMove < 2)
1272 		backMove = (map1YDelay == 1) ? 1 : 0;
1273 
1274 	/*Draw background*/
1275 	if (astralDuration == 0)
1276 		draw_background_1(VGAScreen);
1277 	else
1278 		JE_clr256(VGAScreen);
1279 
1280 	/*Set Movement of background 1*/
1281 	if (--map1YDelay == 0)
1282 	{
1283 		map1YDelay = map1YDelayMax;
1284 
1285 		curLoc += backMove;
1286 
1287 		backPos += backMove;
1288 
1289 		if (backPos > 27)
1290 		{
1291 			backPos -= 28;
1292 			mapY--;
1293 			mapYPos -= 14;  /*Map Width*/
1294 		}
1295 	}
1296 
1297 	if (starActive || astralDuration > 0)
1298 	{
1299 		update_and_draw_starfield(VGAScreen, starfield_speed);
1300 	}
1301 
1302 	if (processorType > 1 && smoothies[5-1])
1303 	{
1304 		iced_blur_filter(game_screen, VGAScreen);
1305 		VGAScreen = game_screen;
1306 	}
1307 
1308 	/*-----------------------BACKGROUNDS------------------------*/
1309 	/*-----------------------BACKGROUND 2------------------------*/
1310 	if (background2over == 3)
1311 	{
1312 		draw_background_2(VGAScreen);
1313 		background2 = true;
1314 	}
1315 
1316 	if (background2over == 0)
1317 	{
1318 		if (!(smoothies[2-1] && processorType < 4) && !(smoothies[1-1] && processorType == 3))
1319 		{
1320 			if (wild && !background2notTransparent)
1321 				draw_background_2_blend(VGAScreen);
1322 			else
1323 				draw_background_2(VGAScreen);
1324 		}
1325 	}
1326 
1327 	if (smoothies[0] && processorType > 2 && smoothie_data[0] == 0)
1328 	{
1329 		lava_filter(game_screen, VGAScreen);
1330 		VGAScreen = game_screen;
1331 	}
1332 	if (smoothies[2-1] && processorType > 2)
1333 	{
1334 		water_filter(game_screen, VGAScreen);
1335 		VGAScreen = game_screen;
1336 	}
1337 
1338 	/*-----------------------Ground Enemy------------------------*/
1339 	lastEnemyOnScreen = enemyOnScreen;
1340 
1341 	tempMapXOfs = mapXOfs;
1342 	tempBackMove = backMove;
1343 	JE_drawEnemy(50);
1344 	JE_drawEnemy(100);
1345 
1346 	if (enemyOnScreen == 0 || enemyOnScreen == lastEnemyOnScreen)
1347 	{
1348 		if (stopBackgroundNum == 1)
1349 			stopBackgroundNum = 9;
1350 	}
1351 
1352 	if (smoothies[0] && processorType > 2 && smoothie_data[0] > 0)
1353 	{
1354 		lava_filter(game_screen, VGAScreen);
1355 		VGAScreen = game_screen;
1356 	}
1357 
1358 	if (superWild)
1359 	{
1360 		neat += 3;
1361 		JE_darkenBackground(neat);
1362 	}
1363 
1364 	/*-----------------------BACKGROUNDS------------------------*/
1365 	/*-----------------------BACKGROUND 2------------------------*/
1366 	if (!(smoothies[2-1] && processorType < 4) &&
1367 	    !(smoothies[1-1] && processorType == 3))
1368 	{
1369 		if (background2over == 1)
1370 		{
1371 			if (wild && !background2notTransparent)
1372 				draw_background_2_blend(VGAScreen);
1373 			else
1374 				draw_background_2(VGAScreen);
1375 		}
1376 	}
1377 
1378 	if (superWild)
1379 	{
1380 		neat++;
1381 		JE_darkenBackground(neat);
1382 	}
1383 
1384 	if (background3over == 2)
1385 		draw_background_3(VGAScreen);
1386 
1387 	/* New Enemy */
1388 	if (enemiesActive && mt_rand() % 100 > levelEnemyFrequency)
1389 	{
1390 		tempW = levelEnemy[mt_rand() % levelEnemyMax];
1391 		if (tempW == 2)
1392 			soundQueue[3] = S_WEAPON_7;
1393 		b = JE_newEnemy(0, tempW, 0);
1394 	}
1395 
1396 	if (processorType > 1 && smoothies[3-1])
1397 	{
1398 		iced_blur_filter(game_screen, VGAScreen);
1399 		VGAScreen = game_screen;
1400 	}
1401 	if (processorType > 1 && smoothies[4-1])
1402 	{
1403 		blur_filter(game_screen, VGAScreen);
1404 		VGAScreen = game_screen;
1405 	}
1406 
1407 	/* Draw Sky Enemy */
1408 	if (!skyEnemyOverAll)
1409 	{
1410 		lastEnemyOnScreen = enemyOnScreen;
1411 
1412 		tempMapXOfs = mapX2Ofs;
1413 		tempBackMove = 0;
1414 		JE_drawEnemy(25);
1415 
1416 		if (enemyOnScreen == lastEnemyOnScreen)
1417 		{
1418 			if (stopBackgroundNum == 2)
1419 				stopBackgroundNum = 9;
1420 		}
1421 	}
1422 
1423 	if (background3over == 0)
1424 		draw_background_3(VGAScreen);
1425 
1426 	/* Draw Top Enemy */
1427 	if (!topEnemyOver)
1428 	{
1429 		tempMapXOfs = (background3x1 == 0) ? oldMapX3Ofs : mapXOfs;
1430 		tempBackMove = backMove3;
1431 		JE_drawEnemy(75);
1432 	}
1433 
1434 	/* Player Shot Images */
1435 	for (int z = 0; z < MAX_PWEAPON; z++)
1436 	{
1437 		if (shotAvail[z] != 0)
1438 		{
1439 			bool is_special = false;
1440 			int tempShotX = 0, tempShotY = 0;
1441 			JE_byte chain;
1442 			JE_byte playerNum;
1443 			JE_word tempX2, tempY2;
1444 			JE_integer damage;
1445 
1446 			if (!player_shot_move_and_draw(z, &is_special, &tempShotX, &tempShotY, &damage, &temp2, &chain, &playerNum, &tempX2, &tempY2))
1447 			{
1448 				goto draw_player_shot_loop_end;
1449 			}
1450 
1451 			for (b = 0; b < 100; b++)
1452 			{
1453 				if (enemyAvail[b] == 0)
1454 				{
1455 					bool collided;
1456 
1457 					if (z == MAX_PWEAPON - 1)
1458 					{
1459 						temp = 25 - abs(zinglonDuration - 25);
1460 						collided = abs(enemy[b].ex + enemy[b].mapoffset - (player[0].x + 7)) < temp;
1461 						temp2 = 9;
1462 						chain = 0;
1463 						damage = 10;
1464 					}
1465 					else if (is_special)
1466 					{
1467 						collided = ((enemy[b].enemycycle == 0) &&
1468 						            (abs(enemy[b].ex + enemy[b].mapoffset - tempShotX - tempX2) < (25 + tempX2)) &&
1469 						            (abs(enemy[b].ey - tempShotY - 12 - tempY2)                 < (29 + tempY2))) ||
1470 						           ((enemy[b].enemycycle > 0) &&
1471 						            (abs(enemy[b].ex + enemy[b].mapoffset - tempShotX - tempX2) < (13 + tempX2)) &&
1472 						            (abs(enemy[b].ey - tempShotY - 6 - tempY2)                  < (15 + tempY2)));
1473 					}
1474 					else
1475 					{
1476 						collided = ((enemy[b].enemycycle == 0) &&
1477 						            (abs(enemy[b].ex + enemy[b].mapoffset - tempShotX) < 25) && (abs(enemy[b].ey - tempShotY - 12) < 29)) ||
1478 						           ((enemy[b].enemycycle > 0) &&
1479 						            (abs(enemy[b].ex + enemy[b].mapoffset - tempShotX) < 13) && (abs(enemy[b].ey - tempShotY - 6) < 15));
1480 					}
1481 
1482 					if (collided)
1483 					{
1484 						if (chain > 0)
1485 						{
1486 							shotMultiPos[SHOT_MISC] = 0;
1487 							b = player_shot_create(0, SHOT_MISC, tempShotX, tempShotY, mouseX, mouseY, chain, playerNum);
1488 							shotAvail[z] = 0;
1489 							goto draw_player_shot_loop_end;
1490 						}
1491 
1492 						infiniteShot = false;
1493 
1494 						if (damage == 99)
1495 						{
1496 							damage = 0;
1497 							doIced = 40;
1498 							enemy[b].iced = 40;
1499 						}
1500 						else
1501 						{
1502 							doIced = 0;
1503 							if (damage >= 250)
1504 							{
1505 								damage = damage - 250;
1506 								infiniteShot = true;
1507 							}
1508 						}
1509 
1510 						int armorleft = enemy[b].armorleft;
1511 
1512 						temp = enemy[b].linknum;
1513 						if (temp == 0)
1514 							temp = 255;
1515 
1516 						if (enemy[b].armorleft < 255)
1517 						{
1518 							for (unsigned int i = 0; i < COUNTOF(boss_bar); i++)
1519 								if (temp == boss_bar[i].link_num)
1520 									boss_bar[i].color = 6;
1521 
1522 							if (enemy[b].enemyground)
1523 								enemy[b].filter = temp2;
1524 
1525 							for (unsigned int e = 0; e < COUNTOF(enemy); e++)
1526 							{
1527 								if (enemy[e].linknum == temp &&
1528 								    enemyAvail[e] != 1 &&
1529 								    enemy[e].enemyground != 0)
1530 								{
1531 									if (doIced)
1532 										enemy[e].iced = doIced;
1533 									enemy[e].filter = temp2;
1534 								}
1535 							}
1536 						}
1537 
1538 						if (armorleft > damage)
1539 						{
1540 							if (z != MAX_PWEAPON - 1)
1541 							{
1542 								if (enemy[b].armorleft != 255)
1543 								{
1544 									enemy[b].armorleft -= damage;
1545 									JE_setupExplosion(tempShotX, tempShotY, 0, 0, false, false);
1546 								}
1547 								else
1548 								{
1549 									JE_doSP(tempShotX + 6, tempShotY + 6, damage / 2 + 3, damage / 4 + 2, temp2);
1550 								}
1551 							}
1552 
1553 							soundQueue[5] = S_ENEMY_HIT;
1554 
1555 							if ((armorleft - damage <= enemy[b].edlevel) &&
1556 							    ((!enemy[b].edamaged) ^ (enemy[b].edani < 0)))
1557 							{
1558 
1559 								for (temp3 = 0; temp3 < 100; temp3++)
1560 								{
1561 									if (enemyAvail[temp3] != 1)
1562 									{
1563 										int linknum = enemy[temp3].linknum;
1564 										if (
1565 										     (temp3 == b) ||
1566 										     (
1567 										       (temp != 255) &&
1568 										       (
1569 										         ((enemy[temp3].edlevel > 0) && (linknum == temp)) ||
1570 										         (
1571 										           (enemyContinualDamage && (temp - 100 == linknum)) ||
1572 										           ((linknum > 40) && (linknum / 20 == temp / 20) && (linknum <= temp))
1573 										         )
1574 										       )
1575 										     )
1576 										   )
1577 										{
1578 											enemy[temp3].enemycycle = 1;
1579 
1580 											enemy[temp3].edamaged = !enemy[temp3].edamaged;
1581 
1582 											if (enemy[temp3].edani != 0)
1583 											{
1584 												enemy[temp3].ani = abs(enemy[temp3].edani);
1585 												enemy[temp3].aniactive = 1;
1586 												enemy[temp3].animax = 0;
1587 												enemy[temp3].animin = enemy[temp3].edgr;
1588 												enemy[temp3].enemycycle = enemy[temp3].animin - 1;
1589 
1590 											}
1591 											else if (enemy[temp3].edgr > 0)
1592 											{
1593 												enemy[temp3].egr[1-1] = enemy[temp3].edgr;
1594 												enemy[temp3].ani = 1;
1595 												enemy[temp3].aniactive = 0;
1596 												enemy[temp3].animax = 0;
1597 												enemy[temp3].animin = 1;
1598 											}
1599 											else
1600 											{
1601 												enemyAvail[temp3] = 1;
1602 												enemyKilled++;
1603 											}
1604 
1605 											enemy[temp3].aniwhenfire = 0;
1606 
1607 											if (enemy[temp3].armorleft > (unsigned char)enemy[temp3].edlevel)
1608 												enemy[temp3].armorleft = enemy[temp3].edlevel;
1609 
1610 											tempX = enemy[temp3].ex + enemy[temp3].mapoffset;
1611 											tempY = enemy[temp3].ey;
1612 
1613 											if (enemyDat[enemy[temp3].enemytype].esize != 1)
1614 												JE_setupExplosion(tempX, tempY - 6, 0, 1, false, false);
1615 											else
1616 												JE_setupExplosionLarge(enemy[temp3].enemyground, enemy[temp3].explonum / 2, tempX, tempY);
1617 										}
1618 									}
1619 								}
1620 							}
1621 						}
1622 						else
1623 						{
1624 
1625 							if ((temp == 254) && (superEnemy254Jump > 0))
1626 								JE_eventJump(superEnemy254Jump);
1627 
1628 							for (temp2 = 0; temp2 < 100; temp2++)
1629 							{
1630 								if (enemyAvail[temp2] != 1)
1631 								{
1632 									temp3 = enemy[temp2].linknum;
1633 									if ((temp2 == b) || (temp == 254) ||
1634 									    ((temp != 255) && ((temp == temp3) || (temp - 100 == temp3)
1635 									    || ((temp3 > 40) && (temp3 / 20 == temp / 20) && (temp3 <= temp)))))
1636 									{
1637 
1638 										int enemy_screen_x = enemy[temp2].ex + enemy[temp2].mapoffset;
1639 
1640 										if (enemy[temp2].special)
1641 										{
1642 											assert((unsigned int) enemy[temp2].flagnum-1 < COUNTOF(globalFlags));
1643 											globalFlags[enemy[temp2].flagnum-1] = enemy[temp2].setto;
1644 										}
1645 
1646 										if ((enemy[temp2].enemydie > 0) &&
1647 										    !((superArcadeMode != SA_NONE) &&
1648 										      (enemyDat[enemy[temp2].enemydie].value == 30000)))
1649 										{
1650 											int temp_b = b;
1651 											tempW = enemy[temp2].enemydie;
1652 											int enemy_offset = temp2 - (temp2 % 25);
1653 											if (enemyDat[tempW].value > 30000)
1654 											{
1655 												enemy_offset = 0;
1656 											}
1657 											b = JE_newEnemy(enemy_offset, tempW, 0);
1658 											if (b != 0) {
1659 												if ((superArcadeMode != SA_NONE) && (enemy[b-1].evalue > 30000))
1660 												{
1661 													superArcadePowerUp++;
1662 													if (superArcadePowerUp > 5)
1663 														superArcadePowerUp = 1;
1664 													enemy[b-1].egr[1-1] = 5 + superArcadePowerUp * 2;
1665 													enemy[b-1].evalue = 30000 + superArcadePowerUp;
1666 												}
1667 
1668 												if (enemy[b-1].evalue != 0)
1669 													enemy[b-1].scoreitem = true;
1670 												else
1671 													enemy[b-1].scoreitem = false;
1672 
1673 												enemy[b-1].ex = enemy[temp2].ex;
1674 												enemy[b-1].ey = enemy[temp2].ey;
1675 											}
1676 											b = temp_b;
1677 										}
1678 
1679 										if ((enemy[temp2].evalue > 0) && (enemy[temp2].evalue < 10000))
1680 										{
1681 											if (enemy[temp2].evalue == 1)
1682 											{
1683 												cubeMax++;
1684 											}
1685 											else
1686 											{
1687 												// in galaga mode player 2 is sidekick, so give cash to player 1
1688 												player[galagaMode ? 0 : playerNum - 1].cash += enemy[temp2].evalue;
1689 											}
1690 										}
1691 
1692 										if ((enemy[temp2].edlevel == -1) && (temp == temp3))
1693 										{
1694 											enemy[temp2].edlevel = 0;
1695 											enemyAvail[temp2] = 2;
1696 											enemy[temp2].egr[1-1] = enemy[temp2].edgr;
1697 											enemy[temp2].ani = 1;
1698 											enemy[temp2].aniactive = 0;
1699 											enemy[temp2].animax = 0;
1700 											enemy[temp2].animin = 1;
1701 											enemy[temp2].edamaged = true;
1702 											enemy[temp2].enemycycle = 1;
1703 										} else {
1704 											enemyAvail[temp2] = 1;
1705 											enemyKilled++;
1706 										}
1707 
1708 										if (enemyDat[enemy[temp2].enemytype].esize == 1)
1709 										{
1710 											JE_setupExplosionLarge(enemy[temp2].enemyground, enemy[temp2].explonum, enemy_screen_x, enemy[temp2].ey);
1711 											soundQueue[6] = S_EXPLOSION_9;
1712 										}
1713 										else
1714 										{
1715 											JE_setupExplosion(enemy_screen_x, enemy[temp2].ey, 0, 1, false, false);
1716 											soundQueue[6] = S_SELECT; // S_EXPLOSION_8
1717 										}
1718 									}
1719 								}
1720 							}
1721 						}
1722 
1723 						if (infiniteShot)
1724 						{
1725 							damage += 250;
1726 						}
1727 						else if (z != MAX_PWEAPON - 1)
1728 						{
1729 							if (damage <= armorleft)
1730 							{
1731 								shotAvail[z] = 0;
1732 								goto draw_player_shot_loop_end;
1733 							}
1734 							else
1735 							{
1736 								playerShotData[z].shotDmg -= armorleft;
1737 							}
1738 						}
1739 					}
1740 				}
1741 			}
1742 
1743 draw_player_shot_loop_end:
1744 			;
1745 		}
1746 	}
1747 
1748 	/* Player movement indicators for shots that track your ship */
1749 	for (uint i = 0; i < COUNTOF(player); ++i)
1750 	{
1751 		player[i].last_x_shot_move = player[i].x;
1752 		player[i].last_y_shot_move = player[i].y;
1753 	}
1754 
1755 	/*=================================*/
1756 	/*=======Collisions Detection======*/
1757 	/*=================================*/
1758 
1759 	for (uint i = 0; i < (twoPlayerMode ? 2 : 1); ++i)
1760 		if (player[i].is_alive && !endLevel)
1761 			JE_playerCollide(&player[i], i + 1);
1762 
1763 	if (firstGameOver)
1764 		JE_mainGamePlayerFunctions();      /*--------PLAYER DRAW+MOVEMENT---------*/
1765 
1766 	if (!endLevel)
1767 	{    /*MAIN DRAWING IS STOPPED STARTING HERE*/
1768 
1769 		/* Draw Enemy Shots */
1770 		for (int z = 0; z < ENEMY_SHOT_MAX; z++)
1771 		{
1772 			if (enemyShotAvail[z] == 0)
1773 			{
1774 				enemyShot[z].sxm += enemyShot[z].sxc;
1775 				enemyShot[z].sx += enemyShot[z].sxm;
1776 
1777 				if (enemyShot[z].tx != 0)
1778 				{
1779 					if (enemyShot[z].sx > player[0].x)
1780 					{
1781 						if (enemyShot[z].sxm > -enemyShot[z].tx)
1782 						{
1783 							enemyShot[z].sxm--;
1784 						}
1785 					} else {
1786 						if (enemyShot[z].sxm < enemyShot[z].tx)
1787 						{
1788 							enemyShot[z].sxm++;
1789 						}
1790 					}
1791 				}
1792 
1793 				enemyShot[z].sym += enemyShot[z].syc;
1794 				enemyShot[z].sy += enemyShot[z].sym;
1795 
1796 				if (enemyShot[z].ty != 0)
1797 				{
1798 					if (enemyShot[z].sy > player[0].y)
1799 					{
1800 						if (enemyShot[z].sym > -enemyShot[z].ty)
1801 						{
1802 							enemyShot[z].sym--;
1803 						}
1804 					} else {
1805 						if (enemyShot[z].sym < enemyShot[z].ty)
1806 						{
1807 							enemyShot[z].sym++;
1808 						}
1809 					}
1810 				}
1811 
1812 				if (enemyShot[z].duration-- == 0 || enemyShot[z].sy > 190 || enemyShot[z].sy <= -14 || enemyShot[z].sx > 275 || enemyShot[z].sx <= 0)
1813 				{
1814 					enemyShotAvail[z] = true;
1815 				}
1816 				else  // check if shot collided with player
1817 				{
1818 					for (uint i = 0; i < (twoPlayerMode ? 2 : 1); ++i)
1819 					{
1820 						if (player[i].is_alive &&
1821 						    enemyShot[z].sx > player[i].x - (signed)player[i].shot_hit_area_x &&
1822 						    enemyShot[z].sx < player[i].x + (signed)player[i].shot_hit_area_x &&
1823 						    enemyShot[z].sy > player[i].y - (signed)player[i].shot_hit_area_y &&
1824 						    enemyShot[z].sy < player[i].y + (signed)player[i].shot_hit_area_y)
1825 						{
1826 							tempX = enemyShot[z].sx;
1827 							tempY = enemyShot[z].sy;
1828 							temp = enemyShot[z].sdmg;
1829 
1830 							enemyShotAvail[z] = true;
1831 
1832 							JE_setupExplosion(tempX, tempY, 0, 0, false, false);
1833 
1834 							if (player[i].invulnerable_ticks == 0)
1835 							{
1836 								if ((temp = JE_playerDamage(temp, &player[i])) > 0)
1837 								{
1838 									player[i].x_velocity += (enemyShot[z].sxm * temp) / 2;
1839 									player[i].y_velocity += (enemyShot[z].sym * temp) / 2;
1840 								}
1841 							}
1842 
1843 							break;
1844 						}
1845 					}
1846 
1847 					if (enemyShotAvail[z] == false)
1848 					{
1849 						if (enemyShot[z].animax != 0)
1850 						{
1851 							if (++enemyShot[z].animate >= enemyShot[z].animax)
1852 								enemyShot[z].animate = 0;
1853 						}
1854 
1855 						if (enemyShot[z].sgr >= 500)
1856 							blit_sprite2(VGAScreen, enemyShot[z].sx, enemyShot[z].sy, shapesW2, enemyShot[z].sgr + enemyShot[z].animate - 500);
1857 						else
1858 							blit_sprite2(VGAScreen, enemyShot[z].sx, enemyShot[z].sy, shapesC1, enemyShot[z].sgr + enemyShot[z].animate);
1859 					}
1860 				}
1861 
1862 			}
1863 		}
1864 	}
1865 
1866 	if (background3over == 1)
1867 		draw_background_3(VGAScreen);
1868 
1869 	/* Draw Top Enemy */
1870 	if (topEnemyOver)
1871 	{
1872 		tempMapXOfs = (background3x1 == 0) ? oldMapX3Ofs : oldMapXOfs;
1873 		tempBackMove = backMove3;
1874 		JE_drawEnemy(75);
1875 	}
1876 
1877 	/* Draw Sky Enemy */
1878 	if (skyEnemyOverAll)
1879 	{
1880 		lastEnemyOnScreen = enemyOnScreen;
1881 
1882 		tempMapXOfs = mapX2Ofs;
1883 		tempBackMove = 0;
1884 		JE_drawEnemy(25);
1885 
1886 		if (enemyOnScreen == lastEnemyOnScreen)
1887 		{
1888 			if (stopBackgroundNum == 2)
1889 				stopBackgroundNum = 9;
1890 		}
1891 	}
1892 
1893 	/*-------------------------- Sequenced Explosions -------------------------*/
1894 	enemyStillExploding = false;
1895 	for (int i = 0; i < MAX_REPEATING_EXPLOSIONS; i++)
1896 	{
1897 		if (rep_explosions[i].ttl != 0)
1898 		{
1899 			enemyStillExploding = true;
1900 
1901 			if (rep_explosions[i].delay > 0)
1902 			{
1903 				rep_explosions[i].delay--;
1904 				continue;
1905 			}
1906 
1907 			rep_explosions[i].y += backMove2 + 1;
1908 			tempX = rep_explosions[i].x + (mt_rand() % 24) - 12;
1909 			tempY = rep_explosions[i].y + (mt_rand() % 27) - 24;
1910 
1911 			if (rep_explosions[i].big)
1912 			{
1913 				JE_setupExplosionLarge(false, 2, tempX, tempY);
1914 
1915 				if (rep_explosions[i].ttl == 1 || mt_rand() % 5 == 1)
1916 					soundQueue[7] = S_EXPLOSION_11;
1917 				else
1918 					soundQueue[6] = S_EXPLOSION_9;
1919 
1920 				rep_explosions[i].delay = 4 + (mt_rand() % 3);
1921 			}
1922 			else
1923 			{
1924 				JE_setupExplosion(tempX, tempY, 0, 1, false, false);
1925 
1926 				soundQueue[5] = S_EXPLOSION_4;
1927 
1928 				rep_explosions[i].delay = 3;
1929 			}
1930 
1931 			rep_explosions[i].ttl--;
1932 		}
1933 	}
1934 
1935 	/*---------------------------- Draw Explosions ----------------------------*/
1936 	for (int j = 0; j < MAX_EXPLOSIONS; j++)
1937 	{
1938 		if (explosions[j].ttl != 0)
1939 		{
1940 			if (explosions[j].fixed_position != true)
1941 			{
1942 				explosions[j].sprite++;
1943 				explosions[j].y += explodeMove;
1944 			}
1945 			else if (explosions[j].follow_player == true)
1946 			{
1947 				explosions[j].x += explosionFollowAmountX;
1948 				explosions[j].y += explosionFollowAmountY;
1949 			}
1950 			explosions[j].y += explosions[j].delta_y;
1951 			explosions[j].x += explosions[j].delta_x;
1952 
1953 			if (explosions[j].y > 200 - 14)
1954 			{
1955 				explosions[j].ttl = 0;
1956 			}
1957 			else
1958 			{
1959 				if (explosionTransparent)
1960 					blit_sprite2_blend(VGAScreen, explosions[j].x, explosions[j].y, shapes6, explosions[j].sprite + 1);
1961 				else
1962 					blit_sprite2(VGAScreen, explosions[j].x, explosions[j].y, shapes6, explosions[j].sprite + 1);
1963 
1964 				explosions[j].ttl--;
1965 			}
1966 		}
1967 	}
1968 
1969 	if (!portConfigChange)
1970 		portConfigDone = true;
1971 
1972 
1973 	/*-----------------------BACKGROUNDS------------------------*/
1974 	/*-----------------------BACKGROUND 2------------------------*/
1975 	if (!(smoothies[2-1] && processorType < 4) &&
1976 	    !(smoothies[1-1] && processorType == 3))
1977 	{
1978 		if (background2over == 2)
1979 		{
1980 			if (wild && !background2notTransparent)
1981 				draw_background_2_blend(VGAScreen);
1982 			else
1983 				draw_background_2(VGAScreen);
1984 		}
1985 	}
1986 
1987 	/*-------------------------Warning---------------------------*/
1988 	if ((player[0].is_alive && player[0].armor < 6) ||
1989 	    (twoPlayerMode && !galagaMode && player[1].is_alive && player[1].armor < 6))
1990 	{
1991 		int armor_amount = (player[0].is_alive && player[0].armor < 6) ? player[0].armor : player[1].armor;
1992 
1993 		if (armorShipDelay > 0)
1994 		{
1995 			armorShipDelay--;
1996 		}
1997 		else
1998 		{
1999 			tempW = 560;
2000 			b = JE_newEnemy(50, tempW, 0);
2001 			if (b > 0)
2002 			{
2003 				enemy[b-1].enemydie = 560 + (mt_rand() % 3) + 1;
2004 				enemy[b-1].eyc -= backMove3;
2005 				enemy[b-1].armorleft = 4;
2006 			}
2007 			armorShipDelay = 500;
2008 		}
2009 
2010 		if ((player[0].is_alive && player[0].armor < 6 && (!isNetworkGame || thisPlayerNum == 1)) ||
2011 		    (twoPlayerMode && player[1].is_alive && player[1].armor < 6 && (!isNetworkGame || thisPlayerNum == 2)))
2012 		{
2013 
2014 			tempW = armor_amount * 4 + 8;
2015 			if (warningSoundDelay > tempW)
2016 				warningSoundDelay = tempW;
2017 
2018 			if (warningSoundDelay > 1)
2019 			{
2020 				warningSoundDelay--;
2021 			}
2022 			else
2023 			{
2024 				soundQueue[7] = S_WARNING;
2025 				warningSoundDelay = tempW;
2026 			}
2027 
2028 			warningCol += warningColChange;
2029 			if (warningCol > 113 + (14 - (armor_amount * 2)))
2030 			{
2031 				warningColChange = -warningColChange;
2032 				warningCol = 113 + (14 - (armor_amount * 2));
2033 			}
2034 			else if (warningCol < 113)
2035 			{
2036 				warningColChange = -warningColChange;
2037 			}
2038 			fill_rectangle_xy(VGAScreen, 24, 181, 138, 183, warningCol);
2039 			fill_rectangle_xy(VGAScreen, 175, 181, 287, 183, warningCol);
2040 			fill_rectangle_xy(VGAScreen, 24, 0, 287, 3, warningCol);
2041 
2042 			JE_outText(VGAScreen, 140, 178, "WARNING", 7, (warningCol % 16) / 2);
2043 
2044 		}
2045 	}
2046 
2047 	/*------- Random Explosions --------*/
2048 	if (randomExplosions && mt_rand() % 10 == 1)
2049 		JE_setupExplosionLarge(false, 20, mt_rand() % 280, mt_rand() % 180);
2050 
2051 	/*=================================*/
2052 	/*=======The Sound Routine=========*/
2053 	/*=================================*/
2054 	if (firstGameOver)
2055 	{
2056 		temp = 0;
2057 		for (temp2 = 0; temp2 < SFX_CHANNELS; temp2++)
2058 		{
2059 			if (soundQueue[temp2] != S_NONE)
2060 			{
2061 				temp = soundQueue[temp2];
2062 				if (temp2 == 3)
2063 					temp3 = fxPlayVol;
2064 				else if (temp == 15)
2065 					temp3 = fxPlayVol / 4;
2066 				else   /*Lightning*/
2067 					temp3 = fxPlayVol / 2;
2068 
2069 				JE_multiSamplePlay(digiFx[temp-1], fxSize[temp-1], temp2, temp3);
2070 
2071 				soundQueue[temp2] = S_NONE;
2072 			}
2073 		}
2074 	}
2075 
2076 	if (returnActive && enemyOnScreen == 0)
2077 	{
2078 		JE_eventJump(65535);
2079 		returnActive = false;
2080 	}
2081 
2082 	/*-------      DEbug      ---------*/
2083 	debugTime = SDL_GetTicks();
2084 	tempW = lastmouse_but;
2085 	tempX = mouse_x;
2086 	tempY = mouse_y;
2087 
2088 	if (debug)
2089 	{
2090 		strcpy(tempStr, "");
2091 		for (temp = 0; temp < 9; temp++)
2092 		{
2093 			sprintf(tempStr, "%s%c", tempStr,  smoothies[temp] + 48);
2094 		}
2095 		sprintf(buffer, "SM = %s", tempStr);
2096 		JE_outText(VGAScreen, 30, 70, buffer, 4, 0);
2097 
2098 		sprintf(buffer, "Memory left = %d", -1);
2099 		JE_outText(VGAScreen, 30, 80, buffer, 4, 0);
2100 		sprintf(buffer, "Enemies onscreen = %d", enemyOnScreen);
2101 		JE_outText(VGAScreen, 30, 90, buffer, 6, 0);
2102 
2103 		debugHist = debugHist + abs((JE_longint)debugTime - (JE_longint)lastDebugTime);
2104 		debugHistCount++;
2105 		sprintf(tempStr, "%2.3f", 1000.0f / roundf(debugHist / debugHistCount));
2106 		sprintf(buffer, "X:%d Y:%-5d  %s FPS  %d %d %d %d", (mapX - 1) * 12 + player[0].x, curLoc, tempStr, player[0].x_velocity, player[0].y_velocity, player[0].x, player[0].y);
2107 		JE_outText(VGAScreen, 45, 175, buffer, 15, 3);
2108 		lastDebugTime = debugTime;
2109 	}
2110 
2111 	if (displayTime > 0)
2112 	{
2113 		displayTime--;
2114 		JE_outTextAndDarken(VGAScreen, 90, 10, miscText[59], 15, (JE_byte)flash - 8, FONT_SHAPES);
2115 		flash += flashChange;
2116 		if (flash > 4 || flash == 0)
2117 			flashChange = -flashChange;
2118 	}
2119 
2120 	/*Pentium Speed Mode?*/
2121 	if (pentiumMode)
2122 	{
2123 		frameCountMax = (frameCountMax == 2) ? 3 : 2;
2124 	}
2125 
2126 	/*--------  Level Timer    ---------*/
2127 	if (levelTimer && levelTimerCountdown > 0)
2128 	{
2129 		levelTimerCountdown--;
2130 		if (levelTimerCountdown == 0)
2131 			JE_eventJump(levelTimerJumpTo);
2132 
2133 		if (levelTimerCountdown > 200)
2134 		{
2135 			if (levelTimerCountdown % 100 == 0)
2136 				soundQueue[7] = S_WARNING;
2137 
2138 			if (levelTimerCountdown % 10 == 0)
2139 				soundQueue[6] = S_CLICK;
2140 		}
2141 		else if (levelTimerCountdown % 20 == 0)
2142 		{
2143 			soundQueue[7] = S_WARNING;
2144 		}
2145 
2146 		JE_textShade (VGAScreen, 140, 6, miscText[66], 7, (levelTimerCountdown % 20) / 3, FULL_SHADE);
2147 		sprintf(buffer, "%.1f", levelTimerCountdown / 100.0f);
2148 		JE_dString (VGAScreen, 100, 2, buffer, SMALL_FONT_SHAPES);
2149 	}
2150 
2151 	/*GAME OVER*/
2152 	if (!constantPlay && !constantDie)
2153 	{
2154 		if (allPlayersGone)
2155 		{
2156 			if (player[0].exploding_ticks > 0 || player[1].exploding_ticks > 0)
2157 			{
2158 				if (galagaMode)
2159 					player[1].exploding_ticks = 0;
2160 
2161 				musicFade = true;
2162 			}
2163 			else
2164 			{
2165 				if (play_demo || normalBonusLevelCurrent || bonusLevelCurrent)
2166 					reallyEndLevel = true;
2167 				else
2168 					JE_dString(VGAScreen, 120, 60, miscText[21], FONT_SHAPES); // game over
2169 
2170 				set_mouse_position(159, 100);
2171 				if (firstGameOver)
2172 				{
2173 					if (!play_demo)
2174 					{
2175 						play_song(SONG_GAMEOVER);
2176 						set_volume(tyrMusicVolume, fxVolume);
2177 					}
2178 					firstGameOver = false;
2179 				}
2180 
2181 				if (!play_demo)
2182 				{
2183 					push_joysticks_as_keyboard();
2184 					service_SDL_events(true);
2185 					if ((newkey || button[0] || button[1] || button[2]) || newmouse)
2186 					{
2187 						reallyEndLevel = true;
2188 					}
2189 				}
2190 
2191 				if (isNetworkGame)
2192 					reallyEndLevel = true;
2193 			}
2194 		}
2195 	}
2196 
2197 	if (play_demo) // input kills demo
2198 	{
2199 		push_joysticks_as_keyboard();
2200 		service_SDL_events(false);
2201 
2202 		if (newkey || newmouse)
2203 		{
2204 			reallyEndLevel = true;
2205 
2206 			stopped_demo = true;
2207 		}
2208 	}
2209 	else // input handling for pausing, menu, cheats
2210 	{
2211 		service_SDL_events(false);
2212 
2213 		if (newkey)
2214 		{
2215 			skipStarShowVGA = false;
2216 			JE_mainKeyboardInput();
2217 			newkey = false;
2218 			if (skipStarShowVGA)
2219 				goto level_loop;
2220 		}
2221 
2222 		if (pause_pressed)
2223 		{
2224 			pause_pressed = false;
2225 
2226 			if (isNetworkGame)
2227 				pauseRequest = true;
2228 			else
2229 				JE_pauseGame();
2230 		}
2231 
2232 		if (ingamemenu_pressed)
2233 		{
2234 			ingamemenu_pressed = false;
2235 
2236 			if (isNetworkGame)
2237 			{
2238 				inGameMenuRequest = true;
2239 			}
2240 			else
2241 			{
2242 				yourInGameMenuRequest = true;
2243 				JE_doInGameSetup();
2244 				skipStarShowVGA = true;
2245 			}
2246 		}
2247 	}
2248 
2249 	/*Network Update*/
2250 #ifdef WITH_NETWORK
2251 	if (isNetworkGame)
2252 	{
2253 		if (!reallyEndLevel)
2254 		{
2255 			Uint16 requests = (pauseRequest == true) |
2256 			                  (inGameMenuRequest == true) << 1 |
2257 			                  (skipLevelRequest == true) << 2 |
2258 			                  (nortShipRequest == true) << 3;
2259 			SDLNet_Write16(requests,        &packet_state_out[0]->data[14]);
2260 
2261 			SDLNet_Write16(difficultyLevel, &packet_state_out[0]->data[16]);
2262 			SDLNet_Write16(player[0].x,     &packet_state_out[0]->data[18]);
2263 			SDLNet_Write16(player[1].x,     &packet_state_out[0]->data[20]);
2264 			SDLNet_Write16(player[0].y,     &packet_state_out[0]->data[22]);
2265 			SDLNet_Write16(player[1].y,     &packet_state_out[0]->data[24]);
2266 			SDLNet_Write16(curLoc,          &packet_state_out[0]->data[26]);
2267 
2268 			network_state_send();
2269 
2270 			if (network_state_update())
2271 			{
2272 				assert(SDLNet_Read16(&packet_state_in[0]->data[26]) == SDLNet_Read16(&packet_state_out[network_delay]->data[26]));
2273 
2274 				requests = SDLNet_Read16(&packet_state_in[0]->data[14]) ^ SDLNet_Read16(&packet_state_out[network_delay]->data[14]);
2275 				if (requests & 1)
2276 				{
2277 					JE_pauseGame();
2278 				}
2279 				if (requests & 2)
2280 				{
2281 					yourInGameMenuRequest = SDLNet_Read16(&packet_state_out[network_delay]->data[14]) & 2;
2282 					JE_doInGameSetup();
2283 					yourInGameMenuRequest = false;
2284 					if (haltGame)
2285 						reallyEndLevel = true;
2286 				}
2287 				if (requests & 4)
2288 				{
2289 					levelTimer = true;
2290 					levelTimerCountdown = 0;
2291 					endLevel = true;
2292 					levelEnd = 40;
2293 				}
2294 				if (requests & 8) // nortship
2295 				{
2296 					player[0].items.ship = 12;                     // Nort Ship
2297 					player[0].items.special = 13;                  // Astral Zone
2298 					player[0].items.weapon[FRONT_WEAPON].id = 36;  // NortShip Super Pulse
2299 					player[0].items.weapon[REAR_WEAPON].id = 37;   // NortShip Spreader
2300 					shipGr = 1;
2301 				}
2302 
2303 				for (int i = 0; i < 2; i++)
2304 				{
2305 					if (SDLNet_Read16(&packet_state_in[0]->data[18 + i * 2]) != SDLNet_Read16(&packet_state_out[network_delay]->data[18 + i * 2]) || SDLNet_Read16(&packet_state_in[0]->data[20 + i * 2]) != SDLNet_Read16(&packet_state_out[network_delay]->data[20 + i * 2]))
2306 					{
2307 						char temp[64];
2308 						sprintf(temp, "Player %d is unsynchronized!", i + 1);
2309 
2310 						JE_textShade(game_screen, 40, 110 + i * 10, temp, 9, 2, FULL_SHADE);
2311 					}
2312 				}
2313 			}
2314 		}
2315 
2316 		JE_clearSpecialRequests();
2317 	}
2318 #endif
2319 
2320 	/** Test **/
2321 	JE_drawSP();
2322 
2323 	/*Filtration*/
2324 	if (filterActive)
2325 	{
2326 		JE_filterScreen(levelFilter, levelBrightness);
2327 	}
2328 
2329 	draw_boss_bar();
2330 
2331 	JE_inGameDisplays();
2332 
2333 	VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
2334 
2335 	JE_starShowVGA();
2336 
2337 	/*Start backgrounds if no enemies on screen
2338 	  End level if number of enemies left to kill equals 0.*/
2339 	if (stopBackgroundNum == 9 && backMove == 0 && !enemyStillExploding)
2340 	{
2341 		backMove = 1;
2342 		backMove2 = 2;
2343 		backMove3 = 3;
2344 		explodeMove = 2;
2345 		stopBackgroundNum = 0;
2346 		stopBackgrounds = false;
2347 		if (waitToEndLevel)
2348 		{
2349 			endLevel = true;
2350 			levelEnd = 40;
2351 		}
2352 		if (allPlayersGone)
2353 		{
2354 			reallyEndLevel = true;
2355 		}
2356 	}
2357 
2358 	if (!endLevel && enemyOnScreen == 0)
2359 	{
2360 		if (readyToEndLevel && !enemyStillExploding)
2361 		{
2362 			if (levelTimerCountdown > 0)
2363 			{
2364 				levelTimer = false;
2365 			}
2366 			readyToEndLevel = false;
2367 			endLevel = true;
2368 			levelEnd = 40;
2369 			if (allPlayersGone)
2370 			{
2371 				reallyEndLevel = true;
2372 			}
2373 		}
2374 		if (stopBackgrounds)
2375 		{
2376 			stopBackgrounds = false;
2377 			backMove = 1;
2378 			backMove2 = 2;
2379 			backMove3 = 3;
2380 			explodeMove = 2;
2381 		}
2382 	}
2383 
2384 
2385 	/*Other Network Functions*/
2386 	JE_handleChat();
2387 
2388 	if (reallyEndLevel)
2389 	{
2390 		goto start_level;
2391 	}
2392 	goto level_loop;
2393 }
2394 
2395 /* --- Load Level/Map Data --- */
JE_loadMap(void)2396 void JE_loadMap( void )
2397 {
2398 	JE_DanCShape shape;
2399 
2400 	JE_word x, y;
2401 	JE_integer yy;
2402 	JE_word mapSh[3][128]; /* [1..3, 0..127] */
2403 	JE_byte *ref[3][128]; /* [1..3, 0..127] */
2404 	char s[256];
2405 
2406 	JE_byte mapBuf[15 * 600]; /* [1..15 * 600] */
2407 	JE_word bufLoc;
2408 
2409 	char buffer[256];
2410 	int i;
2411 	Uint8 pic_buffer[320*200]; /* screen buffer, 8-bit specific */
2412 	Uint8 *vga, *pic, *vga2; /* screen pointer, 8-bit specific */
2413 
2414 	lastCubeMax = cubeMax;
2415 
2416 	/*Defaults*/
2417 	songBuy = DEFAULT_SONG_BUY;  /*Item Screen default song*/
2418 
2419 	/* Load LEVELS.DAT - Section = MAINLEVEL */
2420 	saveLevel = mainLevel;
2421 
2422 new_game:
2423 	galagaMode  = false;
2424 	useLastBank = false;
2425 	extraGame   = false;
2426 	haltGame = false;
2427 
2428 	gameLoaded = false;
2429 
2430 	if (!play_demo)
2431 	{
2432 		do
2433 		{
2434 			FILE *ep_f = dir_fopen_die(data_dir(), episode_file, "rb");
2435 
2436 			jumpSection = false;
2437 			loadLevelOk = false;
2438 
2439 			/* Seek Section # Mainlevel */
2440 			int x = 0;
2441 			while (x < mainLevel)
2442 			{
2443 				read_encrypted_pascal_string(s, sizeof(s), ep_f);
2444 				if (s[0] == '*')
2445 				{
2446 					x++;
2447 					s[0] = ' ';
2448 				}
2449 			}
2450 
2451 			ESCPressed = false;
2452 
2453 			do
2454 			{
2455 				if (gameLoaded)
2456 				{
2457 					fclose(ep_f);
2458 
2459 					if (mainLevel == 0)  // if quit itemscreen
2460 						return;          // back to title screen
2461 					else
2462 						goto new_game;
2463 				}
2464 
2465 				strcpy(s, " ");
2466 				read_encrypted_pascal_string(s, sizeof(s), ep_f);
2467 
2468 				if (s[0] == ']')
2469 				{
2470 					switch (s[1])
2471 					{
2472 					case 'A':
2473 						JE_playAnim("tyrend.anm", 0, 7);
2474 						break;
2475 
2476 					case 'G':
2477 						mapOrigin = atoi(strnztcpy(buffer, s + 4, 2));
2478 						mapPNum   = atoi(strnztcpy(buffer, s + 7, 1));
2479 						for (i = 0; i < mapPNum; i++)
2480 						{
2481 							mapPlanet[i] = atoi(strnztcpy(buffer, s + 1 + (i + 1) * 8, 2));
2482 							mapSection[i] = atoi(strnztcpy(buffer, s + 4 + (i + 1) * 8, 3));
2483 						}
2484 						break;
2485 
2486 					case '?':
2487 						temp = atoi(strnztcpy(buffer, s + 4, 2));
2488 						for (i = 0; i < temp; i++)
2489 						{
2490 							cubeList[i] = atoi(strnztcpy(buffer, s + 3 + (i + 1) * 4, 3));
2491 						}
2492 						if (cubeMax > temp)
2493 							cubeMax = temp;
2494 						break;
2495 
2496 					case '!':
2497 						cubeMax = atoi(strnztcpy(buffer, s + 4, 2));    /*Auto set CubeMax*/
2498 						break;
2499 
2500 					case '+':
2501 						temp = atoi(strnztcpy(buffer, s + 4, 2));
2502 						cubeMax += temp;
2503 						if (cubeMax > 4)
2504 							cubeMax = 4;
2505 						break;
2506 
2507 					case 'g':
2508 						galagaMode = true;   /*GALAGA mode*/
2509 
2510 						player[1].items = player[0].items;
2511 						player[1].items.weapon[REAR_WEAPON].id = 15;  // Vulcan Cannon
2512 						for (uint i = 0; i < COUNTOF(player[1].items.sidekick); ++i)
2513 							player[1].items.sidekick[i] = 0;          // None
2514 						break;
2515 
2516 					case 'x':
2517 						extraGame = true;
2518 						break;
2519 
2520 					case 'e': // ENGAGE mode, used for mini-games
2521 						doNotSaveBackup = true;
2522 						constantDie = false;
2523 						onePlayerAction = true;
2524 						superTyrian = true;
2525 						twoPlayerMode = false;
2526 
2527 						player[0].cash = 0;
2528 
2529 						player[0].items.ship = 13;                     // The Stalker 21.126
2530 						player[0].items.weapon[FRONT_WEAPON].id = 39;  // Atomic RailGun
2531 						player[0].items.weapon[REAR_WEAPON].id = 0;    // None
2532 						for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i)
2533 							player[0].items.sidekick[i] = 0;           // None
2534 						player[0].items.generator = 2;                 // Advanced MR-12
2535 						player[0].items.shield = 4;                    // Advanced Integrity Field
2536 						player[0].items.special = 0;                   // None
2537 
2538 						player[0].items.weapon[FRONT_WEAPON].power = 3;
2539 						player[0].items.weapon[REAR_WEAPON].power = 1;
2540 						break;
2541 
2542 					case 'J':  // section jump
2543 						temp = atoi(strnztcpy(buffer, s + 3, 3));
2544 						mainLevel = temp;
2545 						jumpSection = true;
2546 						break;
2547 
2548 					case '2':  // two-player section jump
2549 						temp = atoi(strnztcpy(buffer, s + 3, 3));
2550 						if (twoPlayerMode || onePlayerAction)
2551 						{
2552 							mainLevel = temp;
2553 							jumpSection = true;
2554 						}
2555 						break;
2556 
2557 					case 'w':  // Stalker 21.126 section jump
2558 						temp = atoi(strnztcpy(buffer, s + 3, 3));   /*Allowed to go to Time War?*/
2559 						if (player[0].items.ship == 13)
2560 						{
2561 							mainLevel = temp;
2562 							jumpSection = true;
2563 						}
2564 						break;
2565 
2566 					case 't':
2567 						temp = atoi(strnztcpy(buffer, s + 3, 3));
2568 						if (levelTimer && levelTimerCountdown == 0)
2569 						{
2570 							mainLevel = temp;
2571 							jumpSection = true;
2572 						}
2573 						break;
2574 
2575 					case 'l':
2576 						temp = atoi(strnztcpy(buffer, s + 3, 3));
2577 						if (!all_players_alive())
2578 						{
2579 							mainLevel = temp;
2580 							jumpSection = true;
2581 						}
2582 						break;
2583 
2584 					case 's':
2585 						saveLevel = mainLevel;
2586 						break; /*store savepoint*/
2587 
2588 					case 'b':
2589 						if (twoPlayerMode)
2590 						{
2591 							temp = 22;
2592 						} else {
2593 							temp = 11;
2594 						}
2595 						JE_saveGame(11, "LAST LEVEL    ");
2596 						break;
2597 
2598 					case 'i':
2599 						temp = atoi(strnztcpy(buffer, s + 3, 3));
2600 						songBuy = temp - 1;
2601 						break;
2602 
2603 					case 'I': /*Load Items Available Information*/
2604 						memset(&itemAvail, 0, sizeof(itemAvail));
2605 
2606 						for (int i = 0; i < 9; ++i)
2607 						{
2608 							read_encrypted_pascal_string(s, sizeof(s), ep_f);
2609 
2610 							char buf[256];
2611 							strncpy(buf, (strlen(s) > 8) ? s + 8 : "", sizeof(buf));
2612 
2613 							int j = 0, temp;
2614 							while (str_pop_int(buf, &temp))
2615 								itemAvail[i][j++] = temp;
2616 							itemAvailMax[i] = j;
2617 						}
2618 
2619 						JE_itemScreen();
2620 						break;
2621 
2622 					case 'L':
2623 						nextLevel = atoi(strnztcpy(buffer, s + 9, 3));
2624 						strnztcpy(levelName, s + 13, 9);
2625 						levelSong = atoi(strnztcpy(buffer, s + 22, 2));
2626 						if (nextLevel == 0)
2627 						{
2628 							nextLevel = mainLevel + 1;
2629 						}
2630 						lvlFileNum = atoi(strnztcpy(buffer, s + 25, 2));
2631 						loadLevelOk = true;
2632 						bonusLevelCurrent = (strlen(s) > 28) & (s[28] == '$');
2633 						normalBonusLevelCurrent = (strlen(s) > 27) & (s[27] == '$');
2634 						gameJustLoaded = false;
2635 						break;
2636 
2637 					case '@':
2638 						useLastBank = !useLastBank;
2639 						break;
2640 
2641 					case 'Q':
2642 						ESCPressed = false;
2643 						temp = secretHint + (mt_rand() % 3) * 3;
2644 
2645 						if (twoPlayerMode)
2646 						{
2647 							for (uint i = 0; i < 2; ++i)
2648 								snprintf(levelWarningText[i], sizeof(*levelWarningText), "%s %lu", miscText[40], player[i].cash);
2649 							strcpy(levelWarningText[2], "");
2650 							levelWarningLines = 3;
2651 						}
2652 						else
2653 						{
2654 							sprintf(levelWarningText[0], "%s %lu", miscText[37], JE_totalScore(&player[0]));
2655 							strcpy(levelWarningText[1], "");
2656 							levelWarningLines = 2;
2657 						}
2658 
2659 						for (x = 0; x < temp - 1; x++)
2660 						{
2661 							do
2662 								read_encrypted_pascal_string(s, sizeof(s), ep_f);
2663 							while (s[0] != '#');
2664 						}
2665 
2666 						do
2667 						{
2668 							read_encrypted_pascal_string(s, sizeof(s), ep_f);
2669 							strcpy(levelWarningText[levelWarningLines], s);
2670 							levelWarningLines++;
2671 						}
2672 						while (s[0] != '#');
2673 						levelWarningLines--;
2674 
2675 						JE_wipeKey();
2676 						frameCountMax = 4;
2677 						if (!constantPlay)
2678 							JE_displayText();
2679 
2680 						fade_black(15);
2681 
2682 						JE_nextEpisode();
2683 
2684 						if (jumpBackToEpisode1 && !twoPlayerMode)
2685 						{
2686 							JE_loadPic(VGAScreen, 1, false); // huh?
2687 							JE_clr256(VGAScreen);
2688 
2689 							if (superTyrian)
2690 							{
2691 								// if completed Zinglon's Revenge, show SuperTyrian and Destruct codes
2692 								// if completed SuperTyrian, show Nort-Ship Z code
2693 								superArcadeMode = (initialDifficulty == 8) ? 8 : 1;
2694 							}
2695 
2696 							if (superArcadeMode < SA_ENGAGE)
2697 							{
2698 								if (SANextShip[superArcadeMode] == SA_ENGAGE)
2699 								{
2700 									sprintf(buffer, "%s %s", miscTextB[4], pName[0]);
2701 									JE_dString(VGAScreen, JE_fontCenter(buffer, FONT_SHAPES), 100, buffer, FONT_SHAPES);
2702 
2703 									sprintf(buffer, "Or play... %s", specialName[7]);
2704 									JE_dString(VGAScreen, 80, 180, buffer, SMALL_FONT_SHAPES);
2705 								}
2706 								else
2707 								{
2708 									JE_dString(VGAScreen, JE_fontCenter(superShips[0], FONT_SHAPES), 30, superShips[0], FONT_SHAPES);
2709 									JE_dString(VGAScreen, JE_fontCenter(superShips[SANextShip[superArcadeMode]], SMALL_FONT_SHAPES), 100, superShips[SANextShip[superArcadeMode]], SMALL_FONT_SHAPES);
2710 								}
2711 
2712 								if (SANextShip[superArcadeMode] < SA_NORTSHIPZ)
2713 									blit_sprite2x2(VGAScreen, 148, 70, shapes9, ships[SAShip[SANextShip[superArcadeMode]-1]].shipgraphic);
2714 								else if (SANextShip[superArcadeMode] == SA_NORTSHIPZ)
2715 									trentWin = true;
2716 
2717 								sprintf(buffer, "Type %s at Title", specialName[SANextShip[superArcadeMode]-1]);
2718 								JE_dString(VGAScreen, JE_fontCenter(buffer, SMALL_FONT_SHAPES), 160, buffer, SMALL_FONT_SHAPES);
2719 								JE_showVGA();
2720 
2721 								fade_palette(colors, 50, 0, 255);
2722 
2723 								if (!constantPlay)
2724 									wait_input(true, true, true);
2725 							}
2726 
2727 							jumpSection = true;
2728 
2729 							if (isNetworkGame)
2730 								JE_readTextSync();
2731 
2732 							if (superTyrian)
2733 							{
2734 								fade_black(10);
2735 
2736 								// back to titlescreen
2737 								mainLevel = 0;
2738 								return;
2739 							}
2740 						}
2741 						break;
2742 
2743 					case 'P':
2744 						if (!constantPlay)
2745 						{
2746 							tempX = atoi(strnztcpy(buffer, s + 3, 3));
2747 							if (tempX > 900)
2748 							{
2749 								memcpy(colors, palettes[pcxpal[tempX-1 - 900]], sizeof(colors));
2750 								JE_clr256(VGAScreen);
2751 								JE_showVGA();
2752 								fade_palette(colors, 1, 0, 255);
2753 							}
2754 							else
2755 							{
2756 								if (tempX == 0)
2757 									JE_loadPCX("tshp2.pcx");
2758 								else
2759 									JE_loadPic(VGAScreen, tempX, false);
2760 
2761 								JE_showVGA();
2762 								fade_palette(colors, 10, 0, 255);
2763 							}
2764 						}
2765 						break;
2766 
2767 					case 'U':
2768 						if (!constantPlay)
2769 						{
2770 							memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
2771 
2772 							tempX = atoi(strnztcpy(buffer, s + 3, 3));
2773 							JE_loadPic(VGAScreen, tempX, false);
2774 							memcpy(pic_buffer, VGAScreen->pixels, sizeof(pic_buffer));
2775 
2776 							service_SDL_events(true);
2777 
2778 							for (int z = 0; z <= 199; z++)
2779 							{
2780 								if (!newkey)
2781 								{
2782 									vga = VGAScreen->pixels;
2783 									vga2 = VGAScreen2->pixels;
2784 									pic = pic_buffer + (199 - z) * 320;
2785 
2786 									setjasondelay(1); /* attempting to emulate JE_waitRetrace();*/
2787 
2788 									for (y = 0; y <= 199; y++)
2789 									{
2790 										if (y <= z)
2791 										{
2792 											memcpy(vga, pic, 320);
2793 											pic += 320;
2794 										}
2795 										else
2796 										{
2797 											memcpy(vga, vga2, VGAScreen->pitch);
2798 											vga2 += VGAScreen->pitch;
2799 										}
2800 										vga += VGAScreen->pitch;
2801 									}
2802 
2803 									JE_showVGA();
2804 
2805 									if (isNetworkGame)
2806 									{
2807 										/* TODO: NETWORK */
2808 									}
2809 
2810 									service_wait_delay();
2811 								}
2812 							}
2813 
2814 							memcpy(VGAScreen->pixels, pic_buffer, sizeof(pic_buffer));
2815 						}
2816 						break;
2817 
2818 					case 'V':
2819 						if (!constantPlay)
2820 						{
2821 							/* TODO: NETWORK */
2822 							memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
2823 
2824 							tempX = atoi(strnztcpy(buffer, s + 3, 3));
2825 							JE_loadPic(VGAScreen, tempX, false);
2826 							memcpy(pic_buffer, VGAScreen->pixels, sizeof(pic_buffer));
2827 
2828 							service_SDL_events(true);
2829 							for (int z = 0; z <= 199; z++)
2830 							{
2831 								if (!newkey)
2832 								{
2833 									vga = VGAScreen->pixels;
2834 									vga2 = VGAScreen2->pixels;
2835 									pic = pic_buffer;
2836 
2837 									setjasondelay(1); /* attempting to emulate JE_waitRetrace();*/
2838 
2839 									for (y = 0; y < 199; y++)
2840 									{
2841 										if (y <= 199 - z)
2842 										{
2843 											memcpy(vga, vga2, VGAScreen->pitch);
2844 											vga2 += VGAScreen->pitch;
2845 										}
2846 										else
2847 										{
2848 											memcpy(vga, pic, 320);
2849 											pic += 320;
2850 										}
2851 										vga += VGAScreen->pitch;
2852 									}
2853 
2854 									JE_showVGA();
2855 
2856 									if (isNetworkGame)
2857 									{
2858 										/* TODO: NETWORK */
2859 									}
2860 
2861 									service_wait_delay();
2862 								}
2863 							}
2864 
2865 							memcpy(VGAScreen->pixels, pic_buffer, sizeof(pic_buffer));
2866 						}
2867 						break;
2868 
2869 					case 'R':
2870 						if (!constantPlay)
2871 						{
2872 							/* TODO: NETWORK */
2873 							memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
2874 
2875 							tempX = atoi(strnztcpy(buffer, s + 3, 3));
2876 							JE_loadPic(VGAScreen, tempX, false);
2877 							memcpy(pic_buffer, VGAScreen->pixels, sizeof(pic_buffer));
2878 
2879 							service_SDL_events(true);
2880 
2881 							for (int z = 0; z <= 318; z++)
2882 							{
2883 								if (!newkey)
2884 								{
2885 									vga = VGAScreen->pixels;
2886 									vga2 = VGAScreen2->pixels;
2887 									pic = pic_buffer;
2888 
2889 									setjasondelay(1); /* attempting to emulate JE_waitRetrace();*/
2890 
2891 									for(y = 0; y < 200; y++)
2892 									{
2893 										memcpy(vga, vga2 + z, 319 - z);
2894 										vga += 320 - z;
2895 										vga2 += VGAScreen2->pitch;
2896 										memcpy(vga, pic, z + 1);
2897 										vga += z;
2898 										pic += 320;
2899 									}
2900 
2901 									JE_showVGA();
2902 
2903 									if (isNetworkGame)
2904 									{
2905 										/* TODO: NETWORK */
2906 									}
2907 
2908 									service_wait_delay();
2909 								}
2910 							}
2911 
2912 							memcpy(VGAScreen->pixels, pic_buffer, sizeof(pic_buffer));
2913 						}
2914 						break;
2915 
2916 					case 'C':
2917 						if (!isNetworkGame)
2918 						{
2919 							fade_black(10);
2920 						}
2921 						JE_clr256(VGAScreen);
2922 						JE_showVGA();
2923 						memcpy(colors, palettes[7], sizeof(colors));
2924 						set_palette(colors, 0, 255);
2925 						break;
2926 
2927 					case 'B':
2928 						if (!isNetworkGame)
2929 						{
2930 							fade_black(10);
2931 						}
2932 						break;
2933 					case 'F':
2934 						if (!isNetworkGame)
2935 						{
2936 							fade_white(100);
2937 							fade_black(30);
2938 						}
2939 						JE_clr256(VGAScreen);
2940 						JE_showVGA();
2941 						break;
2942 
2943 					case 'W':
2944 						if (!constantPlay)
2945 						{
2946 							if (!ESCPressed)
2947 							{
2948 								JE_wipeKey();
2949 								warningCol = 14 * 16 + 5;
2950 								warningColChange = 1;
2951 								warningSoundDelay = 0;
2952 								levelWarningDisplay = (s[2] == 'y');
2953 								levelWarningLines = 0;
2954 								frameCountMax = atoi(strnztcpy(buffer, s + 4, 2));
2955 								setjasondelay2(6);
2956 								warningRed = frameCountMax / 10;
2957 								frameCountMax = frameCountMax % 10;
2958 
2959 								do
2960 								{
2961 									read_encrypted_pascal_string(s, sizeof(s), ep_f);
2962 
2963 									if (s[0] != '#')
2964 									{
2965 										strcpy(levelWarningText[levelWarningLines], s);
2966 										levelWarningLines++;
2967 									}
2968 								}
2969 								while (!(s[0] == '#'));
2970 
2971 								JE_displayText();
2972 								newkey = false;
2973 							}
2974 						}
2975 						break;
2976 
2977 					case 'H':
2978 						if (initialDifficulty < 3)
2979 						{
2980 							mainLevel = atoi(strnztcpy(buffer, s + 4, 3));
2981 							jumpSection = true;
2982 						}
2983 						break;
2984 
2985 					case 'h':
2986 						if (initialDifficulty > 2)
2987 						{
2988 							read_encrypted_pascal_string(s, sizeof(s), ep_f);
2989 						}
2990 						break;
2991 
2992 					case 'S':
2993 						if (isNetworkGame)
2994 						{
2995 							JE_readTextSync();
2996 						}
2997 						break;
2998 
2999 					case 'n':
3000 						ESCPressed = false;
3001 						break;
3002 
3003 					case 'M':
3004 						temp = atoi(strnztcpy(buffer, s + 3, 3));
3005 						play_song(temp - 1);
3006 						break;
3007 
3008 #ifdef TYRIAN2000
3009 					case 'T':
3010 						/* TODO: Timed Battle ]T[ 43 44 45 46 47 */
3011 						printf("]T[ 43 44 45 46 47 handle timed battle!");
3012 						break;
3013 
3014 					case 'q':
3015 						/* TODO: Timed Battle end */
3016 						printf("handle timed battle end flag!");
3017 						break;
3018 #endif
3019 					}
3020 				}
3021 
3022 			} while (!(loadLevelOk || jumpSection));
3023 
3024 
3025 			fclose(ep_f);
3026 
3027 		} while (!loadLevelOk);
3028 	}
3029 
3030 	if (play_demo)
3031 		load_next_demo();
3032 	else
3033 		fade_black(50);
3034 
3035 	FILE *level_f = dir_fopen_die(data_dir(), levelFile, "rb");
3036 	fseek(level_f, lvlPos[(lvlFileNum-1) * 2], SEEK_SET);
3037 
3038 	fgetc(level_f); // char_mapFile
3039 	JE_char char_shapeFile = fgetc(level_f);
3040 	efread(&mapX,  sizeof(JE_word), 1, level_f);
3041 	efread(&mapX2, sizeof(JE_word), 1, level_f);
3042 	efread(&mapX3, sizeof(JE_word), 1, level_f);
3043 
3044 	efread(&levelEnemyMax, sizeof(JE_word), 1, level_f);
3045 	for (x = 0; x < levelEnemyMax; x++)
3046 	{
3047 		efread(&levelEnemy[x], sizeof(JE_word), 1, level_f);
3048 	}
3049 
3050 	efread(&maxEvent, sizeof(JE_word), 1, level_f);
3051 	for (x = 0; x < maxEvent; x++)
3052 	{
3053 		efread(&eventRec[x].eventtime, sizeof(JE_word), 1, level_f);
3054 		efread(&eventRec[x].eventtype, sizeof(JE_byte), 1, level_f);
3055 		efread(&eventRec[x].eventdat,  sizeof(JE_integer), 1, level_f);
3056 		efread(&eventRec[x].eventdat2, sizeof(JE_integer), 1, level_f);
3057 		efread(&eventRec[x].eventdat3, sizeof(JE_shortint), 1, level_f);
3058 		efread(&eventRec[x].eventdat5, sizeof(JE_shortint), 1, level_f);
3059 		efread(&eventRec[x].eventdat6, sizeof(JE_shortint), 1, level_f);
3060 		efread(&eventRec[x].eventdat4, sizeof(JE_byte), 1, level_f);
3061 	}
3062 	eventRec[x].eventtime = 65500;  /*Not needed but just in case*/
3063 
3064 	/*debuginfo('Level loaded.');*/
3065 
3066 	/*debuginfo('Loading Map');*/
3067 
3068 	/* MAP SHAPE LOOKUP TABLE - Each map is directly after level */
3069 	efread(mapSh, sizeof(JE_word), sizeof(mapSh) / sizeof(JE_word), level_f);
3070 	for (temp = 0; temp < 3; temp++)
3071 	{
3072 		for (temp2 = 0; temp2 < 128; temp2++)
3073 		{
3074 			mapSh[temp][temp2] = SDL_Swap16(mapSh[temp][temp2]);
3075 		}
3076 	}
3077 
3078 	/* Read Shapes.DAT */
3079 	sprintf(tempStr, "shapes%c.dat", tolower((unsigned char)char_shapeFile));
3080 	FILE *shpFile = dir_fopen_die(data_dir(), tempStr, "rb");
3081 
3082 	for (int z = 0; z < 600; z++)
3083 	{
3084 		JE_boolean shapeBlank = fgetc(shpFile);
3085 
3086 		if (shapeBlank)
3087 			memset(shape, 0, sizeof(shape));
3088 		else
3089 			efread(shape, sizeof(JE_byte), sizeof(shape), shpFile);
3090 
3091 		/* Match 1 */
3092 		for (int x = 0; x <= 71; ++x)
3093 		{
3094 			if (mapSh[0][x] == z+1)
3095 			{
3096 				memcpy(megaData1.shapes[x].sh, shape, sizeof(JE_DanCShape));
3097 
3098 				ref[0][x] = (JE_byte *)megaData1.shapes[x].sh;
3099 			}
3100 		}
3101 
3102 		/* Match 2 */
3103 		for (int x = 0; x <= 71; ++x)
3104 		{
3105 			if (mapSh[1][x] == z+1)
3106 			{
3107 				if (x != 71 && !shapeBlank)
3108 				{
3109 					memcpy(megaData2.shapes[x].sh, shape, sizeof(JE_DanCShape));
3110 
3111 					y = 1;
3112 					for (yy = 0; yy < (24 * 28) >> 1; yy++)
3113 						if (shape[yy] == 0)
3114 							y = 0;
3115 
3116 					megaData2.shapes[x].fill = y;
3117 					ref[1][x] = (JE_byte *)megaData2.shapes[x].sh;
3118 				}
3119 				else
3120 				{
3121 					ref[1][x] = NULL;
3122 				}
3123 			}
3124 		}
3125 
3126 		/*Match 3*/
3127 		for (int x = 0; x <= 71; ++x)
3128 		{
3129 			if (mapSh[2][x] == z+1)
3130 			{
3131 				if (x < 70 && !shapeBlank)
3132 				{
3133 					memcpy(megaData3.shapes[x].sh, shape, sizeof(JE_DanCShape));
3134 
3135 					y = 1;
3136 					for (yy = 0; yy < (24 * 28) >> 1; yy++)
3137 						if (shape[yy] == 0)
3138 							y = 0;
3139 
3140 					megaData3.shapes[x].fill = y;
3141 					ref[2][x] = (JE_byte *)megaData3.shapes[x].sh;
3142 				}
3143 				else
3144 				{
3145 					ref[2][x] = NULL;
3146 				}
3147 			}
3148 		}
3149 	}
3150 
3151 	fclose(shpFile);
3152 
3153 	efread(mapBuf, sizeof(JE_byte), 14 * 300, level_f);
3154 	bufLoc = 0;              /* MAP NUMBER 1 */
3155 	for (y = 0; y < 300; y++)
3156 	{
3157 		for (x = 0; x < 14; x++)
3158 		{
3159 			megaData1.mainmap[y][x] = ref[0][mapBuf[bufLoc]];
3160 			bufLoc++;
3161 		}
3162 	}
3163 
3164 	efread(mapBuf, sizeof(JE_byte), 14 * 600, level_f);
3165 	bufLoc = 0;              /* MAP NUMBER 2 */
3166 	for (y = 0; y < 600; y++)
3167 	{
3168 		for (x = 0; x < 14; x++)
3169 		{
3170 			megaData2.mainmap[y][x] = ref[1][mapBuf[bufLoc]];
3171 			bufLoc++;
3172 		}
3173 	}
3174 
3175 	efread(mapBuf, sizeof(JE_byte), 15 * 600, level_f);
3176 	bufLoc = 0;              /* MAP NUMBER 3 */
3177 	for (y = 0; y < 600; y++)
3178 	{
3179 		for (x = 0; x < 15; x++)
3180 		{
3181 			megaData3.mainmap[y][x] = ref[2][mapBuf[bufLoc]];
3182 			bufLoc++;
3183 		}
3184 	}
3185 
3186 	fclose(level_f);
3187 
3188 	/* Note: The map data is automatically calculated with the correct mapsh
3189 	value and then the pointer is calculated using the formula (MAPSH-1)*168.
3190 	Then, we'll automatically add S2Ofs to get the exact offset location into
3191 	the shape table! This makes it VERY FAST! */
3192 
3193 	/*debuginfo('Map file done.');*/
3194 	/* End of find loop for LEVEL??.DAT */
3195 }
3196 
JE_titleScreen(JE_boolean animate)3197 bool JE_titleScreen( JE_boolean animate )
3198 {
3199 	bool quit = false;
3200 
3201 #ifdef TYRIAN2000
3202 	const int menunum = 6;
3203 #else
3204 	const int menunum = 7;
3205 #endif
3206 
3207 	unsigned int arcade_code_i[SA_ENGAGE] = { 0 };
3208 
3209 	JE_word waitForDemo;
3210 	JE_byte menu = 0;
3211 	JE_boolean redraw = true,
3212 	           fadeIn = false;
3213 
3214 	JE_word temp; /* JE_byte temp; from varz.h will overflow in for loop */
3215 
3216 	play_demo = false;
3217 	stopped_demo = false;
3218 
3219 	redraw = true;
3220 	fadeIn = false;
3221 
3222 	gameLoaded = false;
3223 	jumpSection = false;
3224 
3225 #ifdef WITH_NETWORK
3226 	if (isNetworkGame)
3227 	{
3228 		JE_loadPic(VGAScreen, 2, false);
3229 		memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
3230 		JE_dString(VGAScreen, JE_fontCenter("Waiting for other player.", SMALL_FONT_SHAPES), 140, "Waiting for other player.", SMALL_FONT_SHAPES);
3231 		JE_showVGA();
3232 		fade_palette(colors, 10, 0, 255);
3233 
3234 		network_connect();
3235 
3236 		twoPlayerMode = true;
3237 		if (thisPlayerNum == 1)
3238 		{
3239 			fade_black(10);
3240 
3241 			if (select_episode() && select_difficulty())
3242 			{
3243 				initialDifficulty = difficultyLevel;
3244 
3245 				difficultyLevel++;  /*Make it one step harder for 2-player mode!*/
3246 
3247 				network_prepare(PACKET_DETAILS);
3248 				SDLNet_Write16(episodeNum,      &packet_out_temp->data[4]);
3249 				SDLNet_Write16(difficultyLevel, &packet_out_temp->data[6]);
3250 				network_send(8);  // PACKET_DETAILS
3251 			}
3252 			else
3253 			{
3254 				network_prepare(PACKET_QUIT);
3255 				network_send(4);  // PACKET QUIT
3256 
3257 				network_tyrian_halt(0, true);
3258 			}
3259 		}
3260 		else
3261 		{
3262 			memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
3263 			JE_dString(VGAScreen, JE_fontCenter(networkText[4-1], SMALL_FONT_SHAPES), 140, networkText[4-1], SMALL_FONT_SHAPES);
3264 			JE_showVGA();
3265 
3266 			// until opponent sends details packet
3267 			while (true)
3268 			{
3269 				service_SDL_events(false);
3270 				JE_showVGA();
3271 
3272 				if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_DETAILS)
3273 					break;
3274 
3275 				network_update();
3276 				network_check();
3277 
3278 				SDL_Delay(16);
3279 			}
3280 
3281 			JE_initEpisode(SDLNet_Read16(&packet_in[0]->data[4]));
3282 			difficultyLevel = SDLNet_Read16(&packet_in[0]->data[6]);
3283 			initialDifficulty = difficultyLevel - 1;
3284 			fade_black(10);
3285 
3286 			network_update();
3287 		}
3288 
3289 		for (uint i = 0; i < COUNTOF(player); ++i)
3290 			player[i].cash = 0;
3291 
3292 		player[0].items.ship = 11;  // Silver Ship
3293 
3294 		while (!network_is_sync())
3295 		{
3296 			service_SDL_events(false);
3297 			JE_showVGA();
3298 
3299 			network_check();
3300 			SDL_Delay(16);
3301 		}
3302 	}
3303 	else
3304 #endif
3305 	{
3306 		do
3307 		{
3308 			defaultBrightness = -3;
3309 
3310 			/* Animate instead of quickly fading in */
3311 			if (redraw)
3312 			{
3313 				play_song(SONG_TITLE);
3314 
3315 				menu = 0;
3316 				redraw = false;
3317 				if (animate)
3318 				{
3319 					if (fadeIn)
3320 					{
3321 						fade_black(10);
3322 						fadeIn = false;
3323 					}
3324 
3325 					JE_loadPic(VGAScreen, 4, false);
3326 
3327 					draw_font_hv_shadow(VGAScreen, 2, 192, opentyrian_version, small_font, left_aligned, 15, 0, false, 1);
3328 
3329 					memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
3330 
3331 					temp = moveTyrianLogoUp ? 62 : 4;
3332 
3333 					blit_sprite(VGAScreenSeg, 11, temp, PLANET_SHAPES, 146); // tyrian logo
3334 
3335 					JE_showVGA();
3336 
3337 					fade_palette(colors, 10, 0, 255 - 16);
3338 
3339 					if (moveTyrianLogoUp)
3340 					{
3341 						for (temp = 61; temp >= 4; temp -= 2)
3342 						{
3343 							setjasondelay(2);
3344 
3345 							memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
3346 
3347 							blit_sprite(VGAScreenSeg, 11, temp, PLANET_SHAPES, 146); // tyrian logo
3348 
3349 							JE_showVGA();
3350 
3351 							service_wait_delay();
3352 						}
3353 						moveTyrianLogoUp = false;
3354 					}
3355 
3356 					strcpy(menuText[4], opentyrian_str);  // OpenTyrian override
3357 
3358 					/* Draw Menu Text on Screen */
3359 					for (int i = 0; i < menunum; ++i)
3360 					{
3361 						int x = VGAScreen->w / 2, y = 104 + i * 13;
3362 
3363 						draw_font_hv(VGAScreen, x - 1, y - 1, menuText[i], normal_font, centered, 15, -10);
3364 						draw_font_hv(VGAScreen, x + 1, y + 1, menuText[i], normal_font, centered, 15, -10);
3365 						draw_font_hv(VGAScreen, x + 1, y - 1, menuText[i], normal_font, centered, 15, -10);
3366 						draw_font_hv(VGAScreen, x - 1, y + 1, menuText[i], normal_font, centered, 15, -10);
3367 						draw_font_hv(VGAScreen, x,     y,     menuText[i], normal_font, centered, 15, -3);
3368 					}
3369 
3370 					JE_showVGA();
3371 
3372 					fade_palette(colors, 20, 255 - 16 + 1, 255); // fade in menu items
3373 
3374 					memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
3375 				}
3376 			}
3377 
3378 			memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
3379 
3380 			// highlight selected menu item
3381 			draw_font_hv(VGAScreen, VGAScreen->w / 2, 104 + menu * 13, menuText[menu], normal_font, centered, 15, -1);
3382 
3383 			JE_showVGA();
3384 
3385 			if (trentWin)
3386 			{
3387 				quit = true;
3388 				goto trentWinsGame;
3389 			}
3390 
3391 			waitForDemo = 2000;
3392 			JE_textMenuWait(&waitForDemo, false);
3393 
3394 			if (waitForDemo == 1)
3395 				play_demo = true;
3396 
3397 			if (newkey)
3398 			{
3399 				switch (lastkey_sym)
3400 				{
3401 				case SDLK_UP:
3402 					if (menu == 0)
3403 						menu = menunum-1;
3404 					else
3405 						menu--;
3406 					JE_playSampleNum(S_CURSOR);
3407 					break;
3408 				case SDLK_DOWN:
3409 					if (menu == menunum-1)
3410 						menu = 0;
3411 					else
3412 						menu++;
3413 					JE_playSampleNum(S_CURSOR);
3414 					break;
3415 				default:
3416 					break;
3417 				}
3418 			}
3419 
3420 			for (unsigned int i = 0; i < SA_ENGAGE; i++)
3421 			{
3422 				if (toupper(lastkey_char) == specialName[i][arcade_code_i[i]])
3423 					arcade_code_i[i]++;
3424 				else
3425 					arcade_code_i[i] = 0;
3426 
3427 				if (arcade_code_i[i] > 0 && arcade_code_i[i] == strlen(specialName[i]))
3428 				{
3429 					if (i+1 == SA_DESTRUCT)
3430 					{
3431 						loadDestruct = true;
3432 					}
3433 					else if (i+1 == SA_ENGAGE)
3434 					{
3435 						/* SuperTyrian */
3436 
3437 						JE_playSampleNum(V_DATA_CUBE);
3438 						JE_whoa();
3439 
3440 						initialDifficulty = keysactive[SDLK_SCROLLOCK] ? 6 : 8;
3441 
3442 						JE_clr256(VGAScreen);
3443 						JE_outText(VGAScreen, 10, 10, "Cheat codes have been disabled.", 15, 4);
3444 						if (initialDifficulty == 8)
3445 							JE_outText(VGAScreen, 10, 20, "Difficulty level has been set to Lord of Game.", 15, 4);
3446 						else
3447 							JE_outText(VGAScreen, 10, 20, "Difficulty level has been set to Suicide.", 15, 4);
3448 						JE_outText(VGAScreen, 10, 30, "It is imperative that you discover the special codes.", 15, 4);
3449 						if (initialDifficulty == 8)
3450 							JE_outText(VGAScreen, 10, 40, "(Next time, for an easier challenge hold down SCROLL LOCK.)", 15, 4);
3451 						JE_outText(VGAScreen, 10, 60, "Prepare to play...", 15, 4);
3452 
3453 						char buf[10+1+15+1];
3454 						snprintf(buf, sizeof(buf), "%s %s", miscTextB[4], pName[0]);
3455 						JE_dString(VGAScreen, JE_fontCenter(buf, FONT_SHAPES), 110, buf, FONT_SHAPES);
3456 
3457 						play_song(16);
3458 						JE_playSampleNum(V_DANGER);
3459 						JE_showVGA();
3460 
3461 						wait_noinput(true, true, true);
3462 						wait_input(true, true, true);
3463 
3464 						JE_initEpisode(1);
3465 						constantDie = false;
3466 						superTyrian = true;
3467 						onePlayerAction = true;
3468 						gameLoaded = true;
3469 						difficultyLevel = initialDifficulty;
3470 
3471 						player[0].cash = 0;
3472 
3473 						player[0].items.ship = 13;                     // The Stalker 21.126
3474 						player[0].items.weapon[FRONT_WEAPON].id = 39;  // Atomic RailGun
3475 					}
3476 					else
3477 					{
3478 						player[0].items.ship = SAShip[i];
3479 
3480 						fade_black(10);
3481 						if (select_episode() && select_difficulty())
3482 						{
3483 							/* Start special mode! */
3484 							fade_black(10);
3485 							JE_loadPic(VGAScreen, 1, false);
3486 							JE_clr256(VGAScreen);
3487 							JE_dString(VGAScreen, JE_fontCenter(superShips[0], FONT_SHAPES), 30, superShips[0], FONT_SHAPES);
3488 							JE_dString(VGAScreen, JE_fontCenter(superShips[i+1], SMALL_FONT_SHAPES), 100, superShips[i+1], SMALL_FONT_SHAPES);
3489 							tempW = ships[player[0].items.ship].shipgraphic;
3490 							if (tempW != 1)
3491 								blit_sprite2x2(VGAScreen, 148, 70, shapes9, tempW);
3492 
3493 							JE_showVGA();
3494 							fade_palette(colors, 50, 0, 255);
3495 
3496 							wait_input(true, true, true);
3497 
3498 							twoPlayerMode = false;
3499 							onePlayerAction = true;
3500 							superArcadeMode = i+1;
3501 							gameLoaded = true;
3502 							initialDifficulty = ++difficultyLevel;
3503 
3504 							player[0].cash = 0;
3505 
3506 							player[0].items.weapon[FRONT_WEAPON].id = SAWeapon[i][0];
3507 							player[0].items.special = SASpecialWeapon[i];
3508 							if (superArcadeMode == SA_NORTSHIPZ)
3509 							{
3510 								for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i)
3511 									player[0].items.sidekick[i] = 24;  // Companion Ship Quicksilver
3512 							}
3513 						}
3514 						else
3515 						{
3516 							redraw = true;
3517 							fadeIn = true;
3518 						}
3519 					}
3520 					newkey = false;
3521 				}
3522 			}
3523 			lastkey_char = '\0';
3524 
3525 			if (newkey)
3526 			{
3527 				switch (lastkey_sym)
3528 				{
3529 				case SDLK_ESCAPE:
3530 					quit = true;
3531 					break;
3532 				case SDLK_RETURN:
3533 					JE_playSampleNum(S_SELECT);
3534 					switch (menu)
3535 					{
3536 					case 0: /* New game */
3537 						fade_black(10);
3538 
3539 						if (select_gameplay())
3540 						{
3541 							if (select_episode() && select_difficulty())
3542 								gameLoaded = true;
3543 
3544 							initialDifficulty = difficultyLevel;
3545 
3546 							if (onePlayerAction)
3547 							{
3548 								player[0].cash = 0;
3549 
3550 								player[0].items.ship = 8;  // Stalker
3551 							}
3552 							else if (twoPlayerMode)
3553 							{
3554 								for (uint i = 0; i < COUNTOF(player); ++i)
3555 									player[i].cash = 0;
3556 
3557 								player[0].items.ship = 11;  // Silver Ship
3558 
3559 								difficultyLevel++;
3560 
3561 								inputDevice[0] = 1;
3562 								inputDevice[1] = 2;
3563 							}
3564 							else if (richMode)
3565 							{
3566 								player[0].cash = 1000000;
3567 							}
3568 							else
3569 							{
3570 								// allows player to smuggle arcade/super-arcade ships into full game
3571 
3572 								ulong initial_cash[] = { 10000, 15000, 20000, 30000, 35000 };
3573 
3574 								assert(episodeNum >= 1 && episodeNum <= EPISODE_AVAILABLE);
3575 								player[0].cash = initial_cash[episodeNum-1];
3576 							}
3577 						}
3578 						fadeIn = true;
3579 						break;
3580 					case 1: /* Load game */
3581 						JE_loadScreen();
3582 						fadeIn = true;
3583 						break;
3584 					case 2: /* High scores */
3585 						JE_highScoreScreen();
3586 						fadeIn = true;
3587 						break;
3588 					case 3: /* Instructions */
3589 						JE_helpSystem(1);
3590 						fadeIn = true;
3591 						break;
3592 					case 4: /* Ordering info, now OpenTyrian menu */
3593 						opentyrian_menu();
3594 						fadeIn = true;
3595 						break;
3596 #ifdef TYRIAN2000
3597 					case 5: /* Quit */
3598 						quit = true;
3599 						break;
3600 #else
3601 					case 5: /* Demo */
3602 						play_demo = true;
3603 						break;
3604 					case 6: /* Quit */
3605 						quit = true;
3606 						break;
3607 #endif
3608 					}
3609 					redraw = true;
3610 					break;
3611 				default:
3612 					break;
3613 				}
3614 			}
3615 		}
3616 		while (!(quit || gameLoaded || jumpSection || play_demo || loadDestruct));
3617 
3618 trentWinsGame:
3619 		fade_black(15);
3620 	}
3621 
3622 	return quit;
3623 }
3624 
intro_logos(void)3625 void intro_logos( void )
3626 {
3627 	SDL_FillRect(VGAScreen, NULL, 0);
3628 
3629 	fade_white(50);
3630 
3631 	JE_loadPic(VGAScreen, 10, false);
3632 	JE_showVGA();
3633 
3634 	fade_palette(colors, 50, 0, 255);
3635 
3636 	setjasondelay(200);
3637 	wait_delayorinput(true, true, true);
3638 
3639 	fade_black(10);
3640 
3641 	JE_loadPic(VGAScreen, 12, false);
3642 	JE_showVGA();
3643 
3644 	fade_palette(colors, 10, 0, 255);
3645 
3646 	setjasondelay(200);
3647 	wait_delayorinput(true, true, true);
3648 
3649 	fade_black(10);
3650 }
3651 
JE_readTextSync(void)3652 void JE_readTextSync( void )
3653 {
3654 	return;  // this function seems to be unnecessary
3655 
3656 	JE_clr256(VGAScreen);
3657 	JE_showVGA();
3658 	JE_loadPic(VGAScreen, 1, true);
3659 
3660 	JE_barShade(VGAScreen, 3, 3, 316, 196);
3661 	JE_barShade(VGAScreen, 1, 1, 318, 198);
3662 	JE_dString(VGAScreen, 10, 160, "Waiting for other player.", SMALL_FONT_SHAPES);
3663 	JE_showVGA();
3664 
3665 	/* TODO: NETWORK */
3666 
3667 	do
3668 	{
3669 		setjasondelay(2);
3670 
3671 		/* TODO: NETWORK */
3672 
3673 		wait_delay();
3674 
3675 	} while (0 /* TODO: NETWORK */);
3676 }
3677 
3678 
JE_displayText(void)3679 void JE_displayText( void )
3680 {
3681 	/* Display Warning Text */
3682 	tempY = 55;
3683 	if (warningRed)
3684 	{
3685 		tempY = 2;
3686 	}
3687 	for (temp = 0; temp < levelWarningLines; temp++)
3688 	{
3689 		if (!ESCPressed)
3690 		{
3691 			JE_outCharGlow(10, tempY, levelWarningText[temp]);
3692 
3693 			if (haltGame)
3694 			{
3695 				JE_tyrianHalt(5);
3696 			}
3697 
3698 			tempY += 10;
3699 		}
3700 	}
3701 	if (frameCountMax != 0)
3702 	{
3703 		frameCountMax = 6;
3704 		temp = 1;
3705 	} else {
3706 		temp = 0;
3707 	}
3708 	textGlowFont = TINY_FONT;
3709 	tempW = 184;
3710 	if (warningRed)
3711 	{
3712 		tempW = 7 * 16 + 6;
3713 	}
3714 
3715 	JE_outCharGlow(JE_fontCenter(miscText[4], TINY_FONT), tempW, miscText[4]);
3716 
3717 	do
3718 	{
3719 		if (levelWarningDisplay)
3720 		{
3721 			JE_updateWarning(VGAScreen);
3722 		}
3723 
3724 		setjasondelay(1);
3725 
3726 		NETWORK_KEEP_ALIVE();
3727 
3728 		wait_delay();
3729 
3730 	} while (!(JE_anyButton() || (frameCountMax == 0 && temp == 1) || ESCPressed));
3731 	levelWarningDisplay = false;
3732 }
3733 
JE_newEnemy(int enemyOffset,Uint16 eDatI,Sint16 uniqueShapeTableI)3734 Sint16 JE_newEnemy( int enemyOffset, Uint16 eDatI, Sint16 uniqueShapeTableI )
3735 {
3736 	for (int i = enemyOffset; i < enemyOffset + 25; ++i)
3737 	{
3738 		if (enemyAvail[i] == 1)
3739 		{
3740 			enemyAvail[i] = JE_makeEnemy(&enemy[i], eDatI, uniqueShapeTableI);
3741 			return i + 1;
3742 		}
3743 	}
3744 
3745 	return 0;
3746 }
3747 
JE_makeEnemy(struct JE_SingleEnemyType * enemy,Uint16 eDatI,Sint16 uniqueShapeTableI)3748 uint JE_makeEnemy( struct JE_SingleEnemyType *enemy, Uint16 eDatI, Sint16 uniqueShapeTableI )
3749 {
3750 	uint avail;
3751 
3752 	JE_byte shapeTableI;
3753 
3754 	if (superArcadeMode != SA_NONE && eDatI == 534)
3755 		eDatI = 533;
3756 
3757 	enemyShapeTables[5-1] = 21;   /*Coins&Gems*/
3758 	enemyShapeTables[6-1] = 26;   /*Two-Player Stuff*/
3759 
3760 	if (uniqueShapeTableI > 0)
3761 	{
3762 		shapeTableI = uniqueShapeTableI;
3763 	}
3764 	else
3765 	{
3766 		shapeTableI = enemyDat[eDatI].shapebank;
3767 	}
3768 
3769 	Sprite2_array *sprite2s = NULL;
3770 	for (uint i = 0; i < 6; ++i)
3771 		if (shapeTableI == enemyShapeTables[i])
3772 			sprite2s = &eShapes[i];
3773 
3774 	if (sprite2s != NULL)
3775 		enemy->sprite2s = sprite2s;
3776 	else
3777 		// maintain buggy Tyrian behavior (use shape table value from previous enemy that occupied this index in the enemy array)
3778 		fprintf(stderr, "warning: ignoring sprite from unloaded shape table %d\n", shapeTableI);
3779 
3780 	enemy->enemydatofs = &enemyDat[eDatI];
3781 
3782 	enemy->mapoffset = 0;
3783 
3784 	for (uint i = 0; i < 3; ++i)
3785 	{
3786 		enemy->eshotmultipos[i] = 0;
3787 	}
3788 
3789 	enemy->enemyground = (enemyDat[eDatI].explosiontype & 1) == 0;
3790 	enemy->explonum = enemyDat[eDatI].explosiontype >> 1;
3791 
3792 	enemy->launchfreq = enemyDat[eDatI].elaunchfreq;
3793 	enemy->launchwait = enemyDat[eDatI].elaunchfreq;
3794 	enemy->launchtype = enemyDat[eDatI].elaunchtype % 1000;
3795 	enemy->launchspecial = enemyDat[eDatI].elaunchtype / 1000;
3796 
3797 	enemy->xaccel = enemyDat[eDatI].xaccel;
3798 	enemy->yaccel = enemyDat[eDatI].yaccel;
3799 
3800 	enemy->xminbounce = -10000;
3801 	enemy->xmaxbounce = 10000;
3802 	enemy->yminbounce = -10000;
3803 	enemy->ymaxbounce = 10000;
3804 	/*Far enough away to be impossible to reach*/
3805 
3806 	for (uint i = 0; i < 3; ++i)
3807 	{
3808 		enemy->tur[i] = enemyDat[eDatI].tur[i];
3809 	}
3810 
3811 	enemy->ani = enemyDat[eDatI].ani;
3812 	enemy->animin = 1;
3813 
3814 	switch (enemyDat[eDatI].animate)
3815 	{
3816 	case 0:
3817 		enemy->enemycycle = 1;
3818 		enemy->aniactive = 0;
3819 		enemy->animax = 0;
3820 		enemy->aniwhenfire = 0;
3821 		break;
3822 	case 1:
3823 		enemy->enemycycle = 0;
3824 		enemy->aniactive = 1;
3825 		enemy->animax = 0;
3826 		enemy->aniwhenfire = 0;
3827 		break;
3828 	case 2:
3829 		enemy->enemycycle = 1;
3830 		enemy->aniactive = 2;
3831 		enemy->animax = enemy->ani;
3832 		enemy->aniwhenfire = 2;
3833 		break;
3834 	}
3835 
3836 	if (enemyDat[eDatI].startxc != 0)
3837 		enemy->ex = enemyDat[eDatI].startx + (mt_rand() % (enemyDat[eDatI].startxc * 2)) - enemyDat[eDatI].startxc + 1;
3838 	else
3839 		enemy->ex = enemyDat[eDatI].startx + 1;
3840 
3841 	if (enemyDat[eDatI].startyc != 0)
3842 		enemy->ey = enemyDat[eDatI].starty + (mt_rand() % (enemyDat[eDatI].startyc * 2)) - enemyDat[eDatI].startyc + 1;
3843 	else
3844 		enemy->ey = enemyDat[eDatI].starty + 1;
3845 
3846 	enemy->exc = enemyDat[eDatI].xmove;
3847 	enemy->eyc = enemyDat[eDatI].ymove;
3848 	enemy->excc = enemyDat[eDatI].xcaccel;
3849 	enemy->eycc = enemyDat[eDatI].ycaccel;
3850 	enemy->exccw = abs(enemy->excc);
3851 	enemy->exccwmax = enemy->exccw;
3852 	enemy->eyccw = abs(enemy->eycc);
3853 	enemy->eyccwmax = enemy->eyccw;
3854 	enemy->exccadd = (enemy->excc > 0) ? 1 : -1;
3855 	enemy->eyccadd = (enemy->eycc > 0) ? 1 : -1;
3856 	enemy->special = false;
3857 	enemy->iced = 0;
3858 
3859 	if (enemyDat[eDatI].xrev == 0)
3860 		enemy->exrev = 100;
3861 	else if (enemyDat[eDatI].xrev == -99)
3862 		enemy->exrev = 0;
3863 	else
3864 		enemy->exrev = enemyDat[eDatI].xrev;
3865 
3866 	if (enemyDat[eDatI].yrev == 0)
3867 		enemy->eyrev = 100;
3868 	else if (enemyDat[eDatI].yrev == -99)
3869 		enemy->eyrev = 0;
3870 	else
3871 		enemy->eyrev = enemyDat[eDatI].yrev;
3872 
3873 	enemy->exca = (enemy->xaccel > 0) ? 1 : -1;
3874 	enemy->eyca = (enemy->yaccel > 0) ? 1 : -1;
3875 
3876 	enemy->enemytype = eDatI;
3877 
3878 	for (uint i = 0; i < 3; ++i)
3879 	{
3880 		if (enemy->tur[i] == 252)
3881 			enemy->eshotwait[i] = 1;
3882 		else if (enemy->tur[i] > 0)
3883 			enemy->eshotwait[i] = 20;
3884 		else
3885 			enemy->eshotwait[i] = 255;
3886 	}
3887 	for (uint i = 0; i < 20; ++i)
3888 		enemy->egr[i] = enemyDat[eDatI].egraphic[i];
3889 	enemy->size = enemyDat[eDatI].esize;
3890 	enemy->linknum = 0;
3891 	enemy->edamaged = enemyDat[eDatI].dani < 0;
3892 	enemy->enemydie = enemyDat[eDatI].eenemydie;
3893 
3894 	enemy->freq[1-1] = enemyDat[eDatI].freq[1-1];
3895 	enemy->freq[2-1] = enemyDat[eDatI].freq[2-1];
3896 	enemy->freq[3-1] = enemyDat[eDatI].freq[3-1];
3897 
3898 	enemy->edani   = enemyDat[eDatI].dani;
3899 	enemy->edgr    = enemyDat[eDatI].dgr;
3900 	enemy->edlevel = enemyDat[eDatI].dlevel;
3901 
3902 	enemy->fixedmovey = 0;
3903 
3904 	enemy->filter = 0x00;
3905 
3906 	int tempValue = 0;
3907 	if (enemyDat[eDatI].value > 1 && enemyDat[eDatI].value < 10000)
3908 	{
3909 		switch (difficultyLevel)
3910 		{
3911 		case -1:
3912 		case 0:
3913 			tempValue = enemyDat[eDatI].value * 0.75f;
3914 			break;
3915 		case 1:
3916 		case 2:
3917 			tempValue = enemyDat[eDatI].value;
3918 			break;
3919 		case 3:
3920 			tempValue = enemyDat[eDatI].value * 1.125f;
3921 			break;
3922 		case 4:
3923 			tempValue = enemyDat[eDatI].value * 1.5f;
3924 			break;
3925 		case 5:
3926 			tempValue = enemyDat[eDatI].value * 2;
3927 			break;
3928 		case 6:
3929 			tempValue = enemyDat[eDatI].value * 2.5f;
3930 			break;
3931 		case 7:
3932 		case 8:
3933 			tempValue = enemyDat[eDatI].value * 4;
3934 			break;
3935 		case 9:
3936 		case 10:
3937 			tempValue = enemyDat[eDatI].value * 8;
3938 			break;
3939 		}
3940 		if (tempValue > 10000)
3941 			tempValue = 10000;
3942 		enemy->evalue = tempValue;
3943 	}
3944 	else
3945 	{
3946 		enemy->evalue = enemyDat[eDatI].value;
3947 	}
3948 
3949 	int tempArmor = 1;
3950 	if (enemyDat[eDatI].armor > 0)
3951 	{
3952 		if (enemyDat[eDatI].armor != 255)
3953 		{
3954 			switch (difficultyLevel)
3955 			{
3956 			case -1:
3957 			case 0:
3958 				tempArmor = enemyDat[eDatI].armor * 0.5f + 1;
3959 				break;
3960 			case 1:
3961 				tempArmor = enemyDat[eDatI].armor * 0.75f + 1;
3962 				break;
3963 			case 2:
3964 				tempArmor = enemyDat[eDatI].armor;
3965 				break;
3966 			case 3:
3967 				tempArmor = enemyDat[eDatI].armor * 1.2f;
3968 				break;
3969 			case 4:
3970 				tempArmor = enemyDat[eDatI].armor * 1.5f;
3971 				break;
3972 			case 5:
3973 				tempArmor = enemyDat[eDatI].armor * 1.8f;
3974 				break;
3975 			case 6:
3976 				tempArmor = enemyDat[eDatI].armor * 2;
3977 				break;
3978 			case 7:
3979 				tempArmor = enemyDat[eDatI].armor * 3;
3980 				break;
3981 			case 8:
3982 				tempArmor = enemyDat[eDatI].armor * 4;
3983 				break;
3984 			case 9:
3985 			case 10:
3986 				tempArmor = enemyDat[eDatI].armor * 8;
3987 				break;
3988 			}
3989 
3990 			if (tempArmor > 254)
3991 			{
3992 				tempArmor = 254;
3993 			}
3994 		}
3995 		else
3996 		{
3997 			tempArmor = 255;
3998 		}
3999 
4000 		enemy->armorleft = tempArmor;
4001 
4002 		avail = 0;
4003 		enemy->scoreitem = false;
4004 	}
4005 	else
4006 	{
4007 		avail = 2;
4008 		enemy->armorleft = 255;
4009 		if (enemy->evalue != 0)
4010 			enemy->scoreitem = true;
4011 	}
4012 
4013 	if (!enemy->scoreitem)
4014 	{
4015 		totalEnemy++;  /*Destruction ratio*/
4016 	}
4017 
4018 	/* indicates what to set ENEMYAVAIL to */
4019 	return avail;
4020 }
4021 
JE_createNewEventEnemy(JE_byte enemyTypeOfs,JE_word enemyOffset,Sint16 uniqueShapeTableI)4022 void JE_createNewEventEnemy( JE_byte enemyTypeOfs, JE_word enemyOffset, Sint16 uniqueShapeTableI )
4023 {
4024 	int i;
4025 
4026 	b = 0;
4027 
4028 	for(i = enemyOffset; i < enemyOffset + 25; i++)
4029 	{
4030 		if (enemyAvail[i] == 1)
4031 		{
4032 			b = i + 1;
4033 			break;
4034 		}
4035 	}
4036 
4037 	if (b == 0)
4038 	{
4039 		return;
4040 	}
4041 
4042 	tempW = eventRec[eventLoc-1].eventdat + enemyTypeOfs;
4043 
4044 	enemyAvail[b-1] = JE_makeEnemy(&enemy[b-1], tempW, uniqueShapeTableI);
4045 
4046 	if (eventRec[eventLoc-1].eventdat2 != -99)
4047 	{
4048 		switch (enemyOffset)
4049 		{
4050 		case 0:
4051 			enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - (mapX - 1) * 24;
4052 			enemy[b-1].ey -= backMove2;
4053 			break;
4054 		case 25:
4055 		case 75:
4056 			enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - (mapX - 1) * 24 - 12;
4057 			enemy[b-1].ey -= backMove;
4058 			break;
4059 		case 50:
4060 			if (background3x1)
4061 			{
4062 				enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - (mapX - 1) * 24 - 12;
4063 			} else {
4064 				enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - mapX3 * 24 - 24 * 2 + 6;
4065 			}
4066 			enemy[b-1].ey -= backMove3;
4067 
4068 			if (background3x1b)
4069 			{
4070 				enemy[b-1].ex -= 6;
4071 			}
4072 			break;
4073 		}
4074 		enemy[b-1].ey = -28;
4075 		if (background3x1b && enemyOffset == 50)
4076 		{
4077 			enemy[b-1].ey += 4;
4078 		}
4079 	}
4080 
4081 	if (smallEnemyAdjust && enemy[b-1].size == 0)
4082 	{
4083 		enemy[b-1].ex -= 10;
4084 		enemy[b-1].ey -= 7;
4085 	}
4086 
4087 	enemy[b-1].ey += eventRec[eventLoc-1].eventdat5;
4088 	enemy[b-1].eyc += eventRec[eventLoc-1].eventdat3;
4089 	enemy[b-1].linknum = eventRec[eventLoc-1].eventdat4;
4090 	enemy[b-1].fixedmovey = eventRec[eventLoc-1].eventdat6;
4091 }
4092 
JE_eventJump(JE_word jump)4093 void JE_eventJump( JE_word jump )
4094 {
4095 	JE_word tempW;
4096 
4097 	if (jump == 65535)
4098 	{
4099 		curLoc = returnLoc;
4100 	}
4101 	else
4102 	{
4103 		returnLoc = curLoc + 1;
4104 		curLoc = jump;
4105 	}
4106 	tempW = 0;
4107 	do
4108 	{
4109 		tempW++;
4110 	}
4111 	while (!(eventRec[tempW-1].eventtime >= curLoc));
4112 	eventLoc = tempW - 1;
4113 }
4114 
JE_searchFor(JE_byte PLType,JE_byte * out_index)4115 bool JE_searchFor/*enemy*/( JE_byte PLType, JE_byte* out_index )
4116 {
4117 	int found_id = -1;
4118 
4119 	for (int i = 0; i < 100; i++)
4120 	{
4121 		if (enemyAvail[i] == 0 && enemy[i].linknum == PLType)
4122 		{
4123 			found_id = i;
4124 			if (galagaMode)
4125 			{
4126 				enemy[i].evalue += enemy[i].evalue;
4127 			}
4128 		}
4129 	}
4130 
4131 	if (found_id != -1) {
4132 		if (out_index) {
4133 			*out_index = found_id;
4134 		}
4135 		return true;
4136 	} else {
4137 		return false;
4138 	}
4139 }
4140 
JE_eventSystem(void)4141 void JE_eventSystem( void )
4142 {
4143 	switch (eventRec[eventLoc-1].eventtype)
4144 	{
4145 	case 1:
4146 		starfield_speed = eventRec[eventLoc-1].eventdat;
4147 		break;
4148 
4149 	case 2:
4150 		map1YDelay = 1;
4151 		map1YDelayMax = 1;
4152 		map2YDelay = 1;
4153 		map2YDelayMax = 1;
4154 
4155 		backMove = eventRec[eventLoc-1].eventdat;
4156 		backMove2 = eventRec[eventLoc-1].eventdat2;
4157 
4158 		if (backMove2 > 0)
4159 			explodeMove = backMove2;
4160 		else
4161 			explodeMove = backMove;
4162 
4163 		backMove3 = eventRec[eventLoc-1].eventdat3;
4164 
4165 		if (backMove > 0)
4166 			stopBackgroundNum = 0;
4167 		break;
4168 
4169 	case 3:
4170 		backMove = 1;
4171 		map1YDelay = 3;
4172 		map1YDelayMax = 3;
4173 		backMove2 = 1;
4174 		map2YDelay = 2;
4175 		map2YDelayMax = 2;
4176 		backMove3 = 1;
4177 		break;
4178 
4179 	case 4:
4180 		stopBackgrounds = true;
4181 		switch (eventRec[eventLoc-1].eventdat)
4182 		{
4183 		case 0:
4184 		case 1:
4185 			stopBackgroundNum = 1;
4186 			break;
4187 		case 2:
4188 			stopBackgroundNum = 2;
4189 			break;
4190 		case 3:
4191 			stopBackgroundNum = 3;
4192 			break;
4193 		}
4194 		break;
4195 
4196 	case 5:  // load enemy shape banks
4197 		{
4198 			Uint8 newEnemyShapeTables[] =
4199 			{
4200 				eventRec[eventLoc-1].eventdat > 0 ? eventRec[eventLoc-1].eventdat : 0,
4201 				eventRec[eventLoc-1].eventdat2 > 0 ? eventRec[eventLoc-1].eventdat2 : 0,
4202 				eventRec[eventLoc-1].eventdat3 > 0 ? eventRec[eventLoc-1].eventdat3 : 0,
4203 				eventRec[eventLoc-1].eventdat4 > 0 ? eventRec[eventLoc-1].eventdat4 : 0,
4204 			};
4205 
4206 			for (unsigned int i = 0; i < COUNTOF(newEnemyShapeTables); ++i)
4207 			{
4208 				if (enemyShapeTables[i] != newEnemyShapeTables[i])
4209 				{
4210 					if (newEnemyShapeTables[i] > 0)
4211 					{
4212 						assert(newEnemyShapeTables[i] <= COUNTOF(shapeFile));
4213 						JE_loadCompShapes(&eShapes[i], shapeFile[newEnemyShapeTables[i] - 1]);
4214 					}
4215 					else
4216 						free_sprite2s(&eShapes[i]);
4217 
4218 					enemyShapeTables[i] = newEnemyShapeTables[i];
4219 				}
4220 			}
4221 		}
4222 		break;
4223 
4224 	case 6: /* Ground Enemy */
4225 		JE_createNewEventEnemy(0, 25, 0);
4226 		break;
4227 
4228 	case 7: /* Top Enemy */
4229 		JE_createNewEventEnemy(0, 50, 0);
4230 		break;
4231 
4232 	case 8:
4233 		starActive = false;
4234 		break;
4235 
4236 	case 9:
4237 		starActive = true;
4238 		break;
4239 
4240 	case 10: /* Ground Enemy 2 */
4241 		JE_createNewEventEnemy(0, 75, 0);
4242 		break;
4243 
4244 	case 11:
4245 		if (allPlayersGone || eventRec[eventLoc-1].eventdat == 1)
4246 			reallyEndLevel = true;
4247 		else
4248 			if (!endLevel)
4249 			{
4250 				readyToEndLevel = false;
4251 				endLevel = true;
4252 				levelEnd = 40;
4253 			}
4254 		break;
4255 
4256 	case 12: /* Custom 4x4 Ground Enemy */
4257 		{
4258 			uint temp = 0;
4259 			switch (eventRec[eventLoc-1].eventdat6)
4260 			{
4261 			case 0:
4262 			case 1:
4263 				temp = 25;
4264 				break;
4265 			case 2:
4266 				temp = 0;
4267 				break;
4268 			case 3:
4269 				temp = 50;
4270 				break;
4271 			case 4:
4272 				temp = 75;
4273 				break;
4274 			}
4275 			eventRec[eventLoc-1].eventdat6 = 0;   /* We use EVENTDAT6 for the background */
4276 			JE_createNewEventEnemy(0, temp, 0);
4277 			JE_createNewEventEnemy(1, temp, 0);
4278 			enemy[b-1].ex += 24;
4279 			JE_createNewEventEnemy(2, temp, 0);
4280 			enemy[b-1].ey -= 28;
4281 			JE_createNewEventEnemy(3, temp, 0);
4282 			enemy[b-1].ex += 24;
4283 			enemy[b-1].ey -= 28;
4284 			break;
4285 		}
4286 	case 13:
4287 		enemiesActive = false;
4288 		break;
4289 
4290 	case 14:
4291 		enemiesActive = true;
4292 		break;
4293 
4294 	case 15: /* Sky Enemy */
4295 		JE_createNewEventEnemy(0, 0, 0);
4296 		break;
4297 
4298 	case 16:
4299 		if (eventRec[eventLoc-1].eventdat > 9)
4300 		{
4301 			fprintf(stderr, "warning: event 16: bad event data\n");
4302 		}
4303 		else
4304 		{
4305 			JE_drawTextWindow(outputs[eventRec[eventLoc-1].eventdat-1]);
4306 			soundQueue[3] = windowTextSamples[eventRec[eventLoc-1].eventdat-1];
4307 		}
4308 		break;
4309 
4310 	case 17: /* Ground Bottom */
4311 		JE_createNewEventEnemy(0, 25, 0);
4312 		if (b > 0)
4313 		{
4314 			enemy[b-1].ey = 190 + eventRec[eventLoc-1].eventdat5;
4315 		}
4316 		break;
4317 
4318 	case 18: /* Sky Enemy on Bottom */
4319 		JE_createNewEventEnemy(0, 0, 0);
4320 		if (b > 0)
4321 		{
4322 			enemy[b-1].ey = 190 + eventRec[eventLoc-1].eventdat5;
4323 		}
4324 		break;
4325 
4326 	case 19: /* Enemy Global Move */
4327 	{
4328 		int initial_i, max_i;
4329 		bool all_enemies;
4330 
4331 		if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90)
4332 		{
4333 			initial_i = 0;
4334 			max_i = 100;
4335 			all_enemies = false;
4336 			eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80];
4337 		}
4338 		else
4339 		{
4340 			switch (eventRec[eventLoc-1].eventdat3)
4341 			{
4342 			case 0:
4343 				initial_i = 0;
4344 				max_i = 100;
4345 				all_enemies = false;
4346 				break;
4347 			case 2:
4348 				initial_i = 0;
4349 				max_i = 25;
4350 				all_enemies = true;
4351 				break;
4352 			case 1:
4353 				initial_i = 25;
4354 				max_i = 50;
4355 				all_enemies = true;
4356 				break;
4357 			case 3:
4358 				initial_i = 50;
4359 				max_i = 75;
4360 				all_enemies = true;
4361 				break;
4362 			case 99:
4363 				initial_i = 0;
4364 				max_i = 100;
4365 				all_enemies = true;
4366 				break;
4367 			}
4368 		}
4369 
4370 		for (int i = initial_i; i < max_i; i++)
4371 		{
4372 			if (all_enemies || enemy[i].linknum == eventRec[eventLoc-1].eventdat4)
4373 			{
4374 				if (eventRec[eventLoc-1].eventdat != -99)
4375 					enemy[i].exc = eventRec[eventLoc-1].eventdat;
4376 
4377 				if (eventRec[eventLoc-1].eventdat2 != -99)
4378 					enemy[i].eyc = eventRec[eventLoc-1].eventdat2;
4379 
4380 				if (eventRec[eventLoc-1].eventdat6 != 0)
4381 					enemy[i].fixedmovey = eventRec[eventLoc-1].eventdat6;
4382 
4383 				if (eventRec[eventLoc-1].eventdat6 == -99)
4384 					enemy[i].fixedmovey = 0;
4385 
4386 				if (eventRec[eventLoc-1].eventdat5 > 0)
4387 					enemy[i].enemycycle = eventRec[eventLoc-1].eventdat5;
4388 			}
4389 		}
4390 		break;
4391 	}
4392 
4393 	case 20: /* Enemy Global Accel */
4394 		if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90)
4395 			eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80];
4396 
4397 		for (temp = 0; temp < 100; temp++)
4398 		{
4399 			if (enemyAvail[temp] != 1
4400 			    && (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4 || eventRec[eventLoc-1].eventdat4 == 0))
4401 			{
4402 				if (eventRec[eventLoc-1].eventdat != -99)
4403 				{
4404 					enemy[temp].excc = eventRec[eventLoc-1].eventdat;
4405 					enemy[temp].exccw = abs(eventRec[eventLoc-1].eventdat);
4406 					enemy[temp].exccwmax = abs(eventRec[eventLoc-1].eventdat);
4407 					if (eventRec[eventLoc-1].eventdat > 0)
4408 						enemy[temp].exccadd = 1;
4409 					else
4410 						enemy[temp].exccadd = -1;
4411 				}
4412 
4413 				if (eventRec[eventLoc-1].eventdat2 != -99)
4414 				{
4415 					enemy[temp].eycc = eventRec[eventLoc-1].eventdat2;
4416 					enemy[temp].eyccw = abs(eventRec[eventLoc-1].eventdat2);
4417 					enemy[temp].eyccwmax = abs(eventRec[eventLoc-1].eventdat2);
4418 					if (eventRec[eventLoc-1].eventdat2 > 0)
4419 						enemy[temp].eyccadd = 1;
4420 					else
4421 						enemy[temp].eyccadd = -1;
4422 				}
4423 
4424 				if (eventRec[eventLoc-1].eventdat5 > 0)
4425 				{
4426 					enemy[temp].enemycycle = eventRec[eventLoc-1].eventdat5;
4427 				}
4428 				if (eventRec[eventLoc-1].eventdat6 > 0)
4429 				{
4430 					enemy[temp].ani = eventRec[eventLoc-1].eventdat6;
4431 					enemy[temp].animin = eventRec[eventLoc-1].eventdat5;
4432 					enemy[temp].animax = 0;
4433 					enemy[temp].aniactive = 1;
4434 				}
4435 			}
4436 		}
4437 		break;
4438 
4439 	case 21:
4440 		background3over = 1;
4441 		break;
4442 
4443 	case 22:
4444 		background3over = 0;
4445 		break;
4446 
4447 	case 23: /* Sky Enemy on Bottom */
4448 		JE_createNewEventEnemy(0, 50, 0);
4449 		if (b > 0)
4450 			enemy[b-1].ey = 180 + eventRec[eventLoc-1].eventdat5;
4451 		break;
4452 
4453 	case 24: /* Enemy Global Animate */
4454 		for (temp = 0; temp < 100; temp++)
4455 		{
4456 			if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
4457 			{
4458 				enemy[temp].aniactive = 1;
4459 				enemy[temp].aniwhenfire = 0;
4460 				if (eventRec[eventLoc-1].eventdat2 > 0)
4461 				{
4462 					enemy[temp].enemycycle = eventRec[eventLoc-1].eventdat2;
4463 					enemy[temp].animin = enemy[temp].enemycycle;
4464 				}
4465 				else
4466 				{
4467 					enemy[temp].enemycycle = 0;
4468 				}
4469 
4470 				if (eventRec[eventLoc-1].eventdat > 0)
4471 					enemy[temp].ani = eventRec[eventLoc-1].eventdat;
4472 
4473 				if (eventRec[eventLoc-1].eventdat3 == 1)
4474 				{
4475 					enemy[temp].animax = enemy[temp].ani;
4476 				}
4477 				else if (eventRec[eventLoc-1].eventdat3 == 2)
4478 				{
4479 					enemy[temp].aniactive = 2;
4480 					enemy[temp].animax = enemy[temp].ani;
4481 					enemy[temp].aniwhenfire = 2;
4482 				}
4483 			}
4484 		}
4485 		break;
4486 
4487 	case 25: /* Enemy Global Damage change */
4488 		for (temp = 0; temp < 100; temp++)
4489 		{
4490 			if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
4491 			{
4492 				if (galagaMode)
4493 					enemy[temp].armorleft = roundf(eventRec[eventLoc-1].eventdat * (difficultyLevel / 2));
4494 				else
4495 					enemy[temp].armorleft = eventRec[eventLoc-1].eventdat;
4496 			}
4497 		}
4498 		break;
4499 
4500 	case 26:
4501 		smallEnemyAdjust = eventRec[eventLoc-1].eventdat;
4502 		break;
4503 
4504 	case 27: /* Enemy Global AccelRev */
4505 		if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90)
4506 			eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80];
4507 
4508 		for (temp = 0; temp < 100; temp++)
4509 		{
4510 			if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
4511 			{
4512 				if (eventRec[eventLoc-1].eventdat != -99)
4513 					enemy[temp].exrev = eventRec[eventLoc-1].eventdat;
4514 				if (eventRec[eventLoc-1].eventdat2 != -99)
4515 					enemy[temp].eyrev = eventRec[eventLoc-1].eventdat2;
4516 				if (eventRec[eventLoc-1].eventdat3 != 0 && eventRec[eventLoc-1].eventdat3 < 17)
4517 					enemy[temp].filter = eventRec[eventLoc-1].eventdat3;
4518 			}
4519 		}
4520 		break;
4521 
4522 	case 28:
4523 		topEnemyOver = false;
4524 		break;
4525 
4526 	case 29:
4527 		topEnemyOver = true;
4528 		break;
4529 
4530 	case 30:
4531 		map1YDelay = 1;
4532 		map1YDelayMax = 1;
4533 		map2YDelay = 1;
4534 		map2YDelayMax = 1;
4535 
4536 		backMove = eventRec[eventLoc-1].eventdat;
4537 		backMove2 = eventRec[eventLoc-1].eventdat2;
4538 		explodeMove = backMove2;
4539 		backMove3 = eventRec[eventLoc-1].eventdat3;
4540 		break;
4541 
4542 	case 31: /* Enemy Fire Override */
4543 		for (temp = 0; temp < 100; temp++)
4544 		{
4545 			if (eventRec[eventLoc-1].eventdat4 == 99 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
4546 			{
4547 				enemy[temp].freq[1-1] = eventRec[eventLoc-1].eventdat ;
4548 				enemy[temp].freq[2-1] = eventRec[eventLoc-1].eventdat2;
4549 				enemy[temp].freq[3-1] = eventRec[eventLoc-1].eventdat3;
4550 				for (temp2 = 0; temp2 < 3; temp2++)
4551 				{
4552 					enemy[temp].eshotwait[temp2] = 1;
4553 				}
4554 				if (enemy[temp].launchtype > 0)
4555 				{
4556 					enemy[temp].launchfreq = eventRec[eventLoc-1].eventdat5;
4557 					enemy[temp].launchwait = 1;
4558 				}
4559 			}
4560 		}
4561 		break;
4562 
4563 	case 32:  // create enemy
4564 		JE_createNewEventEnemy(0, 50, 0);
4565 		if (b > 0)
4566 			enemy[b-1].ey = 190;
4567 		break;
4568 
4569 	case 33: /* Enemy From other Enemies */
4570 		if (!((eventRec[eventLoc-1].eventdat == 512 || eventRec[eventLoc-1].eventdat == 513) && (twoPlayerMode || onePlayerAction || superTyrian)))
4571 		{
4572 			if (superArcadeMode != SA_NONE)
4573 			{
4574 				if (eventRec[eventLoc-1].eventdat == 534)
4575 					eventRec[eventLoc-1].eventdat = 827;
4576 			}
4577 			else if (!superTyrian)
4578 			{
4579 				const uint lives = *player[0].lives;
4580 
4581 				if (eventRec[eventLoc-1].eventdat == 533 && (lives == 11 || (mt_rand() % 15) < lives))
4582 				{
4583 					// enemy will drop random special weapon
4584 					eventRec[eventLoc-1].eventdat = 829 + (mt_rand() % 6);
4585 				}
4586 			}
4587 			if (eventRec[eventLoc-1].eventdat == 534 && superTyrian)
4588 				eventRec[eventLoc-1].eventdat = 828 + superTyrianSpecials[mt_rand() % 4];
4589 
4590 			for (temp = 0; temp < 100; temp++)
4591 			{
4592 				if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
4593 					enemy[temp].enemydie = eventRec[eventLoc-1].eventdat;
4594 			}
4595 		}
4596 		break;
4597 
4598 	case 34: /* Start Music Fade */
4599 		if (firstGameOver)
4600 		{
4601 			musicFade = true;
4602 			tempVolume = tyrMusicVolume;
4603 		}
4604 		break;
4605 
4606 	case 35: /* Play new song */
4607 		if (firstGameOver)
4608 		{
4609 			play_song(eventRec[eventLoc-1].eventdat - 1);
4610 			set_volume(tyrMusicVolume, fxVolume);
4611 		}
4612 		musicFade = false;
4613 		break;
4614 
4615 	case 36:
4616 		readyToEndLevel = true;
4617 		break;
4618 
4619 	case 37:
4620 		levelEnemyFrequency = eventRec[eventLoc-1].eventdat;
4621 		break;
4622 
4623 	case 38:
4624 		curLoc = eventRec[eventLoc-1].eventdat;
4625 		int new_event_loc = 1;
4626 		for (tempW = 0; tempW < maxEvent; tempW++)
4627 		{
4628 			if (eventRec[tempW].eventtime <= curLoc)
4629 			{
4630 				new_event_loc = tempW+1 - 1;
4631 			}
4632 		}
4633 		eventLoc = new_event_loc;
4634 		break;
4635 
4636 	case 39: /* Enemy Global Linknum Change */
4637 		for (temp = 0; temp < 100; temp++)
4638 		{
4639 			if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat)
4640 				enemy[temp].linknum = eventRec[eventLoc-1].eventdat2;
4641 		}
4642 		break;
4643 
4644 	case 40: /* Enemy Continual Damage */
4645 		enemyContinualDamage = true;
4646 		break;
4647 
4648 	case 41:
4649 		if (eventRec[eventLoc-1].eventdat == 0)
4650 		{
4651 			memset(enemyAvail, 1, sizeof(enemyAvail));
4652 		}
4653 		else
4654 		{
4655 			for (x = 0; x <= 24; x++)
4656 				enemyAvail[x] = 1;
4657 		}
4658 		break;
4659 
4660 	case 42:
4661 		background3over = 2;
4662 		break;
4663 
4664 	case 43:
4665 		background2over = eventRec[eventLoc-1].eventdat;
4666 		break;
4667 
4668 	case 44:
4669 		filterActive       = (eventRec[eventLoc-1].eventdat > 0);
4670 		filterFade         = (eventRec[eventLoc-1].eventdat == 2);
4671 		levelFilter        = eventRec[eventLoc-1].eventdat2;
4672 		levelBrightness    = eventRec[eventLoc-1].eventdat3;
4673 		levelFilterNew     = eventRec[eventLoc-1].eventdat4;
4674 		levelBrightnessChg = eventRec[eventLoc-1].eventdat5;
4675 		filterFadeStart    = (eventRec[eventLoc-1].eventdat6 == 0);
4676 		break;
4677 
4678 	case 45: /* arcade-only enemy from other enemies */
4679 		if (!superTyrian)
4680 		{
4681 			const uint lives = *player[0].lives;
4682 
4683 			if (eventRec[eventLoc-1].eventdat == 533 && (lives == 11 || (mt_rand() % 15) < lives))
4684 			{
4685 				eventRec[eventLoc-1].eventdat = 829 + (mt_rand() % 6);
4686 			}
4687 			if (twoPlayerMode || onePlayerAction)
4688 			{
4689 				for (temp = 0; temp < 100; temp++)
4690 				{
4691 					if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
4692 						enemy[temp].enemydie = eventRec[eventLoc-1].eventdat;
4693 				}
4694 			}
4695 		}
4696 		break;
4697 
4698 	case 46:  // change difficulty
4699 		if (eventRec[eventLoc-1].eventdat3 != 0)
4700 			damageRate = eventRec[eventLoc-1].eventdat3;
4701 
4702 		if (eventRec[eventLoc-1].eventdat2 == 0 || twoPlayerMode || onePlayerAction)
4703 		{
4704 			difficultyLevel += eventRec[eventLoc-1].eventdat;
4705 			if (difficultyLevel < 1)
4706 				difficultyLevel = 1;
4707 			if (difficultyLevel > 10)
4708 				difficultyLevel = 10;
4709 		}
4710 		break;
4711 
4712 	case 47: /* Enemy Global AccelRev */
4713 		for (temp = 0; temp < 100; temp++)
4714 		{
4715 			if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
4716 				enemy[temp].armorleft = eventRec[eventLoc-1].eventdat;
4717 		}
4718 		break;
4719 
4720 	case 48: /* Background 2 Cannot be Transparent */
4721 		background2notTransparent = true;
4722 		break;
4723 
4724 	case 49:
4725 	case 50:
4726 	case 51:
4727 	case 52:
4728 		tempDat2 = eventRec[eventLoc-1].eventdat;
4729 		eventRec[eventLoc-1].eventdat = 0;
4730 		tempDat = eventRec[eventLoc-1].eventdat3;
4731 		eventRec[eventLoc-1].eventdat3 = 0;
4732 		tempDat3 = eventRec[eventLoc-1].eventdat6;
4733 		eventRec[eventLoc-1].eventdat6 = 0;
4734 		enemyDat[0].armor = tempDat3;
4735 		enemyDat[0].egraphic[1-1] = tempDat2;
4736 		switch (eventRec[eventLoc-1].eventtype - 48)
4737 		{
4738 		case 1:
4739 			temp = 25;
4740 			break;
4741 		case 2:
4742 			temp = 0;
4743 			break;
4744 		case 3:
4745 			temp = 50;
4746 			break;
4747 		case 4:
4748 			temp = 75;
4749 			break;
4750 		}
4751 		JE_createNewEventEnemy(0, temp, tempDat);
4752 		eventRec[eventLoc-1].eventdat = tempDat2;
4753 		eventRec[eventLoc-1].eventdat3 = tempDat;
4754 		eventRec[eventLoc-1].eventdat6 = tempDat3;
4755 		break;
4756 
4757 	case 53:
4758 		forceEvents = (eventRec[eventLoc-1].eventdat != 99);
4759 		break;
4760 
4761 	case 54:
4762 		JE_eventJump(eventRec[eventLoc-1].eventdat);
4763 		break;
4764 
4765 	case 55: /* Enemy Global AccelRev */
4766 		if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90)
4767 			eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80];
4768 
4769 		for (temp = 0; temp < 100; temp++)
4770 		{
4771 			if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
4772 			{
4773 				if (eventRec[eventLoc-1].eventdat != -99)
4774 					enemy[temp].xaccel = eventRec[eventLoc-1].eventdat;
4775 				if (eventRec[eventLoc-1].eventdat2 != -99)
4776 					enemy[temp].yaccel = eventRec[eventLoc-1].eventdat2;
4777 			}
4778 		}
4779 		break;
4780 
4781 	case 56: /* Ground2 Bottom */
4782 		JE_createNewEventEnemy(0, 75, 0);
4783 		if (b > 0)
4784 			enemy[b-1].ey = 190;
4785 		break;
4786 
4787 	case 57:
4788 		superEnemy254Jump = eventRec[eventLoc-1].eventdat;
4789 		break;
4790 
4791 	case 60: /*Assign Special Enemy*/
4792 		for (temp = 0; temp < 100; temp++)
4793 		{
4794 			if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
4795 			{
4796 				enemy[temp].special = true;
4797 				enemy[temp].flagnum = eventRec[eventLoc-1].eventdat;
4798 				enemy[temp].setto  = (eventRec[eventLoc-1].eventdat2 == 1);
4799 			}
4800 		}
4801 		break;
4802 
4803 	case 61:  // if specific flag set to specific value, skip events
4804 		if (globalFlags[eventRec[eventLoc-1].eventdat-1] == eventRec[eventLoc-1].eventdat2)
4805 			eventLoc += eventRec[eventLoc-1].eventdat3;
4806 		break;
4807 
4808 	case 62: /*Play sound effect*/
4809 		soundQueue[3] = eventRec[eventLoc-1].eventdat;
4810 		break;
4811 
4812 	case 63:  // skip events if not in 2-player mode
4813 		if (!twoPlayerMode && !onePlayerAction)
4814 			eventLoc += eventRec[eventLoc-1].eventdat;
4815 		break;
4816 
4817 	case 64:
4818 		if (!(eventRec[eventLoc-1].eventdat == 6 && twoPlayerMode && difficultyLevel > 2))
4819 		{
4820 			smoothies[eventRec[eventLoc-1].eventdat-1] = eventRec[eventLoc-1].eventdat2;
4821 			temp = eventRec[eventLoc-1].eventdat;
4822 			if (temp == 5)
4823 				temp = 3;
4824 			smoothie_data[temp-1] = eventRec[eventLoc-1].eventdat3;
4825 		}
4826 		break;
4827 
4828 	case 65:
4829 		background3x1 = (eventRec[eventLoc-1].eventdat == 0);
4830 		break;
4831 
4832 	case 66: /*If not on this difficulty level or higher then...*/
4833 		if (initialDifficulty <= eventRec[eventLoc-1].eventdat)
4834 			eventLoc += eventRec[eventLoc-1].eventdat2;
4835 		break;
4836 
4837 	case 67:
4838 		levelTimer = (eventRec[eventLoc-1].eventdat == 1);
4839 		levelTimerCountdown = eventRec[eventLoc-1].eventdat3 * 100;
4840 		levelTimerJumpTo   = eventRec[eventLoc-1].eventdat2;
4841 		break;
4842 
4843 	case 68:
4844 		randomExplosions = (eventRec[eventLoc-1].eventdat == 1);
4845 		break;
4846 
4847 	case 69:
4848 		for (uint i = 0; i < COUNTOF(player); ++i)
4849 			player[i].invulnerable_ticks = eventRec[eventLoc-1].eventdat;
4850 		break;
4851 
4852 	case 70:
4853 		if (eventRec[eventLoc-1].eventdat2 == 0)
4854 		{  /*1-10*/
4855 			bool found = false;
4856 
4857 			for (temp = 1; temp <= 19; temp++)
4858 				found = found || JE_searchFor(temp, NULL);
4859 
4860 			if (!found)
4861 				JE_eventJump(eventRec[eventLoc-1].eventdat);
4862 		}
4863 		else if (!JE_searchFor(eventRec[eventLoc-1].eventdat2, NULL)
4864 		         && (eventRec[eventLoc-1].eventdat3 == 0 || !JE_searchFor(eventRec[eventLoc-1].eventdat3, NULL))
4865 		         && (eventRec[eventLoc-1].eventdat4 == 0 || !JE_searchFor(eventRec[eventLoc-1].eventdat4, NULL)))
4866 		{
4867 			JE_eventJump(eventRec[eventLoc-1].eventdat);
4868 		}
4869 		break;
4870 
4871 	case 71:
4872 		if (((((intptr_t)mapYPos - (intptr_t)&megaData1.mainmap) / sizeof(JE_byte *)) * 2) <= (unsigned)eventRec[eventLoc-1].eventdat2)
4873 		{
4874 			JE_eventJump(eventRec[eventLoc-1].eventdat);
4875 		}
4876 		break;
4877 
4878 	case 72:
4879 		background3x1b = (eventRec[eventLoc-1].eventdat == 1);
4880 		break;
4881 
4882 	case 73:
4883 		skyEnemyOverAll = (eventRec[eventLoc-1].eventdat == 1);
4884 		break;
4885 
4886 	case 74: /* Enemy Global BounceParams */
4887 		for (temp = 0; temp < 100; temp++)
4888 		{
4889 			if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
4890 			{
4891 				if (eventRec[eventLoc-1].eventdat5 != -99)
4892 					enemy[temp].xminbounce = eventRec[eventLoc-1].eventdat5;
4893 
4894 				if (eventRec[eventLoc-1].eventdat6 != -99)
4895 					enemy[temp].yminbounce = eventRec[eventLoc-1].eventdat6;
4896 
4897 				if (eventRec[eventLoc-1].eventdat != -99)
4898 					enemy[temp].xmaxbounce = eventRec[eventLoc-1].eventdat;
4899 
4900 				if (eventRec[eventLoc-1].eventdat2 != -99)
4901 					enemy[temp].ymaxbounce = eventRec[eventLoc-1].eventdat2;
4902 			}
4903 		}
4904 		break;
4905 
4906 	case 75:;
4907 		bool temp_no_clue = false; // TODO: figure out what this is doing
4908 
4909 		for (temp = 0; temp < 100; temp++)
4910 		{
4911 			if (enemyAvail[temp] == 0
4912 			    && enemy[temp].eyc == 0
4913 			    && enemy[temp].linknum >= eventRec[eventLoc-1].eventdat
4914 			    && enemy[temp].linknum <= eventRec[eventLoc-1].eventdat2)
4915 			{
4916 				temp_no_clue = true;
4917 			}
4918 		}
4919 
4920 		if (temp_no_clue)
4921 		{
4922 			JE_byte enemy_i;
4923 			do
4924 			{
4925 				temp = (mt_rand() % (eventRec[eventLoc-1].eventdat2 + 1 - eventRec[eventLoc-1].eventdat)) + eventRec[eventLoc-1].eventdat;
4926 			}
4927 			while (!(JE_searchFor(temp, &enemy_i) && enemy[enemy_i].eyc == 0));
4928 
4929 			newPL[eventRec[eventLoc-1].eventdat3 - 80] = temp;
4930 		}
4931 		else
4932 		{
4933 			newPL[eventRec[eventLoc-1].eventdat3 - 80] = 255;
4934 			if (eventRec[eventLoc-1].eventdat4 > 0)
4935 			{ /*Skip*/
4936 				curLoc = eventRec[eventLoc-1 + eventRec[eventLoc-1].eventdat4].eventtime - 1;
4937 				eventLoc += eventRec[eventLoc-1].eventdat4 - 1;
4938 			}
4939 		}
4940 
4941 		break;
4942 
4943 	case 76:
4944 		returnActive = true;
4945 		break;
4946 
4947 	case 77:
4948 		mapYPos = &megaData1.mainmap[0][0];
4949 		mapYPos += eventRec[eventLoc-1].eventdat / 2;
4950 		if (eventRec[eventLoc-1].eventdat2 > 0)
4951 		{
4952 			mapY2Pos = &megaData2.mainmap[0][0];
4953 			mapY2Pos += eventRec[eventLoc-1].eventdat2 / 2;
4954 		}
4955 		else
4956 		{
4957 			mapY2Pos = &megaData2.mainmap[0][0];
4958 			mapY2Pos += eventRec[eventLoc-1].eventdat / 2;
4959 		}
4960 		break;
4961 
4962 	case 78:
4963 		if (galagaShotFreq < 10)
4964 			galagaShotFreq++;
4965 		break;
4966 
4967 	case 79:
4968 		boss_bar[0].link_num = eventRec[eventLoc-1].eventdat;
4969 		boss_bar[1].link_num = eventRec[eventLoc-1].eventdat2;
4970 		break;
4971 
4972 	case 80:  // skip events if in 2-player mode
4973 		if (twoPlayerMode)
4974 			eventLoc += eventRec[eventLoc-1].eventdat;
4975 		break;
4976 
4977 	case 81: /*WRAP2*/
4978 		BKwrap2   = &megaData2.mainmap[0][0];
4979 		BKwrap2   += eventRec[eventLoc-1].eventdat / 2;
4980 		BKwrap2to = &megaData2.mainmap[0][0];
4981 		BKwrap2to += eventRec[eventLoc-1].eventdat2 / 2;
4982 		break;
4983 
4984 	case 82: /*Give SPECIAL WEAPON*/
4985 		player[0].items.special = eventRec[eventLoc-1].eventdat;
4986 		shotMultiPos[SHOT_SPECIAL] = 0;
4987 		shotRepeat[SHOT_SPECIAL] = 0;
4988 		shotMultiPos[SHOT_SPECIAL2] = 0;
4989 		shotRepeat[SHOT_SPECIAL2] = 0;
4990 		break;
4991 
4992 	default:
4993 		fprintf(stderr, "warning: ignoring unknown event %d\n", eventRec[eventLoc-1].eventtype);
4994 		break;
4995 	}
4996 
4997 	eventLoc++;
4998 }
4999 
JE_whoa(void)5000 void JE_whoa( void )
5001 {
5002 	unsigned int i, j, color, offset, timer;
5003 	unsigned int screenSize, topBorder, bottomBorder;
5004 	Uint8 * TempScreen1, * TempScreen2, * TempScreenSwap;
5005 
5006 	/* 'whoa' gets us that nifty screen fade used when you type in
5007 	 * 'engage'.  We need two temporary screen buffers (char arrays can
5008 	 * work too, but these screens already exist) for our effect.
5009 	 * This could probably be a lot more efficient (there's probably a
5010 	 * way to get vgascreen as one of the temp buffers), but it's only called
5011 	 * once so don't worry about it. */
5012 
5013 	TempScreen1  = game_screen->pixels;
5014 	TempScreen2  = VGAScreen2->pixels;
5015 
5016 	screenSize   = VGAScreenSeg->h * VGAScreenSeg->pitch;
5017 	topBorder    = VGAScreenSeg->pitch * 4; /* Seems an arbitrary number of lines */
5018 	bottomBorder = VGAScreenSeg->pitch * 7;
5019 
5020 	/* Okay, one disadvantage to using other screens as temp buffers: they
5021 	 * need to be the right size.  I doubt they'l ever be anything but 320x200,
5022 	 * but just in case, these asserts will clue in whoever stumbles across
5023 	 * the problem.  You can fix it with the stack or malloc. */
5024 	assert( (unsigned)VGAScreen2->h *  VGAScreen2->pitch >= screenSize
5025 	    && (unsigned)game_screen->h * game_screen->pitch >= screenSize);
5026 
5027 
5028 	/* Clear the top and bottom borders.  We don't want to process
5029 	 * them and we don't want to draw them. */
5030 	memset((Uint8 *)VGAScreenSeg->pixels, 0, topBorder);
5031 	memset((Uint8 *)VGAScreenSeg->pixels + screenSize - bottomBorder, 0, bottomBorder);
5032 
5033 	/* Copy our test subject to one of the temporary buffers.  Blank the other */
5034 	memset(TempScreen1, 0, screenSize);
5035 	memcpy(TempScreen2, VGAScreenSeg->pixels, VGAScreenSeg->h * VGAScreenSeg->pitch);
5036 
5037 
5038 	service_SDL_events(true);
5039 	timer = 300; /* About 300 rounds is enough to make the screen mostly black */
5040 
5041 	do
5042 	{
5043 		setjasondelay(1);
5044 
5045 		/* This gets us our 'whoa' effect with pixel bleeding magic.
5046 		 * I'm willing to bet the guy who originally wrote the asm was goofing
5047 		 * around on acid and thought this looked good enough to use. */
5048 		for (i = screenSize - bottomBorder, j = topBorder / 2; i > 0; i--, j++)
5049 		{
5050 			offset = j + i/8192 - 4;
5051 			color = (TempScreen2[offset                    ] * 12 +
5052 			         TempScreen1[offset-VGAScreenSeg->pitch]      +
5053 			         TempScreen1[offset-1                  ]      +
5054 			         TempScreen1[offset+1                  ]      +
5055 			         TempScreen1[offset+VGAScreenSeg->pitch]) / 16;
5056 
5057 			TempScreen1[j] = color;
5058 		}
5059 
5060 		/* Now copy that mess to the buffer. */
5061 		memcpy((Uint8 *)VGAScreenSeg->pixels + topBorder, TempScreen1 + topBorder, screenSize - bottomBorder);
5062 
5063 		JE_showVGA();
5064 
5065 		timer--;
5066 		wait_delay();
5067 
5068 		/* Flip the buffer. */
5069 		TempScreenSwap = TempScreen1;
5070 		TempScreen1    = TempScreen2;
5071 		TempScreen2    = TempScreenSwap;
5072 
5073 	} while (!(timer == 0 || JE_anyButton()));
5074 
5075 	levelWarningLines = 4;
5076 }
5077 
JE_barX(JE_word x1,JE_word y1,JE_word x2,JE_word y2,JE_byte col)5078 void JE_barX( JE_word x1, JE_word y1, JE_word x2, JE_word y2, JE_byte col )
5079 {
5080 	fill_rectangle_xy(VGAScreen, x1, y1,     x2, y1,     col + 1);
5081 	fill_rectangle_xy(VGAScreen, x1, y1 + 1, x2, y2 - 1, col    );
5082 	fill_rectangle_xy(VGAScreen, x1, y2,     x2, y2,     col - 1);
5083 }
5084 
draw_boss_bar(void)5085 void draw_boss_bar( void )
5086 {
5087 	for (unsigned int b = 0; b < COUNTOF(boss_bar); b++)
5088 	{
5089 		if (boss_bar[b].link_num == 0)
5090 			continue;
5091 
5092 		unsigned int armor = 256;  // higher than armor max
5093 
5094 		for (unsigned int e = 0; e < COUNTOF(enemy); e++)  // find most damaged
5095 		{
5096 			if (enemyAvail[e] != 1 && enemy[e].linknum == boss_bar[b].link_num)
5097 				if (enemy[e].armorleft < armor)
5098 					armor = enemy[e].armorleft;
5099 		}
5100 
5101 		if (armor > 255 || armor == 0)  // boss dead?
5102 			boss_bar[b].link_num = 0;
5103 		else
5104 			boss_bar[b].armor = (armor == 255) ? 254 : armor;  // 255 would make the bar too long
5105 	}
5106 
5107 	unsigned int bars = (boss_bar[0].link_num != 0 ? 1 : 0)
5108 	                  + (boss_bar[1].link_num != 0 ? 1 : 0);
5109 
5110 	// if only one bar left, make it the first one
5111 	if (bars == 1 && boss_bar[0].link_num == 0)
5112 	{
5113 		memcpy(&boss_bar[0], &boss_bar[1], sizeof(boss_bar_t));
5114 		boss_bar[1].link_num = 0;
5115 	}
5116 
5117 	for (unsigned int b = 0; b < bars; b++)
5118 	{
5119 		unsigned int x = (bars == 2)
5120 		               ? ((b == 0) ? 125 : 185)
5121 		               : ((levelTimer) ? 250 : 155);  // level timer and boss bar would overlap
5122 
5123 		JE_barX(x - 25, 7, x + 25, 12, 115);
5124 		JE_barX(x - (boss_bar[b].armor / 10), 7, x + (boss_bar[b].armor + 5) / 10, 12, 118 + boss_bar[b].color);
5125 
5126 		if (boss_bar[b].color > 0)
5127 			boss_bar[b].color--;
5128 	}
5129 }
5130 
5131