1413 lines
36 KiB
C++
1413 lines
36 KiB
C++
/*
|
|
* OpenTyrian Classic: 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 "config.h"
|
|
#include "editship.h"
|
|
#include "episodes.h"
|
|
#include "joystick.h"
|
|
#include "lds_play.h"
|
|
#include "loudness.h"
|
|
#include "mainint.h"
|
|
#include "mouse.h"
|
|
#include "mtrand.h"
|
|
#include "network.h"
|
|
#include "nortsong.h"
|
|
#include "nortvars.h"
|
|
#include "opentyr.h"
|
|
#include "sprite.h"
|
|
#include "varz.h"
|
|
#include "vga256d.h"
|
|
#include "video.h"
|
|
|
|
JE_integer tempDat, tempDat2, tempDat3;
|
|
|
|
const JE_byte SANextShip[SA + 2] /* [0..SA + 1] */ = { 3, 9, 6, 2, 5, 1, 4, 3, 7 }; // 0 -> 3 -> 2 -> 6 -> 4 -> 5 -> 1 -> 9 -> 7
|
|
const JE_word SASpecialWeapon[SA] /* [1..SA] */ = { 7, 8, 9, 10, 11, 12, 13 };
|
|
const JE_word SASpecialWeaponB[SA] /* [1..SA] */ = {37, 6, 15, 40, 16, 14, 41 };
|
|
const JE_byte SAShip[SA] /* [1..SA] */ = { 3, 1, 5, 10, 2, 11, 12 };
|
|
const JE_word SAWeapon[SA][5] /* [1..SA, 1..5] */ =
|
|
{ /* R Bl Bk G P */
|
|
{ 9, 31, 32, 33, 34 }, /* Stealth Ship */
|
|
{ 19, 8, 22, 41, 34 }, /* StormWind */
|
|
{ 27, 5, 20, 42, 31 }, /* Techno */
|
|
{ 15, 3, 28, 22, 12 }, /* Enemy */
|
|
{ 23, 35, 25, 14, 6 }, /* Weird */
|
|
{ 2, 5, 21, 4, 7 }, /* Unknown */
|
|
{ 40, 38, 37, 41, 36 } /* NortShip Z */
|
|
};
|
|
|
|
const JE_byte specialArcadeWeapon[PORT_NUM] /* [1..Portnum] */ =
|
|
{
|
|
17,17,18,0,0,0,10,0,0,0,0,0,44,0,10,0,19,0,0,-0,0,0,0,0,0,0,
|
|
-0,0,0,0,45,0,0,0,0,0,0,0,0,0,0,0
|
|
};
|
|
|
|
const JE_byte optionSelect[16][3][2] /* [0..15, 1..3, 1..2] */ =
|
|
{ /* MAIN OPT FRONT */
|
|
{ { 0, 0},{ 0, 0},{ 0, 0} }, /**/
|
|
{ { 1, 1},{16,16},{30,30} }, /*Single Shot*/
|
|
{ { 2, 2},{29,29},{29,20} }, /*Dual Shot*/
|
|
{ { 3, 3},{21,21},{12, 0} }, /*Charge Cannon*/
|
|
{ { 4, 4},{18,18},{16,23} }, /*Vulcan*/
|
|
{ { 0, 0},{ 0, 0},{ 0, 0} }, /**/
|
|
{ { 6, 6},{29,16},{ 0,22} }, /*Super Missile*/
|
|
{ { 7, 7},{19,19},{19,28} }, /*Atom Bomb*/
|
|
{ { 0, 0},{ 0, 0},{ 0, 0} }, /**/
|
|
{ { 0, 0},{ 0, 0},{ 0, 0} }, /**/
|
|
{ {10,10},{21,21},{21,27} }, /*Mini Missile*/
|
|
{ { 0, 0},{ 0, 0},{ 0, 0} }, /**/
|
|
{ { 0, 0},{ 0, 0},{ 0, 0} }, /**/
|
|
{ {13,13},{17,17},{13,26} }, /*MicroBomb*/
|
|
{ { 0, 0},{ 0, 0},{ 0, 0} }, /**/
|
|
{ {15,15},{15,16},{15,16} } /*Post-It*/
|
|
};
|
|
|
|
const JE_word PGR[21] /* [1..21] */ =
|
|
{
|
|
4,
|
|
1,2,3,
|
|
41-21,57-21,73-21,89-21,105-21,
|
|
121-21,137-21,153-21,
|
|
151,151,151,151,73-21,73-21,1,2,4
|
|
/*151,151,151*/
|
|
};
|
|
const JE_byte PAni[21] /* [1..21] */ = {1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1};
|
|
|
|
const JE_word linkGunWeapons[38] /* [1..38] */ =
|
|
{
|
|
0,0,0,0,0,0,0,0,444,445,446,447,0,448,449,0,0,0,0,0,450,451,0,506,0,564,
|
|
445,446,447,448,449,445,446,447,448,449,450,451
|
|
};
|
|
const JE_word chargeGunWeapons[38] /* [1..38] */ =
|
|
{
|
|
0,0,0,0,0,0,0,0,476,458,464,482,0,488,470,0,0,0,0,0,494,500,0,528,0,558,
|
|
458,458,458,458,458,458,458,458,458,458,458,458
|
|
};
|
|
const JE_word linkMultiGr[17] /* [0..16] */ =
|
|
{77,221,183,301,1,282,164,202,58,201,163,281,39,300,182,220,77};
|
|
const JE_word linkSonicGr[17] /* [0..16] */ =
|
|
{85,242,131,303,47,284,150,223,66,224,149,283,9,302,130,243,85};
|
|
const JE_word linkMult2Gr[17] /* [0..16] */ =
|
|
{78,299,295,297,2,278,276,280,59,279,275,277,40,296,294,298,78};
|
|
|
|
const JE_byte randomEnemyLaunchSounds[3] /* [1..3] */ = {13,6,26};
|
|
|
|
/* YKS: Twiddle cheat sheet:
|
|
* 1: UP
|
|
* 2: DOWN
|
|
* 3: LEFT
|
|
* 4: RIGHT
|
|
* 5: UP+FIRE
|
|
* 6: DOWN+FIRE
|
|
* 7: LEFT+FIRE
|
|
* 8: RIGHT+FIRE
|
|
* 9: Release all keys (directions and fire)
|
|
*/
|
|
const JE_byte keyboardCombos[26][8] /* [1..26, 1..8] */ =
|
|
{
|
|
{ 2, 1, 2, 5, 137, 0, 0, 0}, /*Invulnerability*/
|
|
{ 4, 3, 2, 5, 138, 0, 0, 0}, /*Atom Bomb*/
|
|
{ 3, 4, 6, 139, 0, 0, 0, 0}, /*Seeker Bombs*/
|
|
{ 2, 5, 142, 0, 0, 0, 0, 0}, /*Ice Blast*/
|
|
{ 6, 2, 6, 143, 0, 0, 0, 0}, /*Auto Repair*/
|
|
{ 6, 7, 5, 8, 6, 7, 5, 112 }, /*Spin Wave*/
|
|
{ 7, 8, 101, 0, 0, 0, 0, 0}, /*Repulsor*/
|
|
{ 1, 7, 6, 146, 0, 0, 0, 0}, /*Protron Field*/
|
|
{ 8, 6, 7, 1, 120, 0, 0, 0}, /*Minefield*/
|
|
{ 3, 6, 8, 5, 121, 0, 0, 0}, /*Post-It Blast*/
|
|
{ 1, 2, 7, 8, 119, 0, 0, 0}, /*Drone Ship - TBC*/
|
|
{ 3, 4, 3, 6, 123, 0, 0, 0}, /*Repair Player 2*/
|
|
{ 6, 7, 5, 8, 124, 0, 0, 0}, /*Super Bomb - TBC*/
|
|
{ 1, 6, 125, 0, 0, 0, 0, 0}, /*Hot Dog*/
|
|
{ 9, 5, 126, 0, 0, 0, 0, 0}, /*Lightning UP */
|
|
{ 1, 7, 127, 0, 0, 0, 0, 0}, /*Lightning UP+LEFT */
|
|
{ 1, 8, 128, 0, 0, 0, 0, 0}, /*Lightning UP+RIGHT*/
|
|
{ 9, 7, 129, 0, 0, 0, 0, 0}, /*Lightning LEFT */
|
|
{ 9, 8, 130, 0, 0, 0, 0, 0}, /*Lightning RIGHT*/
|
|
{ 4, 2, 3, 5, 131, 0, 0, 0}, /*Warfly */
|
|
{ 3, 1, 2, 8, 132, 0, 0, 0}, /*FrontBlaster */
|
|
{ 2, 4, 5, 133, 0, 0, 0, 0}, /*Gerund */
|
|
{ 3, 4, 2, 8, 134, 0, 0, 0}, /*FireBomb */
|
|
{ 1, 4, 6, 135, 0, 0, 0, 0}, /*Indigo */
|
|
{ 1, 3, 6, 137, 0, 0, 0, 0}, /*Invulnerability [easier] */
|
|
{ 1, 4, 3, 4, 7, 136, 0, 0} /*D-Media Protron Drone */
|
|
};
|
|
|
|
const JE_byte shipCombosB[21] /* [1..21] */ =
|
|
{15,16,17,18,19,20,21,22,23,24, 7, 8, 5,25,14, 4, 6, 3, 9, 2,26};
|
|
/*!! SUPER Tyrian !!*/
|
|
const JE_byte superTyrianSpecials[4] /* [1..4] */ = {1,2,4,5};
|
|
|
|
const JE_byte shipCombos[14][3] /* [0..12, 1..3] */ =
|
|
{
|
|
{ 5, 4, 7}, /*2nd Player ship*/
|
|
{ 1, 2, 0}, /*USP Talon*/
|
|
{14, 4, 0}, /*Super Carrot*/
|
|
{ 4, 5, 0}, /*Gencore Phoenix*/
|
|
{ 6, 5, 0}, /*Gencore Maelstrom*/
|
|
{ 7, 8, 0}, /*MicroCorp Stalker*/
|
|
{ 7, 9, 0}, /*MicroCorp Stalker-B*/
|
|
{10, 3, 5}, /*Prototype Stalker-C*/
|
|
{ 5, 8, 9}, /*Stalker*/
|
|
{ 1, 3, 0}, /*USP Fang*/
|
|
{ 7,16,17}, /*U-Ship*/
|
|
{ 2,11,12}, /*1st Player ship*/
|
|
{ 3, 8,10}, /*Nort ship*/
|
|
{ 0, 0, 0} // Dummy entry added for Stalker 21.126
|
|
};
|
|
|
|
/*Street-Fighter Commands*/
|
|
JE_byte SFCurrentCode[2][21]; /* [1..2, 1..21] */
|
|
JE_byte SFExecuted[2]; /* [1..2] */
|
|
|
|
/*Special General Data*/
|
|
JE_byte lvlFileNum;
|
|
JE_word maxEvent, eventLoc;
|
|
/*JE_word maxenemies;*/
|
|
JE_word tempBackMove, explodeMove; /*Speed of background movement*/
|
|
JE_byte levelEnd;
|
|
JE_word levelEndFxWait;
|
|
JE_shortint levelEndWarp;
|
|
JE_boolean endLevel, reallyEndLevel, waitToEndLevel, playerEndLevel,
|
|
normalBonusLevelCurrent, bonusLevelCurrent,
|
|
smallEnemyAdjust, readyToEndLevel, quitRequested;
|
|
|
|
JE_byte newPL[10]; /* [0..9] */ /*Eventsys event 75 parameter*/
|
|
JE_word returnLoc;
|
|
JE_boolean returnActive;
|
|
JE_word galagaShotFreq;
|
|
JE_longint galagaLife;
|
|
|
|
JE_boolean debug = false; /*Debug Mode*/
|
|
Uint32 debugTime, lastDebugTime;
|
|
JE_longint debugHistCount;
|
|
JE_real debugHist;
|
|
JE_word curLoc; /*Current Pixel location of background 1*/
|
|
|
|
JE_boolean firstGameOver, gameLoaded, enemyStillExploding;
|
|
|
|
|
|
/* Destruction Ratio */
|
|
JE_word totalEnemy;
|
|
JE_word enemyKilled;
|
|
|
|
/* Shape/Map Data - All in one Segment! */
|
|
struct JE_MegaDataType1 megaData1;
|
|
struct JE_MegaDataType2 megaData2;
|
|
struct JE_MegaDataType3 megaData3;
|
|
|
|
/* Secret Level Display */
|
|
JE_byte flash;
|
|
JE_shortint flashChange;
|
|
JE_byte displayTime;
|
|
|
|
/* Demo Stuff */
|
|
bool play_demo = false, record_demo = false, stopped_demo = false;
|
|
Uint8 demo_num = 0;
|
|
FILE *demo_file = NULL;
|
|
|
|
Uint8 demo_keys, next_demo_keys;
|
|
Uint16 demo_keys_wait;
|
|
|
|
/* Sound Effects Queue */
|
|
JE_byte soundQueue[8]; /* [0..7] */
|
|
|
|
/*Level Event Data*/
|
|
JE_boolean enemyContinualDamage;
|
|
JE_boolean enemiesActive;
|
|
JE_boolean forceEvents;
|
|
JE_boolean stopBackgrounds;
|
|
JE_byte stopBackgroundNum;
|
|
JE_byte damageRate; /*Rate at which a player takes damage*/
|
|
JE_boolean background3x1; /*Background 3 enemies use Background 1 X offset*/
|
|
JE_boolean background3x1b; /*Background 3 enemies moved 8 pixels left*/
|
|
|
|
JE_boolean levelTimer;
|
|
JE_word levelTimerCountdown;
|
|
JE_word levelTimerJumpTo;
|
|
JE_boolean randomExplosions;
|
|
|
|
JE_boolean editShip1, editShip2;
|
|
|
|
JE_boolean globalFlags[10]; /* [1..10] */
|
|
JE_byte levelSong;
|
|
|
|
/* DESTRUCT game */
|
|
JE_boolean loadDestruct;
|
|
|
|
/* MapView Data */
|
|
JE_word mapOrigin, mapPNum;
|
|
JE_byte mapPlanet[5], mapSection[5]; /* [1..5] */
|
|
|
|
/* Interface Constants */
|
|
JE_boolean moveTyrianLogoUp;
|
|
JE_boolean skipStarShowVGA;
|
|
|
|
/*EnemyData*/
|
|
JE_EnemyType enemy;
|
|
JE_EnemyAvailType enemyAvail;
|
|
JE_word enemyOffset;
|
|
JE_word enemyOnScreen;
|
|
JE_byte enemyShapeTables[6]; /* [1..6] */
|
|
JE_boolean uniqueEnemy;
|
|
JE_word superEnemy254Jump;
|
|
|
|
/*EnemyShotData*/
|
|
JE_boolean fireButtonHeld;
|
|
JE_boolean enemyShotAvail[ENEMY_SHOT_MAX]; /* [1..Enemyshotmax] */
|
|
EnemyShotType enemyShot[ENEMY_SHOT_MAX]; /* [1..Enemyshotmax] */
|
|
|
|
/* Player Shot Data */
|
|
JE_byte zinglonDuration;
|
|
JE_byte astralDuration;
|
|
JE_word flareDuration;
|
|
JE_boolean flareStart;
|
|
JE_shortint flareColChg;
|
|
JE_byte specialWait;
|
|
JE_byte nextSpecialWait;
|
|
JE_boolean spraySpecial;
|
|
JE_byte doIced;
|
|
JE_boolean infiniteShot;
|
|
|
|
PlayerShotDataType playerShotData[MAX_PWEAPON + 1]; /* [1..MaxPWeapon+1] */
|
|
|
|
JE_byte chain;
|
|
|
|
/*PlayerData*/
|
|
JE_boolean allPlayersGone; /*Both players dead and finished exploding*/
|
|
|
|
JE_byte shotAvail[MAX_PWEAPON]; /* [1..MaxPWeapon] */ /*0:Avail 1-255:Duration left*/
|
|
const uint shadowYDist = 10;
|
|
|
|
JE_real optionSatelliteRotate;
|
|
|
|
JE_integer optionAttachmentMove;
|
|
JE_boolean optionAttachmentLinked, optionAttachmentReturn;
|
|
|
|
|
|
JE_byte chargeWait, chargeLevel, chargeMax, chargeGr, chargeGrWait;
|
|
|
|
JE_word neat;
|
|
|
|
|
|
/*ExplosionData*/
|
|
explosion_type explosions[MAX_EXPLOSIONS]; /* [1..ExplosionMax] */
|
|
JE_integer explosionFollowAmountX, explosionFollowAmountY;
|
|
|
|
/*Repeating Explosions*/
|
|
rep_explosion_type rep_explosions[MAX_REPEATING_EXPLOSIONS]; /* [1..20] */
|
|
|
|
/*SuperPixels*/
|
|
superpixel_type superpixels[MAX_SUPERPIXELS]; /* [0..MaxSP] */
|
|
unsigned int last_superpixel;
|
|
|
|
/*Temporary Numbers*/
|
|
JE_integer tempI, tempI2, tempI3, tempI4;
|
|
JE_longint tempL;
|
|
|
|
JE_byte temp, temp2, temp3, temp4, temp5, tempPos;
|
|
JE_word tempX, tempY, tempX2, tempY2;
|
|
JE_word tempW, tempW2;
|
|
|
|
JE_boolean doNotSaveBackup;
|
|
|
|
JE_word x, y;
|
|
JE_integer b;
|
|
JE_byte playerNum;
|
|
|
|
JE_byte **BKwrap1to, **BKwrap2to, **BKwrap3to,
|
|
**BKwrap1, **BKwrap2, **BKwrap3;
|
|
|
|
JE_shortint specialWeaponFilter, specialWeaponFreq;
|
|
JE_word specialWeaponWpn;
|
|
JE_boolean linkToPlayer;
|
|
|
|
JE_word shipGr, shipGr2;
|
|
Sprite2_array *shipGrPtr, *shipGr2ptr;
|
|
|
|
void JE_getShipInfo( void )
|
|
{
|
|
JE_boolean extraShip, extraShip2;
|
|
|
|
shipGrPtr = &shapes9;
|
|
shipGr2ptr = &shapes9;
|
|
|
|
powerAdd = powerSys[player[0].items.generator].power;
|
|
|
|
extraShip = player[0].items.ship > 90;
|
|
if (extraShip)
|
|
{
|
|
JE_byte base = (player[0].items.ship - 91) * 15;
|
|
shipGr = JE_SGr(player[0].items.ship - 90, &shipGrPtr);
|
|
player[0].armor = extraShips[base + 7];
|
|
}
|
|
else
|
|
{
|
|
shipGr = ships[player[0].items.ship].shipgraphic;
|
|
player[0].armor = ships[player[0].items.ship].dmg;
|
|
}
|
|
|
|
extraShip2 = player[1].items.ship > 90;
|
|
if (extraShip2)
|
|
{
|
|
JE_byte base2 = (player[1].items.ship - 91) * 15;
|
|
shipGr2 = JE_SGr(player[1].items.ship - 90, &shipGr2ptr);
|
|
player[1].armor = extraShips[base2 + 7]; /* bug? */
|
|
}
|
|
else
|
|
{
|
|
shipGr2 = 0;
|
|
player[1].armor = 10;
|
|
}
|
|
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
{
|
|
player[i].initial_armor = player[i].armor;
|
|
|
|
|
|
uint temp = ((i == 0 && extraShip) ||
|
|
(i == 1 && extraShip2)) ? 2 : ships[player[i].items.ship].ani;
|
|
|
|
if (temp == 0)
|
|
{
|
|
player[i].shot_hit_area_x = 12;
|
|
player[i].shot_hit_area_y = 10;
|
|
}
|
|
else
|
|
{
|
|
player[i].shot_hit_area_x = 11;
|
|
player[i].shot_hit_area_y = 14;
|
|
}
|
|
}
|
|
}
|
|
|
|
JE_word JE_SGr( JE_word ship, Sprite2_array **ptr )
|
|
{
|
|
const JE_word GR[15] /* [1..15] */ = {233, 157, 195, 271, 81, 0, 119, 5, 43, 81, 119, 157, 195, 233, 271};
|
|
|
|
JE_word tempW = extraShips[(ship - 1) * 15];
|
|
if (tempW > 7)
|
|
*ptr = (Sprite2_array*)extraShapes;
|
|
|
|
return GR[tempW-1];
|
|
}
|
|
|
|
void JE_drawOptions( void )
|
|
{
|
|
SDL_Surface *temp_surface = VGAScreen;
|
|
VGAScreen = VGAScreenSeg;
|
|
|
|
Player *this_player = &player[twoPlayerMode ? 1 : 0];
|
|
|
|
for (uint i = 0; i < COUNTOF(this_player->sidekick); ++i)
|
|
{
|
|
JE_OptionType *this_option = &options[this_player->items.sidekick[i]];
|
|
|
|
this_player->sidekick[i].ammo =
|
|
this_player->sidekick[i].ammo_max = this_option->ammo;
|
|
|
|
this_player->sidekick[i].ammo_refill_ticks =
|
|
this_player->sidekick[i].ammo_refill_ticks_max = (105 - this_player->sidekick[i].ammo) * 4;
|
|
|
|
this_player->sidekick[i].style = this_option->tr;
|
|
|
|
this_player->sidekick[i].animation_enabled = (this_option->option == 1);
|
|
this_player->sidekick[i].animation_frame = 0;
|
|
|
|
this_player->sidekick[i].charge = 0;
|
|
this_player->sidekick[i].charge_ticks = 20;
|
|
|
|
|
|
// draw initial sidekick HUD
|
|
const int y = hud_sidekick_y[twoPlayerMode ? 1 : 0][i];
|
|
|
|
fill_rectangle_xy(VGAScreenSeg, 284, y, 284 + 28, y + 15, 0);
|
|
if (this_option->icongr > 0)
|
|
blit_sprite(VGAScreenSeg, 284, y, OPTION_SHAPES, this_option->icongr - 1); // sidekick HUD icon
|
|
draw_segmented_gauge(VGAScreenSeg, 284, y + 13, 112, 2, 2, MAX(1, this_player->sidekick[i].ammo_max / 10), this_player->sidekick[i].ammo);
|
|
}
|
|
|
|
VGAScreen = temp_surface;
|
|
|
|
JE_drawOptionLevel();
|
|
}
|
|
|
|
void JE_drawOptionLevel( void )
|
|
{
|
|
if (twoPlayerMode)
|
|
{
|
|
for (temp = 1; temp <= 3; temp++)
|
|
{
|
|
fill_rectangle_xy(VGAScreenSeg, 268, 127 + (temp - 1) * 6, 269, 127 + 3 + (temp - 1) * 6, 193 + ((player[1].items.sidekick_level - 100) == temp) * 11);
|
|
}
|
|
}
|
|
}
|
|
|
|
void JE_tyrianHalt( JE_byte code )
|
|
{
|
|
deinit_audio();
|
|
deinit_video();
|
|
deinit_joysticks();
|
|
|
|
/* TODO: NETWORK */
|
|
|
|
free_main_shape_tables();
|
|
|
|
free_sprite2s(&shapes6);
|
|
|
|
for (int i = 0; i < SAMPLE_COUNT; i++)
|
|
{
|
|
free(digiFx[i]);
|
|
}
|
|
|
|
if (code != 9)
|
|
{
|
|
/*
|
|
TODO?
|
|
JE_drawANSI("exitmsg.bin");
|
|
JE_gotoXY(1,22);*/
|
|
|
|
JE_saveConfiguration();
|
|
}
|
|
|
|
/* endkeyboard; */
|
|
|
|
if (code == 9)
|
|
{
|
|
/* OutputString('call=file0002.EXE' + #0'); TODO? */
|
|
}
|
|
|
|
if (code == 5)
|
|
{
|
|
code = 0;
|
|
}
|
|
|
|
if (trentWin)
|
|
{
|
|
printf("\n"
|
|
"\n"
|
|
"\n"
|
|
"\n"
|
|
"Sleep well, Trent, you deserve the rest.\n"
|
|
"You now have permission to borrow my ship on your next mission.\n"
|
|
"\n"
|
|
"Also, you might want to try out the YESXMAS parameter.\n"
|
|
" Type: File0001 YESXMAS\n"
|
|
"\n"
|
|
"You'll need the 2.1 patch, though!\n"
|
|
"\n");
|
|
}
|
|
|
|
SDL_Quit();
|
|
exit(code);
|
|
}
|
|
|
|
void JE_initPlayerShot( JE_word portNum, uint shot_i, JE_word PX, JE_word PY, JE_word mouseX, JE_word mouseY, JE_word wpNum, JE_byte playerNum )
|
|
{
|
|
const JE_byte soundChannel[11] /* [1..11] */ = {0, 2, 4, 4, 2, 2, 5, 5, 1, 4, 1};
|
|
|
|
if (portNum <= PORT_NUM)
|
|
{
|
|
if (wpNum > 0 && wpNum <= WEAP_NUM)
|
|
{
|
|
if (power >= weaponPort[portNum].poweruse)
|
|
{
|
|
power -= weaponPort[portNum].poweruse;
|
|
|
|
if (weapons[wpNum].sound > 0)
|
|
{
|
|
soundQueue[soundChannel[shot_i]] = weapons[wpNum].sound;
|
|
}
|
|
|
|
/*Rot*/
|
|
for (tempW = 1; tempW <= weapons[wpNum].multi; tempW++)
|
|
{
|
|
|
|
for (b = 0; b < MAX_PWEAPON; b++)
|
|
{
|
|
if (shotAvail[b] == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (b == MAX_PWEAPON)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (shotMultiPos[shot_i] == weapons[wpNum].max || shotMultiPos[shot_i] > 8)
|
|
{
|
|
shotMultiPos[shot_i] = 1;
|
|
} else {
|
|
shotMultiPos[shot_i]++;
|
|
}
|
|
|
|
playerShotData[b].chainReaction = 0;
|
|
|
|
playerShotData[b].playerNumber = playerNum;
|
|
|
|
playerShotData[b].shotAni = 0;
|
|
|
|
playerShotData[b].shotComplicated = weapons[wpNum].circlesize != 0;
|
|
|
|
if (weapons[wpNum].circlesize == 0)
|
|
{
|
|
playerShotData[b].shotDevX = 0;
|
|
playerShotData[b].shotDirX = 0;
|
|
playerShotData[b].shotDevY = 0;
|
|
playerShotData[b].shotDirY = 0;
|
|
playerShotData[b].shotCirSizeX = 0;
|
|
playerShotData[b].shotCirSizeY = 0;
|
|
} else {
|
|
temp2 = weapons[wpNum].circlesize;
|
|
|
|
if (temp2 > 19)
|
|
{
|
|
temp3 = temp2 % 20;
|
|
playerShotData[b].shotCirSizeX = temp3;
|
|
playerShotData[b].shotDevX = temp3 >> 1;
|
|
|
|
temp2 = temp2 / 20;
|
|
playerShotData[b].shotCirSizeY = temp2;
|
|
playerShotData[b].shotDevY = temp2 >> 1;
|
|
} else {
|
|
playerShotData[b].shotCirSizeX = temp2;
|
|
playerShotData[b].shotCirSizeY = temp2;
|
|
playerShotData[b].shotDevX = temp2 >> 1;
|
|
playerShotData[b].shotDevY = temp2 >> 1;
|
|
}
|
|
playerShotData[b].shotDirX = 1;
|
|
playerShotData[b].shotDirY = -1;
|
|
}
|
|
|
|
playerShotData[b].shotTrail = weapons[wpNum].trail;
|
|
|
|
if (weapons[wpNum].attack[shotMultiPos[shot_i]-1] > 99 && weapons[wpNum].attack[shotMultiPos[shot_i]-1] < 250)
|
|
{
|
|
playerShotData[b].chainReaction = weapons[wpNum].attack[shotMultiPos[shot_i]-1] - 100;
|
|
playerShotData[b].shotDmg = 1;
|
|
} else {
|
|
playerShotData[b].shotDmg = weapons[wpNum].attack[shotMultiPos[shot_i]-1];
|
|
}
|
|
|
|
playerShotData[b].shotBlastFilter = weapons[wpNum].shipblastfilter;
|
|
|
|
tempI = weapons[wpNum].by[shotMultiPos[shot_i]-1];
|
|
|
|
/*Note: Only front selection used for player shots...*/
|
|
|
|
playerShotData[b].shotX = PX + weapons[wpNum].bx[shotMultiPos[shot_i]-1];
|
|
|
|
playerShotData[b].shotY = PY + tempI;
|
|
playerShotData[b].shotYC = -weapons[wpNum].acceleration;
|
|
playerShotData[b].shotXC = weapons[wpNum].accelerationx;
|
|
|
|
playerShotData[b].shotXM = weapons[wpNum].sx[shotMultiPos[shot_i]-1];
|
|
|
|
temp2 = weapons[wpNum].del[shotMultiPos[shot_i]-1];
|
|
|
|
if (temp2 == 121)
|
|
{
|
|
playerShotData[b].shotTrail = 0;
|
|
temp2 = 255;
|
|
}
|
|
|
|
playerShotData[b].shotGr = weapons[wpNum].sg[shotMultiPos[shot_i]-1];
|
|
if (playerShotData[b].shotGr == 0)
|
|
{
|
|
shotAvail[b] = 0;
|
|
} else {
|
|
shotAvail[b] = temp2;
|
|
}
|
|
if (temp2 > 100 && temp2 < 120)
|
|
{
|
|
playerShotData[b].shotAniMax = (temp2 - 100 + 1);
|
|
} else {
|
|
playerShotData[b].shotAniMax = weapons[wpNum].weapani + 1;
|
|
}
|
|
|
|
if (temp2 == 99 || temp2 == 98)
|
|
{
|
|
tempI = PX - mouseX;
|
|
if (tempI < -5)
|
|
{
|
|
tempI = -5;
|
|
}
|
|
if (tempI > 5)
|
|
{
|
|
tempI = 5;
|
|
}
|
|
playerShotData[b].shotXM += tempI;
|
|
}
|
|
|
|
|
|
if (temp2 == 99 || temp2 == 100)
|
|
{
|
|
tempI = PY - mouseY - weapons[wpNum].sy[shotMultiPos[shot_i]-1];
|
|
if (tempI < -4)
|
|
{
|
|
tempI = -4;
|
|
}
|
|
if (tempI > 4)
|
|
{
|
|
tempI = 4;
|
|
}
|
|
playerShotData[b].shotYM = tempI;
|
|
} else {
|
|
if (weapons[wpNum].sy[shotMultiPos[shot_i]-1] == 98)
|
|
{
|
|
playerShotData[b].shotYM = 0;
|
|
playerShotData[b].shotYC = -1;
|
|
} else {
|
|
if (weapons[wpNum].sy[shotMultiPos[shot_i]-1] > 100)
|
|
{
|
|
playerShotData[b].shotYM = weapons[wpNum].sy[shotMultiPos[shot_i]-1];
|
|
playerShotData[b].shotY -= player[playerShotData[b].playerNumber-1].delta_y_shot_move;
|
|
} else {
|
|
playerShotData[b].shotYM = -weapons[wpNum].sy[shotMultiPos[shot_i]-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (weapons[wpNum].sx[shotMultiPos[shot_i]-1] > 100)
|
|
{
|
|
playerShotData[b].shotXM = weapons[wpNum].sx[shotMultiPos[shot_i]-1];
|
|
playerShotData[b].shotX -= player[playerShotData[b].playerNumber-1].delta_x_shot_move;
|
|
if (playerShotData[b].shotXM == 101)
|
|
{
|
|
playerShotData[b].shotY -= player[playerShotData[b].playerNumber-1].delta_y_shot_move;
|
|
}
|
|
}
|
|
|
|
|
|
if (weapons[wpNum].aim > 5) /*Guided Shot*/
|
|
{
|
|
uint best_dist = 65000;
|
|
temp3 = 0;
|
|
/*Find Closest Enemy*/
|
|
for (x = 0; x < 100; x++)
|
|
{
|
|
if (enemyAvail[x] != 1 && !enemy[x].scoreitem)
|
|
{
|
|
y = abs(enemy[x].ex - playerShotData[b].shotX) + abs(enemy[x].ey - playerShotData[b].shotY);
|
|
if (y < best_dist)
|
|
{
|
|
best_dist = y;
|
|
temp3 = x + 1;
|
|
}
|
|
}
|
|
}
|
|
playerShotData[b].aimAtEnemy = temp3;
|
|
playerShotData[b].aimDelay = 5;
|
|
playerShotData[b].aimDelayMax = weapons[wpNum].aim - 5;
|
|
}
|
|
else
|
|
{
|
|
playerShotData[b].aimAtEnemy = 0;
|
|
}
|
|
|
|
shotRepeat[shot_i] = weapons[wpNum].shotrepeat;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void JE_specialComplete( JE_byte playerNum, JE_byte specialType )
|
|
{
|
|
nextSpecialWait = 0;
|
|
switch (special[specialType].stype)
|
|
{
|
|
/*Weapon*/
|
|
case 1:
|
|
if (playerNum == 1)
|
|
JE_initPlayerShot(0, SHOT_SPECIAL2, player[0].x, player[0].y, mouseX, mouseY, special[specialType].wpn, playerNum);
|
|
else
|
|
JE_initPlayerShot(0, SHOT_SPECIAL2, player[1].x, player[1].y, mouseX, mouseY, special[specialType].wpn, playerNum);
|
|
|
|
shotRepeat[SHOT_SPECIAL] = shotRepeat[SHOT_SPECIAL2];
|
|
break;
|
|
/*Repulsor*/
|
|
case 2:
|
|
for (temp = 0; temp < ENEMY_SHOT_MAX; temp++)
|
|
{
|
|
if (!enemyShotAvail[temp])
|
|
{
|
|
if (player[0].x > enemyShot[temp].sx)
|
|
enemyShot[temp].sxm--;
|
|
else if (player[0].x < enemyShot[temp].sx)
|
|
enemyShot[temp].sxm++;
|
|
|
|
if (player[0].y > enemyShot[temp].sy)
|
|
enemyShot[temp].sym--;
|
|
else if (player[0].y < enemyShot[temp].sy)
|
|
enemyShot[temp].sym++;
|
|
}
|
|
}
|
|
break;
|
|
/*Zinglon Blast*/
|
|
case 3:
|
|
zinglonDuration = 50;
|
|
shotRepeat[SHOT_SPECIAL] = 100;
|
|
soundQueue[7] = S_SOUL_OF_ZINGLON;
|
|
break;
|
|
/*Attractor*/
|
|
case 4:
|
|
for (temp = 0; temp < 100; temp++)
|
|
{
|
|
if (enemyAvail[temp] != 1 && enemy[temp].scoreitem
|
|
&& enemy[temp].evalue != 0)
|
|
{
|
|
if (player[0].x > enemy[temp].ex)
|
|
enemy[temp].exc++;
|
|
else if (player[0].x < enemy[temp].ex)
|
|
enemy[temp].exc--;
|
|
|
|
if (player[0].y > enemy[temp].ey)
|
|
enemy[temp].eyc++;
|
|
else if (player[0].y < enemy[temp].ey)
|
|
enemy[temp].eyc--;
|
|
}
|
|
}
|
|
break;
|
|
/*Flare*/
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 16:
|
|
if (flareDuration == 0)
|
|
flareStart = true;
|
|
|
|
specialWeaponWpn = special[specialType].wpn;
|
|
linkToPlayer = false;
|
|
spraySpecial = false;
|
|
switch (special[specialType].stype)
|
|
{
|
|
case 5:
|
|
specialWeaponFilter = 7;
|
|
specialWeaponFreq = 2;
|
|
flareDuration = 50;
|
|
break;
|
|
case 6:
|
|
specialWeaponFilter = 1;
|
|
specialWeaponFreq = 7;
|
|
flareDuration = 200 + 25 * player[0].items.weapon[FRONT_WEAPON].power;
|
|
break;
|
|
case 7:
|
|
specialWeaponFilter = 3;
|
|
specialWeaponFreq = 3;
|
|
flareDuration = 50 + 10 * player[0].items.weapon[FRONT_WEAPON].power;
|
|
zinglonDuration = 50;
|
|
shotRepeat[SHOT_SPECIAL] = 100;
|
|
soundQueue[7] = S_SOUL_OF_ZINGLON;
|
|
break;
|
|
case 8:
|
|
specialWeaponFilter = -99;
|
|
specialWeaponFreq = 7;
|
|
flareDuration = 10 + player[0].items.weapon[FRONT_WEAPON].power;
|
|
break;
|
|
case 9:
|
|
specialWeaponFilter = -99;
|
|
specialWeaponFreq = 8;
|
|
flareDuration = 8 + 2 * player[0].items.weapon[FRONT_WEAPON].power;
|
|
linkToPlayer = true;
|
|
nextSpecialWait = special[specialType].pwr;
|
|
break;
|
|
case 10:
|
|
specialWeaponFilter = -99;
|
|
specialWeaponFreq = 8;
|
|
flareDuration = 14 + 4 * player[0].items.weapon[FRONT_WEAPON].power;
|
|
linkToPlayer = true;
|
|
break;
|
|
case 11:
|
|
specialWeaponFilter = -99;
|
|
specialWeaponFreq = special[specialType].pwr;
|
|
flareDuration = 10 + 10 * player[0].items.weapon[FRONT_WEAPON].power;
|
|
astralDuration = 20 + 10 * player[0].items.weapon[FRONT_WEAPON].power;
|
|
break;
|
|
case 16:
|
|
specialWeaponFilter = -99;
|
|
specialWeaponFreq = 8;
|
|
flareDuration = temp2 * 16 + 8;
|
|
linkToPlayer = true;
|
|
spraySpecial = true;
|
|
break;
|
|
}
|
|
break;
|
|
case 12:
|
|
player[playerNum-1].invulnerable_ticks = temp2 * 10;
|
|
|
|
if (superArcadeMode > 0 && superArcadeMode <= SA)
|
|
{
|
|
shotRepeat[SHOT_SPECIAL] = 250;
|
|
JE_initPlayerShot(0, SHOT_SPECIAL2, player[0].x, player[0].y, mouseX, mouseY, 707, 1);
|
|
player[0].invulnerable_ticks = 100;
|
|
}
|
|
break;
|
|
case 13:
|
|
player[0].armor += temp2 / 4 + 1;
|
|
|
|
soundQueue[3] = S_POWERUP;
|
|
break;
|
|
case 14:
|
|
player[1].armor += temp2 / 4 + 1;
|
|
|
|
soundQueue[3] = S_POWERUP;
|
|
break;
|
|
|
|
case 17: // spawn left or right sidekick
|
|
soundQueue[3] = S_POWERUP;
|
|
|
|
if (player[0].items.sidekick[LEFT_SIDEKICK] == special[specialType].wpn)
|
|
{
|
|
player[0].items.sidekick[RIGHT_SIDEKICK] = special[specialType].wpn;
|
|
shotMultiPos[RIGHT_SIDEKICK] = 0;
|
|
}
|
|
else
|
|
{
|
|
player[0].items.sidekick[LEFT_SIDEKICK] = special[specialType].wpn;
|
|
shotMultiPos[LEFT_SIDEKICK] = 0;
|
|
}
|
|
|
|
JE_drawOptions();
|
|
break;
|
|
|
|
case 18: // spawn right sidekick
|
|
player[0].items.sidekick[RIGHT_SIDEKICK] = special[specialType].wpn;
|
|
|
|
JE_drawOptions();
|
|
|
|
soundQueue[4] = S_POWERUP;
|
|
|
|
shotMultiPos[RIGHT_SIDEKICK] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void JE_doSpecialShot( JE_byte playerNum, uint *armor, uint *shield )
|
|
{
|
|
if (player[0].items.special > 0)
|
|
{
|
|
if (shotRepeat[SHOT_SPECIAL] == 0 && specialWait == 0 && flareDuration < 2 && zinglonDuration < 2)
|
|
blit_sprite2(VGAScreen, 47, 4, shapes9, 94);
|
|
else
|
|
blit_sprite2(VGAScreen, 47, 4, shapes9, 93);
|
|
}
|
|
|
|
if (shotRepeat[SHOT_SPECIAL] > 0)
|
|
{
|
|
--shotRepeat[SHOT_SPECIAL];
|
|
}
|
|
if (specialWait > 0)
|
|
{
|
|
specialWait--;
|
|
}
|
|
temp = SFExecuted[playerNum-1];
|
|
if (temp > 0 && shotRepeat[SHOT_SPECIAL] == 0 && flareDuration == 0)
|
|
{
|
|
temp2 = special[temp].pwr;
|
|
|
|
bool can_afford = true;
|
|
|
|
if (temp2 > 0)
|
|
{
|
|
if (temp2 < 98) // costs some shield
|
|
{
|
|
if (*shield >= temp2)
|
|
*shield -= temp2;
|
|
else
|
|
can_afford = false;
|
|
}
|
|
else if (temp2 == 98) // costs all shield
|
|
{
|
|
if (*shield < 4)
|
|
can_afford = false;
|
|
temp2 = *shield;
|
|
*shield = 0;
|
|
}
|
|
else if (temp2 == 99) // costs half shield
|
|
{
|
|
temp2 = *shield / 2;
|
|
*shield = temp2;
|
|
}
|
|
else // costs some armor
|
|
{
|
|
temp2 -= 100;
|
|
if (*armor > temp2)
|
|
*armor -= temp2;
|
|
else
|
|
can_afford = false;
|
|
}
|
|
}
|
|
|
|
shotMultiPos[SHOT_SPECIAL] = 0;
|
|
shotMultiPos[SHOT_SPECIAL2] = 0;
|
|
|
|
if (can_afford)
|
|
JE_specialComplete(playerNum, temp);
|
|
|
|
SFExecuted[playerNum-1] = 0;
|
|
|
|
JE_wipeShieldArmorBars();
|
|
VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
|
|
JE_drawShield();
|
|
JE_drawArmor();
|
|
VGAScreen = game_screen; /* side-effect of game_screen */
|
|
}
|
|
|
|
if (playerNum == 1 && player[0].items.special > 0)
|
|
{ /*Main Begin*/
|
|
|
|
if (superArcadeMode > 0 && (button[2-1] || button[3-1]))
|
|
{
|
|
fireButtonHeld = false;
|
|
}
|
|
if (!button[1-1] && !(superArcadeMode != SA_NONE && (button[2-1] || button[3-1])))
|
|
{
|
|
fireButtonHeld = false;
|
|
}
|
|
else if (shotRepeat[SHOT_SPECIAL] == 0 && !fireButtonHeld && !(flareDuration > 0) && specialWait == 0)
|
|
{
|
|
fireButtonHeld = true;
|
|
JE_specialComplete(playerNum, player[0].items.special);
|
|
}
|
|
|
|
} /*Main End*/
|
|
|
|
if (astralDuration > 0)
|
|
astralDuration--;
|
|
|
|
shotAvail[MAX_PWEAPON-1] = 0;
|
|
if (flareDuration > 1)
|
|
{
|
|
if (specialWeaponFilter != -99)
|
|
{
|
|
if (levelFilter == -99 && levelBrightness == -99)
|
|
{
|
|
filterActive = false;
|
|
}
|
|
if (!filterActive)
|
|
{
|
|
levelFilter = specialWeaponFilter;
|
|
if (levelFilter == 7)
|
|
{
|
|
levelBrightness = 0;
|
|
}
|
|
filterActive = true;
|
|
}
|
|
|
|
if (mt_rand() % 2 == 0)
|
|
flareColChg = -1;
|
|
else
|
|
flareColChg = 1;
|
|
|
|
if (levelFilter == 7)
|
|
{
|
|
if (levelBrightness < -6)
|
|
{
|
|
flareColChg = 1;
|
|
}
|
|
if (levelBrightness > 6)
|
|
{
|
|
flareColChg = -1;
|
|
}
|
|
levelBrightness += flareColChg;
|
|
}
|
|
}
|
|
|
|
if ((signed)(mt_rand() % 6) < specialWeaponFreq)
|
|
{
|
|
b = 0;
|
|
|
|
if (linkToPlayer)
|
|
{
|
|
if (shotRepeat[SHOT_SPECIAL] == 0)
|
|
{
|
|
JE_initPlayerShot(0, SHOT_SPECIAL, player[0].x, player[0].y, mouseX, mouseY, specialWeaponWpn, playerNum);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
JE_initPlayerShot(0, SHOT_SPECIAL, mt_rand() % 280, mt_rand() % 180, mouseX, mouseY, specialWeaponWpn, playerNum);
|
|
}
|
|
|
|
if (spraySpecial && b > 0)
|
|
{
|
|
playerShotData[b].shotXM = (mt_rand() % 5) - 2;
|
|
playerShotData[b].shotYM = (mt_rand() % 5) - 2;
|
|
if (playerShotData[b].shotYM == 0)
|
|
{
|
|
playerShotData[b].shotYM++;
|
|
}
|
|
}
|
|
}
|
|
|
|
flareDuration--;
|
|
if (flareDuration == 1)
|
|
{
|
|
specialWait = nextSpecialWait;
|
|
}
|
|
}
|
|
else if (flareStart)
|
|
{
|
|
flareStart = false;
|
|
shotRepeat[SHOT_SPECIAL] = linkToPlayer ? 15 : 200;
|
|
flareDuration = 0;
|
|
if (levelFilter == specialWeaponFilter)
|
|
{
|
|
levelFilter = -99;
|
|
levelBrightness = -99;
|
|
filterActive = false;
|
|
}
|
|
}
|
|
|
|
if (zinglonDuration > 1)
|
|
{
|
|
temp = 25 - abs(zinglonDuration - 25);
|
|
|
|
JE_barBright(VGAScreen, player[0].x + 7 - temp, 0, player[0].x + 7 + temp, 184);
|
|
JE_barBright(VGAScreen, player[0].x + 7 - temp - 2, 0, player[0].x + 7 + temp + 2, 184);
|
|
|
|
zinglonDuration--;
|
|
if (zinglonDuration % 5 == 0)
|
|
{
|
|
shotAvail[MAX_PWEAPON-1] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void JE_setupExplosion( signed int x, signed int y, signed int delta_y, unsigned int type, bool fixed_position, bool follow_player )
|
|
{
|
|
const struct {
|
|
JE_word sprite;
|
|
JE_byte ttl;
|
|
} explosion_data[53] /* [1..53] */ = {
|
|
{ 144, 7 },
|
|
{ 120, 12 },
|
|
{ 190, 12 },
|
|
{ 209, 12 },
|
|
{ 152, 12 },
|
|
{ 171, 12 },
|
|
{ 133, 7 }, /*White Smoke*/
|
|
{ 1, 12 },
|
|
{ 20, 12 },
|
|
{ 39, 12 },
|
|
{ 58, 12 },
|
|
{ 110, 3 },
|
|
{ 76, 7 },
|
|
{ 91, 3 },
|
|
/*15*/ { 227, 3 },
|
|
{ 230, 3 },
|
|
{ 233, 3 },
|
|
{ 252, 3 },
|
|
{ 246, 3 },
|
|
/*20*/ { 249, 3 },
|
|
{ 265, 3 },
|
|
{ 268, 3 },
|
|
{ 271, 3 },
|
|
{ 236, 3 },
|
|
/*25*/ { 239, 3 },
|
|
{ 242, 3 },
|
|
{ 261, 3 },
|
|
{ 274, 3 },
|
|
{ 277, 3 },
|
|
/*30*/ { 280, 3 },
|
|
{ 299, 3 },
|
|
{ 284, 3 },
|
|
{ 287, 3 },
|
|
{ 290, 3 },
|
|
/*35*/ { 293, 3 },
|
|
{ 165, 8 }, /*Coin Values*/
|
|
{ 184, 8 },
|
|
{ 203, 8 },
|
|
{ 222, 8 },
|
|
{ 168, 8 },
|
|
{ 187, 8 },
|
|
{ 206, 8 },
|
|
{ 225, 10 },
|
|
{ 169, 10 },
|
|
{ 188, 10 },
|
|
{ 207, 20 },
|
|
{ 226, 14 },
|
|
{ 170, 14 },
|
|
{ 189, 14 },
|
|
{ 208, 14 },
|
|
{ 246, 14 },
|
|
{ 227, 14 },
|
|
{ 265, 14 }
|
|
};
|
|
|
|
if (y > -16 && y < 190)
|
|
{
|
|
for (int i = 0; i < MAX_EXPLOSIONS; i++)
|
|
{
|
|
if (explosions[i].ttl == 0)
|
|
{
|
|
explosions[i].x = x;
|
|
explosions[i].y = y;
|
|
if (type == 6)
|
|
{
|
|
explosions[i].y += 12;
|
|
explosions[i].x += 2;
|
|
} else if (type == 98)
|
|
{
|
|
type = 6;
|
|
}
|
|
explosions[i].sprite = explosion_data[type].sprite;
|
|
explosions[i].ttl = explosion_data[type].ttl;
|
|
explosions[i].follow_player = follow_player;
|
|
explosions[i].fixed_position = fixed_position;
|
|
explosions[i].delta_x = 0;
|
|
explosions[i].delta_y = delta_y;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void JE_setupExplosionLarge( JE_boolean enemyGround, JE_byte exploNum, JE_integer x, JE_integer y )
|
|
{
|
|
if (y >= 0)
|
|
{
|
|
if (enemyGround)
|
|
{
|
|
JE_setupExplosion(x - 6, y - 14, 0, 2, false, false);
|
|
JE_setupExplosion(x + 6, y - 14, 0, 4, false, false);
|
|
JE_setupExplosion(x - 6, y, 0, 3, false, false);
|
|
JE_setupExplosion(x + 6, y, 0, 5, false, false);
|
|
} else {
|
|
JE_setupExplosion(x - 6, y - 14, 0, 7, false, false);
|
|
JE_setupExplosion(x + 6, y - 14, 0, 9, false, false);
|
|
JE_setupExplosion(x - 6, y, 0, 8, false, false);
|
|
JE_setupExplosion(x + 6, y, 0, 10, false, false);
|
|
}
|
|
|
|
bool big;
|
|
|
|
if (exploNum > 10)
|
|
{
|
|
exploNum -= 10;
|
|
big = true;
|
|
}
|
|
else
|
|
{
|
|
big = false;
|
|
}
|
|
|
|
if (exploNum)
|
|
{
|
|
for (int i = 0; i < MAX_REPEATING_EXPLOSIONS; i++)
|
|
{
|
|
if (rep_explosions[i].ttl == 0)
|
|
{
|
|
rep_explosions[i].ttl = exploNum;
|
|
rep_explosions[i].delay = 2;
|
|
rep_explosions[i].x = x;
|
|
rep_explosions[i].y = y;
|
|
rep_explosions[i].big = big;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void JE_wipeShieldArmorBars( void )
|
|
{
|
|
if (!twoPlayerMode || galagaMode)
|
|
{
|
|
fill_rectangle_xy(VGAScreenSeg, 270, 137, 278, 194 - player[0].shield * 2, 0);
|
|
}
|
|
else
|
|
{
|
|
fill_rectangle_xy(VGAScreenSeg, 270, 60 - 44, 278, 60, 0);
|
|
fill_rectangle_xy(VGAScreenSeg, 270, 194 - 44, 278, 194, 0);
|
|
}
|
|
if (!twoPlayerMode || galagaMode)
|
|
{
|
|
fill_rectangle_xy(VGAScreenSeg, 307, 137, 315, 194 - player[0].armor * 2, 0);
|
|
}
|
|
else
|
|
{
|
|
fill_rectangle_xy(VGAScreenSeg, 307, 60 - 44, 315, 60, 0);
|
|
fill_rectangle_xy(VGAScreenSeg, 307, 194 - 44, 315, 194, 0);
|
|
}
|
|
}
|
|
|
|
JE_byte JE_playerDamage( JE_byte temp,
|
|
Player *this_player )
|
|
{
|
|
int playerDamage = 0;
|
|
soundQueue[7] = S_SHIELD_HIT;
|
|
|
|
/* Player Damage Routines */
|
|
if (this_player->shield < temp)
|
|
{
|
|
playerDamage = temp;
|
|
temp -= this_player->shield;
|
|
this_player->shield = 0;
|
|
|
|
if (temp > 0)
|
|
{
|
|
/*Through Shields - Now Armor */
|
|
|
|
if (this_player->armor < temp)
|
|
{
|
|
temp -= this_player->armor;
|
|
this_player->armor = 0;
|
|
|
|
if (this_player->is_alive && !youAreCheating)
|
|
{
|
|
levelTimer = false;
|
|
this_player->is_alive = false;
|
|
this_player->exploding_ticks = 60;
|
|
levelEnd = 40;
|
|
tempVolume = tyrMusicVolume;
|
|
soundQueue[1] = S_EXPLOSION_22;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this_player->armor -= temp;
|
|
soundQueue[7] = S_HULL_HIT;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this_player->shield -= temp;
|
|
|
|
JE_setupExplosion(this_player->x - 17, this_player->y - 12, 0, 14, false, !twoPlayerMode);
|
|
JE_setupExplosion(this_player->x - 5 , this_player->y - 12, 0, 15, false, !twoPlayerMode);
|
|
JE_setupExplosion(this_player->x + 7 , this_player->y - 12, 0, 16, false, !twoPlayerMode);
|
|
JE_setupExplosion(this_player->x + 19, this_player->y - 12, 0, 17, false, !twoPlayerMode);
|
|
|
|
JE_setupExplosion(this_player->x - 17, this_player->y + 2, 0, 18, false, !twoPlayerMode);
|
|
JE_setupExplosion(this_player->x + 19, this_player->y + 2, 0, 19, false, !twoPlayerMode);
|
|
|
|
JE_setupExplosion(this_player->x - 17, this_player->y + 16, 0, 20, false, !twoPlayerMode);
|
|
JE_setupExplosion(this_player->x - 5 , this_player->y + 16, 0, 21, false, !twoPlayerMode);
|
|
JE_setupExplosion(this_player->x + 7 , this_player->y + 16, 0, 22, false, !twoPlayerMode);
|
|
}
|
|
|
|
JE_wipeShieldArmorBars();
|
|
VGAScreen = VGAScreenSeg; /* side-effect of game_screen */
|
|
JE_drawShield();
|
|
JE_drawArmor();
|
|
VGAScreen = game_screen; /* side-effect of game_screen */
|
|
|
|
return playerDamage;
|
|
}
|
|
|
|
JE_word JE_portConfigs( void )
|
|
{
|
|
const uint player_index = twoPlayerMode ? 1 : 0;
|
|
return tempW = weaponPort[player[player_index].items.weapon[REAR_WEAPON].id].opnum;
|
|
}
|
|
|
|
void JE_drawShield( void )
|
|
{
|
|
if (twoPlayerMode && !galagaMode)
|
|
{
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
JE_dBar3(VGAScreen, 270, 60 + 134 * i, roundf(player[i].shield * 0.8f), 144);
|
|
}
|
|
else
|
|
{
|
|
JE_dBar3(VGAScreen, 270, 194, player[0].shield, 144);
|
|
if (player[0].shield != player[0].shield_max)
|
|
{
|
|
const uint y = 193 - (player[0].shield_max * 2);
|
|
JE_rectangle(VGAScreen, 270, y, 278, y, 68); /* <MXD> SEGa000 */
|
|
}
|
|
}
|
|
}
|
|
|
|
void JE_drawArmor( void )
|
|
{
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
if (player[i].armor > 28)
|
|
player[i].armor = 28;
|
|
|
|
if (twoPlayerMode && !galagaMode)
|
|
{
|
|
for (uint i = 0; i < COUNTOF(player); ++i)
|
|
JE_dBar3(VGAScreen, 307, 60 + 134 * i, roundf(player[i].armor * 0.8f), 224);
|
|
}
|
|
else
|
|
{
|
|
JE_dBar3(VGAScreen, 307, 194, player[0].armor, 224);
|
|
}
|
|
}
|
|
|
|
void JE_doSP( JE_word x, JE_word y, JE_word num, JE_byte explowidth, JE_byte color ) /* superpixels */
|
|
{
|
|
for (temp = 0; temp < num; temp++)
|
|
{
|
|
JE_real tempr = mt_rand_lt1() * (2 * M_PI);
|
|
signed int tempy = roundf(cosf(tempr) * mt_rand_1() * explowidth);
|
|
signed int tempx = roundf(sinf(tempr) * mt_rand_1() * explowidth);
|
|
|
|
if (++last_superpixel >= MAX_SUPERPIXELS)
|
|
last_superpixel = 0;
|
|
superpixels[last_superpixel].x = tempx + x;
|
|
superpixels[last_superpixel].y = tempy + y;
|
|
superpixels[last_superpixel].delta_x = tempx;
|
|
superpixels[last_superpixel].delta_y = tempy + 1;
|
|
superpixels[last_superpixel].color = color;
|
|
superpixels[last_superpixel].z = 15;
|
|
}
|
|
}
|
|
|
|
void JE_drawSP( void )
|
|
{
|
|
for (int i = MAX_SUPERPIXELS; i--; )
|
|
{
|
|
if (superpixels[i].z)
|
|
{
|
|
superpixels[i].x += superpixels[i].delta_x;
|
|
superpixels[i].y += superpixels[i].delta_y;
|
|
|
|
if (superpixels[i].x < (unsigned)VGAScreen->w && superpixels[i].y < (unsigned)VGAScreen->h)
|
|
{
|
|
Uint8 *s = (Uint8 *)VGAScreen->pixels; /* screen pointer, 8-bit specific */
|
|
s += superpixels[i].y * VGAScreen->pitch;
|
|
s += superpixels[i].x;
|
|
|
|
*s = (((*s & 0x0f) + superpixels[i].z) >> 1) + superpixels[i].color;
|
|
if (superpixels[i].x > 0)
|
|
*(s - 1) = (((*(s - 1) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color;
|
|
if (superpixels[i].x < VGAScreen->w - 1u)
|
|
*(s + 1) = (((*(s + 1) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color;
|
|
if (superpixels[i].y > 0)
|
|
*(s - VGAScreen->pitch) = (((*(s - VGAScreen->pitch) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color;
|
|
if (superpixels[i].y < VGAScreen->h - 1u)
|
|
*(s + VGAScreen->pitch) = (((*(s + VGAScreen->pitch) & 0x0f) + (superpixels[i].z >> 1)) >> 1) + superpixels[i].color;
|
|
}
|
|
|
|
superpixels[i].z--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// kate: tab-width 4; vim: set noet:
|