5158 lines
121 KiB
C
5158 lines
121 KiB
C
/*
|
|
* OpenTyrian: A modern cross-platform port of Tyrian
|
|
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
#include "animlib.h"
|
|
#include "backgrnd.h"
|
|
#include "episodes.h"
|
|
#include "file.h"
|
|
#include "font.h"
|
|
#include "fonthand.h"
|
|
#include "game_menu.h"
|
|
#include "joystick.h"
|
|
#include "keyboard.h"
|
|
#include "lds_play.h"
|
|
#include "loudness.h"
|
|
#include "lvllib.h"
|
|
#include "menus.h"
|
|
#include "mainint.h"
|
|
#include "mouse.h"
|
|
#include "mtrand.h"
|
|
#include "network.h"
|
|
#include "nortsong.h"
|
|
#include "nortvars.h"
|
|
#include "opentyr.h"
|
|
#include "params.h"
|
|
#include "pcxload.h"
|
|
#include "pcxmast.h"
|
|
#include "picload.h"
|
|
#include "setup.h"
|
|
#include "shots.h"
|
|
#include "sprite.h"
|
|
#include "tyrian2.h"
|
|
#include "vga256d.h"
|
|
#include "video.h"
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
#include <android/log.h>
|
|
#include "SDL_screenkeyboard.h"
|
|
|
|
inline static void blit_enemy( SDL_Surface *surface, unsigned int i, signed int x_offset, signed int y_offset, signed int sprite_offset );
|
|
|
|
boss_bar_t boss_bar[2];
|
|
|
|
/* Level Event Data */
|
|
JE_boolean quit, loadLevelOk;
|
|
|
|
struct JE_EventRecType eventRec[EVENT_MAXIMUM]; /* [1..eventMaximum] */
|
|
JE_word levelEnemyMax;
|
|
JE_word levelEnemyFrequency;
|
|
JE_word levelEnemy[40]; /* [1..40] */
|
|
|
|
char tempStr[31];
|
|
|
|
/* Data used for ItemScreen procedure to indicate items available */
|
|
JE_byte itemAvail[9][10]; /* [1..9, 1..10] */
|
|
JE_byte itemAvailMax[9]; /* [1..9] */
|
|
|
|
void JE_starShowVGA( void )
|
|
{
|
|
JE_byte *src;
|
|
Uint8 *s = NULL; /* screen pointer, 8-bit specific */
|
|
|
|
int x, y, lightx, lighty, lightdist;
|
|
|
|
if (!playerEndLevel && !skipStarShowVGA)
|
|
{
|
|
|
|
s = VGAScreenSeg->pixels;
|
|
|
|
src = game_screen->pixels;
|
|
src += 24;
|
|
|
|
if (smoothScroll != 0 /*&& thisPlayerNum != 2*/)
|
|
{
|
|
wait_delay();
|
|
setjasondelay(frameCountMax);
|
|
}
|
|
|
|
if (starShowVGASpecialCode == 1)
|
|
{
|
|
src += game_screen->pitch * 183;
|
|
for (y = 0; y < 184; y++)
|
|
{
|
|
memmove(s, src, 264);
|
|
s += VGAScreenSeg->pitch;
|
|
src -= game_screen->pitch;
|
|
}
|
|
}
|
|
else if (starShowVGASpecialCode == 2 && processorType >= 2)
|
|
{
|
|
lighty = 172 - player[0].y;
|
|
lightx = 281 - player[0].x;
|
|
|
|
for (y = 184; y; y--)
|
|
{
|
|
if (lighty > y)
|
|
{
|
|
for (x = 320 - 56; x; x--)
|
|
{
|
|
*s = (*src & 0xf0) | ((*src >> 2) & 0x03);
|
|
s++;
|
|
src++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (x = 320 - 56; x; x--)
|
|
{
|
|
lightdist = abs(lightx - x) + lighty;
|
|
if (lightdist < y)
|
|
*s = *src;
|
|
else if (lightdist - y <= 5)
|
|
*s = (*src & 0xf0) | (((*src & 0x0f) + (3 * (5 - (lightdist - y)))) / 4);
|
|
else
|
|
*s = (*src & 0xf0) | ((*src & 0x0f) >> 2);
|
|
s++;
|
|
src++;
|
|
}
|
|
}
|
|
s += 56 + VGAScreenSeg->pitch - 320;
|
|
src += 56 + VGAScreenSeg->pitch - 320;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (y = 0; y < 184; y++)
|
|
{
|
|
memmove(s, src, 264);
|
|
s += VGAScreenSeg->pitch;
|
|
src += game_screen->pitch;
|
|
}
|
|
}
|
|
JE_showVGA();
|
|
}
|
|
|
|
quitRequested = false;
|
|
skipStarShowVGA = false;
|
|
}
|
|
|
|
inline static void blit_enemy( SDL_Surface *surface, unsigned int i, signed int x_offset, signed int y_offset, signed int sprite_offset )
|
|
{
|
|
if (enemy[i].sprite2s == NULL)
|
|
{
|
|
fprintf(stderr, "warning: enemy %d sprite missing\n", i);
|
|
return;
|
|
}
|
|
|
|
const int x = enemy[i].ex + x_offset + tempMapXOfs,
|
|
y = enemy[i].ey + y_offset;
|
|
const unsigned int index = enemy[i].egr[enemy[i].enemycycle - 1] + sprite_offset;
|
|
|
|
if (enemy[i].filter != 0)
|
|
blit_sprite2_filter(surface, x, y, *enemy[i].sprite2s, index, enemy[i].filter);
|
|
else
|
|
blit_sprite2(surface, x, y, *enemy[i].sprite2s, index);
|
|
}
|
|
|
|
void JE_drawEnemy( int enemyOffset ) // actually does a whole lot more than just drawing
|
|
{
|
|
player[0].x -= 25;
|
|
|
|
for (int i = enemyOffset - 25; i < enemyOffset; i++)
|
|
{
|
|
if (enemyAvail[i] != 1)
|
|
{
|
|
enemy[i].mapoffset = tempMapXOfs;
|
|
|
|
if (enemy[i].xaccel && enemy[i].xaccel - 89u > mt_rand() % 11)
|
|
{
|
|
if (player[0].x > enemy[i].ex)
|
|
{
|
|
if (enemy[i].exc < enemy[i].xaccel - 89)
|
|
enemy[i].exc++;
|
|
}
|
|
else
|
|
{
|
|
if (enemy[i].exc >= 0 || -enemy[i].exc < enemy[i].xaccel - 89)
|
|
enemy[i].exc--;
|
|
}
|
|
}
|
|
|
|
if (enemy[i].yaccel && enemy[i].yaccel - 89u > mt_rand() % 11)
|
|
{
|
|
if (player[0].y > enemy[i].ey)
|
|
{
|
|
if (enemy[i].eyc < enemy[i].yaccel - 89)
|
|
enemy[i].eyc++;
|
|
}
|
|
else
|
|
{
|
|
if (enemy[i].eyc >= 0 || -enemy[i].eyc < enemy[i].yaccel - 89)
|
|
enemy[i].eyc--;
|
|
}
|
|
}
|
|
|
|
if (enemy[i].ex + tempMapXOfs > -29 && enemy[i].ex + tempMapXOfs < 300)
|
|
{
|
|
if (enemy[i].aniactive == 1)
|
|
{
|
|
enemy[i].enemycycle++;
|
|
|
|
if (enemy[i].enemycycle == enemy[i].animax)
|
|
enemy[i].aniactive = enemy[i].aniwhenfire;
|
|
else if (enemy[i].enemycycle > enemy[i].ani)
|
|
enemy[i].enemycycle = enemy[i].animin;
|
|
}
|
|
|
|
if (enemy[i].egr[enemy[i].enemycycle - 1] == 999)
|
|
goto enemy_gone;
|
|
|
|
if (enemy[i].size == 1) // 2x2 enemy
|
|
{
|
|
if (enemy[i].ey > -13)
|
|
{
|
|
blit_enemy(VGAScreen, i, -6, -7, 0);
|
|
blit_enemy(VGAScreen, i, 6, -7, 1);
|
|
}
|
|
if (enemy[i].ey > -26 && enemy[i].ey < 182)
|
|
{
|
|
blit_enemy(VGAScreen, i, -6, 7, 19);
|
|
blit_enemy(VGAScreen, i, 6, 7, 20);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (enemy[i].ey > -13)
|
|
blit_enemy(VGAScreen, i, 0, 0, 0);
|
|
}
|
|
|
|
enemy[i].filter = 0;
|
|
}
|
|
|
|
if (enemy[i].excc)
|
|
{
|
|
if (--enemy[i].exccw <= 0)
|
|
{
|
|
if (enemy[i].exc == enemy[i].exrev)
|
|
{
|
|
enemy[i].excc = -enemy[i].excc;
|
|
enemy[i].exrev = -enemy[i].exrev;
|
|
enemy[i].exccadd = -enemy[i].exccadd;
|
|
}
|
|
else
|
|
{
|
|
enemy[i].exc += enemy[i].exccadd;
|
|
enemy[i].exccw = enemy[i].exccwmax;
|
|
if (enemy[i].exc == enemy[i].exrev)
|
|
{
|
|
enemy[i].excc = -enemy[i].excc;
|
|
enemy[i].exrev = -enemy[i].exrev;
|
|
enemy[i].exccadd = -enemy[i].exccadd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (enemy[i].eycc)
|
|
{
|
|
if (--enemy[i].eyccw <= 0)
|
|
{
|
|
if (enemy[i].eyc == enemy[i].eyrev)
|
|
{
|
|
enemy[i].eycc = -enemy[i].eycc;
|
|
enemy[i].eyrev = -enemy[i].eyrev;
|
|
enemy[i].eyccadd = -enemy[i].eyccadd;
|
|
}
|
|
else
|
|
{
|
|
enemy[i].eyc += enemy[i].eyccadd;
|
|
enemy[i].eyccw = enemy[i].eyccwmax;
|
|
if (enemy[i].eyc == enemy[i].eyrev)
|
|
{
|
|
enemy[i].eycc = -enemy[i].eycc;
|
|
enemy[i].eyrev = -enemy[i].eyrev;
|
|
enemy[i].eyccadd = -enemy[i].eyccadd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enemy[i].ey += enemy[i].fixedmovey;
|
|
|
|
enemy[i].ex += enemy[i].exc;
|
|
if (enemy[i].ex < -80 || enemy[i].ex > 340)
|
|
goto enemy_gone;
|
|
|
|
enemy[i].ey += enemy[i].eyc;
|
|
if (enemy[i].ey < -112 || enemy[i].ey > 190)
|
|
goto enemy_gone;
|
|
|
|
goto enemy_still_exists;
|
|
|
|
enemy_gone:
|
|
/* enemy[i].egr[10] &= 0x00ff; <MXD> madness? */
|
|
enemyAvail[i] = 1;
|
|
goto draw_enemy_end;
|
|
|
|
enemy_still_exists:
|
|
|
|
/*X bounce*/
|
|
if (enemy[i].ex <= enemy[i].xminbounce || enemy[i].ex >= enemy[i].xmaxbounce)
|
|
enemy[i].exc = -enemy[i].exc;
|
|
|
|
/*Y bounce*/
|
|
if (enemy[i].ey <= enemy[i].yminbounce || enemy[i].ey >= enemy[i].ymaxbounce)
|
|
enemy[i].eyc = -enemy[i].eyc;
|
|
|
|
/* Evalue != 0 - score item at boundary */
|
|
if (enemy[i].scoreitem)
|
|
{
|
|
if (enemy[i].ex < -5)
|
|
enemy[i].ex++;
|
|
if (enemy[i].ex > 245)
|
|
enemy[i].ex--;
|
|
}
|
|
|
|
enemy[i].ey += tempBackMove;
|
|
|
|
if (enemy[i].ex <= -24 || enemy[i].ex >= 296)
|
|
goto draw_enemy_end;
|
|
|
|
tempX = enemy[i].ex;
|
|
tempY = enemy[i].ey;
|
|
|
|
temp = enemy[i].enemytype;
|
|
|
|
/* Enemy Shots */
|
|
if (enemy[i].edamaged == 1)
|
|
goto draw_enemy_end;
|
|
|
|
enemyOnScreen++;
|
|
|
|
if (enemy[i].iced)
|
|
{
|
|
enemy[i].iced--;
|
|
if (enemy[i].enemyground != 0)
|
|
{
|
|
enemy[i].filter = 0x09;
|
|
}
|
|
goto draw_enemy_end;
|
|
}
|
|
|
|
for (int j = 3; j > 0; j--)
|
|
{
|
|
if (enemy[i].freq[j-1])
|
|
{
|
|
temp3 = enemy[i].tur[j-1];
|
|
|
|
if (--enemy[i].eshotwait[j-1] == 0 && temp3)
|
|
{
|
|
enemy[i].eshotwait[j-1] = enemy[i].freq[j-1];
|
|
if (difficultyLevel > 2)
|
|
{
|
|
enemy[i].eshotwait[j-1] = (enemy[i].eshotwait[j-1] / 2) + 1;
|
|
if (difficultyLevel > 7)
|
|
enemy[i].eshotwait[j-1] = (enemy[i].eshotwait[j-1] / 2) + 1;
|
|
}
|
|
|
|
if (galagaMode && (enemy[i].eyc == 0 || (mt_rand() % 400) >= galagaShotFreq))
|
|
goto draw_enemy_end;
|
|
|
|
switch (temp3)
|
|
{
|
|
case 252: /* Savara Boss DualMissile */
|
|
if (enemy[i].ey > 20)
|
|
{
|
|
JE_setupExplosion(tempX - 8 + tempMapXOfs, tempY - 20 - backMove * 8, -2, 6, false, false);
|
|
JE_setupExplosion(tempX + 4 + tempMapXOfs, tempY - 20 - backMove * 8, -2, 6, false, false);
|
|
}
|
|
break;
|
|
case 251:; /* Suck-O-Magnet */
|
|
const int attractivity = 4 - (abs(player[0].x - tempX) + abs(player[0].y - tempY)) / 100;
|
|
player[0].x_velocity += (player[0].x > tempX) ? -attractivity : attractivity;
|
|
break;
|
|
case 253: /* Left ShortRange Magnet */
|
|
if (abs(player[0].x + 25 - 14 - tempX) < 24 && abs(player[0].y - tempY) < 28)
|
|
{
|
|
player[0].x_velocity += 2;
|
|
}
|
|
if (twoPlayerMode &&
|
|
(abs(player[1].x - 14 - tempX) < 24 && abs(player[1].y - tempY) < 28))
|
|
{
|
|
player[1].x_velocity += 2;
|
|
}
|
|
break;
|
|
case 254: /* Left ShortRange Magnet */
|
|
if (abs(player[0].x + 25 - 14 - tempX) < 24 && abs(player[0].y - tempY) < 28)
|
|
{
|
|
player[0].x_velocity -= 2;
|
|
}
|
|
if (twoPlayerMode &&
|
|
(abs(player[1].x - 14 - tempX) < 24 && abs(player[1].y - tempY) < 28))
|
|
{
|
|
player[1].x_velocity -= 2;
|
|
}
|
|
break;
|
|
case 255: /* Magneto RePulse!! */
|
|
if (difficultyLevel != 1) /*DIF*/
|
|
{
|
|
if (j == 3)
|
|
{
|
|
enemy[i].filter = 0x70;
|
|
}
|
|
else
|
|
{
|
|
const int repulsivity = 4 - (abs(player[0].x - tempX) + abs(player[0].y - tempY)) / 20;
|
|
if (repulsivity > 0)
|
|
player[0].x_velocity += (player[0].x > tempX) ? repulsivity : -repulsivity;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
/*Rot*/
|
|
for (int tempCount = weapons[temp3].multi; tempCount > 0; tempCount--)
|
|
{
|
|
for (b = 0; b < ENEMY_SHOT_MAX; b++)
|
|
{
|
|
if (enemyShotAvail[b] == 1)
|
|
break;
|
|
}
|
|
if (b == ENEMY_SHOT_MAX)
|
|
goto draw_enemy_end;
|
|
|
|
enemyShotAvail[b] = !enemyShotAvail[b];
|
|
|
|
if (weapons[temp3].sound > 0)
|
|
{
|
|
do
|
|
temp = mt_rand() % 8;
|
|
while (temp == 3);
|
|
soundQueue[temp] = weapons[temp3].sound;
|
|
}
|
|
|
|
if (enemy[i].aniactive == 2)
|
|
enemy[i].aniactive = 1;
|
|
|
|
if (++enemy[i].eshotmultipos[j-1] > weapons[temp3].max)
|
|
enemy[i].eshotmultipos[j-1] = 1;
|
|
|
|
int tempPos = enemy[i].eshotmultipos[j-1] - 1;
|
|
|
|
if (j == 1)
|
|
temp2 = 4;
|
|
|
|
enemyShot[b].sx = tempX + weapons[temp3].bx[tempPos] + tempMapXOfs;
|
|
enemyShot[b].sy = tempY + weapons[temp3].by[tempPos];
|
|
enemyShot[b].sdmg = weapons[temp3].attack[tempPos];
|
|
enemyShot[b].tx = weapons[temp3].tx;
|
|
enemyShot[b].ty = weapons[temp3].ty;
|
|
enemyShot[b].duration = weapons[temp3].del[tempPos];
|
|
enemyShot[b].animate = 0;
|
|
enemyShot[b].animax = weapons[temp3].weapani;
|
|
|
|
enemyShot[b].sgr = weapons[temp3].sg[tempPos];
|
|
switch (j)
|
|
{
|
|
case 1:
|
|
enemyShot[b].syc = weapons[temp3].acceleration;
|
|
enemyShot[b].sxc = weapons[temp3].accelerationx;
|
|
|
|
enemyShot[b].sxm = weapons[temp3].sx[tempPos];
|
|
enemyShot[b].sym = weapons[temp3].sy[tempPos];
|
|
break;
|
|
case 3:
|
|
enemyShot[b].sxc = -weapons[temp3].acceleration;
|
|
enemyShot[b].syc = weapons[temp3].accelerationx;
|
|
|
|
enemyShot[b].sxm = -weapons[temp3].sy[tempPos];
|
|
enemyShot[b].sym = -weapons[temp3].sx[tempPos];
|
|
break;
|
|
case 2:
|
|
enemyShot[b].sxc = weapons[temp3].acceleration;
|
|
enemyShot[b].syc = -weapons[temp3].acceleration;
|
|
|
|
enemyShot[b].sxm = weapons[temp3].sy[tempPos];
|
|
enemyShot[b].sym = -weapons[temp3].sx[tempPos];
|
|
break;
|
|
}
|
|
|
|
if (weapons[temp3].aim > 0)
|
|
{
|
|
int aim = weapons[temp3].aim;
|
|
|
|
/*DIF*/
|
|
if (difficultyLevel > 2)
|
|
{
|
|
aim += difficultyLevel - 2;
|
|
}
|
|
|
|
JE_word target_x = player[0].x;
|
|
JE_word target_y = player[0].y;
|
|
|
|
if (twoPlayerMode)
|
|
{
|
|
// fire at live player(s)
|
|
if (player[0].is_alive && !player[1].is_alive)
|
|
temp = 0;
|
|
else if (player[1].is_alive && !player[0].is_alive)
|
|
temp = 1;
|
|
else
|
|
temp = mt_rand() % 2;
|
|
|
|
if (temp == 1)
|
|
{
|
|
target_x = player[1].x - 25;
|
|
target_y = player[1].y;
|
|
}
|
|
}
|
|
|
|
int relative_x = (target_x + 25) - tempX - tempMapXOfs - 4;
|
|
if (relative_x == 0)
|
|
relative_x = 1;
|
|
int relative_y = target_y - tempY;
|
|
if (relative_y == 0)
|
|
relative_y = 1;
|
|
const int longest_side = MAX(abs(relative_x), abs(relative_y));
|
|
enemyShot[b].sxm = roundf((float)relative_x / longest_side * aim);
|
|
enemyShot[b].sym = roundf((float)relative_y / longest_side * aim);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Enemy Launch Routine */
|
|
if (enemy[i].launchfreq)
|
|
{
|
|
if (--enemy[i].launchwait == 0)
|
|
{
|
|
enemy[i].launchwait = enemy[i].launchfreq;
|
|
|
|
if (enemy[i].launchspecial != 0)
|
|
{
|
|
/*Type 1 : Must be inline with player*/
|
|
if (abs(enemy[i].ey - player[0].y) > 5)
|
|
goto draw_enemy_end;
|
|
}
|
|
|
|
if (enemy[i].aniactive == 2)
|
|
{
|
|
enemy[i].aniactive = 1;
|
|
}
|
|
|
|
if (enemy[i].launchtype == 0)
|
|
goto draw_enemy_end;
|
|
|
|
tempW = enemy[i].launchtype;
|
|
b = JE_newEnemy(enemyOffset == 50 ? 75 : enemyOffset - 25, tempW, 0);
|
|
|
|
/*Launch Enemy Placement*/
|
|
if (b > 0)
|
|
{
|
|
struct JE_SingleEnemyType* e = &enemy[b-1];
|
|
|
|
e->ex = tempX;
|
|
e->ey = tempY + enemyDat[e->enemytype].startyc;
|
|
if (e->size == 0)
|
|
e->ey -= 7;
|
|
|
|
if (e->launchtype > 0 && e->launchfreq == 0)
|
|
{
|
|
if (e->launchtype > 90)
|
|
{
|
|
e->ex += mt_rand() % ((e->launchtype - 90) * 4) - (e->launchtype - 90) * 2;
|
|
}
|
|
else
|
|
{
|
|
int target_x = (player[0].x + 25) - tempX - tempMapXOfs - 4;
|
|
if (target_x == 0)
|
|
target_x = 1;
|
|
int tempI5 = player[0].y - tempY;
|
|
if (tempI5 == 0)
|
|
tempI5 = 1;
|
|
const int longest_side = MAX(abs(target_x), abs(tempI5));
|
|
e->exc = roundf(((float)target_x / longest_side) * e->launchtype);
|
|
e->eyc = roundf(((float)tempI5 / longest_side) * e->launchtype);
|
|
}
|
|
}
|
|
|
|
do
|
|
temp = mt_rand() % 8;
|
|
while (temp == 3);
|
|
soundQueue[temp] = randomEnemyLaunchSounds[(mt_rand() % 3)];
|
|
|
|
if (enemy[i].launchspecial == 1
|
|
&& enemy[i].linknum < 100)
|
|
{
|
|
e->linknum = enemy[i].linknum;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
draw_enemy_end:
|
|
;
|
|
}
|
|
|
|
player[0].x += 25;
|
|
}
|
|
|
|
void JE_main( void )
|
|
{
|
|
char buffer[256];
|
|
|
|
int lastEnemyOnScreen;
|
|
|
|
/* NOTE: BEGIN MAIN PROGRAM HERE AFTER LOADING A GAME OR STARTING A NEW ONE */
|
|
|
|
/* ----------- GAME ROUTINES ------------------------------------- */
|
|
/* We need to jump to the beginning to make space for the routines */
|
|
/* --------------------------------------------------------------- */
|
|
goto start_level_first;
|
|
|
|
|
|
/*------------------------------GAME LOOP-----------------------------------*/
|
|
|
|
|
|
/* Startlevel is called after a previous level is over. If the first level
|
|
is started for a gaming session, startlevelfirst is called instead and
|
|
this code is skipped. The code here finishes the level and prepares for
|
|
the loadmap function. */
|
|
|
|
start_level:
|
|
|
|
if (galagaMode)
|
|
twoPlayerMode = false;
|
|
|
|
JE_clearKeyboard();
|
|
|
|
free_sprite2s(&eShapes[0]);
|
|
free_sprite2s(&eShapes[1]);
|
|
free_sprite2s(&eShapes[2]);
|
|
free_sprite2s(&eShapes[3]);
|
|
|
|
/* Normal speed */
|
|
if (fastPlay != 0)
|
|
{
|
|
smoothScroll = true;
|
|
speed = 0x4300;
|
|
JE_resetTimerInt();
|
|
JE_setTimerInt();
|
|
}
|
|
|
|
if (play_demo || record_demo)
|
|
{
|
|
if (demo_file)
|
|
{
|
|
fclose(demo_file);
|
|
demo_file = NULL;
|
|
}
|
|
|
|
if (play_demo)
|
|
{
|
|
stop_song();
|
|
fade_black(10);
|
|
|
|
wait_noinput(true, true, true);
|
|
}
|
|
}
|
|
|
|
difficultyLevel = oldDifficultyLevel; /*Return difficulty to normal*/
|
|
|
|
if (!play_demo)
|
|
{
|
|
if ((!all_players_dead() || normalBonusLevelCurrent || bonusLevelCurrent) && !playerEndLevel)
|
|
{
|
|
mainLevel = nextLevel;
|
|
JE_endLevelAni();
|
|
|
|
fade_song();
|
|
}
|
|
else
|
|
{
|
|
fade_song();
|
|
fade_black(10);
|
|
|
|
JE_loadGame(twoPlayerMode ? 22 : 11);
|
|
if (doNotSaveBackup)
|
|
{
|
|
superTyrian = false;
|
|
onePlayerAction = false;
|
|
player[0].items.super_arcade_mode = SA_NONE;
|
|
}
|
|
if (bonusLevelCurrent && !playerEndLevel)
|
|
{
|
|
mainLevel = nextLevel;
|
|
}
|
|
}
|
|
}
|
|
doNotSaveBackup = false;
|
|
|
|
if (play_demo)
|
|
return;
|
|
|
|
start_level_first:
|
|
|
|
set_volume(tyrMusicVolume, fxVolume);
|
|
|
|
endLevel = false;
|
|
reallyEndLevel = false;
|
|
playerEndLevel = false;
|
|
extraGame = false;
|
|
|
|
doNotSaveBackup = false;
|
|
|
|
android_cleanup_screen_keys();
|
|
|
|
JE_loadMap();
|
|
|
|
if (mainLevel == 0) // if quit itemscreen
|
|
return; // back to titlescreen
|
|
|
|
android_setup_screen_keys();
|
|
|
|
android_show_tutorial();
|
|
|
|
fade_song();
|
|
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
player[i].is_alive = true;
|
|
|
|
oldDifficultyLevel = difficultyLevel;
|
|
if (episodeNum == EPISODE_AVAILABLE)
|
|
difficultyLevel--;
|
|
if (difficultyLevel < 1)
|
|
difficultyLevel = 1;
|
|
|
|
player[0].x = 100;
|
|
player[0].y = 180;
|
|
|
|
player[1].x = 190;
|
|
player[1].y = 180;
|
|
|
|
assert(COUNTOF(player->old_x) == COUNTOF(player->old_y));
|
|
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
{
|
|
for (uint j = 0; j < COUNTOF(player->old_x); ++j)
|
|
{
|
|
player[i].old_x[j] = player[i].x - (19 - j);
|
|
player[i].old_y[j] = player[i].y - 18;
|
|
}
|
|
|
|
player[i].last_x_shot_move = player[i].x;
|
|
player[i].last_y_shot_move = player[i].y;
|
|
}
|
|
|
|
JE_loadPic(VGAScreen, twoPlayerMode ? 6 : 3, false);
|
|
|
|
JE_drawOptions();
|
|
|
|
JE_outText(VGAScreen, 268, twoPlayerMode ? 76 : 118, levelName, 12, 4);
|
|
|
|
JE_showVGA();
|
|
JE_gammaCorrect(&colors, gammaCorrection);
|
|
fade_palette(colors, 50, 0, 255);
|
|
|
|
free_sprite2s(&shapes6);
|
|
JE_loadCompShapes(&shapes6, '6'); // explosion sprites
|
|
|
|
/* MAPX will already be set correctly */
|
|
mapY = 300 - 8;
|
|
mapY2 = 600 - 8;
|
|
mapY3 = 600 - 8;
|
|
mapYPos = &megaData1.mainmap[mapY][0] - 1;
|
|
mapY2Pos = &megaData2.mainmap[mapY2][0] - 1;
|
|
mapY3Pos = &megaData3.mainmap[mapY3][0] - 1;
|
|
mapXPos = 0;
|
|
mapXOfs = 0;
|
|
mapX2Pos = 0;
|
|
mapX3Pos = 0;
|
|
mapX3Ofs = 0;
|
|
mapXbpPos = 0;
|
|
mapX2bpPos = 0;
|
|
mapX3bpPos = 0;
|
|
|
|
map1YDelay = 1;
|
|
map1YDelayMax = 1;
|
|
map2YDelay = 1;
|
|
map2YDelayMax = 1;
|
|
|
|
musicFade = false;
|
|
|
|
backPos = 0;
|
|
backPos2 = 0;
|
|
backPos3 = 0;
|
|
power = 0;
|
|
starfield_speed = 1;
|
|
|
|
/* Setup player ship graphics */
|
|
JE_getShipInfo();
|
|
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
{
|
|
player[i].x_velocity = 0;
|
|
player[i].y_velocity = 0;
|
|
|
|
player[i].invulnerable_ticks = 100;
|
|
}
|
|
|
|
newkey = newmouse = false;
|
|
|
|
/* Initialize Level Data and Debug Mode */
|
|
levelEnd = 255;
|
|
levelEndWarp = -4;
|
|
levelEndFxWait = 0;
|
|
warningCol = 120;
|
|
warningColChange = 1;
|
|
warningSoundDelay = 0;
|
|
armorShipDelay = 50;
|
|
|
|
bonusLevel = false;
|
|
readyToEndLevel = false;
|
|
firstGameOver = true;
|
|
eventLoc = 1;
|
|
curLoc = 0;
|
|
backMove = 1;
|
|
backMove2 = 2;
|
|
backMove3 = 3;
|
|
explodeMove = 2;
|
|
enemiesActive = true;
|
|
for(temp = 0; temp < 3; temp++)
|
|
{
|
|
button[temp] = false;
|
|
}
|
|
stopBackgrounds = false;
|
|
stopBackgroundNum = 0;
|
|
background3x1 = false;
|
|
background3x1b = false;
|
|
background3over = 0;
|
|
background2over = 1;
|
|
topEnemyOver = false;
|
|
skyEnemyOverAll = false;
|
|
smallEnemyAdjust = false;
|
|
starActive = true;
|
|
enemyContinualDamage = false;
|
|
levelEnemyFrequency = 96;
|
|
quitRequested = false;
|
|
|
|
for (unsigned int i = 0; i < COUNTOF(boss_bar); i++)
|
|
boss_bar[i].link_num = 0;
|
|
|
|
forceEvents = false; /*Force events to continue if background movement = 0*/
|
|
|
|
superEnemy254Jump = 0; /*When Enemy with PL 254 dies*/
|
|
|
|
/* Filter Status */
|
|
filterActive = true;
|
|
filterFade = true;
|
|
filterFadeStart = false;
|
|
levelFilter = -99;
|
|
levelBrightness = -14;
|
|
levelBrightnessChg = 1;
|
|
|
|
background2notTransparent = false;
|
|
|
|
uint old_weapon_bar[2] = { 0, 0 }; // only redrawn when they change
|
|
|
|
/* Initially erase power bars */
|
|
lastPower = power / 10;
|
|
|
|
/* Initial Text */
|
|
JE_drawTextWindow(miscText[20]);
|
|
|
|
/* Setup Armor/Shield Data */
|
|
shieldWait = 1;
|
|
shieldT = shields[player[0].items.shield].tpwr * 20;
|
|
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
{
|
|
player[i].shield = shields[player[i].items.shield].mpwr;
|
|
player[i].shield_max = player[i].shield * 2;
|
|
}
|
|
|
|
JE_drawShield();
|
|
JE_drawArmor();
|
|
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
player[i].superbombs = 0;
|
|
|
|
/* Set cubes to 0 */
|
|
cubeMax = 0;
|
|
|
|
/* Secret Level Display */
|
|
flash = 0;
|
|
flashChange = 1;
|
|
displayTime = 0;
|
|
|
|
play_song(levelSong - 1);
|
|
|
|
JE_drawPortConfigButtons();
|
|
|
|
/* --- MAIN LOOP --- */
|
|
|
|
newkey = false;
|
|
|
|
#ifdef WITH_NETWORK
|
|
if (isNetworkGame)
|
|
{
|
|
JE_clearSpecialRequests();
|
|
mt_srand(32402394);
|
|
}
|
|
#endif
|
|
|
|
initialize_starfield();
|
|
|
|
JE_setNewGameSpeed();
|
|
|
|
/* JE_setVol(tyrMusicVolume, fxPlayVol >> 2); NOTE: MXD killed this because it was broken */
|
|
|
|
/*Save backup game*/
|
|
if (!play_demo && !doNotSaveBackup)
|
|
{
|
|
temp = twoPlayerMode ? 22 : 11;
|
|
JE_saveGame(temp, "LAST LEVEL ");
|
|
}
|
|
|
|
if (!play_demo && record_demo)
|
|
{
|
|
Uint8 new_demo_num = 0;
|
|
|
|
do
|
|
{
|
|
sprintf(tempStr, "demorec.%d", new_demo_num++);
|
|
}
|
|
while (dir_file_exists(get_user_directory(), tempStr)); // until file doesn't exist
|
|
|
|
demo_file = dir_fopen_warn(get_user_directory(), tempStr, "wb");
|
|
if (!demo_file)
|
|
exit(1);
|
|
|
|
efwrite(&episodeNum, 1, 1, demo_file);
|
|
efwrite(levelName, 1, 10, demo_file);
|
|
efwrite(&lvlFileNum, 1, 1, demo_file);
|
|
|
|
fputc(player[0].items.weapon[FRONT_WEAPON].id, demo_file);
|
|
fputc(player[0].items.weapon[REAR_WEAPON].id, demo_file);
|
|
fputc(player[0].items.super_arcade_mode, demo_file);
|
|
fputc(player[0].items.sidekick[LEFT_SIDEKICK], demo_file);
|
|
fputc(player[0].items.sidekick[RIGHT_SIDEKICK], demo_file);
|
|
fputc(player[0].items.generator, demo_file);
|
|
|
|
fputc(player[0].items.sidekick_level, demo_file);
|
|
fputc(player[0].items.sidekick_series, demo_file);
|
|
|
|
fputc(initial_episode_num, demo_file);
|
|
|
|
fputc(player[0].items.shield, demo_file);
|
|
fputc(player[0].items.special, demo_file);
|
|
fputc(player[0].items.ship, demo_file);
|
|
|
|
for (uint i = 0; i < 2; ++i)
|
|
fputc(player[0].items.weapon[i].power, demo_file);
|
|
|
|
for (uint i = 0; i < 3; ++i)
|
|
fputc(0, demo_file);
|
|
|
|
efwrite(&levelSong, 1, 1, demo_file);
|
|
|
|
demo_keys = 0;
|
|
demo_keys_wait = 0;
|
|
}
|
|
|
|
twoPlayerLinked = false;
|
|
linkGunDirec = M_PI;
|
|
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
calc_purple_balls_needed(&player[i]);
|
|
|
|
damageRate = 2; /*Normal Rate for Collision Damage*/
|
|
|
|
chargeWait = 5;
|
|
chargeLevel = 0;
|
|
chargeMax = 5;
|
|
chargeGr = 0;
|
|
chargeGrWait = 3;
|
|
|
|
portConfigChange = false;
|
|
|
|
/*Destruction Ratio*/
|
|
totalEnemy = 0;
|
|
enemyKilled = 0;
|
|
|
|
astralDuration = 0;
|
|
|
|
superArcadePowerUp = 1;
|
|
|
|
yourInGameMenuRequest = false;
|
|
|
|
constantLastX = -1;
|
|
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
player[i].exploding_ticks = 0;
|
|
|
|
if (isNetworkGame)
|
|
{
|
|
JE_loadItemDat();
|
|
}
|
|
|
|
memset(enemyAvail, 1, sizeof(enemyAvail));
|
|
for (uint i = 0; i < COUNTOF(enemyShotAvail); i++)
|
|
enemyShotAvail[i] = 1;
|
|
|
|
/*Initialize Shots*/
|
|
memset(playerShotData, 0, sizeof(playerShotData));
|
|
memset(shotAvail, 0, sizeof(shotAvail));
|
|
memset(shotMultiPos, 0, sizeof(shotMultiPos));
|
|
memset(shotRepeat, 1, sizeof(shotRepeat));
|
|
|
|
memset(button, 0, sizeof(button));
|
|
|
|
memset(globalFlags, 0, sizeof(globalFlags));
|
|
|
|
memset(explosions, 0, sizeof(explosions));
|
|
memset(rep_explosions, 0, sizeof(rep_explosions));
|
|
|
|
/* --- Clear Sound Queue --- */
|
|
memset(soundQueue, 0, sizeof(soundQueue));
|
|
soundQueue[3] = V_GOOD_LUCK;
|
|
|
|
memset(enemyShapeTables, 0, sizeof(enemyShapeTables));
|
|
memset(enemy, 0, sizeof(enemy));
|
|
|
|
memset(SFCurrentCode, 0, sizeof(SFCurrentCode));
|
|
memset(SFExecuted, 0, sizeof(SFExecuted));
|
|
|
|
zinglonDuration = 0;
|
|
specialWait = 0;
|
|
nextSpecialWait = 0;
|
|
optionAttachmentMove = 0; /*Launch the Attachments!*/
|
|
optionAttachmentLinked = true;
|
|
|
|
editShip1 = false;
|
|
editShip2 = false;
|
|
|
|
memset(smoothies, 0, sizeof(smoothies));
|
|
|
|
levelTimer = false;
|
|
randomExplosions = false;
|
|
|
|
last_superpixel = 0;
|
|
memset(superpixels, 0, sizeof(superpixels));
|
|
|
|
returnActive = false;
|
|
|
|
galagaShotFreq = 0;
|
|
|
|
if (galagaMode)
|
|
{
|
|
difficultyLevel = 2;
|
|
}
|
|
galagaLife = 10000;
|
|
|
|
JE_drawOptionLevel();
|
|
|
|
// keeps map from scrolling past the top
|
|
BKwrap1 = BKwrap1to = &megaData1.mainmap[1][0];
|
|
BKwrap2 = BKwrap2to = &megaData2.mainmap[1][0];
|
|
BKwrap3 = BKwrap3to = &megaData3.mainmap[1][0];
|
|
|
|
level_loop:
|
|
|
|
//tempScreenSeg = game_screen; /* side-effect of game_screen */
|
|
|
|
if (isNetworkGame)
|
|
{
|
|
smoothies[9-1] = false;
|
|
smoothies[6-1] = false;
|
|
} else {
|
|
starShowVGASpecialCode = smoothies[9-1] + (smoothies[6-1] << 1);
|
|
}
|
|
|
|
/*Background Wrapping*/
|
|
if (mapYPos <= BKwrap1)
|
|
{
|
|
mapYPos = BKwrap1to;
|
|
}
|
|
if (mapY2Pos <= BKwrap2)
|
|
{
|
|
mapY2Pos = BKwrap2to;
|
|
}
|
|
if (mapY3Pos <= BKwrap3)
|
|
{
|
|
mapY3Pos = BKwrap3to;
|
|
}
|
|
|
|
|
|
allPlayersGone = all_players_dead() &&
|
|
((*player[0].lives == 1 && player[0].exploding_ticks == 0) || (!onePlayerAction && !twoPlayerMode)) &&
|
|
((*player[1].lives == 1 && player[1].exploding_ticks == 0) || !twoPlayerMode);
|
|
|
|
|
|
/*-----MUSIC FADE------*/
|
|
if (musicFade)
|
|
{
|
|
if (tempVolume > 10)
|
|
{
|
|
tempVolume--;
|
|
set_volume(tempVolume, fxVolume);
|
|
}
|
|
else
|
|
{
|
|
musicFade = false;
|
|
}
|
|
}
|
|
|
|
if (!allPlayersGone && levelEnd > 0 && endLevel)
|
|
{
|
|
play_song(9);
|
|
musicFade = false;
|
|
}
|
|
else if (!playing && firstGameOver)
|
|
{
|
|
play_song(levelSong - 1);
|
|
}
|
|
|
|
|
|
if (!endLevel) // draw HUD
|
|
{
|
|
VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
|
|
|
|
/*-----------------------Message Bar------------------------*/
|
|
if (textErase > 0 && --textErase == 0)
|
|
blit_sprite(VGAScreenSeg, 16, 189, OPTION_SHAPES, 36); // in-game message area
|
|
|
|
/*------------------------Shield Gen-------------------------*/
|
|
if (galagaMode)
|
|
{
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
player[i].shield = 0;
|
|
|
|
// spawned dragonwing died :(
|
|
if (*player[1].lives == 0 || player[1].armor == 0)
|
|
twoPlayerMode = false;
|
|
|
|
if (player[0].cash >= (unsigned)galagaLife)
|
|
{
|
|
soundQueue[6] = S_EXPLOSION_11;
|
|
soundQueue[7] = S_SOUL_OF_ZINGLON;
|
|
|
|
if (*player[0].lives < 11)
|
|
++(*player[0].lives);
|
|
else
|
|
player[0].cash += 1000;
|
|
|
|
if (galagaLife == 10000)
|
|
galagaLife = 20000;
|
|
else
|
|
galagaLife += 25000;
|
|
}
|
|
}
|
|
else // not galagaMode
|
|
{
|
|
if (twoPlayerMode)
|
|
{
|
|
if (--shieldWait == 0)
|
|
{
|
|
shieldWait = 15;
|
|
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
{
|
|
if (player[i].shield < player[i].shield_max && player[i].is_alive)
|
|
++player[i].shield;
|
|
}
|
|
|
|
JE_drawShield();
|
|
}
|
|
}
|
|
else if (player[0].is_alive && player[0].shield < player[0].shield_max && power > shieldT)
|
|
{
|
|
if (--shieldWait == 0)
|
|
{
|
|
shieldWait = 15;
|
|
|
|
power -= shieldT;
|
|
|
|
++player[0].shield;
|
|
if (player[1].shield < player[0].shield_max)
|
|
++player[1].shield;
|
|
|
|
JE_drawShield();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---------------------Weapon Display-------------------------*/
|
|
for (uint i = 0; i < 2; ++i)
|
|
{
|
|
uint item_power = player[twoPlayerMode ? i : 0].items.weapon[i].power;
|
|
|
|
if (old_weapon_bar[i] != item_power)
|
|
{
|
|
old_weapon_bar[i] = item_power;
|
|
|
|
int x = twoPlayerMode ? 286 : 289,
|
|
y = (i == 0) ? (twoPlayerMode ? 6 : 17) : (twoPlayerMode ? 100 : 38);
|
|
|
|
fill_rectangle_xy(VGAScreenSeg, x, y, x + 1 + 10 * 2, y + 2, 0);
|
|
|
|
for (uint j = 1; j <= item_power; ++j)
|
|
{
|
|
JE_rectangle(VGAScreen, x, y, x + 1, y + 2, 115 + j); /* SEGa000 */
|
|
x += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*------------------------Power Bar-------------------------*/
|
|
if (twoPlayerMode || onePlayerAction)
|
|
{
|
|
power = 900;
|
|
}
|
|
else
|
|
{
|
|
power += powerAdd;
|
|
if (power > 900)
|
|
power = 900;
|
|
|
|
temp = power / 10;
|
|
|
|
if (temp != lastPower)
|
|
{
|
|
if (temp > lastPower)
|
|
fill_rectangle_xy(VGAScreenSeg, 269, 113 - 11 - temp, 276, 114 - 11 - lastPower, 113 + temp / 7);
|
|
else
|
|
fill_rectangle_xy(VGAScreenSeg, 269, 113 - 11 - lastPower, 276, 114 - 11 - temp, 0);
|
|
|
|
lastPower = temp;
|
|
}
|
|
}
|
|
|
|
oldMapX3Ofs = mapX3Ofs;
|
|
|
|
enemyOnScreen = 0;
|
|
}
|
|
|
|
/* use game_screen for all the generic drawing functions */
|
|
VGAScreen = game_screen;
|
|
|
|
/*---------------------------EVENTS-------------------------*/
|
|
while (eventRec[eventLoc-1].eventtime <= curLoc && eventLoc <= maxEvent)
|
|
JE_eventSystem();
|
|
|
|
if (isNetworkGame && reallyEndLevel)
|
|
goto start_level;
|
|
|
|
|
|
/* SMOOTHIES! */
|
|
JE_checkSmoothies();
|
|
if (anySmoothies)
|
|
VGAScreen = VGAScreen2; // this makes things complicated, but we do it anyway :(
|
|
|
|
/* --- BACKGROUNDS --- */
|
|
/* --- BACKGROUND 1 --- */
|
|
|
|
if (forceEvents && !backMove)
|
|
curLoc++;
|
|
|
|
if (map1YDelayMax > 1 && backMove < 2)
|
|
backMove = (map1YDelay == 1) ? 1 : 0;
|
|
|
|
/*Draw background*/
|
|
if (astralDuration == 0)
|
|
draw_background_1(VGAScreen);
|
|
else
|
|
JE_clr256(VGAScreen);
|
|
|
|
/*Set Movement of background 1*/
|
|
if (--map1YDelay == 0)
|
|
{
|
|
map1YDelay = map1YDelayMax;
|
|
|
|
curLoc += backMove;
|
|
|
|
backPos += backMove;
|
|
|
|
if (backPos > 27)
|
|
{
|
|
backPos -= 28;
|
|
mapY--;
|
|
mapYPos -= 14; /*Map Width*/
|
|
}
|
|
}
|
|
|
|
if (starActive || astralDuration > 0)
|
|
{
|
|
update_and_draw_starfield(VGAScreen, starfield_speed);
|
|
}
|
|
|
|
if (processorType > 1 && smoothies[5-1])
|
|
{
|
|
iced_blur_filter(game_screen, VGAScreen);
|
|
VGAScreen = game_screen;
|
|
}
|
|
|
|
/*-----------------------BACKGROUNDS------------------------*/
|
|
/*-----------------------BACKGROUND 2------------------------*/
|
|
if (background2over == 3)
|
|
{
|
|
draw_background_2(VGAScreen);
|
|
background2 = true;
|
|
}
|
|
|
|
if (background2over == 0)
|
|
{
|
|
if (!(smoothies[2-1] && processorType < 4) && !(smoothies[1-1] && processorType == 3))
|
|
{
|
|
if (wild && !background2notTransparent)
|
|
draw_background_2_blend(VGAScreen);
|
|
else
|
|
draw_background_2(VGAScreen);
|
|
}
|
|
}
|
|
|
|
if (smoothies[0] && processorType > 2 && smoothie_data[0] == 0)
|
|
{
|
|
lava_filter(game_screen, VGAScreen);
|
|
VGAScreen = game_screen;
|
|
}
|
|
if (smoothies[2-1] && processorType > 2)
|
|
{
|
|
water_filter(game_screen, VGAScreen);
|
|
VGAScreen = game_screen;
|
|
}
|
|
|
|
/*-----------------------Ground Enemy------------------------*/
|
|
lastEnemyOnScreen = enemyOnScreen;
|
|
|
|
tempMapXOfs = mapXOfs;
|
|
tempBackMove = backMove;
|
|
JE_drawEnemy(50);
|
|
JE_drawEnemy(100);
|
|
|
|
if (enemyOnScreen == 0 || enemyOnScreen == lastEnemyOnScreen)
|
|
{
|
|
if (stopBackgroundNum == 1)
|
|
stopBackgroundNum = 9;
|
|
}
|
|
|
|
if (smoothies[0] && processorType > 2 && smoothie_data[0] > 0)
|
|
{
|
|
lava_filter(game_screen, VGAScreen);
|
|
VGAScreen = game_screen;
|
|
}
|
|
|
|
if (superWild)
|
|
{
|
|
neat += 3;
|
|
JE_darkenBackground(neat);
|
|
}
|
|
|
|
/*-----------------------BACKGROUNDS------------------------*/
|
|
/*-----------------------BACKGROUND 2------------------------*/
|
|
if (!(smoothies[2-1] && processorType < 4) &&
|
|
!(smoothies[1-1] && processorType == 3))
|
|
{
|
|
if (background2over == 1)
|
|
{
|
|
if (wild && !background2notTransparent)
|
|
draw_background_2_blend(VGAScreen);
|
|
else
|
|
draw_background_2(VGAScreen);
|
|
}
|
|
}
|
|
|
|
if (superWild)
|
|
{
|
|
neat++;
|
|
JE_darkenBackground(neat);
|
|
}
|
|
|
|
if (background3over == 2)
|
|
draw_background_3(VGAScreen);
|
|
|
|
/* New Enemy */
|
|
if (enemiesActive && mt_rand() % 100 > levelEnemyFrequency)
|
|
{
|
|
tempW = levelEnemy[mt_rand() % levelEnemyMax];
|
|
if (tempW == 2)
|
|
soundQueue[3] = S_WEAPON_7;
|
|
b = JE_newEnemy(0, tempW, 0);
|
|
}
|
|
|
|
if (processorType > 1 && smoothies[3-1])
|
|
{
|
|
iced_blur_filter(game_screen, VGAScreen);
|
|
VGAScreen = game_screen;
|
|
}
|
|
if (processorType > 1 && smoothies[4-1])
|
|
{
|
|
blur_filter(game_screen, VGAScreen);
|
|
VGAScreen = game_screen;
|
|
}
|
|
|
|
/* Draw Sky Enemy */
|
|
if (!skyEnemyOverAll)
|
|
{
|
|
lastEnemyOnScreen = enemyOnScreen;
|
|
|
|
tempMapXOfs = mapX2Ofs;
|
|
tempBackMove = 0;
|
|
JE_drawEnemy(25);
|
|
|
|
if (enemyOnScreen == lastEnemyOnScreen)
|
|
{
|
|
if (stopBackgroundNum == 2)
|
|
stopBackgroundNum = 9;
|
|
}
|
|
}
|
|
|
|
if (background3over == 0)
|
|
draw_background_3(VGAScreen);
|
|
|
|
/* Draw Top Enemy */
|
|
if (!topEnemyOver)
|
|
{
|
|
tempMapXOfs = (background3x1 == 0) ? oldMapX3Ofs : mapXOfs;
|
|
tempBackMove = backMove3;
|
|
JE_drawEnemy(75);
|
|
}
|
|
|
|
/* Player Shot Images */
|
|
for (int z = 0; z < MAX_PWEAPON; z++)
|
|
{
|
|
if (shotAvail[z] != 0)
|
|
{
|
|
bool is_special = false;
|
|
int tempShotX = 0, tempShotY = 0;
|
|
JE_byte chain;
|
|
JE_byte playerNum;
|
|
JE_word tempX2, tempY2;
|
|
JE_integer damage;
|
|
|
|
if (!player_shot_move_and_draw(z, &is_special, &tempShotX, &tempShotY, &damage, &temp2, &chain, &playerNum, &tempX2, &tempY2))
|
|
{
|
|
goto draw_player_shot_loop_end;
|
|
}
|
|
|
|
for (b = 0; b < 100; b++)
|
|
{
|
|
if (enemyAvail[b] == 0)
|
|
{
|
|
bool collided;
|
|
|
|
if (z == MAX_PWEAPON - 1)
|
|
{
|
|
temp = 25 - abs(zinglonDuration - 25);
|
|
collided = abs(enemy[b].ex + enemy[b].mapoffset - (player[0].x + 7)) < temp;
|
|
temp2 = 9;
|
|
chain = 0;
|
|
damage = 10;
|
|
}
|
|
else if (is_special)
|
|
{
|
|
collided = ((enemy[b].enemycycle == 0) &&
|
|
(abs(enemy[b].ex + enemy[b].mapoffset - tempShotX - tempX2) < (25 + tempX2)) &&
|
|
(abs(enemy[b].ey - tempShotY - 12 - tempY2) < (29 + tempY2))) ||
|
|
((enemy[b].enemycycle > 0) &&
|
|
(abs(enemy[b].ex + enemy[b].mapoffset - tempShotX - tempX2) < (13 + tempX2)) &&
|
|
(abs(enemy[b].ey - tempShotY - 6 - tempY2) < (15 + tempY2)));
|
|
}
|
|
else
|
|
{
|
|
collided = ((enemy[b].enemycycle == 0) &&
|
|
(abs(enemy[b].ex + enemy[b].mapoffset - tempShotX) < 25) && (abs(enemy[b].ey - tempShotY - 12) < 29)) ||
|
|
((enemy[b].enemycycle > 0) &&
|
|
(abs(enemy[b].ex + enemy[b].mapoffset - tempShotX) < 13) && (abs(enemy[b].ey - tempShotY - 6) < 15));
|
|
}
|
|
|
|
if (collided)
|
|
{
|
|
if (chain > 0)
|
|
{
|
|
shotMultiPos[SHOT_MISC] = 0;
|
|
b = player_shot_create(0, SHOT_MISC, tempShotX, tempShotY, mouseX, mouseY, chain, playerNum);
|
|
shotAvail[z] = 0;
|
|
goto draw_player_shot_loop_end;
|
|
}
|
|
|
|
infiniteShot = false;
|
|
|
|
if (damage == 99)
|
|
{
|
|
damage = 0;
|
|
doIced = 40;
|
|
enemy[b].iced = 40;
|
|
}
|
|
else
|
|
{
|
|
doIced = 0;
|
|
if (damage >= 250)
|
|
{
|
|
damage = damage - 250;
|
|
infiniteShot = true;
|
|
}
|
|
}
|
|
|
|
int armorleft = enemy[b].armorleft;
|
|
|
|
temp = enemy[b].linknum;
|
|
if (temp == 0)
|
|
temp = 255;
|
|
|
|
if (enemy[b].armorleft < 255)
|
|
{
|
|
for (unsigned int i = 0; i < COUNTOF(boss_bar); i++)
|
|
if (temp == boss_bar[i].link_num)
|
|
boss_bar[i].color = 6;
|
|
|
|
if (enemy[b].enemyground)
|
|
enemy[b].filter = temp2;
|
|
|
|
for (unsigned int e = 0; e < COUNTOF(enemy); e++)
|
|
{
|
|
if (enemy[e].linknum == temp &&
|
|
enemyAvail[e] != 1 &&
|
|
enemy[e].enemyground != 0)
|
|
{
|
|
if (doIced)
|
|
enemy[e].iced = doIced;
|
|
enemy[e].filter = temp2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (armorleft > damage)
|
|
{
|
|
if (z != MAX_PWEAPON - 1)
|
|
{
|
|
if (enemy[b].armorleft != 255)
|
|
{
|
|
enemy[b].armorleft -= damage;
|
|
JE_setupExplosion(tempShotX, tempShotY, 0, 0, false, false);
|
|
}
|
|
else
|
|
{
|
|
JE_doSP(tempShotX + 6, tempShotY + 6, damage / 2 + 3, damage / 4 + 2, temp2);
|
|
}
|
|
}
|
|
|
|
soundQueue[5] = S_ENEMY_HIT;
|
|
|
|
if ((armorleft - damage <= enemy[b].edlevel) &&
|
|
((!enemy[b].edamaged) ^ (enemy[b].edani < 0)))
|
|
{
|
|
|
|
for (temp3 = 0; temp3 < 100; temp3++)
|
|
{
|
|
if (enemyAvail[temp3] != 1)
|
|
{
|
|
int linknum = enemy[temp3].linknum;
|
|
if (
|
|
(temp3 == b) ||
|
|
(
|
|
(temp != 255) &&
|
|
(
|
|
((enemy[temp3].edlevel > 0) && (linknum == temp)) ||
|
|
(
|
|
(enemyContinualDamage && (temp - 100 == linknum)) ||
|
|
((linknum > 40) && (linknum / 20 == temp / 20) && (linknum <= temp))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
{
|
|
enemy[temp3].enemycycle = 1;
|
|
|
|
enemy[temp3].edamaged = !enemy[temp3].edamaged;
|
|
|
|
if (enemy[temp3].edani != 0)
|
|
{
|
|
enemy[temp3].ani = abs(enemy[temp3].edani);
|
|
enemy[temp3].aniactive = 1;
|
|
enemy[temp3].animax = 0;
|
|
enemy[temp3].animin = enemy[temp3].edgr;
|
|
enemy[temp3].enemycycle = enemy[temp3].animin - 1;
|
|
|
|
}
|
|
else if (enemy[temp3].edgr > 0)
|
|
{
|
|
enemy[temp3].egr[1-1] = enemy[temp3].edgr;
|
|
enemy[temp3].ani = 1;
|
|
enemy[temp3].aniactive = 0;
|
|
enemy[temp3].animax = 0;
|
|
enemy[temp3].animin = 1;
|
|
}
|
|
else
|
|
{
|
|
enemyAvail[temp3] = 1;
|
|
enemyKilled++;
|
|
}
|
|
|
|
enemy[temp3].aniwhenfire = 0;
|
|
|
|
if (enemy[temp3].armorleft > (unsigned char)enemy[temp3].edlevel)
|
|
enemy[temp3].armorleft = enemy[temp3].edlevel;
|
|
|
|
tempX = enemy[temp3].ex + enemy[temp3].mapoffset;
|
|
tempY = enemy[temp3].ey;
|
|
|
|
if (enemyDat[enemy[temp3].enemytype].esize != 1)
|
|
JE_setupExplosion(tempX, tempY - 6, 0, 1, false, false);
|
|
else
|
|
JE_setupExplosionLarge(enemy[temp3].enemyground, enemy[temp3].explonum / 2, tempX, tempY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
if ((temp == 254) && (superEnemy254Jump > 0))
|
|
JE_eventJump(superEnemy254Jump);
|
|
|
|
for (temp2 = 0; temp2 < 100; temp2++)
|
|
{
|
|
if (enemyAvail[temp2] != 1)
|
|
{
|
|
temp3 = enemy[temp2].linknum;
|
|
if ((temp2 == b) || (temp == 254) ||
|
|
((temp != 255) && ((temp == temp3) || (temp - 100 == temp3)
|
|
|| ((temp3 > 40) && (temp3 / 20 == temp / 20) && (temp3 <= temp)))))
|
|
{
|
|
|
|
int enemy_screen_x = enemy[temp2].ex + enemy[temp2].mapoffset;
|
|
|
|
if (enemy[temp2].special)
|
|
{
|
|
assert((unsigned int) enemy[temp2].flagnum-1 < COUNTOF(globalFlags));
|
|
globalFlags[enemy[temp2].flagnum-1] = enemy[temp2].setto;
|
|
}
|
|
|
|
if ((enemy[temp2].enemydie > 0) &&
|
|
!((superArcadeMode != SA_NONE) &&
|
|
(enemyDat[enemy[temp2].enemydie].value == 30000)))
|
|
{
|
|
int temp_b = b;
|
|
tempW = enemy[temp2].enemydie;
|
|
int enemy_offset = temp2 - (temp2 % 25);
|
|
if (enemyDat[tempW].value > 30000)
|
|
{
|
|
enemy_offset = 0;
|
|
}
|
|
b = JE_newEnemy(enemy_offset, tempW, 0);
|
|
if (b != 0) {
|
|
if ((superArcadeMode != SA_NONE) && (enemy[b-1].evalue > 30000))
|
|
{
|
|
superArcadePowerUp++;
|
|
if (superArcadePowerUp > 5)
|
|
superArcadePowerUp = 1;
|
|
enemy[b-1].egr[1-1] = 5 + superArcadePowerUp * 2;
|
|
enemy[b-1].evalue = 30000 + superArcadePowerUp;
|
|
}
|
|
|
|
if (enemy[b-1].evalue != 0)
|
|
enemy[b-1].scoreitem = true;
|
|
else
|
|
enemy[b-1].scoreitem = false;
|
|
|
|
enemy[b-1].ex = enemy[temp2].ex;
|
|
enemy[b-1].ey = enemy[temp2].ey;
|
|
}
|
|
b = temp_b;
|
|
}
|
|
|
|
if ((enemy[temp2].evalue > 0) && (enemy[temp2].evalue < 10000))
|
|
{
|
|
if (enemy[temp2].evalue == 1)
|
|
{
|
|
cubeMax++;
|
|
}
|
|
else
|
|
{
|
|
// in galaga mode player 2 is sidekick, so give cash to player 1
|
|
player[galagaMode ? 0 : playerNum - 1].cash += enemy[temp2].evalue;
|
|
}
|
|
}
|
|
|
|
if ((enemy[temp2].edlevel == -1) && (temp == temp3))
|
|
{
|
|
enemy[temp2].edlevel = 0;
|
|
enemyAvail[temp2] = 2;
|
|
enemy[temp2].egr[1-1] = enemy[temp2].edgr;
|
|
enemy[temp2].ani = 1;
|
|
enemy[temp2].aniactive = 0;
|
|
enemy[temp2].animax = 0;
|
|
enemy[temp2].animin = 1;
|
|
enemy[temp2].edamaged = true;
|
|
enemy[temp2].enemycycle = 1;
|
|
} else {
|
|
enemyAvail[temp2] = 1;
|
|
enemyKilled++;
|
|
}
|
|
|
|
if (enemyDat[enemy[temp2].enemytype].esize == 1)
|
|
{
|
|
JE_setupExplosionLarge(enemy[temp2].enemyground, enemy[temp2].explonum, enemy_screen_x, enemy[temp2].ey);
|
|
soundQueue[6] = S_EXPLOSION_9;
|
|
}
|
|
else
|
|
{
|
|
JE_setupExplosion(enemy_screen_x, enemy[temp2].ey, 0, 1, false, false);
|
|
soundQueue[6] = S_SELECT; // S_EXPLOSION_8
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (infiniteShot)
|
|
{
|
|
damage += 250;
|
|
}
|
|
else if (z != MAX_PWEAPON - 1)
|
|
{
|
|
if (damage <= armorleft)
|
|
{
|
|
shotAvail[z] = 0;
|
|
goto draw_player_shot_loop_end;
|
|
}
|
|
else
|
|
{
|
|
playerShotData[z].shotDmg -= armorleft;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
draw_player_shot_loop_end:
|
|
;
|
|
}
|
|
}
|
|
|
|
/* Player movement indicators for shots that track your ship */
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
{
|
|
player[i].last_x_shot_move = player[i].x;
|
|
player[i].last_y_shot_move = player[i].y;
|
|
}
|
|
|
|
/*=================================*/
|
|
/*=======Collisions Detection======*/
|
|
/*=================================*/
|
|
|
|
for (uint i = 0; i < (twoPlayerMode ? 2 : 1); ++i)
|
|
if (player[i].is_alive && !endLevel)
|
|
JE_playerCollide(&player[i], i + 1);
|
|
|
|
if (firstGameOver)
|
|
JE_mainGamePlayerFunctions(); /*--------PLAYER DRAW+MOVEMENT---------*/
|
|
|
|
if (!endLevel)
|
|
{ /*MAIN DRAWING IS STOPPED STARTING HERE*/
|
|
|
|
/* Draw Enemy Shots */
|
|
for (int z = 0; z < ENEMY_SHOT_MAX; z++)
|
|
{
|
|
if (enemyShotAvail[z] == 0)
|
|
{
|
|
enemyShot[z].sxm += enemyShot[z].sxc;
|
|
enemyShot[z].sx += enemyShot[z].sxm;
|
|
|
|
if (enemyShot[z].tx != 0)
|
|
{
|
|
if (enemyShot[z].sx > player[0].x)
|
|
{
|
|
if (enemyShot[z].sxm > -enemyShot[z].tx)
|
|
{
|
|
enemyShot[z].sxm--;
|
|
}
|
|
} else {
|
|
if (enemyShot[z].sxm < enemyShot[z].tx)
|
|
{
|
|
enemyShot[z].sxm++;
|
|
}
|
|
}
|
|
}
|
|
|
|
enemyShot[z].sym += enemyShot[z].syc;
|
|
enemyShot[z].sy += enemyShot[z].sym;
|
|
|
|
if (enemyShot[z].ty != 0)
|
|
{
|
|
if (enemyShot[z].sy > player[0].y)
|
|
{
|
|
if (enemyShot[z].sym > -enemyShot[z].ty)
|
|
{
|
|
enemyShot[z].sym--;
|
|
}
|
|
} else {
|
|
if (enemyShot[z].sym < enemyShot[z].ty)
|
|
{
|
|
enemyShot[z].sym++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (enemyShot[z].duration-- == 0 || enemyShot[z].sy > 190 || enemyShot[z].sy <= -14 || enemyShot[z].sx > 275 || enemyShot[z].sx <= 0)
|
|
{
|
|
enemyShotAvail[z] = true;
|
|
}
|
|
else // check if shot collided with player
|
|
{
|
|
for (uint i = 0; i < (twoPlayerMode ? 2 : 1); ++i)
|
|
{
|
|
if (player[i].is_alive &&
|
|
enemyShot[z].sx > player[i].x - (signed)player[i].shot_hit_area_x &&
|
|
enemyShot[z].sx < player[i].x + (signed)player[i].shot_hit_area_x &&
|
|
enemyShot[z].sy > player[i].y - (signed)player[i].shot_hit_area_y &&
|
|
enemyShot[z].sy < player[i].y + (signed)player[i].shot_hit_area_y)
|
|
{
|
|
tempX = enemyShot[z].sx;
|
|
tempY = enemyShot[z].sy;
|
|
temp = enemyShot[z].sdmg;
|
|
|
|
enemyShotAvail[z] = true;
|
|
|
|
JE_setupExplosion(tempX, tempY, 0, 0, false, false);
|
|
|
|
if (player[i].invulnerable_ticks == 0)
|
|
{
|
|
if ((temp = JE_playerDamage(temp, &player[i])) > 0)
|
|
{
|
|
player[i].x_velocity += (enemyShot[z].sxm * temp) / 2;
|
|
player[i].y_velocity += (enemyShot[z].sym * temp) / 2;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (enemyShotAvail[z] == false)
|
|
{
|
|
if (enemyShot[z].animax != 0)
|
|
{
|
|
if (++enemyShot[z].animate >= enemyShot[z].animax)
|
|
enemyShot[z].animate = 0;
|
|
}
|
|
|
|
if (enemyShot[z].sgr >= 500)
|
|
blit_sprite2(VGAScreen, enemyShot[z].sx, enemyShot[z].sy, shapesW2, enemyShot[z].sgr + enemyShot[z].animate - 500);
|
|
else
|
|
blit_sprite2(VGAScreen, enemyShot[z].sx, enemyShot[z].sy, shapesC1, enemyShot[z].sgr + enemyShot[z].animate);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (background3over == 1)
|
|
draw_background_3(VGAScreen);
|
|
|
|
/* Draw Top Enemy */
|
|
if (topEnemyOver)
|
|
{
|
|
tempMapXOfs = (background3x1 == 0) ? oldMapX3Ofs : oldMapXOfs;
|
|
tempBackMove = backMove3;
|
|
JE_drawEnemy(75);
|
|
}
|
|
|
|
/* Draw Sky Enemy */
|
|
if (skyEnemyOverAll)
|
|
{
|
|
lastEnemyOnScreen = enemyOnScreen;
|
|
|
|
tempMapXOfs = mapX2Ofs;
|
|
tempBackMove = 0;
|
|
JE_drawEnemy(25);
|
|
|
|
if (enemyOnScreen == lastEnemyOnScreen)
|
|
{
|
|
if (stopBackgroundNum == 2)
|
|
stopBackgroundNum = 9;
|
|
}
|
|
}
|
|
|
|
/*-------------------------- Sequenced Explosions -------------------------*/
|
|
enemyStillExploding = false;
|
|
for (int i = 0; i < MAX_REPEATING_EXPLOSIONS; i++)
|
|
{
|
|
if (rep_explosions[i].ttl != 0)
|
|
{
|
|
enemyStillExploding = true;
|
|
|
|
if (rep_explosions[i].delay > 0)
|
|
{
|
|
rep_explosions[i].delay--;
|
|
continue;
|
|
}
|
|
|
|
rep_explosions[i].y += backMove2 + 1;
|
|
tempX = rep_explosions[i].x + (mt_rand() % 24) - 12;
|
|
tempY = rep_explosions[i].y + (mt_rand() % 27) - 24;
|
|
|
|
if (rep_explosions[i].big)
|
|
{
|
|
JE_setupExplosionLarge(false, 2, tempX, tempY);
|
|
|
|
if (rep_explosions[i].ttl == 1 || mt_rand() % 5 == 1)
|
|
soundQueue[7] = S_EXPLOSION_11;
|
|
else
|
|
soundQueue[6] = S_EXPLOSION_9;
|
|
|
|
rep_explosions[i].delay = 4 + (mt_rand() % 3);
|
|
}
|
|
else
|
|
{
|
|
JE_setupExplosion(tempX, tempY, 0, 1, false, false);
|
|
|
|
soundQueue[5] = S_EXPLOSION_4;
|
|
|
|
rep_explosions[i].delay = 3;
|
|
}
|
|
|
|
rep_explosions[i].ttl--;
|
|
}
|
|
}
|
|
|
|
/*---------------------------- Draw Explosions ----------------------------*/
|
|
for (int j = 0; j < MAX_EXPLOSIONS; j++)
|
|
{
|
|
if (explosions[j].ttl != 0)
|
|
{
|
|
if (explosions[j].fixed_position != true)
|
|
{
|
|
explosions[j].sprite++;
|
|
explosions[j].y += explodeMove;
|
|
}
|
|
else if (explosions[j].follow_player == true)
|
|
{
|
|
explosions[j].x += explosionFollowAmountX;
|
|
explosions[j].y += explosionFollowAmountY;
|
|
}
|
|
explosions[j].y += explosions[j].delta_y;
|
|
explosions[j].x += explosions[j].delta_x;
|
|
|
|
if (explosions[j].y > 200 - 14)
|
|
{
|
|
explosions[j].ttl = 0;
|
|
}
|
|
else
|
|
{
|
|
if (explosionTransparent)
|
|
blit_sprite2_blend(VGAScreen, explosions[j].x, explosions[j].y, shapes6, explosions[j].sprite + 1);
|
|
else
|
|
blit_sprite2(VGAScreen, explosions[j].x, explosions[j].y, shapes6, explosions[j].sprite + 1);
|
|
|
|
explosions[j].ttl--;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!portConfigChange)
|
|
portConfigDone = true;
|
|
|
|
|
|
/*-----------------------BACKGROUNDS------------------------*/
|
|
/*-----------------------BACKGROUND 2------------------------*/
|
|
if (!(smoothies[2-1] && processorType < 4) &&
|
|
!(smoothies[1-1] && processorType == 3))
|
|
{
|
|
if (background2over == 2)
|
|
{
|
|
if (wild && !background2notTransparent)
|
|
draw_background_2_blend(VGAScreen);
|
|
else
|
|
draw_background_2(VGAScreen);
|
|
}
|
|
}
|
|
|
|
/*-------------------------Warning---------------------------*/
|
|
if ((player[0].is_alive && player[0].armor < 6) ||
|
|
(twoPlayerMode && !galagaMode && player[1].is_alive && player[1].armor < 6))
|
|
{
|
|
int armor_amount = (player[0].is_alive && player[0].armor < 6) ? player[0].armor : player[1].armor;
|
|
|
|
if (armorShipDelay > 0)
|
|
{
|
|
armorShipDelay--;
|
|
}
|
|
else
|
|
{
|
|
tempW = 560;
|
|
b = JE_newEnemy(50, tempW, 0);
|
|
if (b > 0)
|
|
{
|
|
enemy[b-1].enemydie = 560 + (mt_rand() % 3) + 1;
|
|
enemy[b-1].eyc -= backMove3;
|
|
enemy[b-1].armorleft = 4;
|
|
}
|
|
armorShipDelay = 500;
|
|
}
|
|
|
|
if ((player[0].is_alive && player[0].armor < 6 && (!isNetworkGame || thisPlayerNum == 1)) ||
|
|
(twoPlayerMode && player[1].is_alive && player[1].armor < 6 && (!isNetworkGame || thisPlayerNum == 2)))
|
|
{
|
|
|
|
tempW = armor_amount * 4 + 8;
|
|
if (warningSoundDelay > tempW)
|
|
warningSoundDelay = tempW;
|
|
|
|
if (warningSoundDelay > 1)
|
|
{
|
|
warningSoundDelay--;
|
|
}
|
|
else
|
|
{
|
|
soundQueue[7] = S_WARNING;
|
|
warningSoundDelay = tempW;
|
|
}
|
|
|
|
warningCol += warningColChange;
|
|
if (warningCol > 113 + (14 - (armor_amount * 2)))
|
|
{
|
|
warningColChange = -warningColChange;
|
|
warningCol = 113 + (14 - (armor_amount * 2));
|
|
}
|
|
else if (warningCol < 113)
|
|
{
|
|
warningColChange = -warningColChange;
|
|
}
|
|
fill_rectangle_xy(VGAScreen, 24, 181, 138, 183, warningCol);
|
|
fill_rectangle_xy(VGAScreen, 175, 181, 287, 183, warningCol);
|
|
fill_rectangle_xy(VGAScreen, 24, 0, 287, 3, warningCol);
|
|
|
|
JE_outText(VGAScreen, 140, 178, "WARNING", 7, (warningCol % 16) / 2);
|
|
|
|
}
|
|
}
|
|
|
|
/*------- Random Explosions --------*/
|
|
if (randomExplosions && mt_rand() % 10 == 1)
|
|
JE_setupExplosionLarge(false, 20, mt_rand() % 280, mt_rand() % 180);
|
|
|
|
/*=================================*/
|
|
/*=======The Sound Routine=========*/
|
|
/*=================================*/
|
|
if (firstGameOver)
|
|
{
|
|
temp = 0;
|
|
for (temp2 = 0; temp2 < SFX_CHANNELS; temp2++)
|
|
{
|
|
if (soundQueue[temp2] != S_NONE)
|
|
{
|
|
temp = soundQueue[temp2];
|
|
if (temp2 == 3)
|
|
temp3 = fxPlayVol;
|
|
else if (temp == 15)
|
|
temp3 = fxPlayVol / 4;
|
|
else /*Lightning*/
|
|
temp3 = fxPlayVol / 2;
|
|
|
|
JE_multiSamplePlay(digiFx[temp-1], fxSize[temp-1], temp2, temp3);
|
|
|
|
soundQueue[temp2] = S_NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (returnActive && enemyOnScreen == 0)
|
|
{
|
|
JE_eventJump(65535);
|
|
returnActive = false;
|
|
}
|
|
|
|
/*------- DEbug ---------*/
|
|
debugTime = SDL_GetTicks();
|
|
tempW = lastmouse_but;
|
|
tempX = mouse_x;
|
|
tempY = mouse_y;
|
|
|
|
if (debug)
|
|
{
|
|
strcpy(tempStr, "");
|
|
for (temp = 0; temp < 9; temp++)
|
|
{
|
|
sprintf(tempStr, "%s%c", tempStr, smoothies[temp] + 48);
|
|
}
|
|
sprintf(buffer, "SM = %s", tempStr);
|
|
JE_outText(VGAScreen, 30, 70, buffer, 4, 0);
|
|
|
|
sprintf(buffer, "Memory left = %d", -1);
|
|
JE_outText(VGAScreen, 30, 80, buffer, 4, 0);
|
|
sprintf(buffer, "Enemies onscreen = %d", enemyOnScreen);
|
|
JE_outText(VGAScreen, 30, 90, buffer, 6, 0);
|
|
|
|
debugHist = debugHist + abs((JE_longint)debugTime - (JE_longint)lastDebugTime);
|
|
debugHistCount++;
|
|
sprintf(tempStr, "%2.3f", 1000.0f / roundf(debugHist / debugHistCount));
|
|
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);
|
|
JE_outText(VGAScreen, 45, 175, buffer, 15, 3);
|
|
lastDebugTime = debugTime;
|
|
}
|
|
|
|
if (displayTime > 0)
|
|
{
|
|
displayTime--;
|
|
JE_outTextAndDarken(VGAScreen, 90, 10, miscText[59], 15, (JE_byte)flash - 8, FONT_SHAPES);
|
|
flash += flashChange;
|
|
if (flash > 4 || flash == 0)
|
|
flashChange = -flashChange;
|
|
}
|
|
|
|
/*Pentium Speed Mode?*/
|
|
if (pentiumMode)
|
|
{
|
|
frameCountMax = (frameCountMax == 2) ? 3 : 2;
|
|
}
|
|
|
|
/*-------- Level Timer ---------*/
|
|
if (levelTimer && levelTimerCountdown > 0)
|
|
{
|
|
levelTimerCountdown--;
|
|
if (levelTimerCountdown == 0)
|
|
JE_eventJump(levelTimerJumpTo);
|
|
|
|
if (levelTimerCountdown > 200)
|
|
{
|
|
if (levelTimerCountdown % 100 == 0)
|
|
soundQueue[7] = S_WARNING;
|
|
|
|
if (levelTimerCountdown % 10 == 0)
|
|
soundQueue[6] = S_CLICK;
|
|
}
|
|
else if (levelTimerCountdown % 20 == 0)
|
|
{
|
|
soundQueue[7] = S_WARNING;
|
|
}
|
|
|
|
JE_textShade (VGAScreen, 140, 6, miscText[66], 7, (levelTimerCountdown % 20) / 3, FULL_SHADE);
|
|
sprintf(buffer, "%.1f", levelTimerCountdown / 100.0f);
|
|
JE_dString (VGAScreen, 100, 2, buffer, SMALL_FONT_SHAPES);
|
|
}
|
|
|
|
/*GAME OVER*/
|
|
if (!constantPlay && !constantDie)
|
|
{
|
|
if (allPlayersGone)
|
|
{
|
|
if (player[0].exploding_ticks > 0 || player[1].exploding_ticks > 0)
|
|
{
|
|
if (galagaMode)
|
|
player[1].exploding_ticks = 0;
|
|
|
|
musicFade = true;
|
|
}
|
|
else
|
|
{
|
|
if (play_demo || normalBonusLevelCurrent || bonusLevelCurrent)
|
|
reallyEndLevel = true;
|
|
else
|
|
JE_dString(VGAScreen, 120, 60, miscText[21], FONT_SHAPES); // game over
|
|
|
|
set_mouse_position(159, 100);
|
|
if (firstGameOver)
|
|
{
|
|
if (!play_demo)
|
|
{
|
|
play_song(SONG_GAMEOVER);
|
|
set_volume(tyrMusicVolume, fxVolume);
|
|
}
|
|
firstGameOver = false;
|
|
}
|
|
|
|
if (!play_demo)
|
|
{
|
|
push_joysticks_as_keyboard();
|
|
service_SDL_events(true);
|
|
if ((newkey || button[0] || button[1] || button[2]) || newmouse)
|
|
{
|
|
reallyEndLevel = true;
|
|
}
|
|
}
|
|
|
|
if (isNetworkGame)
|
|
reallyEndLevel = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (play_demo) // input kills demo
|
|
{
|
|
push_joysticks_as_keyboard();
|
|
service_SDL_events(false);
|
|
|
|
if (newkey || newmouse)
|
|
{
|
|
reallyEndLevel = true;
|
|
|
|
stopped_demo = true;
|
|
}
|
|
}
|
|
else // input handling for pausing, menu, cheats
|
|
{
|
|
service_SDL_events_ignore_pause(false);
|
|
|
|
if (newkey)
|
|
{
|
|
skipStarShowVGA = false;
|
|
JE_mainKeyboardInput();
|
|
newkey = false;
|
|
if (skipStarShowVGA)
|
|
goto level_loop;
|
|
}
|
|
|
|
if (pause_pressed)
|
|
{
|
|
pause_pressed = false;
|
|
|
|
if (isNetworkGame)
|
|
pauseRequest = true;
|
|
else
|
|
JE_pauseGame();
|
|
}
|
|
|
|
if (ingamemenu_pressed)
|
|
{
|
|
ingamemenu_pressed = false;
|
|
|
|
if (isNetworkGame)
|
|
{
|
|
inGameMenuRequest = true;
|
|
}
|
|
else
|
|
{
|
|
yourInGameMenuRequest = true;
|
|
JE_doInGameSetup();
|
|
skipStarShowVGA = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*Network Update*/
|
|
#ifdef WITH_NETWORK
|
|
if (isNetworkGame)
|
|
{
|
|
if (!reallyEndLevel)
|
|
{
|
|
Uint16 requests = (pauseRequest == true) |
|
|
(inGameMenuRequest == true) << 1 |
|
|
(skipLevelRequest == true) << 2 |
|
|
(nortShipRequest == true) << 3;
|
|
SDLNet_Write16(requests, &packet_state_out[0]->data[14]);
|
|
|
|
SDLNet_Write16(difficultyLevel, &packet_state_out[0]->data[16]);
|
|
SDLNet_Write16(player[0].x, &packet_state_out[0]->data[18]);
|
|
SDLNet_Write16(player[1].x, &packet_state_out[0]->data[20]);
|
|
SDLNet_Write16(player[0].y, &packet_state_out[0]->data[22]);
|
|
SDLNet_Write16(player[1].y, &packet_state_out[0]->data[24]);
|
|
SDLNet_Write16(curLoc, &packet_state_out[0]->data[26]);
|
|
|
|
network_state_send();
|
|
|
|
if (network_state_update())
|
|
{
|
|
assert(SDLNet_Read16(&packet_state_in[0]->data[26]) == SDLNet_Read16(&packet_state_out[network_delay]->data[26]));
|
|
|
|
requests = SDLNet_Read16(&packet_state_in[0]->data[14]) ^ SDLNet_Read16(&packet_state_out[network_delay]->data[14]);
|
|
if (requests & 1)
|
|
{
|
|
JE_pauseGame();
|
|
}
|
|
if (requests & 2)
|
|
{
|
|
yourInGameMenuRequest = SDLNet_Read16(&packet_state_out[network_delay]->data[14]) & 2;
|
|
JE_doInGameSetup();
|
|
yourInGameMenuRequest = false;
|
|
if (haltGame)
|
|
reallyEndLevel = true;
|
|
}
|
|
if (requests & 4)
|
|
{
|
|
levelTimer = true;
|
|
levelTimerCountdown = 0;
|
|
endLevel = true;
|
|
levelEnd = 40;
|
|
}
|
|
if (requests & 8) // nortship
|
|
{
|
|
player[0].items.ship = 12; // Nort Ship
|
|
player[0].items.special = 13; // Astral Zone
|
|
player[0].items.weapon[FRONT_WEAPON].id = 36; // NortShip Super Pulse
|
|
player[0].items.weapon[REAR_WEAPON].id = 37; // NortShip Spreader
|
|
shipGr = 1;
|
|
}
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
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]))
|
|
{
|
|
char temp[64];
|
|
sprintf(temp, "Player %d is unsynchronized!", i + 1);
|
|
|
|
JE_textShade(game_screen, 40, 110 + i * 10, temp, 9, 2, FULL_SHADE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
JE_clearSpecialRequests();
|
|
}
|
|
#endif
|
|
|
|
/** Test **/
|
|
JE_drawSP();
|
|
|
|
/*Filtration*/
|
|
if (filterActive)
|
|
{
|
|
JE_filterScreen(levelFilter, levelBrightness);
|
|
}
|
|
|
|
draw_boss_bar();
|
|
|
|
JE_inGameDisplays();
|
|
|
|
VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
|
|
|
|
JE_starShowVGA();
|
|
|
|
/*Start backgrounds if no enemies on screen
|
|
End level if number of enemies left to kill equals 0.*/
|
|
if (stopBackgroundNum == 9 && backMove == 0 && !enemyStillExploding)
|
|
{
|
|
backMove = 1;
|
|
backMove2 = 2;
|
|
backMove3 = 3;
|
|
explodeMove = 2;
|
|
stopBackgroundNum = 0;
|
|
stopBackgrounds = false;
|
|
if (waitToEndLevel)
|
|
{
|
|
endLevel = true;
|
|
levelEnd = 40;
|
|
}
|
|
if (allPlayersGone)
|
|
{
|
|
reallyEndLevel = true;
|
|
}
|
|
}
|
|
|
|
if (!endLevel && enemyOnScreen == 0)
|
|
{
|
|
if (readyToEndLevel && !enemyStillExploding)
|
|
{
|
|
if (levelTimerCountdown > 0)
|
|
{
|
|
levelTimer = false;
|
|
}
|
|
readyToEndLevel = false;
|
|
endLevel = true;
|
|
levelEnd = 40;
|
|
if (allPlayersGone)
|
|
{
|
|
reallyEndLevel = true;
|
|
}
|
|
}
|
|
if (stopBackgrounds)
|
|
{
|
|
stopBackgrounds = false;
|
|
backMove = 1;
|
|
backMove2 = 2;
|
|
backMove3 = 3;
|
|
explodeMove = 2;
|
|
}
|
|
}
|
|
|
|
|
|
/*Other Network Functions*/
|
|
JE_handleChat();
|
|
|
|
if (reallyEndLevel)
|
|
{
|
|
goto start_level;
|
|
}
|
|
goto level_loop;
|
|
}
|
|
|
|
/* --- Load Level/Map Data --- */
|
|
void JE_loadMap( void )
|
|
{
|
|
JE_DanCShape shape;
|
|
|
|
JE_word x, y;
|
|
JE_integer yy;
|
|
JE_word mapSh[3][128]; /* [1..3, 0..127] */
|
|
JE_byte *ref[3][128]; /* [1..3, 0..127] */
|
|
char s[256];
|
|
|
|
JE_byte mapBuf[15 * 600]; /* [1..15 * 600] */
|
|
JE_word bufLoc;
|
|
|
|
char buffer[256];
|
|
int i;
|
|
Uint8 pic_buffer[320*200]; /* screen buffer, 8-bit specific */
|
|
Uint8 *vga, *pic, *vga2; /* screen pointer, 8-bit specific */
|
|
|
|
lastCubeMax = cubeMax;
|
|
|
|
/*Defaults*/
|
|
songBuy = DEFAULT_SONG_BUY; /*Item Screen default song*/
|
|
|
|
/* Load LEVELS.DAT - Section = MAINLEVEL */
|
|
saveLevel = mainLevel;
|
|
|
|
new_game:
|
|
galagaMode = false;
|
|
useLastBank = false;
|
|
extraGame = false;
|
|
haltGame = false;
|
|
|
|
gameLoaded = false;
|
|
|
|
if (!play_demo)
|
|
{
|
|
do
|
|
{
|
|
FILE *ep_f = dir_fopen_die(data_dir(), episode_file, "rb");
|
|
|
|
jumpSection = false;
|
|
loadLevelOk = false;
|
|
|
|
/* Seek Section # Mainlevel */
|
|
int x = 0;
|
|
while (x < mainLevel)
|
|
{
|
|
read_encrypted_pascal_string(s, sizeof(s), ep_f);
|
|
if (s[0] == '*')
|
|
{
|
|
x++;
|
|
s[0] = ' ';
|
|
}
|
|
}
|
|
|
|
ESCPressed = false;
|
|
|
|
do
|
|
{
|
|
if (gameLoaded)
|
|
{
|
|
fclose(ep_f);
|
|
|
|
if (mainLevel == 0) // if quit itemscreen
|
|
return; // back to title screen
|
|
else
|
|
goto new_game;
|
|
}
|
|
|
|
strcpy(s, " ");
|
|
read_encrypted_pascal_string(s, sizeof(s), ep_f);
|
|
|
|
if (s[0] == ']')
|
|
{
|
|
switch (s[1])
|
|
{
|
|
case 'A':
|
|
JE_playAnim("tyrend.anm", 0, 7);
|
|
break;
|
|
|
|
case 'G':
|
|
mapOrigin = atoi(strnztcpy(buffer, s + 4, 2));
|
|
mapPNum = atoi(strnztcpy(buffer, s + 7, 1));
|
|
for (i = 0; i < mapPNum; i++)
|
|
{
|
|
mapPlanet[i] = atoi(strnztcpy(buffer, s + 1 + (i + 1) * 8, 2));
|
|
mapSection[i] = atoi(strnztcpy(buffer, s + 4 + (i + 1) * 8, 3));
|
|
}
|
|
break;
|
|
|
|
case '?':
|
|
temp = atoi(strnztcpy(buffer, s + 4, 2));
|
|
for (i = 0; i < temp; i++)
|
|
{
|
|
cubeList[i] = atoi(strnztcpy(buffer, s + 3 + (i + 1) * 4, 3));
|
|
}
|
|
if (cubeMax > temp)
|
|
cubeMax = temp;
|
|
break;
|
|
|
|
case '!':
|
|
cubeMax = atoi(strnztcpy(buffer, s + 4, 2)); /*Auto set CubeMax*/
|
|
break;
|
|
|
|
case '+':
|
|
temp = atoi(strnztcpy(buffer, s + 4, 2));
|
|
cubeMax += temp;
|
|
if (cubeMax > 4)
|
|
cubeMax = 4;
|
|
break;
|
|
|
|
case 'g':
|
|
galagaMode = true; /*GALAGA mode*/
|
|
|
|
player[1].items = player[0].items;
|
|
player[1].items.weapon[REAR_WEAPON].id = 15; // Vulcan Cannon
|
|
for (uint i = 0; i < COUNTOF(player[1].items.sidekick); ++i)
|
|
player[1].items.sidekick[i] = 0; // None
|
|
break;
|
|
|
|
case 'x':
|
|
extraGame = true;
|
|
break;
|
|
|
|
case 'e': // ENGAGE mode, used for mini-games
|
|
doNotSaveBackup = true;
|
|
constantDie = false;
|
|
onePlayerAction = true;
|
|
superTyrian = true;
|
|
twoPlayerMode = false;
|
|
|
|
player[0].cash = 0;
|
|
|
|
player[0].items.ship = 13; // The Stalker 21.126
|
|
player[0].items.weapon[FRONT_WEAPON].id = 39; // Atomic RailGun
|
|
player[0].items.weapon[REAR_WEAPON].id = 0; // None
|
|
for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i)
|
|
player[0].items.sidekick[i] = 0; // None
|
|
player[0].items.generator = 2; // Advanced MR-12
|
|
player[0].items.shield = 4; // Advanced Integrity Field
|
|
player[0].items.special = 0; // None
|
|
|
|
player[0].items.weapon[FRONT_WEAPON].power = 3;
|
|
player[0].items.weapon[REAR_WEAPON].power = 1;
|
|
break;
|
|
|
|
case 'J': // section jump
|
|
temp = atoi(strnztcpy(buffer, s + 3, 3));
|
|
mainLevel = temp;
|
|
jumpSection = true;
|
|
break;
|
|
|
|
case '2': // two-player section jump
|
|
temp = atoi(strnztcpy(buffer, s + 3, 3));
|
|
if (twoPlayerMode || onePlayerAction)
|
|
{
|
|
mainLevel = temp;
|
|
jumpSection = true;
|
|
}
|
|
break;
|
|
|
|
case 'w': // Stalker 21.126 section jump
|
|
temp = atoi(strnztcpy(buffer, s + 3, 3)); /*Allowed to go to Time War?*/
|
|
if (player[0].items.ship == 13)
|
|
{
|
|
mainLevel = temp;
|
|
jumpSection = true;
|
|
}
|
|
break;
|
|
|
|
case 't':
|
|
temp = atoi(strnztcpy(buffer, s + 3, 3));
|
|
if (levelTimer && levelTimerCountdown == 0)
|
|
{
|
|
mainLevel = temp;
|
|
jumpSection = true;
|
|
}
|
|
break;
|
|
|
|
case 'l':
|
|
temp = atoi(strnztcpy(buffer, s + 3, 3));
|
|
if (!all_players_alive())
|
|
{
|
|
mainLevel = temp;
|
|
jumpSection = true;
|
|
}
|
|
break;
|
|
|
|
case 's':
|
|
saveLevel = mainLevel;
|
|
break; /*store savepoint*/
|
|
|
|
case 'b':
|
|
if (twoPlayerMode)
|
|
{
|
|
temp = 22;
|
|
} else {
|
|
temp = 11;
|
|
}
|
|
JE_saveGame(11, "LAST LEVEL ");
|
|
break;
|
|
|
|
case 'i':
|
|
temp = atoi(strnztcpy(buffer, s + 3, 3));
|
|
songBuy = temp - 1;
|
|
break;
|
|
|
|
case 'I': /*Load Items Available Information*/
|
|
memset(&itemAvail, 0, sizeof(itemAvail));
|
|
|
|
for (int i = 0; i < 9; ++i)
|
|
{
|
|
read_encrypted_pascal_string(s, sizeof(s), ep_f);
|
|
|
|
char buf[256];
|
|
strncpy(buf, (strlen(s) > 8) ? s + 8 : "", sizeof(buf));
|
|
|
|
int j = 0, temp;
|
|
while (str_pop_int(buf, &temp))
|
|
itemAvail[i][j++] = temp;
|
|
itemAvailMax[i] = j;
|
|
}
|
|
|
|
JE_itemScreen();
|
|
break;
|
|
|
|
case 'L':
|
|
nextLevel = atoi(strnztcpy(buffer, s + 9, 3));
|
|
strnztcpy(levelName, s + 13, 9);
|
|
levelSong = atoi(strnztcpy(buffer, s + 22, 2));
|
|
if (nextLevel == 0)
|
|
{
|
|
nextLevel = mainLevel + 1;
|
|
}
|
|
lvlFileNum = atoi(strnztcpy(buffer, s + 25, 2));
|
|
loadLevelOk = true;
|
|
bonusLevelCurrent = (strlen(s) > 28) & (s[28] == '$');
|
|
normalBonusLevelCurrent = (strlen(s) > 27) & (s[27] == '$');
|
|
gameJustLoaded = false;
|
|
break;
|
|
|
|
case '@':
|
|
useLastBank = !useLastBank;
|
|
break;
|
|
|
|
case 'Q':
|
|
ESCPressed = false;
|
|
temp = secretHint + (mt_rand() % 3) * 3;
|
|
|
|
if (twoPlayerMode)
|
|
{
|
|
for (uint i = 0; i < 2; ++i)
|
|
snprintf(levelWarningText[i], sizeof(*levelWarningText), "%s %lu", miscText[40], player[i].cash);
|
|
strcpy(levelWarningText[2], "");
|
|
levelWarningLines = 3;
|
|
}
|
|
else
|
|
{
|
|
sprintf(levelWarningText[0], "%s %lu", miscText[37], JE_totalScore(&player[0]));
|
|
strcpy(levelWarningText[1], "");
|
|
levelWarningLines = 2;
|
|
}
|
|
|
|
for (x = 0; x < temp - 1; x++)
|
|
{
|
|
do
|
|
read_encrypted_pascal_string(s, sizeof(s), ep_f);
|
|
while (s[0] != '#');
|
|
}
|
|
|
|
do
|
|
{
|
|
read_encrypted_pascal_string(s, sizeof(s), ep_f);
|
|
strcpy(levelWarningText[levelWarningLines], s);
|
|
levelWarningLines++;
|
|
}
|
|
while (s[0] != '#');
|
|
levelWarningLines--;
|
|
|
|
JE_wipeKey();
|
|
frameCountMax = 4;
|
|
if (!constantPlay)
|
|
JE_displayText();
|
|
|
|
fade_black(15);
|
|
|
|
JE_nextEpisode();
|
|
|
|
if (jumpBackToEpisode1 && !twoPlayerMode)
|
|
{
|
|
JE_loadPic(VGAScreen, 1, false); // huh?
|
|
JE_clr256(VGAScreen);
|
|
|
|
if (superTyrian)
|
|
{
|
|
// if completed Zinglon's Revenge, show SuperTyrian and Destruct codes
|
|
// if completed SuperTyrian, show Nort-Ship Z code
|
|
superArcadeMode = (initialDifficulty == 8) ? 8 : 1;
|
|
}
|
|
|
|
if (superArcadeMode < SA_ENGAGE)
|
|
{
|
|
if (SANextShip[superArcadeMode] == SA_ENGAGE)
|
|
{
|
|
sprintf(buffer, "%s %s", miscTextB[4], pName[0]);
|
|
JE_dString(VGAScreen, JE_fontCenter(buffer, FONT_SHAPES), 100, buffer, FONT_SHAPES);
|
|
|
|
sprintf(buffer, "Or play... %s", specialName[7]);
|
|
JE_dString(VGAScreen, 80, 180, buffer, SMALL_FONT_SHAPES);
|
|
}
|
|
else
|
|
{
|
|
JE_dString(VGAScreen, JE_fontCenter(superShips[0], FONT_SHAPES), 30, superShips[0], FONT_SHAPES);
|
|
JE_dString(VGAScreen, JE_fontCenter(superShips[SANextShip[superArcadeMode]], SMALL_FONT_SHAPES), 100, superShips[SANextShip[superArcadeMode]], SMALL_FONT_SHAPES);
|
|
}
|
|
|
|
if (SANextShip[superArcadeMode] < SA_NORTSHIPZ)
|
|
blit_sprite2x2(VGAScreen, 148, 70, shapes9, ships[SAShip[SANextShip[superArcadeMode]-1]].shipgraphic);
|
|
else if (SANextShip[superArcadeMode] == SA_NORTSHIPZ)
|
|
trentWin = true;
|
|
|
|
sprintf(buffer, "Type %s at Title", specialName[SANextShip[superArcadeMode]-1]);
|
|
JE_dString(VGAScreen, JE_fontCenter(buffer, SMALL_FONT_SHAPES), 160, buffer, SMALL_FONT_SHAPES);
|
|
JE_showVGA();
|
|
|
|
fade_palette(colors, 50, 0, 255);
|
|
|
|
if (!constantPlay)
|
|
wait_input(true, true, true);
|
|
}
|
|
|
|
jumpSection = true;
|
|
|
|
if (isNetworkGame)
|
|
JE_readTextSync();
|
|
|
|
if (superTyrian)
|
|
{
|
|
fade_black(10);
|
|
|
|
// back to titlescreen
|
|
mainLevel = 0;
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'P':
|
|
if (!constantPlay)
|
|
{
|
|
tempX = atoi(strnztcpy(buffer, s + 3, 3));
|
|
if (tempX > 900)
|
|
{
|
|
memcpy(colors, palettes[pcxpal[tempX-1 - 900]], sizeof(colors));
|
|
JE_clr256(VGAScreen);
|
|
JE_showVGA();
|
|
fade_palette(colors, 1, 0, 255);
|
|
}
|
|
else
|
|
{
|
|
if (tempX == 0)
|
|
JE_loadPCX("tshp2.pcx");
|
|
else
|
|
JE_loadPic(VGAScreen, tempX, false);
|
|
|
|
JE_showVGA();
|
|
fade_palette(colors, 10, 0, 255);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'U':
|
|
if (!constantPlay)
|
|
{
|
|
memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
|
|
|
|
tempX = atoi(strnztcpy(buffer, s + 3, 3));
|
|
JE_loadPic(VGAScreen, tempX, false);
|
|
memcpy(pic_buffer, VGAScreen->pixels, sizeof(pic_buffer));
|
|
|
|
service_SDL_events(true);
|
|
|
|
for (int z = 0; z <= 199; z++)
|
|
{
|
|
if (!newkey)
|
|
{
|
|
vga = VGAScreen->pixels;
|
|
vga2 = VGAScreen2->pixels;
|
|
pic = pic_buffer + (199 - z) * 320;
|
|
|
|
setjasondelay(1); /* attempting to emulate JE_waitRetrace();*/
|
|
|
|
for (y = 0; y <= 199; y++)
|
|
{
|
|
if (y <= z)
|
|
{
|
|
memcpy(vga, pic, 320);
|
|
pic += 320;
|
|
}
|
|
else
|
|
{
|
|
memcpy(vga, vga2, VGAScreen->pitch);
|
|
vga2 += VGAScreen->pitch;
|
|
}
|
|
vga += VGAScreen->pitch;
|
|
}
|
|
|
|
JE_showVGA();
|
|
|
|
if (isNetworkGame)
|
|
{
|
|
/* TODO: NETWORK */
|
|
}
|
|
|
|
service_wait_delay();
|
|
}
|
|
}
|
|
|
|
memcpy(VGAScreen->pixels, pic_buffer, sizeof(pic_buffer));
|
|
}
|
|
break;
|
|
|
|
case 'V':
|
|
if (!constantPlay)
|
|
{
|
|
/* TODO: NETWORK */
|
|
memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
|
|
|
|
tempX = atoi(strnztcpy(buffer, s + 3, 3));
|
|
JE_loadPic(VGAScreen, tempX, false);
|
|
memcpy(pic_buffer, VGAScreen->pixels, sizeof(pic_buffer));
|
|
|
|
service_SDL_events(true);
|
|
for (int z = 0; z <= 199; z++)
|
|
{
|
|
if (!newkey)
|
|
{
|
|
vga = VGAScreen->pixels;
|
|
vga2 = VGAScreen2->pixels;
|
|
pic = pic_buffer;
|
|
|
|
setjasondelay(1); /* attempting to emulate JE_waitRetrace();*/
|
|
|
|
for (y = 0; y < 199; y++)
|
|
{
|
|
if (y <= 199 - z)
|
|
{
|
|
memcpy(vga, vga2, VGAScreen->pitch);
|
|
vga2 += VGAScreen->pitch;
|
|
}
|
|
else
|
|
{
|
|
memcpy(vga, pic, 320);
|
|
pic += 320;
|
|
}
|
|
vga += VGAScreen->pitch;
|
|
}
|
|
|
|
JE_showVGA();
|
|
|
|
if (isNetworkGame)
|
|
{
|
|
/* TODO: NETWORK */
|
|
}
|
|
|
|
service_wait_delay();
|
|
}
|
|
}
|
|
|
|
memcpy(VGAScreen->pixels, pic_buffer, sizeof(pic_buffer));
|
|
}
|
|
break;
|
|
|
|
case 'R':
|
|
if (!constantPlay)
|
|
{
|
|
/* TODO: NETWORK */
|
|
memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
|
|
|
|
tempX = atoi(strnztcpy(buffer, s + 3, 3));
|
|
JE_loadPic(VGAScreen, tempX, false);
|
|
memcpy(pic_buffer, VGAScreen->pixels, sizeof(pic_buffer));
|
|
|
|
service_SDL_events(true);
|
|
|
|
for (int z = 0; z <= 318; z++)
|
|
{
|
|
if (!newkey)
|
|
{
|
|
vga = VGAScreen->pixels;
|
|
vga2 = VGAScreen2->pixels;
|
|
pic = pic_buffer;
|
|
|
|
setjasondelay(1); /* attempting to emulate JE_waitRetrace();*/
|
|
|
|
for(y = 0; y < 200; y++)
|
|
{
|
|
memcpy(vga, vga2 + z, 319 - z);
|
|
vga += 320 - z;
|
|
vga2 += VGAScreen2->pitch;
|
|
memcpy(vga, pic, z + 1);
|
|
vga += z;
|
|
pic += 320;
|
|
}
|
|
|
|
JE_showVGA();
|
|
|
|
if (isNetworkGame)
|
|
{
|
|
/* TODO: NETWORK */
|
|
}
|
|
|
|
service_wait_delay();
|
|
}
|
|
}
|
|
|
|
memcpy(VGAScreen->pixels, pic_buffer, sizeof(pic_buffer));
|
|
}
|
|
break;
|
|
|
|
case 'C':
|
|
if (!isNetworkGame)
|
|
{
|
|
fade_black(10);
|
|
}
|
|
JE_clr256(VGAScreen);
|
|
JE_showVGA();
|
|
memcpy(colors, palettes[7], sizeof(colors));
|
|
set_palette(colors, 0, 255);
|
|
break;
|
|
|
|
case 'B':
|
|
if (!isNetworkGame)
|
|
{
|
|
fade_black(10);
|
|
}
|
|
break;
|
|
case 'F':
|
|
if (!isNetworkGame)
|
|
{
|
|
fade_white(100);
|
|
fade_black(30);
|
|
}
|
|
JE_clr256(VGAScreen);
|
|
JE_showVGA();
|
|
break;
|
|
|
|
case 'W':
|
|
if (!constantPlay)
|
|
{
|
|
if (!ESCPressed)
|
|
{
|
|
JE_wipeKey();
|
|
warningCol = 14 * 16 + 5;
|
|
warningColChange = 1;
|
|
warningSoundDelay = 0;
|
|
levelWarningDisplay = (s[2] == 'y');
|
|
levelWarningLines = 0;
|
|
frameCountMax = atoi(strnztcpy(buffer, s + 4, 2));
|
|
setjasondelay2(6);
|
|
warningRed = frameCountMax / 10;
|
|
frameCountMax = frameCountMax % 10;
|
|
|
|
do
|
|
{
|
|
read_encrypted_pascal_string(s, sizeof(s), ep_f);
|
|
|
|
if (s[0] != '#')
|
|
{
|
|
strcpy(levelWarningText[levelWarningLines], s);
|
|
levelWarningLines++;
|
|
}
|
|
}
|
|
while (!(s[0] == '#'));
|
|
|
|
JE_displayText();
|
|
newkey = false;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'H':
|
|
if (initialDifficulty < 3)
|
|
{
|
|
mainLevel = atoi(strnztcpy(buffer, s + 4, 3));
|
|
jumpSection = true;
|
|
}
|
|
break;
|
|
|
|
case 'h':
|
|
if (initialDifficulty > 2)
|
|
{
|
|
read_encrypted_pascal_string(s, sizeof(s), ep_f);
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
if (isNetworkGame)
|
|
{
|
|
JE_readTextSync();
|
|
}
|
|
break;
|
|
|
|
case 'n':
|
|
ESCPressed = false;
|
|
break;
|
|
|
|
case 'M':
|
|
temp = atoi(strnztcpy(buffer, s + 3, 3));
|
|
play_song(temp - 1);
|
|
break;
|
|
|
|
#ifdef TYRIAN2000
|
|
case 'T':
|
|
/* TODO: Timed Battle ]T[ 43 44 45 46 47 */
|
|
printf("]T[ 43 44 45 46 47 handle timed battle!");
|
|
break;
|
|
|
|
case 'q':
|
|
/* TODO: Timed Battle end */
|
|
printf("handle timed battle end flag!");
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
} while (!(loadLevelOk || jumpSection));
|
|
|
|
|
|
fclose(ep_f);
|
|
|
|
} while (!loadLevelOk);
|
|
}
|
|
|
|
if (play_demo)
|
|
load_next_demo();
|
|
else
|
|
fade_black(50);
|
|
|
|
FILE *level_f = dir_fopen_die(data_dir(), levelFile, "rb");
|
|
fseek(level_f, lvlPos[(lvlFileNum-1) * 2], SEEK_SET);
|
|
|
|
fgetc(level_f); // char_mapFile
|
|
JE_char char_shapeFile = fgetc(level_f);
|
|
efread(&mapX, sizeof(JE_word), 1, level_f);
|
|
efread(&mapX2, sizeof(JE_word), 1, level_f);
|
|
efread(&mapX3, sizeof(JE_word), 1, level_f);
|
|
|
|
efread(&levelEnemyMax, sizeof(JE_word), 1, level_f);
|
|
for (x = 0; x < levelEnemyMax; x++)
|
|
{
|
|
efread(&levelEnemy[x], sizeof(JE_word), 1, level_f);
|
|
}
|
|
|
|
efread(&maxEvent, sizeof(JE_word), 1, level_f);
|
|
for (x = 0; x < maxEvent; x++)
|
|
{
|
|
efread(&eventRec[x].eventtime, sizeof(JE_word), 1, level_f);
|
|
efread(&eventRec[x].eventtype, sizeof(JE_byte), 1, level_f);
|
|
efread(&eventRec[x].eventdat, sizeof(JE_integer), 1, level_f);
|
|
efread(&eventRec[x].eventdat2, sizeof(JE_integer), 1, level_f);
|
|
efread(&eventRec[x].eventdat3, sizeof(JE_shortint), 1, level_f);
|
|
efread(&eventRec[x].eventdat5, sizeof(JE_shortint), 1, level_f);
|
|
efread(&eventRec[x].eventdat6, sizeof(JE_shortint), 1, level_f);
|
|
efread(&eventRec[x].eventdat4, sizeof(JE_byte), 1, level_f);
|
|
}
|
|
eventRec[x].eventtime = 65500; /*Not needed but just in case*/
|
|
|
|
/*debuginfo('Level loaded.');*/
|
|
|
|
/*debuginfo('Loading Map');*/
|
|
|
|
/* MAP SHAPE LOOKUP TABLE - Each map is directly after level */
|
|
efread(mapSh, sizeof(JE_word), sizeof(mapSh) / sizeof(JE_word), level_f);
|
|
for (temp = 0; temp < 3; temp++)
|
|
{
|
|
for (temp2 = 0; temp2 < 128; temp2++)
|
|
{
|
|
mapSh[temp][temp2] = SDL_Swap16(mapSh[temp][temp2]);
|
|
}
|
|
}
|
|
|
|
/* Read Shapes.DAT */
|
|
sprintf(tempStr, "shapes%c.dat", tolower((unsigned char)char_shapeFile));
|
|
FILE *shpFile = dir_fopen_die(data_dir(), tempStr, "rb");
|
|
|
|
for (int z = 0; z < 600; z++)
|
|
{
|
|
JE_boolean shapeBlank = fgetc(shpFile);
|
|
|
|
if (shapeBlank)
|
|
memset(shape, 0, sizeof(shape));
|
|
else
|
|
efread(shape, sizeof(JE_byte), sizeof(shape), shpFile);
|
|
|
|
/* Match 1 */
|
|
for (int x = 0; x <= 71; ++x)
|
|
{
|
|
if (mapSh[0][x] == z+1)
|
|
{
|
|
memcpy(megaData1.shapes[x].sh, shape, sizeof(JE_DanCShape));
|
|
|
|
ref[0][x] = (JE_byte *)megaData1.shapes[x].sh;
|
|
}
|
|
}
|
|
|
|
/* Match 2 */
|
|
for (int x = 0; x <= 71; ++x)
|
|
{
|
|
if (mapSh[1][x] == z+1)
|
|
{
|
|
if (x != 71 && !shapeBlank)
|
|
{
|
|
memcpy(megaData2.shapes[x].sh, shape, sizeof(JE_DanCShape));
|
|
|
|
y = 1;
|
|
for (yy = 0; yy < (24 * 28) >> 1; yy++)
|
|
if (shape[yy] == 0)
|
|
y = 0;
|
|
|
|
megaData2.shapes[x].fill = y;
|
|
ref[1][x] = (JE_byte *)megaData2.shapes[x].sh;
|
|
}
|
|
else
|
|
{
|
|
ref[1][x] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*Match 3*/
|
|
for (int x = 0; x <= 71; ++x)
|
|
{
|
|
if (mapSh[2][x] == z+1)
|
|
{
|
|
if (x < 70 && !shapeBlank)
|
|
{
|
|
memcpy(megaData3.shapes[x].sh, shape, sizeof(JE_DanCShape));
|
|
|
|
y = 1;
|
|
for (yy = 0; yy < (24 * 28) >> 1; yy++)
|
|
if (shape[yy] == 0)
|
|
y = 0;
|
|
|
|
megaData3.shapes[x].fill = y;
|
|
ref[2][x] = (JE_byte *)megaData3.shapes[x].sh;
|
|
}
|
|
else
|
|
{
|
|
ref[2][x] = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(shpFile);
|
|
|
|
efread(mapBuf, sizeof(JE_byte), 14 * 300, level_f);
|
|
bufLoc = 0; /* MAP NUMBER 1 */
|
|
for (y = 0; y < 300; y++)
|
|
{
|
|
for (x = 0; x < 14; x++)
|
|
{
|
|
megaData1.mainmap[y][x] = ref[0][mapBuf[bufLoc]];
|
|
bufLoc++;
|
|
}
|
|
}
|
|
|
|
efread(mapBuf, sizeof(JE_byte), 14 * 600, level_f);
|
|
bufLoc = 0; /* MAP NUMBER 2 */
|
|
for (y = 0; y < 600; y++)
|
|
{
|
|
for (x = 0; x < 14; x++)
|
|
{
|
|
megaData2.mainmap[y][x] = ref[1][mapBuf[bufLoc]];
|
|
bufLoc++;
|
|
}
|
|
}
|
|
|
|
efread(mapBuf, sizeof(JE_byte), 15 * 600, level_f);
|
|
bufLoc = 0; /* MAP NUMBER 3 */
|
|
for (y = 0; y < 600; y++)
|
|
{
|
|
for (x = 0; x < 15; x++)
|
|
{
|
|
megaData3.mainmap[y][x] = ref[2][mapBuf[bufLoc]];
|
|
bufLoc++;
|
|
}
|
|
}
|
|
|
|
fclose(level_f);
|
|
|
|
/* Note: The map data is automatically calculated with the correct mapsh
|
|
value and then the pointer is calculated using the formula (MAPSH-1)*168.
|
|
Then, we'll automatically add S2Ofs to get the exact offset location into
|
|
the shape table! This makes it VERY FAST! */
|
|
|
|
/*debuginfo('Map file done.');*/
|
|
/* End of find loop for LEVEL??.DAT */
|
|
}
|
|
|
|
bool JE_titleScreen( JE_boolean animate )
|
|
{
|
|
bool quit = false;
|
|
|
|
#ifdef TYRIAN2000
|
|
const int menunum = 6;
|
|
#else
|
|
const int menunum = 7;
|
|
#endif
|
|
|
|
const int menu_top = 96, menu_spacing = 14;
|
|
|
|
#ifdef ANDROID
|
|
// Show text input button in main menu, to make entering cheats possible
|
|
SDL_ANDROID_SetScreenKeyboardButtonShown(SDL_ANDROID_SCREENKEYBOARD_BUTTON_TEXT, 1);
|
|
#endif
|
|
|
|
unsigned int arcade_code_i[SA_ENGAGE] = { 0 };
|
|
|
|
JE_word waitForDemo;
|
|
int menu = 0;
|
|
JE_boolean redraw = true,
|
|
fadeIn = false;
|
|
|
|
JE_word temp; /* JE_byte temp; from varz.h will overflow in for loop */
|
|
|
|
play_demo = false;
|
|
stopped_demo = false;
|
|
|
|
redraw = true;
|
|
fadeIn = false;
|
|
|
|
gameLoaded = false;
|
|
jumpSection = false;
|
|
|
|
#ifdef WITH_NETWORK
|
|
if (isNetworkGame)
|
|
{
|
|
JE_loadPic(VGAScreen, 2, false);
|
|
memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
|
|
JE_dString(VGAScreen, JE_fontCenter("Waiting for other player.", SMALL_FONT_SHAPES), 140, "Waiting for other player.", SMALL_FONT_SHAPES);
|
|
JE_showVGA();
|
|
fade_palette(colors, 10, 0, 255);
|
|
|
|
network_connect();
|
|
|
|
twoPlayerMode = true;
|
|
if (thisPlayerNum == 1)
|
|
{
|
|
fade_black(10);
|
|
|
|
if (select_episode() && select_difficulty())
|
|
{
|
|
initialDifficulty = difficultyLevel;
|
|
|
|
difficultyLevel++; /*Make it one step harder for 2-player mode!*/
|
|
|
|
network_prepare(PACKET_DETAILS);
|
|
SDLNet_Write16(episodeNum, &packet_out_temp->data[4]);
|
|
SDLNet_Write16(difficultyLevel, &packet_out_temp->data[6]);
|
|
network_send(8); // PACKET_DETAILS
|
|
}
|
|
else
|
|
{
|
|
network_prepare(PACKET_QUIT);
|
|
network_send(4); // PACKET QUIT
|
|
|
|
network_tyrian_halt(0, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
|
|
JE_dString(VGAScreen, JE_fontCenter(networkText[4-1], SMALL_FONT_SHAPES), 140, networkText[4-1], SMALL_FONT_SHAPES);
|
|
JE_showVGA();
|
|
|
|
// until opponent sends details packet
|
|
while (true)
|
|
{
|
|
service_SDL_events(false);
|
|
JE_showVGA();
|
|
|
|
if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_DETAILS)
|
|
break;
|
|
|
|
network_update();
|
|
network_check();
|
|
|
|
SDL_Delay(16);
|
|
}
|
|
|
|
JE_initEpisode(SDLNet_Read16(&packet_in[0]->data[4]));
|
|
difficultyLevel = SDLNet_Read16(&packet_in[0]->data[6]);
|
|
initialDifficulty = difficultyLevel - 1;
|
|
fade_black(10);
|
|
|
|
network_update();
|
|
}
|
|
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
player[i].cash = 0;
|
|
|
|
player[0].items.ship = 11; // Silver Ship
|
|
|
|
while (!network_is_sync())
|
|
{
|
|
service_SDL_events(false);
|
|
JE_showVGA();
|
|
|
|
network_check();
|
|
SDL_Delay(16);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
do
|
|
{
|
|
defaultBrightness = -3;
|
|
|
|
/* Animate instead of quickly fading in */
|
|
if (redraw)
|
|
{
|
|
play_song(SONG_TITLE);
|
|
|
|
menu = 0;
|
|
redraw = false;
|
|
if (animate)
|
|
{
|
|
if (fadeIn)
|
|
{
|
|
fade_black(10);
|
|
fadeIn = false;
|
|
}
|
|
|
|
JE_loadPic(VGAScreen, 4, false);
|
|
|
|
draw_font_hv_shadow(VGAScreen, 2, 192, opentyrian_version, small_font, left_aligned, 15, 0, false, 1);
|
|
|
|
memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
|
|
|
|
temp = moveTyrianLogoUp ? 62 : 4;
|
|
|
|
blit_sprite(VGAScreenSeg, 11, temp, PLANET_SHAPES, 146); // tyrian logo
|
|
|
|
JE_showVGA();
|
|
|
|
fade_palette(colors, 10, 0, 255 - 16);
|
|
|
|
if (moveTyrianLogoUp)
|
|
{
|
|
for (temp = 61; temp >= 4; temp -= 2)
|
|
{
|
|
setjasondelay(2);
|
|
|
|
memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
|
|
|
|
blit_sprite(VGAScreenSeg, 11, temp, PLANET_SHAPES, 146); // tyrian logo
|
|
|
|
JE_showVGA();
|
|
|
|
service_wait_delay();
|
|
}
|
|
moveTyrianLogoUp = false;
|
|
}
|
|
|
|
strcpy(menuText[4], opentyrian_str); // OpenTyrian override
|
|
|
|
/* Draw Menu Text on Screen */
|
|
for (int i = 0; i <= menunum; ++i)
|
|
{
|
|
int x = VGAScreen->w / 2, y = menu_top + i * menu_spacing;
|
|
|
|
draw_font_hv(VGAScreen, x - 1, y - 1, menuText[i], normal_font, centered, 15, -10);
|
|
draw_font_hv(VGAScreen, x + 1, y + 1, menuText[i], normal_font, centered, 15, -10);
|
|
draw_font_hv(VGAScreen, x + 1, y - 1, menuText[i], normal_font, centered, 15, -10);
|
|
draw_font_hv(VGAScreen, x - 1, y + 1, menuText[i], normal_font, centered, 15, -10);
|
|
draw_font_hv(VGAScreen, x, y, menuText[i], normal_font, centered, 15, -3);
|
|
}
|
|
|
|
JE_showVGA();
|
|
|
|
fade_palette(colors, 20, 255 - 16 + 1, 255); // fade in menu items
|
|
|
|
memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h);
|
|
}
|
|
}
|
|
|
|
memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h);
|
|
|
|
// highlight selected menu item
|
|
draw_font_hv(VGAScreen, VGAScreen->w / 2, menu_top + menu * menu_spacing, menuText[menu], normal_font, centered, 15, -1);
|
|
|
|
JE_showVGA();
|
|
|
|
if (trentWin)
|
|
{
|
|
quit = true;
|
|
goto trentWinsGame;
|
|
}
|
|
|
|
waitForDemo = 2000;
|
|
JE_textMenuWait(&waitForDemo, false);
|
|
|
|
if (waitForDemo == 1)
|
|
play_demo = true;
|
|
|
|
if (select_menuitem_by_touch(menu_top, menu_spacing, menunum, &menu))
|
|
continue;
|
|
if (newkey)
|
|
{
|
|
switch (lastkey_sym)
|
|
{
|
|
case SDLK_UP:
|
|
case SDLK_LCTRL:
|
|
if (menu == 0)
|
|
menu = menunum-1;
|
|
else
|
|
menu--;
|
|
JE_playSampleNum(S_CURSOR);
|
|
break;
|
|
case SDLK_DOWN:
|
|
case SDLK_LALT:
|
|
if (menu == menunum-1)
|
|
menu = 0;
|
|
else
|
|
menu++;
|
|
JE_playSampleNum(S_CURSOR);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (unsigned int i = 0; i < SA_ENGAGE; i++)
|
|
{
|
|
if (toupper(lastkey_char) == specialName[i][arcade_code_i[i]])
|
|
arcade_code_i[i]++;
|
|
else if(lastkey_char != '\0')
|
|
arcade_code_i[i] = 0;
|
|
|
|
if (arcade_code_i[i] > 0 && arcade_code_i[i] == strlen(specialName[i]))
|
|
{
|
|
if (i+1 == SA_DESTRUCT)
|
|
{
|
|
loadDestruct = true;
|
|
}
|
|
else if (i+1 == SA_ENGAGE)
|
|
{
|
|
/* SuperTyrian */
|
|
|
|
JE_playSampleNum(V_DATA_CUBE);
|
|
JE_whoa();
|
|
|
|
initialDifficulty = keysactive[SDLK_SCROLLOCK] ? 6 : 8;
|
|
|
|
JE_clr256(VGAScreen);
|
|
JE_outText(VGAScreen, 10, 10, "Cheat codes have been disabled.", 15, 4);
|
|
if (initialDifficulty == 8)
|
|
JE_outText(VGAScreen, 10, 20, "Difficulty level has been set to Lord of Game.", 15, 4);
|
|
else
|
|
JE_outText(VGAScreen, 10, 20, "Difficulty level has been set to Suicide.", 15, 4);
|
|
JE_outText(VGAScreen, 10, 30, "It is imperative that you discover the special codes.", 15, 4);
|
|
if (initialDifficulty == 8)
|
|
JE_outText(VGAScreen, 10, 40, "(Next time, for an easier challenge hold down SCROLL LOCK.)", 15, 4);
|
|
JE_outText(VGAScreen, 10, 60, "Prepare to play...", 15, 4);
|
|
|
|
char buf[10+1+15+1];
|
|
snprintf(buf, sizeof(buf), "%s %s", miscTextB[4], pName[0]);
|
|
JE_dString(VGAScreen, JE_fontCenter(buf, FONT_SHAPES), 110, buf, FONT_SHAPES);
|
|
|
|
play_song(16);
|
|
JE_playSampleNum(V_DANGER);
|
|
JE_showVGA();
|
|
|
|
wait_noinput(true, true, true);
|
|
wait_input(true, true, true);
|
|
|
|
JE_initEpisode(1);
|
|
constantDie = false;
|
|
superTyrian = true;
|
|
onePlayerAction = true;
|
|
gameLoaded = true;
|
|
difficultyLevel = initialDifficulty;
|
|
|
|
player[0].cash = 0;
|
|
|
|
player[0].items.ship = 13; // The Stalker 21.126
|
|
player[0].items.weapon[FRONT_WEAPON].id = 39; // Atomic RailGun
|
|
}
|
|
else
|
|
{
|
|
player[0].items.ship = SAShip[i];
|
|
|
|
fade_black(10);
|
|
if (select_episode() && select_difficulty())
|
|
{
|
|
/* Start special mode! */
|
|
fade_black(10);
|
|
JE_loadPic(VGAScreen, 1, false);
|
|
JE_clr256(VGAScreen);
|
|
JE_dString(VGAScreen, JE_fontCenter(superShips[0], FONT_SHAPES), 30, superShips[0], FONT_SHAPES);
|
|
JE_dString(VGAScreen, JE_fontCenter(superShips[i+1], SMALL_FONT_SHAPES), 100, superShips[i+1], SMALL_FONT_SHAPES);
|
|
tempW = ships[player[0].items.ship].shipgraphic;
|
|
if (tempW != 1)
|
|
blit_sprite2x2(VGAScreen, 148, 70, shapes9, tempW);
|
|
|
|
JE_showVGA();
|
|
fade_palette(colors, 50, 0, 255);
|
|
|
|
wait_input(true, true, true);
|
|
|
|
twoPlayerMode = false;
|
|
onePlayerAction = true;
|
|
superArcadeMode = i+1;
|
|
gameLoaded = true;
|
|
initialDifficulty = ++difficultyLevel;
|
|
|
|
player[0].cash = 0;
|
|
|
|
player[0].items.weapon[FRONT_WEAPON].id = SAWeapon[i][0];
|
|
player[0].items.special = SASpecialWeapon[i];
|
|
if (superArcadeMode == SA_NORTSHIPZ)
|
|
{
|
|
for (uint i = 0; i < COUNTOF(player[0].items.sidekick); ++i)
|
|
player[0].items.sidekick[i] = 24; // Companion Ship Quicksilver
|
|
}
|
|
}
|
|
else
|
|
{
|
|
redraw = true;
|
|
fadeIn = true;
|
|
}
|
|
}
|
|
newkey = false;
|
|
}
|
|
}
|
|
lastkey_char = '\0';
|
|
|
|
if (newkey)
|
|
{
|
|
switch (lastkey_sym)
|
|
{
|
|
case SDLK_ESCAPE:
|
|
quit = true;
|
|
break;
|
|
case SDLK_RETURN:
|
|
case SDLK_SPACE:
|
|
JE_playSampleNum(S_SELECT);
|
|
switch (menu)
|
|
{
|
|
case 0: /* New game */
|
|
fade_black(10);
|
|
|
|
if (select_gameplay())
|
|
{
|
|
if (select_episode() && select_difficulty())
|
|
gameLoaded = true;
|
|
|
|
initialDifficulty = difficultyLevel;
|
|
|
|
if (onePlayerAction)
|
|
{
|
|
player[0].cash = 0;
|
|
|
|
player[0].items.ship = 8; // Stalker
|
|
}
|
|
else if (twoPlayerMode)
|
|
{
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
player[i].cash = 0;
|
|
|
|
player[0].items.ship = 11; // Silver Ship
|
|
|
|
difficultyLevel++;
|
|
|
|
inputDevice[0] = 1;
|
|
inputDevice[1] = 2;
|
|
}
|
|
else if (richMode)
|
|
{
|
|
player[0].cash = 1000000;
|
|
}
|
|
else
|
|
{
|
|
// allows player to smuggle arcade/super-arcade ships into full game
|
|
|
|
ulong initial_cash[] = { 10000, 15000, 20000, 30000, 35000 };
|
|
|
|
assert(episodeNum >= 1 && episodeNum <= EPISODE_AVAILABLE);
|
|
player[0].cash = initial_cash[episodeNum-1];
|
|
}
|
|
}
|
|
fadeIn = true;
|
|
break;
|
|
case 1: /* Load game */
|
|
JE_loadScreen();
|
|
fadeIn = true;
|
|
break;
|
|
case 2: /* High scores */
|
|
JE_highScoreScreen();
|
|
fadeIn = true;
|
|
break;
|
|
case 3: /* Instructions */
|
|
JE_helpSystem(1);
|
|
fadeIn = true;
|
|
break;
|
|
case 4: /* Ordering info, now OpenTyrian menu */
|
|
opentyrian_menu();
|
|
fadeIn = true;
|
|
break;
|
|
#ifdef TYRIAN2000
|
|
case 5: /* Quit */
|
|
quit = true;
|
|
break;
|
|
#else
|
|
case 5: /* Demo */
|
|
play_demo = true;
|
|
break;
|
|
case 6: /* Quit */
|
|
quit = true;
|
|
break;
|
|
#endif
|
|
}
|
|
redraw = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (!(quit || gameLoaded || jumpSection || play_demo || loadDestruct));
|
|
|
|
trentWinsGame:
|
|
fade_black(15);
|
|
}
|
|
|
|
#ifdef ANDROID
|
|
// Hide text input button for other parts of the game
|
|
SDL_ANDROID_SetScreenKeyboardButtonShown(SDL_ANDROID_SCREENKEYBOARD_BUTTON_TEXT, 0);
|
|
#endif
|
|
|
|
return quit;
|
|
}
|
|
|
|
void intro_logos( void )
|
|
{
|
|
SDL_FillRect(VGAScreen, NULL, 0);
|
|
|
|
fade_white(50);
|
|
|
|
JE_loadPic(VGAScreen, 10, false);
|
|
JE_showVGA();
|
|
|
|
fade_palette(colors, 50, 0, 255);
|
|
|
|
setjasondelay(200);
|
|
wait_delayorinput(true, true, true);
|
|
|
|
fade_black(10);
|
|
|
|
JE_loadPic(VGAScreen, 12, false);
|
|
JE_showVGA();
|
|
|
|
fade_palette(colors, 10, 0, 255);
|
|
|
|
setjasondelay(200);
|
|
wait_delayorinput(true, true, true);
|
|
|
|
fade_black(10);
|
|
}
|
|
|
|
void JE_readTextSync( void )
|
|
{
|
|
return; // this function seems to be unnecessary
|
|
|
|
JE_clr256(VGAScreen);
|
|
JE_showVGA();
|
|
JE_loadPic(VGAScreen, 1, true);
|
|
|
|
JE_barShade(VGAScreen, 3, 3, 316, 196);
|
|
JE_barShade(VGAScreen, 1, 1, 318, 198);
|
|
JE_dString(VGAScreen, 10, 160, "Waiting for other player.", SMALL_FONT_SHAPES);
|
|
JE_showVGA();
|
|
|
|
/* TODO: NETWORK */
|
|
|
|
do
|
|
{
|
|
setjasondelay(2);
|
|
|
|
/* TODO: NETWORK */
|
|
|
|
wait_delay();
|
|
|
|
} while (0 /* TODO: NETWORK */);
|
|
}
|
|
|
|
|
|
void JE_displayText( void )
|
|
{
|
|
/* Display Warning Text */
|
|
tempY = 55;
|
|
if (warningRed)
|
|
{
|
|
tempY = 2;
|
|
}
|
|
for (temp = 0; temp < levelWarningLines; temp++)
|
|
{
|
|
if (!ESCPressed)
|
|
{
|
|
JE_outCharGlow(10, tempY, levelWarningText[temp]);
|
|
|
|
if (haltGame)
|
|
{
|
|
JE_tyrianHalt(5);
|
|
}
|
|
|
|
tempY += 10;
|
|
}
|
|
}
|
|
if (frameCountMax != 0)
|
|
{
|
|
frameCountMax = 6;
|
|
temp = 1;
|
|
} else {
|
|
temp = 0;
|
|
}
|
|
textGlowFont = TINY_FONT;
|
|
tempW = 184;
|
|
if (warningRed)
|
|
{
|
|
tempW = 7 * 16 + 6;
|
|
}
|
|
|
|
JE_outCharGlow(JE_fontCenter(miscText[4], TINY_FONT), tempW, miscText[4]);
|
|
|
|
do
|
|
{
|
|
if (levelWarningDisplay)
|
|
{
|
|
JE_updateWarning(VGAScreen);
|
|
}
|
|
|
|
setjasondelay(1);
|
|
|
|
NETWORK_KEEP_ALIVE();
|
|
|
|
wait_delay();
|
|
|
|
} while (!(JE_anyButton() || (frameCountMax == 0 && temp == 1) || ESCPressed));
|
|
levelWarningDisplay = false;
|
|
}
|
|
|
|
Sint16 JE_newEnemy( int enemyOffset, Uint16 eDatI, Sint16 uniqueShapeTableI )
|
|
{
|
|
for (int i = enemyOffset; i < enemyOffset + 25; ++i)
|
|
{
|
|
if (enemyAvail[i] == 1)
|
|
{
|
|
enemyAvail[i] = JE_makeEnemy(&enemy[i], eDatI, uniqueShapeTableI);
|
|
return i + 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint JE_makeEnemy( struct JE_SingleEnemyType *enemy, Uint16 eDatI, Sint16 uniqueShapeTableI )
|
|
{
|
|
uint avail;
|
|
|
|
JE_byte shapeTableI;
|
|
|
|
if (superArcadeMode != SA_NONE && eDatI == 534)
|
|
eDatI = 533;
|
|
|
|
enemyShapeTables[5-1] = 21; /*Coins&Gems*/
|
|
enemyShapeTables[6-1] = 26; /*Two-Player Stuff*/
|
|
|
|
if (uniqueShapeTableI > 0)
|
|
{
|
|
shapeTableI = uniqueShapeTableI;
|
|
}
|
|
else
|
|
{
|
|
shapeTableI = enemyDat[eDatI].shapebank;
|
|
}
|
|
|
|
Sprite2_array *sprite2s = NULL;
|
|
for (uint i = 0; i < 6; ++i)
|
|
if (shapeTableI == enemyShapeTables[i])
|
|
sprite2s = &eShapes[i];
|
|
|
|
if (sprite2s != NULL)
|
|
enemy->sprite2s = sprite2s;
|
|
else
|
|
// maintain buggy Tyrian behavior (use shape table value from previous enemy that occupied this index in the enemy array)
|
|
fprintf(stderr, "warning: ignoring sprite from unloaded shape table %d\n", shapeTableI);
|
|
|
|
enemy->enemydatofs = &enemyDat[eDatI];
|
|
|
|
enemy->mapoffset = 0;
|
|
|
|
for (uint i = 0; i < 3; ++i)
|
|
{
|
|
enemy->eshotmultipos[i] = 0;
|
|
}
|
|
|
|
enemy->enemyground = (enemyDat[eDatI].explosiontype & 1) == 0;
|
|
enemy->explonum = enemyDat[eDatI].explosiontype >> 1;
|
|
|
|
enemy->launchfreq = enemyDat[eDatI].elaunchfreq;
|
|
enemy->launchwait = enemyDat[eDatI].elaunchfreq;
|
|
enemy->launchtype = enemyDat[eDatI].elaunchtype % 1000;
|
|
enemy->launchspecial = enemyDat[eDatI].elaunchtype / 1000;
|
|
|
|
enemy->xaccel = enemyDat[eDatI].xaccel;
|
|
enemy->yaccel = enemyDat[eDatI].yaccel;
|
|
|
|
enemy->xminbounce = -10000;
|
|
enemy->xmaxbounce = 10000;
|
|
enemy->yminbounce = -10000;
|
|
enemy->ymaxbounce = 10000;
|
|
/*Far enough away to be impossible to reach*/
|
|
|
|
for (uint i = 0; i < 3; ++i)
|
|
{
|
|
enemy->tur[i] = enemyDat[eDatI].tur[i];
|
|
}
|
|
|
|
enemy->ani = enemyDat[eDatI].ani;
|
|
enemy->animin = 1;
|
|
|
|
switch (enemyDat[eDatI].animate)
|
|
{
|
|
case 0:
|
|
enemy->enemycycle = 1;
|
|
enemy->aniactive = 0;
|
|
enemy->animax = 0;
|
|
enemy->aniwhenfire = 0;
|
|
break;
|
|
case 1:
|
|
enemy->enemycycle = 0;
|
|
enemy->aniactive = 1;
|
|
enemy->animax = 0;
|
|
enemy->aniwhenfire = 0;
|
|
break;
|
|
case 2:
|
|
enemy->enemycycle = 1;
|
|
enemy->aniactive = 2;
|
|
enemy->animax = enemy->ani;
|
|
enemy->aniwhenfire = 2;
|
|
break;
|
|
}
|
|
|
|
if (enemyDat[eDatI].startxc != 0)
|
|
enemy->ex = enemyDat[eDatI].startx + (mt_rand() % (enemyDat[eDatI].startxc * 2)) - enemyDat[eDatI].startxc + 1;
|
|
else
|
|
enemy->ex = enemyDat[eDatI].startx + 1;
|
|
|
|
if (enemyDat[eDatI].startyc != 0)
|
|
enemy->ey = enemyDat[eDatI].starty + (mt_rand() % (enemyDat[eDatI].startyc * 2)) - enemyDat[eDatI].startyc + 1;
|
|
else
|
|
enemy->ey = enemyDat[eDatI].starty + 1;
|
|
|
|
enemy->exc = enemyDat[eDatI].xmove;
|
|
enemy->eyc = enemyDat[eDatI].ymove;
|
|
enemy->excc = enemyDat[eDatI].xcaccel;
|
|
enemy->eycc = enemyDat[eDatI].ycaccel;
|
|
enemy->exccw = abs(enemy->excc);
|
|
enemy->exccwmax = enemy->exccw;
|
|
enemy->eyccw = abs(enemy->eycc);
|
|
enemy->eyccwmax = enemy->eyccw;
|
|
enemy->exccadd = (enemy->excc > 0) ? 1 : -1;
|
|
enemy->eyccadd = (enemy->eycc > 0) ? 1 : -1;
|
|
enemy->special = false;
|
|
enemy->iced = 0;
|
|
|
|
if (enemyDat[eDatI].xrev == 0)
|
|
enemy->exrev = 100;
|
|
else if (enemyDat[eDatI].xrev == -99)
|
|
enemy->exrev = 0;
|
|
else
|
|
enemy->exrev = enemyDat[eDatI].xrev;
|
|
|
|
if (enemyDat[eDatI].yrev == 0)
|
|
enemy->eyrev = 100;
|
|
else if (enemyDat[eDatI].yrev == -99)
|
|
enemy->eyrev = 0;
|
|
else
|
|
enemy->eyrev = enemyDat[eDatI].yrev;
|
|
|
|
enemy->exca = (enemy->xaccel > 0) ? 1 : -1;
|
|
enemy->eyca = (enemy->yaccel > 0) ? 1 : -1;
|
|
|
|
enemy->enemytype = eDatI;
|
|
|
|
for (uint i = 0; i < 3; ++i)
|
|
{
|
|
if (enemy->tur[i] == 252)
|
|
enemy->eshotwait[i] = 1;
|
|
else if (enemy->tur[i] > 0)
|
|
enemy->eshotwait[i] = 20;
|
|
else
|
|
enemy->eshotwait[i] = 255;
|
|
}
|
|
for (uint i = 0; i < 20; ++i)
|
|
enemy->egr[i] = enemyDat[eDatI].egraphic[i];
|
|
enemy->size = enemyDat[eDatI].esize;
|
|
enemy->linknum = 0;
|
|
enemy->edamaged = enemyDat[eDatI].dani < 0;
|
|
enemy->enemydie = enemyDat[eDatI].eenemydie;
|
|
|
|
enemy->freq[1-1] = enemyDat[eDatI].freq[1-1];
|
|
enemy->freq[2-1] = enemyDat[eDatI].freq[2-1];
|
|
enemy->freq[3-1] = enemyDat[eDatI].freq[3-1];
|
|
|
|
enemy->edani = enemyDat[eDatI].dani;
|
|
enemy->edgr = enemyDat[eDatI].dgr;
|
|
enemy->edlevel = enemyDat[eDatI].dlevel;
|
|
|
|
enemy->fixedmovey = 0;
|
|
|
|
enemy->filter = 0x00;
|
|
|
|
int tempValue = 0;
|
|
if (enemyDat[eDatI].value > 1 && enemyDat[eDatI].value < 10000)
|
|
{
|
|
switch (difficultyLevel)
|
|
{
|
|
case -1:
|
|
case 0:
|
|
tempValue = enemyDat[eDatI].value * 0.75f;
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
tempValue = enemyDat[eDatI].value;
|
|
break;
|
|
case 3:
|
|
tempValue = enemyDat[eDatI].value * 1.125f;
|
|
break;
|
|
case 4:
|
|
tempValue = enemyDat[eDatI].value * 1.5f;
|
|
break;
|
|
case 5:
|
|
tempValue = enemyDat[eDatI].value * 2;
|
|
break;
|
|
case 6:
|
|
tempValue = enemyDat[eDatI].value * 2.5f;
|
|
break;
|
|
case 7:
|
|
case 8:
|
|
tempValue = enemyDat[eDatI].value * 4;
|
|
break;
|
|
case 9:
|
|
case 10:
|
|
tempValue = enemyDat[eDatI].value * 8;
|
|
break;
|
|
}
|
|
if (tempValue > 10000)
|
|
tempValue = 10000;
|
|
enemy->evalue = tempValue;
|
|
}
|
|
else
|
|
{
|
|
enemy->evalue = enemyDat[eDatI].value;
|
|
}
|
|
|
|
int tempArmor = 1;
|
|
if (enemyDat[eDatI].armor > 0)
|
|
{
|
|
if (enemyDat[eDatI].armor != 255)
|
|
{
|
|
switch (difficultyLevel)
|
|
{
|
|
case -1:
|
|
case 0:
|
|
tempArmor = enemyDat[eDatI].armor * 0.5f + 1;
|
|
break;
|
|
case 1:
|
|
tempArmor = enemyDat[eDatI].armor * 0.75f + 1;
|
|
break;
|
|
case 2:
|
|
tempArmor = enemyDat[eDatI].armor;
|
|
break;
|
|
case 3:
|
|
tempArmor = enemyDat[eDatI].armor * 1.2f;
|
|
break;
|
|
case 4:
|
|
tempArmor = enemyDat[eDatI].armor * 1.5f;
|
|
break;
|
|
case 5:
|
|
tempArmor = enemyDat[eDatI].armor * 1.8f;
|
|
break;
|
|
case 6:
|
|
tempArmor = enemyDat[eDatI].armor * 2;
|
|
break;
|
|
case 7:
|
|
tempArmor = enemyDat[eDatI].armor * 3;
|
|
break;
|
|
case 8:
|
|
tempArmor = enemyDat[eDatI].armor * 4;
|
|
break;
|
|
case 9:
|
|
case 10:
|
|
tempArmor = enemyDat[eDatI].armor * 8;
|
|
break;
|
|
}
|
|
|
|
if (tempArmor > 254)
|
|
{
|
|
tempArmor = 254;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tempArmor = 255;
|
|
}
|
|
|
|
enemy->armorleft = tempArmor;
|
|
|
|
avail = 0;
|
|
enemy->scoreitem = false;
|
|
}
|
|
else
|
|
{
|
|
avail = 2;
|
|
enemy->armorleft = 255;
|
|
if (enemy->evalue != 0)
|
|
enemy->scoreitem = true;
|
|
}
|
|
|
|
if (!enemy->scoreitem)
|
|
{
|
|
totalEnemy++; /*Destruction ratio*/
|
|
}
|
|
|
|
/* indicates what to set ENEMYAVAIL to */
|
|
return avail;
|
|
}
|
|
|
|
void JE_createNewEventEnemy( JE_byte enemyTypeOfs, JE_word enemyOffset, Sint16 uniqueShapeTableI )
|
|
{
|
|
int i;
|
|
|
|
b = 0;
|
|
|
|
for(i = enemyOffset; i < enemyOffset + 25; i++)
|
|
{
|
|
if (enemyAvail[i] == 1)
|
|
{
|
|
b = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (b == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tempW = eventRec[eventLoc-1].eventdat + enemyTypeOfs;
|
|
|
|
enemyAvail[b-1] = JE_makeEnemy(&enemy[b-1], tempW, uniqueShapeTableI);
|
|
|
|
if (eventRec[eventLoc-1].eventdat2 != -99)
|
|
{
|
|
switch (enemyOffset)
|
|
{
|
|
case 0:
|
|
enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - (mapX - 1) * 24;
|
|
enemy[b-1].ey -= backMove2;
|
|
break;
|
|
case 25:
|
|
case 75:
|
|
enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - (mapX - 1) * 24 - 12;
|
|
enemy[b-1].ey -= backMove;
|
|
break;
|
|
case 50:
|
|
if (background3x1)
|
|
{
|
|
enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - (mapX - 1) * 24 - 12;
|
|
} else {
|
|
enemy[b-1].ex = eventRec[eventLoc-1].eventdat2 - mapX3 * 24 - 24 * 2 + 6;
|
|
}
|
|
enemy[b-1].ey -= backMove3;
|
|
|
|
if (background3x1b)
|
|
{
|
|
enemy[b-1].ex -= 6;
|
|
}
|
|
break;
|
|
}
|
|
enemy[b-1].ey = -28;
|
|
if (background3x1b && enemyOffset == 50)
|
|
{
|
|
enemy[b-1].ey += 4;
|
|
}
|
|
}
|
|
|
|
if (smallEnemyAdjust && enemy[b-1].size == 0)
|
|
{
|
|
enemy[b-1].ex -= 10;
|
|
enemy[b-1].ey -= 7;
|
|
}
|
|
|
|
enemy[b-1].ey += eventRec[eventLoc-1].eventdat5;
|
|
enemy[b-1].eyc += eventRec[eventLoc-1].eventdat3;
|
|
enemy[b-1].linknum = eventRec[eventLoc-1].eventdat4;
|
|
enemy[b-1].fixedmovey = eventRec[eventLoc-1].eventdat6;
|
|
}
|
|
|
|
void JE_eventJump( JE_word jump )
|
|
{
|
|
JE_word tempW;
|
|
|
|
if (jump == 65535)
|
|
{
|
|
curLoc = returnLoc;
|
|
}
|
|
else
|
|
{
|
|
returnLoc = curLoc + 1;
|
|
curLoc = jump;
|
|
}
|
|
tempW = 0;
|
|
do
|
|
{
|
|
tempW++;
|
|
}
|
|
while (!(eventRec[tempW-1].eventtime >= curLoc));
|
|
eventLoc = tempW - 1;
|
|
}
|
|
|
|
bool JE_searchFor/*enemy*/( JE_byte PLType, JE_byte* out_index )
|
|
{
|
|
int found_id = -1;
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
if (enemyAvail[i] == 0 && enemy[i].linknum == PLType)
|
|
{
|
|
found_id = i;
|
|
if (galagaMode)
|
|
{
|
|
enemy[i].evalue += enemy[i].evalue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found_id != -1) {
|
|
if (out_index) {
|
|
*out_index = found_id;
|
|
}
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void JE_eventSystem( void )
|
|
{
|
|
switch (eventRec[eventLoc-1].eventtype)
|
|
{
|
|
case 1:
|
|
starfield_speed = eventRec[eventLoc-1].eventdat;
|
|
break;
|
|
|
|
case 2:
|
|
map1YDelay = 1;
|
|
map1YDelayMax = 1;
|
|
map2YDelay = 1;
|
|
map2YDelayMax = 1;
|
|
|
|
backMove = eventRec[eventLoc-1].eventdat;
|
|
backMove2 = eventRec[eventLoc-1].eventdat2;
|
|
|
|
if (backMove2 > 0)
|
|
explodeMove = backMove2;
|
|
else
|
|
explodeMove = backMove;
|
|
|
|
backMove3 = eventRec[eventLoc-1].eventdat3;
|
|
|
|
if (backMove > 0)
|
|
stopBackgroundNum = 0;
|
|
break;
|
|
|
|
case 3:
|
|
backMove = 1;
|
|
map1YDelay = 3;
|
|
map1YDelayMax = 3;
|
|
backMove2 = 1;
|
|
map2YDelay = 2;
|
|
map2YDelayMax = 2;
|
|
backMove3 = 1;
|
|
break;
|
|
|
|
case 4:
|
|
stopBackgrounds = true;
|
|
switch (eventRec[eventLoc-1].eventdat)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
stopBackgroundNum = 1;
|
|
break;
|
|
case 2:
|
|
stopBackgroundNum = 2;
|
|
break;
|
|
case 3:
|
|
stopBackgroundNum = 3;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 5: // load enemy shape banks
|
|
{
|
|
Uint8 newEnemyShapeTables[] =
|
|
{
|
|
eventRec[eventLoc-1].eventdat > 0 ? eventRec[eventLoc-1].eventdat : 0,
|
|
eventRec[eventLoc-1].eventdat2 > 0 ? eventRec[eventLoc-1].eventdat2 : 0,
|
|
eventRec[eventLoc-1].eventdat3 > 0 ? eventRec[eventLoc-1].eventdat3 : 0,
|
|
eventRec[eventLoc-1].eventdat4 > 0 ? eventRec[eventLoc-1].eventdat4 : 0,
|
|
};
|
|
|
|
for (unsigned int i = 0; i < COUNTOF(newEnemyShapeTables); ++i)
|
|
{
|
|
if (enemyShapeTables[i] != newEnemyShapeTables[i])
|
|
{
|
|
if (newEnemyShapeTables[i] > 0)
|
|
{
|
|
assert(newEnemyShapeTables[i] <= COUNTOF(shapeFile));
|
|
JE_loadCompShapes(&eShapes[i], shapeFile[newEnemyShapeTables[i] - 1]);
|
|
}
|
|
else
|
|
free_sprite2s(&eShapes[i]);
|
|
|
|
enemyShapeTables[i] = newEnemyShapeTables[i];
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 6: /* Ground Enemy */
|
|
JE_createNewEventEnemy(0, 25, 0);
|
|
break;
|
|
|
|
case 7: /* Top Enemy */
|
|
JE_createNewEventEnemy(0, 50, 0);
|
|
break;
|
|
|
|
case 8:
|
|
starActive = false;
|
|
break;
|
|
|
|
case 9:
|
|
starActive = true;
|
|
break;
|
|
|
|
case 10: /* Ground Enemy 2 */
|
|
JE_createNewEventEnemy(0, 75, 0);
|
|
break;
|
|
|
|
case 11:
|
|
if (allPlayersGone || eventRec[eventLoc-1].eventdat == 1)
|
|
reallyEndLevel = true;
|
|
else
|
|
if (!endLevel)
|
|
{
|
|
readyToEndLevel = false;
|
|
endLevel = true;
|
|
levelEnd = 40;
|
|
}
|
|
break;
|
|
|
|
case 12: /* Custom 4x4 Ground Enemy */
|
|
{
|
|
uint temp = 0;
|
|
switch (eventRec[eventLoc-1].eventdat6)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
temp = 25;
|
|
break;
|
|
case 2:
|
|
temp = 0;
|
|
break;
|
|
case 3:
|
|
temp = 50;
|
|
break;
|
|
case 4:
|
|
temp = 75;
|
|
break;
|
|
}
|
|
eventRec[eventLoc-1].eventdat6 = 0; /* We use EVENTDAT6 for the background */
|
|
JE_createNewEventEnemy(0, temp, 0);
|
|
JE_createNewEventEnemy(1, temp, 0);
|
|
enemy[b-1].ex += 24;
|
|
JE_createNewEventEnemy(2, temp, 0);
|
|
enemy[b-1].ey -= 28;
|
|
JE_createNewEventEnemy(3, temp, 0);
|
|
enemy[b-1].ex += 24;
|
|
enemy[b-1].ey -= 28;
|
|
break;
|
|
}
|
|
case 13:
|
|
enemiesActive = false;
|
|
break;
|
|
|
|
case 14:
|
|
enemiesActive = true;
|
|
break;
|
|
|
|
case 15: /* Sky Enemy */
|
|
JE_createNewEventEnemy(0, 0, 0);
|
|
break;
|
|
|
|
case 16:
|
|
if (eventRec[eventLoc-1].eventdat > 9)
|
|
{
|
|
fprintf(stderr, "warning: event 16: bad event data\n");
|
|
}
|
|
else
|
|
{
|
|
JE_drawTextWindow(outputs[eventRec[eventLoc-1].eventdat-1]);
|
|
soundQueue[3] = windowTextSamples[eventRec[eventLoc-1].eventdat-1];
|
|
}
|
|
break;
|
|
|
|
case 17: /* Ground Bottom */
|
|
JE_createNewEventEnemy(0, 25, 0);
|
|
if (b > 0)
|
|
{
|
|
enemy[b-1].ey = 190 + eventRec[eventLoc-1].eventdat5;
|
|
}
|
|
break;
|
|
|
|
case 18: /* Sky Enemy on Bottom */
|
|
JE_createNewEventEnemy(0, 0, 0);
|
|
if (b > 0)
|
|
{
|
|
enemy[b-1].ey = 190 + eventRec[eventLoc-1].eventdat5;
|
|
}
|
|
break;
|
|
|
|
case 19: /* Enemy Global Move */
|
|
{
|
|
int initial_i = 0, max_i = 0;
|
|
bool all_enemies = false;
|
|
|
|
if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90)
|
|
{
|
|
initial_i = 0;
|
|
max_i = 100;
|
|
all_enemies = false;
|
|
eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80];
|
|
}
|
|
else
|
|
{
|
|
switch (eventRec[eventLoc-1].eventdat3)
|
|
{
|
|
case 0:
|
|
initial_i = 0;
|
|
max_i = 100;
|
|
all_enemies = false;
|
|
break;
|
|
case 2:
|
|
initial_i = 0;
|
|
max_i = 25;
|
|
all_enemies = true;
|
|
break;
|
|
case 1:
|
|
initial_i = 25;
|
|
max_i = 50;
|
|
all_enemies = true;
|
|
break;
|
|
case 3:
|
|
initial_i = 50;
|
|
max_i = 75;
|
|
all_enemies = true;
|
|
break;
|
|
case 99:
|
|
initial_i = 0;
|
|
max_i = 100;
|
|
all_enemies = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (int i = initial_i; i < max_i; i++)
|
|
{
|
|
if (all_enemies || enemy[i].linknum == eventRec[eventLoc-1].eventdat4)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat != -99)
|
|
enemy[i].exc = eventRec[eventLoc-1].eventdat;
|
|
|
|
if (eventRec[eventLoc-1].eventdat2 != -99)
|
|
enemy[i].eyc = eventRec[eventLoc-1].eventdat2;
|
|
|
|
if (eventRec[eventLoc-1].eventdat6 != 0)
|
|
enemy[i].fixedmovey = eventRec[eventLoc-1].eventdat6;
|
|
|
|
if (eventRec[eventLoc-1].eventdat6 == -99)
|
|
enemy[i].fixedmovey = 0;
|
|
|
|
if (eventRec[eventLoc-1].eventdat5 > 0)
|
|
enemy[i].enemycycle = eventRec[eventLoc-1].eventdat5;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 20: /* Enemy Global Accel */
|
|
if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90)
|
|
eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80];
|
|
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (enemyAvail[temp] != 1
|
|
&& (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4 || eventRec[eventLoc-1].eventdat4 == 0))
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat != -99)
|
|
{
|
|
enemy[temp].excc = eventRec[eventLoc-1].eventdat;
|
|
enemy[temp].exccw = abs(eventRec[eventLoc-1].eventdat);
|
|
enemy[temp].exccwmax = abs(eventRec[eventLoc-1].eventdat);
|
|
if (eventRec[eventLoc-1].eventdat > 0)
|
|
enemy[temp].exccadd = 1;
|
|
else
|
|
enemy[temp].exccadd = -1;
|
|
}
|
|
|
|
if (eventRec[eventLoc-1].eventdat2 != -99)
|
|
{
|
|
enemy[temp].eycc = eventRec[eventLoc-1].eventdat2;
|
|
enemy[temp].eyccw = abs(eventRec[eventLoc-1].eventdat2);
|
|
enemy[temp].eyccwmax = abs(eventRec[eventLoc-1].eventdat2);
|
|
if (eventRec[eventLoc-1].eventdat2 > 0)
|
|
enemy[temp].eyccadd = 1;
|
|
else
|
|
enemy[temp].eyccadd = -1;
|
|
}
|
|
|
|
if (eventRec[eventLoc-1].eventdat5 > 0)
|
|
{
|
|
enemy[temp].enemycycle = eventRec[eventLoc-1].eventdat5;
|
|
}
|
|
if (eventRec[eventLoc-1].eventdat6 > 0)
|
|
{
|
|
enemy[temp].ani = eventRec[eventLoc-1].eventdat6;
|
|
enemy[temp].animin = eventRec[eventLoc-1].eventdat5;
|
|
enemy[temp].animax = 0;
|
|
enemy[temp].aniactive = 1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 21:
|
|
background3over = 1;
|
|
break;
|
|
|
|
case 22:
|
|
background3over = 0;
|
|
break;
|
|
|
|
case 23: /* Sky Enemy on Bottom */
|
|
JE_createNewEventEnemy(0, 50, 0);
|
|
if (b > 0)
|
|
enemy[b-1].ey = 180 + eventRec[eventLoc-1].eventdat5;
|
|
break;
|
|
|
|
case 24: /* Enemy Global Animate */
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
|
|
{
|
|
enemy[temp].aniactive = 1;
|
|
enemy[temp].aniwhenfire = 0;
|
|
if (eventRec[eventLoc-1].eventdat2 > 0)
|
|
{
|
|
enemy[temp].enemycycle = eventRec[eventLoc-1].eventdat2;
|
|
enemy[temp].animin = enemy[temp].enemycycle;
|
|
}
|
|
else
|
|
{
|
|
enemy[temp].enemycycle = 0;
|
|
}
|
|
|
|
if (eventRec[eventLoc-1].eventdat > 0)
|
|
enemy[temp].ani = eventRec[eventLoc-1].eventdat;
|
|
|
|
if (eventRec[eventLoc-1].eventdat3 == 1)
|
|
{
|
|
enemy[temp].animax = enemy[temp].ani;
|
|
}
|
|
else if (eventRec[eventLoc-1].eventdat3 == 2)
|
|
{
|
|
enemy[temp].aniactive = 2;
|
|
enemy[temp].animax = enemy[temp].ani;
|
|
enemy[temp].aniwhenfire = 2;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 25: /* Enemy Global Damage change */
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
|
|
{
|
|
if (galagaMode)
|
|
enemy[temp].armorleft = roundf(eventRec[eventLoc-1].eventdat * (difficultyLevel / 2));
|
|
else
|
|
enemy[temp].armorleft = eventRec[eventLoc-1].eventdat;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 26:
|
|
smallEnemyAdjust = eventRec[eventLoc-1].eventdat;
|
|
break;
|
|
|
|
case 27: /* Enemy Global AccelRev */
|
|
if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90)
|
|
eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80];
|
|
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat != -99)
|
|
enemy[temp].exrev = eventRec[eventLoc-1].eventdat;
|
|
if (eventRec[eventLoc-1].eventdat2 != -99)
|
|
enemy[temp].eyrev = eventRec[eventLoc-1].eventdat2;
|
|
if (eventRec[eventLoc-1].eventdat3 != 0 && eventRec[eventLoc-1].eventdat3 < 17)
|
|
enemy[temp].filter = eventRec[eventLoc-1].eventdat3;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 28:
|
|
topEnemyOver = false;
|
|
break;
|
|
|
|
case 29:
|
|
topEnemyOver = true;
|
|
break;
|
|
|
|
case 30:
|
|
map1YDelay = 1;
|
|
map1YDelayMax = 1;
|
|
map2YDelay = 1;
|
|
map2YDelayMax = 1;
|
|
|
|
backMove = eventRec[eventLoc-1].eventdat;
|
|
backMove2 = eventRec[eventLoc-1].eventdat2;
|
|
explodeMove = backMove2;
|
|
backMove3 = eventRec[eventLoc-1].eventdat3;
|
|
break;
|
|
|
|
case 31: /* Enemy Fire Override */
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat4 == 99 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
|
|
{
|
|
enemy[temp].freq[1-1] = eventRec[eventLoc-1].eventdat ;
|
|
enemy[temp].freq[2-1] = eventRec[eventLoc-1].eventdat2;
|
|
enemy[temp].freq[3-1] = eventRec[eventLoc-1].eventdat3;
|
|
for (temp2 = 0; temp2 < 3; temp2++)
|
|
{
|
|
enemy[temp].eshotwait[temp2] = 1;
|
|
}
|
|
if (enemy[temp].launchtype > 0)
|
|
{
|
|
enemy[temp].launchfreq = eventRec[eventLoc-1].eventdat5;
|
|
enemy[temp].launchwait = 1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 32: // create enemy
|
|
JE_createNewEventEnemy(0, 50, 0);
|
|
if (b > 0)
|
|
enemy[b-1].ey = 190;
|
|
break;
|
|
|
|
case 33: /* Enemy From other Enemies */
|
|
if (!((eventRec[eventLoc-1].eventdat == 512 || eventRec[eventLoc-1].eventdat == 513) && (twoPlayerMode || onePlayerAction || superTyrian)))
|
|
{
|
|
if (superArcadeMode != SA_NONE)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat == 534)
|
|
eventRec[eventLoc-1].eventdat = 827;
|
|
}
|
|
else if (!superTyrian)
|
|
{
|
|
const uint lives = *player[0].lives;
|
|
|
|
if (eventRec[eventLoc-1].eventdat == 533 && (lives == 11 || (mt_rand() % 15) < lives))
|
|
{
|
|
// enemy will drop random special weapon
|
|
eventRec[eventLoc-1].eventdat = 829 + (mt_rand() % 6);
|
|
}
|
|
}
|
|
if (eventRec[eventLoc-1].eventdat == 534 && superTyrian)
|
|
eventRec[eventLoc-1].eventdat = 828 + superTyrianSpecials[mt_rand() % 4];
|
|
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
|
|
enemy[temp].enemydie = eventRec[eventLoc-1].eventdat;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 34: /* Start Music Fade */
|
|
if (firstGameOver)
|
|
{
|
|
musicFade = true;
|
|
tempVolume = tyrMusicVolume;
|
|
}
|
|
break;
|
|
|
|
case 35: /* Play new song */
|
|
if (firstGameOver)
|
|
{
|
|
play_song(eventRec[eventLoc-1].eventdat - 1);
|
|
set_volume(tyrMusicVolume, fxVolume);
|
|
}
|
|
musicFade = false;
|
|
break;
|
|
|
|
case 36:
|
|
readyToEndLevel = true;
|
|
break;
|
|
|
|
case 37:
|
|
levelEnemyFrequency = eventRec[eventLoc-1].eventdat;
|
|
break;
|
|
|
|
case 38:
|
|
curLoc = eventRec[eventLoc-1].eventdat;
|
|
int new_event_loc = 1;
|
|
for (tempW = 0; tempW < maxEvent; tempW++)
|
|
{
|
|
if (eventRec[tempW].eventtime <= curLoc)
|
|
{
|
|
new_event_loc = tempW+1 - 1;
|
|
}
|
|
}
|
|
eventLoc = new_event_loc;
|
|
break;
|
|
|
|
case 39: /* Enemy Global Linknum Change */
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat)
|
|
enemy[temp].linknum = eventRec[eventLoc-1].eventdat2;
|
|
}
|
|
break;
|
|
|
|
case 40: /* Enemy Continual Damage */
|
|
enemyContinualDamage = true;
|
|
break;
|
|
|
|
case 41:
|
|
if (eventRec[eventLoc-1].eventdat == 0)
|
|
{
|
|
memset(enemyAvail, 1, sizeof(enemyAvail));
|
|
}
|
|
else
|
|
{
|
|
for (x = 0; x <= 24; x++)
|
|
enemyAvail[x] = 1;
|
|
}
|
|
break;
|
|
|
|
case 42:
|
|
background3over = 2;
|
|
break;
|
|
|
|
case 43:
|
|
background2over = eventRec[eventLoc-1].eventdat;
|
|
break;
|
|
|
|
case 44:
|
|
filterActive = (eventRec[eventLoc-1].eventdat > 0);
|
|
filterFade = (eventRec[eventLoc-1].eventdat == 2);
|
|
levelFilter = eventRec[eventLoc-1].eventdat2;
|
|
levelBrightness = eventRec[eventLoc-1].eventdat3;
|
|
levelFilterNew = eventRec[eventLoc-1].eventdat4;
|
|
levelBrightnessChg = eventRec[eventLoc-1].eventdat5;
|
|
filterFadeStart = (eventRec[eventLoc-1].eventdat6 == 0);
|
|
break;
|
|
|
|
case 45: /* arcade-only enemy from other enemies */
|
|
if (!superTyrian)
|
|
{
|
|
const uint lives = *player[0].lives;
|
|
|
|
if (eventRec[eventLoc-1].eventdat == 533 && (lives == 11 || (mt_rand() % 15) < lives))
|
|
{
|
|
eventRec[eventLoc-1].eventdat = 829 + (mt_rand() % 6);
|
|
}
|
|
if (twoPlayerMode || onePlayerAction)
|
|
{
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
|
|
enemy[temp].enemydie = eventRec[eventLoc-1].eventdat;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 46: // change difficulty
|
|
if (eventRec[eventLoc-1].eventdat3 != 0)
|
|
damageRate = eventRec[eventLoc-1].eventdat3;
|
|
|
|
if (eventRec[eventLoc-1].eventdat2 == 0 || twoPlayerMode || onePlayerAction)
|
|
{
|
|
difficultyLevel += eventRec[eventLoc-1].eventdat;
|
|
if (difficultyLevel < 1)
|
|
difficultyLevel = 1;
|
|
if (difficultyLevel > 10)
|
|
difficultyLevel = 10;
|
|
}
|
|
break;
|
|
|
|
case 47: /* Enemy Global AccelRev */
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
|
|
enemy[temp].armorleft = eventRec[eventLoc-1].eventdat;
|
|
}
|
|
break;
|
|
|
|
case 48: /* Background 2 Cannot be Transparent */
|
|
background2notTransparent = true;
|
|
break;
|
|
|
|
case 49:
|
|
case 50:
|
|
case 51:
|
|
case 52:
|
|
tempDat2 = eventRec[eventLoc-1].eventdat;
|
|
eventRec[eventLoc-1].eventdat = 0;
|
|
tempDat = eventRec[eventLoc-1].eventdat3;
|
|
eventRec[eventLoc-1].eventdat3 = 0;
|
|
tempDat3 = eventRec[eventLoc-1].eventdat6;
|
|
eventRec[eventLoc-1].eventdat6 = 0;
|
|
enemyDat[0].armor = tempDat3;
|
|
enemyDat[0].egraphic[1-1] = tempDat2;
|
|
switch (eventRec[eventLoc-1].eventtype - 48)
|
|
{
|
|
case 1:
|
|
temp = 25;
|
|
break;
|
|
case 2:
|
|
temp = 0;
|
|
break;
|
|
case 3:
|
|
temp = 50;
|
|
break;
|
|
case 4:
|
|
temp = 75;
|
|
break;
|
|
}
|
|
JE_createNewEventEnemy(0, temp, tempDat);
|
|
eventRec[eventLoc-1].eventdat = tempDat2;
|
|
eventRec[eventLoc-1].eventdat3 = tempDat;
|
|
eventRec[eventLoc-1].eventdat6 = tempDat3;
|
|
break;
|
|
|
|
case 53:
|
|
forceEvents = (eventRec[eventLoc-1].eventdat != 99);
|
|
break;
|
|
|
|
case 54:
|
|
JE_eventJump(eventRec[eventLoc-1].eventdat);
|
|
break;
|
|
|
|
case 55: /* Enemy Global AccelRev */
|
|
if (eventRec[eventLoc-1].eventdat3 > 79 && eventRec[eventLoc-1].eventdat3 < 90)
|
|
eventRec[eventLoc-1].eventdat4 = newPL[eventRec[eventLoc-1].eventdat3 - 80];
|
|
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat != -99)
|
|
enemy[temp].xaccel = eventRec[eventLoc-1].eventdat;
|
|
if (eventRec[eventLoc-1].eventdat2 != -99)
|
|
enemy[temp].yaccel = eventRec[eventLoc-1].eventdat2;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 56: /* Ground2 Bottom */
|
|
JE_createNewEventEnemy(0, 75, 0);
|
|
if (b > 0)
|
|
enemy[b-1].ey = 190;
|
|
break;
|
|
|
|
case 57:
|
|
superEnemy254Jump = eventRec[eventLoc-1].eventdat;
|
|
break;
|
|
|
|
case 60: /*Assign Special Enemy*/
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
|
|
{
|
|
enemy[temp].special = true;
|
|
enemy[temp].flagnum = eventRec[eventLoc-1].eventdat;
|
|
enemy[temp].setto = (eventRec[eventLoc-1].eventdat2 == 1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 61: // if specific flag set to specific value, skip events
|
|
if (globalFlags[eventRec[eventLoc-1].eventdat-1] == eventRec[eventLoc-1].eventdat2)
|
|
eventLoc += eventRec[eventLoc-1].eventdat3;
|
|
break;
|
|
|
|
case 62: /*Play sound effect*/
|
|
soundQueue[3] = eventRec[eventLoc-1].eventdat;
|
|
break;
|
|
|
|
case 63: // skip events if not in 2-player mode
|
|
if (!twoPlayerMode && !onePlayerAction)
|
|
eventLoc += eventRec[eventLoc-1].eventdat;
|
|
break;
|
|
|
|
case 64:
|
|
if (!(eventRec[eventLoc-1].eventdat == 6 && twoPlayerMode && difficultyLevel > 2))
|
|
{
|
|
smoothies[eventRec[eventLoc-1].eventdat-1] = eventRec[eventLoc-1].eventdat2;
|
|
temp = eventRec[eventLoc-1].eventdat;
|
|
if (temp == 5)
|
|
temp = 3;
|
|
smoothie_data[temp-1] = eventRec[eventLoc-1].eventdat3;
|
|
}
|
|
break;
|
|
|
|
case 65:
|
|
background3x1 = (eventRec[eventLoc-1].eventdat == 0);
|
|
break;
|
|
|
|
case 66: /*If not on this difficulty level or higher then...*/
|
|
if (initialDifficulty <= eventRec[eventLoc-1].eventdat)
|
|
eventLoc += eventRec[eventLoc-1].eventdat2;
|
|
break;
|
|
|
|
case 67:
|
|
levelTimer = (eventRec[eventLoc-1].eventdat == 1);
|
|
levelTimerCountdown = eventRec[eventLoc-1].eventdat3 * 100;
|
|
levelTimerJumpTo = eventRec[eventLoc-1].eventdat2;
|
|
break;
|
|
|
|
case 68:
|
|
randomExplosions = (eventRec[eventLoc-1].eventdat == 1);
|
|
break;
|
|
|
|
case 69:
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
player[i].invulnerable_ticks = eventRec[eventLoc-1].eventdat;
|
|
break;
|
|
|
|
case 70:
|
|
if (eventRec[eventLoc-1].eventdat2 == 0)
|
|
{ /*1-10*/
|
|
bool found = false;
|
|
|
|
for (temp = 1; temp <= 19; temp++)
|
|
found = found || JE_searchFor(temp, NULL);
|
|
|
|
if (!found)
|
|
JE_eventJump(eventRec[eventLoc-1].eventdat);
|
|
}
|
|
else if (!JE_searchFor(eventRec[eventLoc-1].eventdat2, NULL)
|
|
&& (eventRec[eventLoc-1].eventdat3 == 0 || !JE_searchFor(eventRec[eventLoc-1].eventdat3, NULL))
|
|
&& (eventRec[eventLoc-1].eventdat4 == 0 || !JE_searchFor(eventRec[eventLoc-1].eventdat4, NULL)))
|
|
{
|
|
JE_eventJump(eventRec[eventLoc-1].eventdat);
|
|
}
|
|
break;
|
|
|
|
case 71:
|
|
if (((((intptr_t)mapYPos - (intptr_t)&megaData1.mainmap) / sizeof(JE_byte *)) * 2) <= (unsigned)eventRec[eventLoc-1].eventdat2)
|
|
{
|
|
JE_eventJump(eventRec[eventLoc-1].eventdat);
|
|
}
|
|
break;
|
|
|
|
case 72:
|
|
background3x1b = (eventRec[eventLoc-1].eventdat == 1);
|
|
break;
|
|
|
|
case 73:
|
|
skyEnemyOverAll = (eventRec[eventLoc-1].eventdat == 1);
|
|
break;
|
|
|
|
case 74: /* Enemy Global BounceParams */
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat4 == 0 || enemy[temp].linknum == eventRec[eventLoc-1].eventdat4)
|
|
{
|
|
if (eventRec[eventLoc-1].eventdat5 != -99)
|
|
enemy[temp].xminbounce = eventRec[eventLoc-1].eventdat5;
|
|
|
|
if (eventRec[eventLoc-1].eventdat6 != -99)
|
|
enemy[temp].yminbounce = eventRec[eventLoc-1].eventdat6;
|
|
|
|
if (eventRec[eventLoc-1].eventdat != -99)
|
|
enemy[temp].xmaxbounce = eventRec[eventLoc-1].eventdat;
|
|
|
|
if (eventRec[eventLoc-1].eventdat2 != -99)
|
|
enemy[temp].ymaxbounce = eventRec[eventLoc-1].eventdat2;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 75:;
|
|
bool temp_no_clue = false; // TODO: figure out what this is doing
|
|
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (enemyAvail[temp] == 0
|
|
&& enemy[temp].eyc == 0
|
|
&& enemy[temp].linknum >= eventRec[eventLoc-1].eventdat
|
|
&& enemy[temp].linknum <= eventRec[eventLoc-1].eventdat2)
|
|
{
|
|
temp_no_clue = true;
|
|
}
|
|
}
|
|
|
|
if (temp_no_clue)
|
|
{
|
|
JE_byte enemy_i;
|
|
do
|
|
{
|
|
temp = (mt_rand() % (eventRec[eventLoc-1].eventdat2 + 1 - eventRec[eventLoc-1].eventdat)) + eventRec[eventLoc-1].eventdat;
|
|
}
|
|
while (!(JE_searchFor(temp, &enemy_i) && enemy[enemy_i].eyc == 0));
|
|
|
|
newPL[eventRec[eventLoc-1].eventdat3 - 80] = temp;
|
|
}
|
|
else
|
|
{
|
|
newPL[eventRec[eventLoc-1].eventdat3 - 80] = 255;
|
|
if (eventRec[eventLoc-1].eventdat4 > 0)
|
|
{ /*Skip*/
|
|
curLoc = eventRec[eventLoc-1 + eventRec[eventLoc-1].eventdat4].eventtime - 1;
|
|
eventLoc += eventRec[eventLoc-1].eventdat4 - 1;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 76:
|
|
returnActive = true;
|
|
break;
|
|
|
|
case 77:
|
|
mapYPos = &megaData1.mainmap[0][0];
|
|
mapYPos += eventRec[eventLoc-1].eventdat / 2;
|
|
if (eventRec[eventLoc-1].eventdat2 > 0)
|
|
{
|
|
mapY2Pos = &megaData2.mainmap[0][0];
|
|
mapY2Pos += eventRec[eventLoc-1].eventdat2 / 2;
|
|
}
|
|
else
|
|
{
|
|
mapY2Pos = &megaData2.mainmap[0][0];
|
|
mapY2Pos += eventRec[eventLoc-1].eventdat / 2;
|
|
}
|
|
break;
|
|
|
|
case 78:
|
|
if (galagaShotFreq < 10)
|
|
galagaShotFreq++;
|
|
break;
|
|
|
|
case 79:
|
|
boss_bar[0].link_num = eventRec[eventLoc-1].eventdat;
|
|
boss_bar[1].link_num = eventRec[eventLoc-1].eventdat2;
|
|
break;
|
|
|
|
case 80: // skip events if in 2-player mode
|
|
if (twoPlayerMode)
|
|
eventLoc += eventRec[eventLoc-1].eventdat;
|
|
break;
|
|
|
|
case 81: /*WRAP2*/
|
|
BKwrap2 = &megaData2.mainmap[0][0];
|
|
BKwrap2 += eventRec[eventLoc-1].eventdat / 2;
|
|
BKwrap2to = &megaData2.mainmap[0][0];
|
|
BKwrap2to += eventRec[eventLoc-1].eventdat2 / 2;
|
|
break;
|
|
|
|
case 82: /*Give SPECIAL WEAPON*/
|
|
player[0].items.special = eventRec[eventLoc-1].eventdat;
|
|
shotMultiPos[SHOT_SPECIAL] = 0;
|
|
shotRepeat[SHOT_SPECIAL] = 0;
|
|
shotMultiPos[SHOT_SPECIAL2] = 0;
|
|
shotRepeat[SHOT_SPECIAL2] = 0;
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "warning: ignoring unknown event %d\n", eventRec[eventLoc-1].eventtype);
|
|
break;
|
|
}
|
|
|
|
eventLoc++;
|
|
}
|
|
|
|
void JE_whoa( void )
|
|
{
|
|
unsigned int i, j, color, offset, timer;
|
|
unsigned int screenSize, topBorder, bottomBorder;
|
|
Uint8 * TempScreen1, * TempScreen2, * TempScreenSwap;
|
|
|
|
/* 'whoa' gets us that nifty screen fade used when you type in
|
|
* 'engage'. We need two temporary screen buffers (char arrays can
|
|
* work too, but these screens already exist) for our effect.
|
|
* This could probably be a lot more efficient (there's probably a
|
|
* way to get vgascreen as one of the temp buffers), but it's only called
|
|
* once so don't worry about it. */
|
|
|
|
TempScreen1 = game_screen->pixels;
|
|
TempScreen2 = VGAScreen2->pixels;
|
|
|
|
screenSize = VGAScreenSeg->h * VGAScreenSeg->pitch;
|
|
topBorder = VGAScreenSeg->pitch * 4; /* Seems an arbitrary number of lines */
|
|
bottomBorder = VGAScreenSeg->pitch * 7;
|
|
|
|
/* Okay, one disadvantage to using other screens as temp buffers: they
|
|
* need to be the right size. I doubt they'l ever be anything but 320x200,
|
|
* but just in case, these asserts will clue in whoever stumbles across
|
|
* the problem. You can fix it with the stack or malloc. */
|
|
assert( (unsigned)VGAScreen2->h * VGAScreen2->pitch >= screenSize
|
|
&& (unsigned)game_screen->h * game_screen->pitch >= screenSize);
|
|
|
|
|
|
/* Clear the top and bottom borders. We don't want to process
|
|
* them and we don't want to draw them. */
|
|
memset((Uint8 *)VGAScreenSeg->pixels, 0, topBorder);
|
|
memset((Uint8 *)VGAScreenSeg->pixels + screenSize - bottomBorder, 0, bottomBorder);
|
|
|
|
/* Copy our test subject to one of the temporary buffers. Blank the other */
|
|
memset(TempScreen1, 0, screenSize);
|
|
memcpy(TempScreen2, VGAScreenSeg->pixels, VGAScreenSeg->h * VGAScreenSeg->pitch);
|
|
|
|
|
|
service_SDL_events(true);
|
|
timer = 300; /* About 300 rounds is enough to make the screen mostly black */
|
|
|
|
do
|
|
{
|
|
setjasondelay(1);
|
|
|
|
/* This gets us our 'whoa' effect with pixel bleeding magic.
|
|
* I'm willing to bet the guy who originally wrote the asm was goofing
|
|
* around on acid and thought this looked good enough to use. */
|
|
for (i = screenSize - bottomBorder, j = topBorder / 2; i > 0; i--, j++)
|
|
{
|
|
offset = j + i/8192 - 4;
|
|
color = (TempScreen2[offset ] * 12 +
|
|
TempScreen1[offset-VGAScreenSeg->pitch] +
|
|
TempScreen1[offset-1 ] +
|
|
TempScreen1[offset+1 ] +
|
|
TempScreen1[offset+VGAScreenSeg->pitch]) / 16;
|
|
|
|
TempScreen1[j] = color;
|
|
}
|
|
|
|
/* Now copy that mess to the buffer. */
|
|
memcpy((Uint8 *)VGAScreenSeg->pixels + topBorder, TempScreen1 + topBorder, screenSize - bottomBorder);
|
|
|
|
JE_showVGA();
|
|
|
|
timer--;
|
|
wait_delay();
|
|
|
|
/* Flip the buffer. */
|
|
TempScreenSwap = TempScreen1;
|
|
TempScreen1 = TempScreen2;
|
|
TempScreen2 = TempScreenSwap;
|
|
|
|
} while (!(timer == 0 || JE_anyButton()));
|
|
|
|
levelWarningLines = 4;
|
|
}
|
|
|
|
void JE_barX( JE_word x1, JE_word y1, JE_word x2, JE_word y2, JE_byte col )
|
|
{
|
|
fill_rectangle_xy(VGAScreen, x1, y1, x2, y1, col + 1);
|
|
fill_rectangle_xy(VGAScreen, x1, y1 + 1, x2, y2 - 1, col );
|
|
fill_rectangle_xy(VGAScreen, x1, y2, x2, y2, col - 1);
|
|
}
|
|
|
|
void draw_boss_bar( void )
|
|
{
|
|
for (unsigned int b = 0; b < COUNTOF(boss_bar); b++)
|
|
{
|
|
if (boss_bar[b].link_num == 0)
|
|
continue;
|
|
|
|
unsigned int armor = 256; // higher than armor max
|
|
|
|
for (unsigned int e = 0; e < COUNTOF(enemy); e++) // find most damaged
|
|
{
|
|
if (enemyAvail[e] != 1 && enemy[e].linknum == boss_bar[b].link_num)
|
|
if (enemy[e].armorleft < armor)
|
|
armor = enemy[e].armorleft;
|
|
}
|
|
|
|
if (armor > 255 || armor == 0) // boss dead?
|
|
boss_bar[b].link_num = 0;
|
|
else
|
|
boss_bar[b].armor = (armor == 255) ? 254 : armor; // 255 would make the bar too long
|
|
}
|
|
|
|
unsigned int bars = (boss_bar[0].link_num != 0 ? 1 : 0)
|
|
+ (boss_bar[1].link_num != 0 ? 1 : 0);
|
|
|
|
// if only one bar left, make it the first one
|
|
if (bars == 1 && boss_bar[0].link_num == 0)
|
|
{
|
|
memcpy(&boss_bar[0], &boss_bar[1], sizeof(boss_bar_t));
|
|
boss_bar[1].link_num = 0;
|
|
}
|
|
|
|
for (unsigned int b = 0; b < bars; b++)
|
|
{
|
|
unsigned int x = (bars == 2)
|
|
? ((b == 0) ? 125 : 185)
|
|
: ((levelTimer) ? 250 : 155); // level timer and boss bar would overlap
|
|
|
|
JE_barX(x - 25, 7, x + 25, 12, 115);
|
|
JE_barX(x - (boss_bar[b].armor / 10), 7, x + (boss_bar[b].armor + 5) / 10, 12, 118 + boss_bar[b].color);
|
|
|
|
if (boss_bar[b].color > 0)
|
|
boss_bar[b].color--;
|
|
}
|
|
}
|
|
|