ledHeadWii/source/game/SubChase.c
2020-05-25 18:02:06 +02:00

584 lines
12 KiB
C

/*
LEDhead
Copyright 2001, Peter Hirschberg
Author: Peter Hirschberg
The current version of this SOURCE CODE as well as the official
versions of the LEDHEAD APPLICATION are available from my website
at: http://www.peterhirschberg.com
Based on the handheld electronic games by Mattel Electronics.
All trademarks copyrighted by their respective owners. This
program is not affiliated or endorsed by Mattel Electronics.
License agreement:
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 (license.txt); if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Email : peter@peterhirschberg.com
Website : http://www.peterhirschberg.com
*/
#include "SubChase.h"
#include "Games.h"
// constants
typedef int BLIP;
static BLIP Blips[SUBCHASE_BLIP_COLUMNS][SUBCHASE_BLIP_ROWS];
#define TIME_SONAR_SLOW 5
#define TIME_SONAR_FAST 2
#define TIME_ENEMY_SUB_MOVE 30
#define TIME_INITIAL_FIRE_TORPEDO_DELAY 250
#define TIME_FIRE_TORPEDO_DELAY 20
#define TIME_TORPEDO_MOVE 6
#define TIME_KILL_GAME_TIMER 80
// game variables
static BOOL bGameOver;
static BOOL bInFrame = FALSE;
static BOOL bPower;
static int nScore;
static int nCharges;
static int nChargeValue;
static int nTimerSonar;
static int nTimerEnemySubMove;
static int nTimerFireTorpedo;
static int nTimerMoveTorpedo;
static int nKillGameTimer;
static int nSubDirX;
static int nTorpedoDirX;
static BOOL bPlayerHasMoved;
static BOOL bInitialTorpedoFired = FALSE;
static void InitGame();
static void PositionEnemySub();
static void FireTorpedoes();
static void DrawBlips();
static void DrawScore(int nDisplay);
typedef struct OBJECT
{
int x;
int y;
BOOL bEnable;
}OBJECT;
static OBJECT player;
static OBJECT sub;
static OBJECT torpedo[2];
BOOL SubChase_GetPower()
{
return (bPower ? TRUE : FALSE);
}
void SubChase_PowerOn()
{
InitGame();
bPower = TRUE;
}
void SubChase_PowerOff()
{
bPower = FALSE;
}
int SubChase_GetSkill()
{
return 0;
}
void SubChase_SetSkill(int i)
{
}
void InitGame()
{
bGameOver = FALSE;
nScore = 0;
nCharges = 30;
nChargeValue = 5;
player.x = 3;
player.y = 1;
torpedo[0].bEnable = FALSE;
torpedo[1].bEnable = FALSE;
nTorpedoDirX = 1;
nTimerFireTorpedo = TIME_INITIAL_FIRE_TORPEDO_DELAY;
nKillGameTimer = TIME_KILL_GAME_TIMER;
bPlayerHasMoved = FALSE;
nTimerSonar = 0;
PositionEnemySub();
Platform_IsNewSecond();
}
void SubChase_Run(int tu)
{
int x, y;
// prevent reentrancy
if (bInFrame){ return; }
bInFrame = TRUE;
// init the blips field
for (y = 0; y < SUBCHASE_BLIP_ROWS; y++){
for (x = 0; x < SUBCHASE_BLIP_COLUMNS; x++){
Blips[x][y] = BLIP_OFF;
}
}
// handle power off, and game over states
if (bPower){
if (bGameOver)
{
Blips[player.x][player.y] = BLIP_BRIGHT;
DrawBlips();
DrawScore(nScore);
bInFrame = FALSE;
return;
}
} else {
SubChase_ClearScreen();
DrawScore(-1);
bInFrame = FALSE;
return;
}
// run the game
BOOL bChange;
if (SubChase_GetInputLEFT(&bChange))
{
bPlayerHasMoved = TRUE;
if (bChange)
{
// move left
if (player.x > 0)
{
player.x--;
}
}
}
else if (SubChase_GetInputRIGHT(&bChange))
{
bPlayerHasMoved = TRUE;
if (bChange)
{
// move right
if (player.x < (SUBCHASE_BLIP_COLUMNS-1))
{
player.x++;
}
}
}
else if (SubChase_GetInputUP(&bChange))
{
bPlayerHasMoved = TRUE;
if (bChange)
{
// move up
if (player.y > 0)
{
player.y--;
}
}
}
else if (SubChase_GetInputDOWN(&bChange))
{
bPlayerHasMoved = TRUE;
if (bChange)
{
// move down
if (player.y < (SUBCHASE_BLIP_ROWS-1))
{
player.y++;
}
}
}
if (SubChase_GetInputFIRE(NULL))
{
// release depth charge - check for hit
if ((player.x == sub.x) && (player.y == sub.y))
{
// hit
{
// clear the screen except for the player's ship
SubChase_ClearScreen();
DrawScore(-1);
Platform_StartDraw();
SubChase_DrawBlip(BLIP_BRIGHT, player.x, player.y);
Platform_EndDraw();
}
SubChase_PlaySound(SUBCHASE_SOUND_HIT, PLAYSOUNDFLAGS_PRIORITY);
nScore+=nChargeValue;
nChargeValue = 5;
bInitialTorpedoFired = TRUE;
PositionEnemySub();
}
else
{
// miss
{
// clear the screen except for the player's ship
SubChase_ClearScreen();
DrawScore(-1);
Platform_StartDraw();
SubChase_DrawBlip(BLIP_BRIGHT, player.x, player.y);
Platform_EndDraw();
}
SubChase_PlaySound(SUBCHASE_SOUND_CHARGE, PLAYSOUNDFLAGS_PRIORITY);
nTimerEnemySubMove = 0;
// decrease charge value
if (nChargeValue==5)
{
nChargeValue=3;
}
else if (nChargeValue==3)
{
nChargeValue=2;
}
else if (nChargeValue==2)
{
nChargeValue=1;
}
// decrease number of charges and check for game over
--nCharges;
if (nCharges == 0)
{
// GAME OVER!
{
// clear the screen except for the player's ship
SubChase_ClearScreen();
DrawScore(-1);
Platform_StartDraw();
SubChase_DrawBlip(BLIP_BRIGHT, player.x, player.y);
Platform_EndDraw();
}
SubChase_PlaySound(SUBCHASE_SOUND_SINK, PLAYSOUNDFLAGS_PRIORITY);
bGameOver = TRUE;
bInFrame = FALSE;
return;
}
}
}
// check for proximity to enemy sub
int nSonar = 0;
if (((sub.x == player.x) && (sub.y == player.y))
|| ((sub.x == player.x) && (sub.y == player.y-1))
|| ((sub.x == player.x) && (sub.y == player.y+1)))
{
// fast
nSonar = 1;
}
else if (((sub.x == player.x-1) && (sub.y == player.y-1))
|| ((sub.x == player.x-1) && (sub.y == player.y))
|| ((sub.x == player.x-1) && (sub.y == player.y+1))
|| ((sub.x == player.x+1) && (sub.y == player.y-1))
|| ((sub.x == player.x+1) && (sub.y == player.y))
|| ((sub.x == player.x+1) && (sub.y == player.y+1)))
{
// slow
nSonar = 2;
}
if (nSonar)
{
++nTimerSonar;
if (nSonar==2)
{
if (nTimerSonar > TIME_SONAR_SLOW)
{
SubChase_PlaySound(SUBCHASE_SOUND_SONAR, PLAYSOUNDFLAGS_ASYNC);
nTimerSonar = 0;
}
}
else
{
if (nTimerSonar > TIME_SONAR_FAST)
{
SubChase_PlaySound(SUBCHASE_SOUND_SONAR, PLAYSOUNDFLAGS_ASYNC);
nTimerSonar = 0;
}
}
}
else
{
nTimerSonar = 0;
}
// update the blips
Blips[player.x][player.y] = BLIP_BRIGHT;
// Blips[sub.x][sub.y] = BLIP_DIM;
if (torpedo[0].bEnable)
{
if ((torpedo[0].x >= 0) && (torpedo[0].x < SUBCHASE_BLIP_COLUMNS))
{
Blips[torpedo[0].x][torpedo[0].y] = BLIP_DIM;
}
}
if (torpedo[1].bEnable)
{
if ((torpedo[1].x >= 0) && (torpedo[1].x < SUBCHASE_BLIP_COLUMNS))
{
Blips[torpedo[1].x][torpedo[1].y] = BLIP_DIM;
}
}
// check for torpedo hit
if (((torpedo[0].bEnable) && (torpedo[0].x == player.x) && (torpedo[0].y == player.y))
|| ((torpedo[0].bEnable) && (torpedo[0].x == player.x) && (torpedo[0].y == player.y)))
{
// torpedo hit
{
// clear the screen except for the player's ship
SubChase_ClearScreen();
DrawScore(-1);
Platform_StartDraw();
SubChase_DrawBlip(BLIP_BRIGHT, player.x, player.y);
Platform_EndDraw();
}
SubChase_PlaySound(SUBCHASE_SOUND_SINK, PLAYSOUNDFLAGS_PRIORITY);
bGameOver = TRUE;
bInFrame = FALSE;
return;
}
DrawBlips();
DrawScore(nScore);
// move the enemy sub
--nTimerEnemySubMove;
if (nTimerEnemySubMove <= 0)
{
nTimerEnemySubMove = TIME_ENEMY_SUB_MOVE;
if (nSubDirX > 0)
{
if (sub.x >= (SUBCHASE_BLIP_COLUMNS-1))
{
nSubDirX = -1;
}
}
else
{
if (sub.x <= 0)
{
nSubDirX = 1;
}
}
sub.x += nSubDirX;
}
// move the torpedoes
--nTimerMoveTorpedo;
if (nTimerMoveTorpedo <= 0)
{
nTimerMoveTorpedo = TIME_TORPEDO_MOVE;
for (int i=0; i<2; i++)
{
if (torpedo[i].bEnable)
{
torpedo[i].x += nTorpedoDirX;
if ((torpedo[i].x < 0) && (nTorpedoDirX < 0))
{
torpedo[i].bEnable = FALSE;
}
if ((torpedo[i].x >= SUBCHASE_BLIP_COLUMNS) && (nTorpedoDirX > 0))
{
torpedo[i].bEnable = FALSE;
}
}
}
}
if (nKillGameTimer > 0)
{
--nKillGameTimer;
}
if (!bPlayerHasMoved && (nKillGameTimer <= 0))
{
// player is just sitting there
// fire a torpedo at him right now
// (as per real game)
FireTorpedoes();
bPlayerHasMoved = TRUE;
}
// randomly fire torpedoes as required
if ((torpedo[0].bEnable == FALSE) && (torpedo[1].bEnable == FALSE))
{
if (nTimerFireTorpedo > 0)
{
--nTimerFireTorpedo;
}
if (Platform_Random(5) == 0)
{
if (nTimerFireTorpedo <= 0)
{
FireTorpedoes();
}
}
}
bInFrame = FALSE;
}
void DrawBlips()
{
Platform_StartDraw();
// draw the blips field
for (int y = 0; y < SUBCHASE_BLIP_ROWS; y++){
for (int x = 0; x < SUBCHASE_BLIP_COLUMNS; x++)
{
switch(Blips[x][y]){
case BLIP_OFF:
case BLIP_DIM:
case BLIP_BRIGHT:
SubChase_DrawBlip(Blips[x][y], x, y);
break;
}
}
}
Platform_EndDraw();
}
void DrawScore(int nDisplay)
{
// draw the display
Platform_StartDraw();
SubChase_DrawScore(nDisplay);
Platform_EndDraw();
}
void PositionEnemySub()
{
nTimerEnemySubMove = TIME_ENEMY_SUB_MOVE;
nSubDirX = Platform_Random(2) ? 1 : -1;
while (1)
{
sub.x = Platform_Random(SUBCHASE_BLIP_COLUMNS);
sub.y = Platform_Random(SUBCHASE_BLIP_ROWS);
if (((sub.x == player.x) && (sub.y == player.y))
|| ((sub.x == player.x-1) && (sub.y == player.y-1))
|| ((sub.x == player.x-1) && (sub.y == player.y))
|| ((sub.x == player.x-1) && (sub.y == player.y+1))
|| ((sub.x == player.x+1) && (sub.y == player.y-1))
|| ((sub.x == player.x+1) && (sub.y == player.y))
|| ((sub.x == player.x+1) && (sub.y == player.y+1))
|| ((sub.x == player.x) && (sub.y == player.y-1))
|| ((sub.x == player.x) && (sub.y == player.y+1)))
{
// try again
}
else
{
return;
}
}
}
static void FireTorpedoes()
{
nTimerFireTorpedo = TIME_FIRE_TORPEDO_DELAY;
nTimerMoveTorpedo = TIME_TORPEDO_MOVE;
// enable 1 or more torpedoes
torpedo[0].bEnable = TRUE;
if (bInitialTorpedoFired)
{
torpedo[1].bEnable = Platform_Random(7) ? FALSE : TRUE;
}
// pick the direction based on where the player is
if (player.x < 3)
{
nTorpedoDirX = -1;
}
else if (player.x > 3)
{
nTorpedoDirX = 1;
}
else
{
if (!bPlayerHasMoved)
{
// when player hasn't moved, the torpedo is always from the right
nTorpedoDirX = -1;
}
else
{
nTorpedoDirX = (Platform_Random(2)) ? 1 : -1;
}
}
if (nTorpedoDirX > 0)
{
if ((player.x == (SUBCHASE_BLIP_COLUMNS-1)) && Platform_Random(2))
{
torpedo[0].x = 3;
torpedo[1].x = 3;
}
else
{
torpedo[0].x = player.x - Platform_Random(5) - 3;
torpedo[1].x = player.x - Platform_Random(5) - 3;
}
}
else
{
if ((player.x == 0) && Platform_Random(2))
{
torpedo[0].x = 3;
torpedo[1].x = 3;
}
else
{
torpedo[0].x = player.x + Platform_Random(5) + 3;
torpedo[1].x = player.x + Platform_Random(5) + 3;
}
}
torpedo[0].y = player.y;
torpedo[1].y = Platform_Random(3);
bInitialTorpedoFired = TRUE;
}