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