Files
commandergenius/project/jni/application/alienblaster/racer.cpp

1156 lines
34 KiB
C++

/***************************************************************************
alienBlaster
Copyright (C) 2004
Paul Grathwohl, Arne Hormann, Daniel Kuehn, Soenke Schwardt
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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
***************************************************************************/
using namespace std;
#include "racer.h"
#include "surfaceDB.h"
#include "shot.h"
#include "shots.h"
#include "items.h"
#include "item.h"
#include "font.h"
#include "boundingBox.h"
#include "enemys.h"
#include "enemy.h"
#include "mixer.h"
#include "global.h"
#include "banners.h"
#include "shieldGlow.h"
Racer::Racer( string fnSprite, int whichPlayer, Vector2D startpos , int newShipType) {
spriteRacerBase = surfaceDB.loadSurface( fnSprite );
drawRectBase.w = spriteRacerBase->w;
drawRectBase.h = spriteRacerBase->h;
playerNr = whichPlayer;
pos = startpos;
shipType = newShipType;
// init weaponary and specials
timeLastShotPrimary = SDL_GetTicks();
timeLastShotSecondary = SDL_GetTicks();
lastDumbfireWasLeft = false;
timeLastHeatseekerUsed = SDL_GetTicks();
timeLastNukeUsed = SDL_GetTicks();
lastHeatseekerWasLeft = false;
deflectorActive = false;
deflectorTimeLeft = -1;
for ( int i = 0; i < NR_SECONDARY_WEAPONS; i++ ) {
secondaryWeaponsAvailability[ i ] = false;
}
for ( int i = 0; i < NR_SPECIALS; i++ ) {
specialsAvailability[ i ] = 0;
}
specialsAvailability[ SPECIAL_NONE ] = 1; // this one is always present
// assign values dependant on shiptype
switch (shipType) {
case LIGHT_FIGHTER:
{
maxShield = LIGHT_FIGHTER_MAX_SHIELD;
maxDamage = LIGHT_FIGHTER_MAX_DAMAGE;
shield = maxShield;
damage = maxDamage;
maxVel = LIGHT_FIGHTER_VEL_MAX;
spriteShadow = surfaceDB.loadSurface( FN_LIGHT_FIGHTER_SHADOW, true );
shieldGlow = new ShieldGlow( LIGHT_FIGHTER );
if ( playerNr == 0 ) {
spriteFighterIcon = surfaceDB.loadSurface( FN_LIGHT_FIGHTER_1_SMALL );
} else {
spriteFighterIcon = surfaceDB.loadSurface( FN_LIGHT_FIGHTER_2_SMALL );
}
if ( arcadeGame ) {
secondaryWeaponsAvailability[ SHOT_DUMBFIRE_DOUBLE-100 ] = true;
secondaryWeaponsAvailability[ SHOT_KICK_ASS_ROCKET-100 ] = true;
secondaryWeaponsAvailability[ SHOT_HELLFIRE-100 ] = true;
secondaryWeaponsAvailability[ SHOT_MACHINE_GUN-100 ] = true;
secondaryWeaponsAvailability[ SHOT_ENERGY_BEAM-100 ] = true;
primaryShotType = SHOT_TRIPLE;
activeSecondary = SHOT_HELLFIRE;
activeSpecial = SPECIAL_NUKE; switchSpecials(); // init specials
} else {
secondaryWeaponsAvailability[ 0 ] = true; // Dumbfire is always available
primaryShotType = SHOT_NORMAL;
activeSecondary = SHOT_DUMBFIRE;
activeSpecial = SPECIAL_NUKE; switchSpecials(); // init specials
}
break;
}
case HEAVY_FIGHTER:
{
maxShield = HEAVY_FIGHTER_MAX_SHIELD;
maxDamage = HEAVY_FIGHTER_MAX_DAMAGE;
shield = maxShield;
damage = maxDamage;
maxVel = HEAVY_FIGHTER_VEL_MAX;
spriteShadow = surfaceDB.loadSurface( FN_HEAVY_FIGHTER_SHADOW, true );
shieldGlow = new ShieldGlow( HEAVY_FIGHTER );
if ( playerNr == 0 ) {
spriteFighterIcon = surfaceDB.loadSurface( FN_HEAVY_FIGHTER_1_SMALL );
} else {
spriteFighterIcon = surfaceDB.loadSurface( FN_HEAVY_FIGHTER_2_SMALL );
}
if ( arcadeGame ) {
secondaryWeaponsAvailability[ SHOT_HF_DUMBFIRE_DOUBLE-100 ] = true;
secondaryWeaponsAvailability[ SHOT_HF_KICK_ASS_ROCKET-100 ] = true;
secondaryWeaponsAvailability[ SHOT_HF_LASER-100 ] = true;
primaryShotType = SHOT_HF_QUINTO;
activeSecondary = SHOT_HF_KICK_ASS_ROCKET;
activeSpecial = SPECIAL_NUKE; switchSpecials(); // init specials
} else {
// Dumbfire is always available
secondaryWeaponsAvailability[ SHOT_HF_DUMBFIRE-100 ] = true;
specialsAvailability[ SPECIAL_DEFLECTOR ] = 1;
primaryShotType = SHOT_HF_NORMAL;
activeSecondary = SHOT_HF_DUMBFIRE;
specialsAvailability[ SPECIAL_NUKE ] = 1;
activeSpecial = SPECIAL_NUKE; switchSpecials(); // init specials
}
break;
}
}
spriteHPStat = surfaceDB.loadSurface( FN_HITPOINTS_STAT );
pixPerHP = spriteHPStat->w / (maxDamage + maxShield);
shieldDamageEndTime = 0;
shieldDamageActive = false;
if ( whichPlayer == 0 ) {
font = new Font( FN_FONT_NUMBERS_LEFT );
} else {
font = new Font( FN_FONT_NUMBERS_RIGHT );
}
fontSize = font->getCharWidth();
sndShotPrimary = Mixer::mixer().loadSample( FN_SOUND_SHOT_PRIMARY );
sndShotSecondary = Mixer::mixer().loadSample( FN_SOUND_SHOT_SECONDARY );
spriteSpecials = surfaceDB.loadSurface( FN_ICONS_SPECIALS );
spriteSecondaryWeapons = surfaceDB.loadSurface( FN_ICONS_SECONDARY_WEAPONS );
spriteDeflector = surfaceDB.loadSurface( FN_HEAVY_FIGHTER_DEFLECTOR, true );
drawRectDeflector.w = spriteDeflector->w;
drawRectDeflector.h = spriteDeflector->h;
boundaryRect =
new RectangleGeo(Vector2D(spriteRacerBase->w/(2*RACER_IMAGE_CNT), spriteRacerBase->h/2),
Vector2D(320-spriteRacerBase->w/(2*RACER_IMAGE_CNT), 200-spriteRacerBase->h/2));
boundingBox = new BoundingBox( lroundf(pos.getX() - (spriteRacerBase->w / RACER_IMAGE_CNT) * 0.45),
lroundf(pos.getY() - spriteRacerBase->h * 0.45),
lroundf((spriteRacerBase->w / RACER_IMAGE_CNT) * 0.9),
lroundf(spriteRacerBase->h * 0.9) );
shipAngle = -90;
vel = Vector2D(0,0);
thrust = false;
backwards = false;
left = false;
right = false;
fireWeapons = false;
useSpecial = false;
points = 0;
timeLastMove = SDL_GetTicks();
}
Racer::~Racer() {
delete boundaryRect;
delete boundingBox;
if (font) delete font;
delete shieldGlow;
}
Vector2D Racer::move( int dT ) {
// TODO: move this to a correct place
if ( deflectorActive ) {
deflectorTimeLeft -= dT;
if (deflectorTimeLeft < 0) deflectorActive = false;
}
Vector2D oldPos = pos;
if ( thrust ) {
pos += Vector2D( 0, -maxVel ) * dT / 1000.0;
}
if ( backwards ) {
pos += Vector2D( 0, maxVel ) * dT / 1000.0;
}
if ( left ) {
pos += Vector2D( -maxVel, 0 ) * dT / 1000.0;
}
if ( right ) {
pos += Vector2D( maxVel, 0 ) * dT / 1000.0;
}
clipWorld();
updateBoundingBox();
return oldPos;
}
void Racer::clipWorld() {
int left = lroundf(pos.getX()) - (spriteRacerBase->w / (2*RACER_IMAGE_CNT));
int top = lroundf(pos.getY()) - (spriteRacerBase->h / 2);
int right = lroundf(pos.getX()) + (spriteRacerBase->w / (2*RACER_IMAGE_CNT));
int bottom = lroundf(pos.getY()) + (spriteRacerBase->h / 2);
if ( left <= 1 ) {
pos.setX( 1 + spriteRacerBase->w / (2*RACER_IMAGE_CNT) );
} else if ( right >= SCREEN_WIDTH - 1 ) {
pos.setX( SCREEN_WIDTH - 2 - spriteRacerBase->w / (2*RACER_IMAGE_CNT));
}
if ( top <= 1 ) {
pos.setY( 1 + spriteRacerBase->h / 2 );
} else if ( bottom >= SCREEN_HEIGHT - 1 ) {
pos.setY( SCREEN_HEIGHT - 2 - spriteRacerBase->h / 2 );
}
}
void Racer::drawStats( SdlCompat_AcceleratedSurface *screen ) {
SDL_Rect srcR, destR;
int indent = 5;
if ( playerNr == 1 ) {
indent = screen->w -
( 7 + 3 * fontSize + (spriteSpecials->w / (NR_SPECIALS-1)) ) -
( 5 + spriteSecondaryWeapons->w / NR_SECONDARY_WEAPONS );
}
int x = indent;
// draw Secondary Weapon
srcR.x = (activeSecondary - SHOT_DUMBFIRE) * spriteSecondaryWeapons->w / NR_SECONDARY_WEAPONS;
srcR.y = 0;
srcR.w = spriteSecondaryWeapons->w / NR_SECONDARY_WEAPONS;
srcR.h = spriteSecondaryWeapons->h;
destR.x = x;
destR.y = 25;
destR.w = spriteSecondaryWeapons->w / NR_SECONDARY_WEAPONS;
x += destR.w + 5;
destR.h = spriteSecondaryWeapons->h;
SDL_BlitSurface( spriteSecondaryWeapons, &srcR, screen, &destR );
// draw active special and amount of it
if ( activeSpecial != SPECIAL_NONE ) {
int pixPerSpecial = spriteSpecials->w / (NR_SPECIALS - 1);
srcR.y = 0;
srcR.w = pixPerSpecial;
srcR.h = spriteSpecials->h;
srcR.x = (activeSpecial - SPECIAL_NUKE) * pixPerSpecial;
destR.x = x;
destR.y = 25;
destR.w = pixPerSpecial;
x += pixPerSpecial + 2;
destR.h = spriteSpecials->h;
SDL_BlitSurface( spriteSpecials, &srcR, screen, &destR );
int digitCnt = 1;
int i=1;
while ( specialsAvailability[ activeSpecial ] >= i*10 ) {
digitCnt++;
i *= 10;
}
font->drawInt( screen, x, 25,
specialsAvailability[ activeSpecial ], digitCnt, 0);
}
if ( !onePlayerGame ) {
// draw Icon
switch (playerNr) {
case 0: indent = 10 + spriteHPStat->w; break;
case 1: indent = screen->w - (20 + spriteHPStat->w + spriteFighterIcon->w); break;
default: break;
}
destR.x = indent;
destR.w = spriteFighterIcon->w;
destR.y = 2;
destR.h = spriteFighterIcon->h;
SDL_BlitSurface( spriteFighterIcon, 0, screen, &destR );
}
// draw shields and damage
switch (playerNr) {
case 0: indent = 5; break;
case 1: indent = screen->w - (15 + spriteHPStat->w); break;
default: break;
}
// draw damage
srcR.x = 0;
srcR.y = 0;
srcR.w = lroundf(damage * pixPerHP);
srcR.h = spriteHPStat->h;
destR.x = indent;
destR.w = srcR.w;
destR.y = 5;
destR.h = spriteHPStat->h;
SDL_BlitSurface( spriteHPStat, &srcR, screen, &destR );
// draw shield
destR.x = indent + srcR.w;
srcR.x = spriteHPStat->w / 2;
srcR.w = lroundf(shield * pixPerHP);
destR.w = srcR.w;
destR.h = spriteHPStat->h;
SDL_BlitSurface( spriteHPStat, &srcR, screen, &destR );
}
void Racer::drawShadow( SdlCompat_AcceleratedSurface *screen ) {
SDL_Rect destR;
destR.x = lroundf(pos.getX()) - (spriteShadow->w / 2) - 10;
destR.y = lroundf(pos.getY()) - (spriteShadow->h / 2) + 10;
destR.w = spriteShadow->w;
destR.h = spriteShadow->h;
SDL_BlitSurface( spriteShadow, 0, screen, &destR );
}
void Racer::drawRacer( SdlCompat_AcceleratedSurface *screen ) {
SDL_Rect srcR;
SDL_Rect destR;
destR.x = lroundf(pos.getX()) - (spriteRacerBase->w / (2*RACER_IMAGE_CNT));
destR.y = lroundf(pos.getY()) - (spriteRacerBase->h / 2);
destR.w = spriteRacerBase->w / RACER_IMAGE_CNT;
destR.h = spriteRacerBase->h;
int idx = 0; // normal pos
if ( !left && !right && !thrust && !backwards ) idx = 0; //stop
else if ( left && !right && !thrust && !backwards ) idx = 1; // left
else if ( !left && right && !thrust && !backwards ) idx = 2; // right
else if ( !left && !right && thrust && !backwards ) idx = 3; // forward
else if ( !left && !right && !thrust && backwards ) idx = 4; // backward
else if ( left && !right && thrust && !backwards ) idx = 5; // left-forward
else if ( !left && right && thrust && !backwards ) idx = 6; // right-forward
else if ( left && !right && !thrust && backwards ) idx = 7; // left-backward
else if ( !left && right && !thrust && backwards ) idx = 8; // right-backward
srcR.x = idx * (spriteRacerBase->w / RACER_IMAGE_CNT);
srcR.y = 0;
srcR.w = (spriteRacerBase->w / RACER_IMAGE_CNT);
srcR.h = spriteRacerBase->h;
SDL_BlitSurface( spriteRacerBase, &srcR, screen, &destR );
if ( shieldDamageActive ) {
int shieldGlowTimeLeft = shieldDamageEndTime - SDL_GetTicks();
if ( shieldGlowTimeLeft < 0 ) {
shieldDamageActive = false;
} else {
shieldGlow->draw( screen, pos, RACER_SHIELD_DAMAGE_LIFETIME - shieldGlowTimeLeft );
}
}
if ( deflectorActive ) {
drawRectDeflector.x = lroundf(pos.getX()) - spriteDeflector->w / 2;
drawRectDeflector.y = lroundf(pos.getY()) - spriteDeflector->h / 2;
SDL_BlitSurface( spriteDeflector, 0, screen, &drawRectDeflector );
}
}
void Racer::switchSecondary() {
int newActive = (activeSecondary-100 + 1) % NR_SECONDARY_WEAPONS;
while ( newActive != activeSecondary-100 &&
secondaryWeaponsAvailability[ newActive ] == false ) {
newActive = (newActive + 1) % NR_SECONDARY_WEAPONS;
}
activeSecondary = (ShotTypes)(newActive+100);
if ( activeSecondary == SHOT_DUMBFIRE &&
secondaryWeaponsAvailability[ SHOT_DUMBFIRE_DOUBLE - 100 ] ) {
activeSecondary = SHOT_DUMBFIRE_DOUBLE;
}
// same for heavy-fighter
if ( activeSecondary == SHOT_HF_DUMBFIRE &&
secondaryWeaponsAvailability[ SHOT_HF_DUMBFIRE_DOUBLE - 100 ] ) {
activeSecondary = SHOT_HF_DUMBFIRE_DOUBLE;
}
// TODO: ugly workaround...
if ( activeSecondary == SHOT_KICK_ASS_ROCKET ||
activeSecondary == SHOT_HF_KICK_ASS_ROCKET ) {
timeLastShotSecondary -= RACER_COOLDOWN_KICK_ASS_ROCKET / 2;
}
}
void Racer::switchSpecials() {
int newActive = activeSpecial + 1;
if ( newActive == NR_SPECIALS ) newActive = 1;
for(int i=0; i < NR_SPECIALS-1; ++i) {
// Only Sönke knows what the following does ;-)
if (specialsAvailability[ ((activeSpecial + i) % (NR_SPECIALS-1))+1 ] != 0) {
activeSpecial = (SpecialTypes)(((activeSpecial + i) % (NR_SPECIALS-1))+1);
return;
}
}
activeSpecial = SPECIAL_NONE;
}
void Racer::shootPrimary() {
if ( fireWeapons ) {
switch ( primaryShotType ) {
case SHOT_NORMAL:
{
if ( (SDL_GetTicks() - RACER_COOLDOWN_SHOT_NORMAL) > timeLastShotPrimary ) {
Shot *shot =
new Shot( SHOT_NORMAL, playerNr,
pos + Vector2D(0, -spriteRacerBase->h / 2),
-90 + (rand() % SPREAD_ANGLE_SHOT_NORMAL) -
SPREAD_ANGLE_SHOT_NORMAL / 2 );
shots->addShot( shot );
Mixer::mixer().playSample( sndShotPrimary, 0 );
timeLastShotPrimary = SDL_GetTicks();
}
break;
}
case SHOT_NORMAL_HEAVY:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_SHOT_NORMAL_HEAVY > timeLastShotPrimary ) {
Shot *shot =
new Shot( SHOT_NORMAL_HEAVY, playerNr,
pos + Vector2D(0, -spriteRacerBase->h / 2), -90 );
shots->addShot( shot );
Mixer::mixer().playSample( sndShotPrimary, 0 );
timeLastShotPrimary = SDL_GetTicks();
}
break;
}
case SHOT_DOUBLE:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_SHOT_DOUBLE > timeLastShotPrimary ) {
Shot *shot1 =
new Shot( SHOT_DOUBLE, playerNr, pos + Vector2D(-8,-2), -95 );
Shot *shot2 =
new Shot( SHOT_DOUBLE, playerNr, pos + Vector2D(8,-2), -85 );
shots->addShot(shot1);
shots->addShot(shot2);
Mixer::mixer().playSample( sndShotPrimary, 0 );
timeLastShotPrimary = SDL_GetTicks();
}
break;
}
case SHOT_DOUBLE_HEAVY:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_SHOT_DOUBLE_HEAVY > timeLastShotPrimary ) {
Shot *shot1 =
new Shot( SHOT_DOUBLE_HEAVY, playerNr, pos + Vector2D(-8,-2), -95 );
Shot *shot2 =
new Shot( SHOT_DOUBLE_HEAVY, playerNr, pos + Vector2D(8,-2), -85 );
shots->addShot(shot1);
shots->addShot(shot2);
Mixer::mixer().playSample( sndShotPrimary, 0 );
timeLastShotPrimary = SDL_GetTicks();
}
break;
}
case SHOT_TRIPLE:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_SHOT_TRIPLE > timeLastShotPrimary ) {
Shot *shot1 =
new Shot( SHOT_TRIPLE, playerNr, pos + Vector2D(-8, -2), -100 );
Shot *shot2 =
new Shot( SHOT_TRIPLE, playerNr, pos + Vector2D(0, -spriteRacerBase->h / 2), -90 );
Shot *shot3 =
new Shot( SHOT_TRIPLE, playerNr, pos + Vector2D(8, -2), -80 );
shots->addShot(shot1);
shots->addShot(shot2);
shots->addShot(shot3);
Mixer::mixer().playSample( sndShotPrimary, 0 );
timeLastShotPrimary = SDL_GetTicks();
}
break;
}
// HEAVY FIGHTER SHOTS
case SHOT_HF_NORMAL:
{
if ( (SDL_GetTicks() - RACER_COOLDOWN_SHOT_HF_NORMAL) > timeLastShotPrimary ) {
Shot *shot =
new Shot( SHOT_HF_NORMAL, playerNr,
pos + Vector2D(0, -spriteRacerBase->h / 2), -90 );
shots->addShot( shot );
Mixer::mixer().playSample( sndShotPrimary, 0 );
timeLastShotPrimary = SDL_GetTicks();
}
break;
}
case SHOT_HF_DOUBLE:
{
if ( (SDL_GetTicks() - RACER_COOLDOWN_SHOT_HF_DOUBLE) > timeLastShotPrimary ) {
Shot *shot = new Shot( SHOT_HF_DOUBLE, playerNr, pos + Vector2D(-12, -12), -90 );
shots->addShot( shot );
shot = new Shot( SHOT_HF_DOUBLE, playerNr, pos + Vector2D(12, -12), -90 );
shots->addShot( shot );
Mixer::mixer().playSample( sndShotPrimary, 0 );
timeLastShotPrimary = SDL_GetTicks();
}
break;
}
case SHOT_HF_TRIPLE:
{
if ( (SDL_GetTicks() - RACER_COOLDOWN_SHOT_HF_TRIPLE) > timeLastShotPrimary ) {
Shot *shot = new Shot( SHOT_HF_TRIPLE, playerNr, pos + Vector2D(-12, -12), -103 );
shots->addShot( shot );
shot = new Shot( SHOT_HF_TRIPLE, playerNr,
pos + Vector2D(0, -spriteRacerBase->h / 2), -90 );
shots->addShot( shot );
shot = new Shot( SHOT_HF_TRIPLE, playerNr, pos + Vector2D(12, -12), -77 );
shots->addShot( shot );
Mixer::mixer().playSample( sndShotPrimary, 0 );
timeLastShotPrimary = SDL_GetTicks();
}
break;
}
case SHOT_HF_QUATTRO:
{
if ( (SDL_GetTicks() - RACER_COOLDOWN_SHOT_HF_QUATTRO) > timeLastShotPrimary ) {
Shot *shot = new Shot( SHOT_HF_QUATTRO, playerNr, pos + Vector2D(-30, -15), -100 );
shots->addShot( shot );
shot = new Shot( SHOT_HF_QUATTRO, playerNr, pos + Vector2D(-12, -12), -90 );
shots->addShot( shot );
shot = new Shot( SHOT_HF_QUATTRO, playerNr, pos + Vector2D(12, -12), -90 );
shots->addShot( shot );
shot = new Shot( SHOT_HF_QUATTRO, playerNr, pos + Vector2D(30, -15), -80 );
shots->addShot( shot );
Mixer::mixer().playSample( sndShotPrimary, 0 );
timeLastShotPrimary = SDL_GetTicks();
}
break;
}
case SHOT_HF_QUINTO:
{
if ( (SDL_GetTicks() - RACER_COOLDOWN_SHOT_HF_QUINTO) > timeLastShotPrimary ) {
Shot *shot = new Shot( SHOT_HF_QUINTO, playerNr, pos + Vector2D(-30, -15), -110 );
shots->addShot( shot );
shot = new Shot( SHOT_HF_QUINTO, playerNr, pos + Vector2D(-12, -12), -100 );
shots->addShot( shot );
shot = new Shot( SHOT_HF_QUINTO, playerNr,
pos + Vector2D(0, -spriteRacerBase->h / 2), -90 );
shots->addShot( shot );
shot = new Shot( SHOT_HF_QUINTO, playerNr, pos + Vector2D(12, -12), -80 );
shots->addShot( shot );
shot = new Shot( SHOT_HF_QUINTO, playerNr, pos + Vector2D(30, -15), -70 );
shots->addShot( shot );
Mixer::mixer().playSample( sndShotPrimary, 0 );
timeLastShotPrimary = SDL_GetTicks();
}
break;
}
default:
{
cout << "Racer::shootPrimary: unexpected primaryShotType: "
<< primaryShotType << endl;
break;
}
}
}
}
void Racer::shootSecondary() {
if ( fireWeapons ) {
switch ( activeSecondary ) {
case SHOT_DUMBFIRE:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_DUMBFIRE > timeLastShotSecondary ) {
Shot *shot =
new Shot( SHOT_DUMBFIRE, playerNr, pos + Vector2D(0, -5), -90 );
shots->addShot(shot);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastShotSecondary = SDL_GetTicks();
}
break;
}
case SHOT_DUMBFIRE_DOUBLE:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_DUMBFIRE_DOUBLE > timeLastShotSecondary ) {
Shot *shot;
if ( lastDumbfireWasLeft ) {
shot = new Shot( SHOT_DUMBFIRE_DOUBLE, playerNr, pos + Vector2D(15,-3), -90 );
} else {
shot = new Shot( SHOT_DUMBFIRE_DOUBLE, playerNr, pos + Vector2D(-15,-3), -90 );
}
lastDumbfireWasLeft = !lastDumbfireWasLeft;
shots->addShot(shot);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastShotSecondary = SDL_GetTicks();
}
break;
}
case SHOT_KICK_ASS_ROCKET:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_KICK_ASS_ROCKET > timeLastShotSecondary ) {
Shot *shot =
new Shot( SHOT_KICK_ASS_ROCKET, playerNr, pos, -90 );
shots->addShot(shot);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastShotSecondary = SDL_GetTicks();
}
break;
}
case SHOT_HELLFIRE:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_HELLFIRE > timeLastShotSecondary ) {
Shot *shot1 =
new Shot( SHOT_HELLFIRE, playerNr, pos + Vector2D(-15, -3), -180 );
Shot *shot2 =
new Shot( SHOT_HELLFIRE, playerNr, pos + Vector2D(15, -3), 0 );
shots->addShot(shot1);
shots->addShot(shot2);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastShotSecondary = SDL_GetTicks();
}
break;
}
case SHOT_MACHINE_GUN:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_MACHINE_GUN > timeLastShotSecondary ) {
int idxNearestEnemy1 = 0;
float distFarestY1 = -1;
int idxNearestEnemy2 = 0;
float distFarestY2 = -1;
float angle1 = -90;
float angle2 = -90;
float maxDistY = pos.getY() + 40; // only enemys in or already in the screen
for ( unsigned int i = 0; i < enemys->getNrEnemys(); i++ ) {
// angle of the vector from the racer position to the enemy
float angleEnemy = (enemys->getEnemy(i)->getPos() - pos).getDirection();
if ( -90 <= angleEnemy && angleEnemy < -60 ) {
float distY = pos.getY() - enemys->getEnemy(i)->getPos().getY();
if ( distFarestY1 < distY && distY < maxDistY ) {
distFarestY1 = distY;
idxNearestEnemy1 = i;
angle2 = angleEnemy + 5;
}
} else {
if ( -120 < angleEnemy && angleEnemy < -90 ) {
float distY = pos.getY() - enemys->getEnemy(i)->getPos().getY();
if ( distFarestY2 < distY && distY < maxDistY ) {
distFarestY2 = distY;
idxNearestEnemy2 = i;
angle1 = angleEnemy - 5;
}
}
}
}
Shot *shot1 =
new Shot( SHOT_MACHINE_GUN, playerNr,
pos + Vector2D(-3, -spriteRacerBase->h/2), angle1 );
Shot *shot2 =
new Shot( SHOT_MACHINE_GUN, playerNr,
pos + Vector2D(+3, -spriteRacerBase->h/2), angle2 );
shots->addShot(shot1);
shots->addShot(shot2);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastShotSecondary = SDL_GetTicks();
}
break;
}
case SHOT_ENERGY_BEAM:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_ENERGY_BEAM > timeLastShotSecondary ) {
Shot *shot =
new Shot( SHOT_ENERGY_BEAM, playerNr, pos + Vector2D(-1, -10), -90 );
shots->addShot(shot);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastShotSecondary = SDL_GetTicks();
}
break;
}
// HEAVY FIGHTER SHOTS
case SHOT_HF_DUMBFIRE:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_HF_DUMBFIRE > timeLastShotSecondary ) {
Shot *shot =
new Shot( SHOT_HF_DUMBFIRE, playerNr, pos + Vector2D(-30, -5), -90 );
shots->addShot(shot);
shot =
new Shot( SHOT_HF_DUMBFIRE, playerNr, pos + Vector2D(30, -5), -90 );
shots->addShot(shot);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastShotSecondary = SDL_GetTicks();
}
break;
}
case SHOT_HF_DUMBFIRE_DOUBLE:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_HF_DUMBFIRE_DOUBLE > timeLastShotSecondary ) {
Shot *shot =
new Shot( SHOT_HF_DUMBFIRE_DOUBLE, playerNr, pos + Vector2D(-30, -5), -90 );
shots->addShot(shot);
shot =
new Shot( SHOT_HF_DUMBFIRE_DOUBLE, playerNr, pos + Vector2D(30, -5), -90 );
shots->addShot(shot);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastShotSecondary = SDL_GetTicks();
}
break;
}
case SHOT_HF_KICK_ASS_ROCKET:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_HF_KICK_ASS_ROCKET > timeLastShotSecondary ) {
Shot *shot1 =
new Shot( SHOT_HF_KICK_ASS_ROCKET, playerNr, pos + Vector2D(-30,0), -90 );
shots->addShot(shot1);
Shot *shot2 =
new Shot( SHOT_HF_KICK_ASS_ROCKET, playerNr, pos + Vector2D(30,0), -90 );
shots->addShot(shot2);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastShotSecondary = SDL_GetTicks();
}
break;
}
case SHOT_HF_LASER:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_HF_LASER > timeLastShotSecondary ) {
Shot *shot1 =
new Shot( SHOT_HF_LASER, playerNr, pos + Vector2D(-30,-10), -90 );
shots->addShot(shot1);
Shot *shot2 =
new Shot( SHOT_HF_LASER, playerNr, pos + Vector2D(30,-10), -90 );
shots->addShot(shot2);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastShotSecondary = SDL_GetTicks();
}
break;
}
default:
{
cout << "Racer::shootSecondary: unexpected activeSecondary: "
<< activeSecondary << endl;
break;
}
}
}
}
void Racer::shootSpecial() {
if ( useSpecial ) {
switch ( activeSpecial ) {
case SPECIAL_HEATSEEKER:
{
if ( SDL_GetTicks() - RACER_COOLDOWN_SPECIAL_HEATSEEKER > timeLastHeatseekerUsed &&
specialsAvailability[ SPECIAL_HEATSEEKER ] > 0 ) {
Shot *shot;
if ( lastHeatseekerWasLeft ) {
shot = new Shot( SPECIAL_SHOT_HEATSEEKER, playerNr, pos + Vector2D(15,-3), -90 );
} else {
shot = new Shot( SPECIAL_SHOT_HEATSEEKER, playerNr, pos + Vector2D(-15,-3), -90 );
}
lastHeatseekerWasLeft = !lastHeatseekerWasLeft;
shots->addShot(shot);
Mixer::mixer().playSample( sndShotSecondary, 0 );
timeLastHeatseekerUsed = SDL_GetTicks();
specialsAvailability[ SPECIAL_HEATSEEKER ]--;
}
break;
}
default: break;
}
}
}
bool Racer::collidesWith( const Vector2D &shotPosOld, const Vector2D &shotPosNew ) {
return boundingBox->overlaps(shotPosOld, shotPosNew);
}
bool Racer::collidesWith( BoundingBox *box ) {
return boundingBox->overlaps( box );
}
bool Racer::collidesWith( const Circle &circle ) {
return boundingBox->overlaps( circle );
}
bool Racer::collidesWithAsCircle( const Circle &circle ) {
return ( (circle.getRadius() + (spriteRacerBase->w / RACER_IMAGE_CNT)/2) > circle.getCenter().distanceTo( pos ) );
}
bool Racer::collidesWithAsCircle( BoundingBox *box ) {
return ( box->overlaps( Circle( pos, spriteRacerBase->h >> 1 ) ) );
}
BoundingBox *Racer::getBoundingBox() {
return boundingBox;
}
bool Racer::isDead() {
return (damage < 0);
}
void Racer::receiveDamage( float amount ) {
if ( lroundf(shield) >= amount ) {
shield -= amount;
shieldDamageActive = true;
shieldDamageEndTime = SDL_GetTicks() + RACER_SHIELD_DAMAGE_LIFETIME;
return;
}
amount -= shield;
shield = 0;
damage -= amount;
}
void Racer::doDamage( ShotTypes shotType ) {
switch (shotType) {
case ENEMY_SHOT_NORMAL:
{
receiveDamage( DAMAGE_ENEMY_SHOT_NORMAL );
break;
}
case ENEMY_SHOT_TANK_ROCKET:
{
receiveDamage( DAMAGE_ENEMY_SHOT_TANK_ROCKET );
break;
}
default:
{
cout << "Racer::doDamage: unexpected shotType: " << shotType << endl;
break;
}
}
}
void Racer::rechargeShield ( int dT ) {
float amount;
if ( shipType == LIGHT_FIGHTER ) {
amount = LIGHT_FIGHTER_SHIELD_RECHARGE * dT / 100000.0;
} else {
amount = HEAVY_FIGHTER_SHIELD_RECHARGE * dT / 100000.0;
}
if (shield + amount < maxShield) shield += amount;
else shield = maxShield;
}
void Racer::receivePoints( float amount ) {
float oldPoints = points;
points += amount;
if ( arcadeGame ) {
// time for a health item?
for ( int i = 0; i < NR_ARCACE_POINTS_FOR_HEALTH_ITEM; i++ ) {
if ( oldPoints < ARCADE_POINTS_FOR_HEALTH_ITEM[ i ] &&
ARCADE_POINTS_FOR_HEALTH_ITEM[ i ] <= points ) {
Item *health = new Item( Vector2D( SCREEN_WIDTH / 2, -30 ),
Vector2D( 0, 30 ),
ITEM_HEALTH );
items->addItem( health );
banners->addBanner( BANNER_HEALTH, BANNER_MODE_FLY_FROM_LEFT, BANNER_BONUS_NONE );
break;
}
}
}
}
Vector2D Racer::setVel( const Vector2D &newVel ) {
Vector2D temp = vel;
vel = newVel;
if ( vel.getLength() >= getActVelMax() ) {
vel.setLength(getActVelMax());
}
return temp;
}
void Racer::setPos( const Vector2D &newPos ) {
pos = newPos;
updateBoundingBox();
}
void Racer::updateBoundingBox() {
boundingBox->moveUpperBound( lroundf(pos.getY() - spriteRacerBase->h * 0.45) );
boundingBox->moveLeftBound( lroundf(pos.getX() - (spriteRacerBase->w / RACER_IMAGE_CNT) * 0.45) );
}
void Racer::pickUpItems() {
for ( unsigned int i = 0; i < items->getNrItems(); i++ ) {
Item *item = items->getItem(i);
if ( !item->isExpired() && boundingBox->overlaps( item->getBoundingBox() ) ) {
switch (item->getType()) {
case ITEM_PRIMARY_UPGRADE:
{
int newPrimaryShotType = primaryShotType + 1;
if ( shipType == LIGHT_FIGHTER && newPrimaryShotType <= SHOT_TRIPLE )
primaryShotType = (ShotTypes)newPrimaryShotType;
else if ( shipType == HEAVY_FIGHTER && newPrimaryShotType <= SHOT_HF_QUINTO )
primaryShotType = (ShotTypes)newPrimaryShotType;
item->pickedUp();
addBannerItemCollected( BANNER_ITEM_PRIMARY_UPGRADE_COLLECTED );
break;
}
case ITEM_DUMBFIRE_DOUBLE:
{
if ( shipType == LIGHT_FIGHTER ) {
secondaryWeaponsAvailability[ SHOT_DUMBFIRE_DOUBLE - 100 ] = true;
if (activeSecondary == SHOT_DUMBFIRE ) activeSecondary = SHOT_DUMBFIRE_DOUBLE;
} else {
secondaryWeaponsAvailability[ SHOT_HF_DUMBFIRE_DOUBLE - 100 ] = true;
if (activeSecondary == SHOT_HF_DUMBFIRE ) activeSecondary = SHOT_HF_DUMBFIRE_DOUBLE;
}
item->pickedUp();
addBannerItemCollected( BANNER_ITEM_DUMBFIRE_DOUBLE_COLLECTED );
break;
}
case ITEM_KICK_ASS_ROCKET:
{
if ( shipType == LIGHT_FIGHTER )
secondaryWeaponsAvailability[ SHOT_KICK_ASS_ROCKET - 100 ] = true;
else
secondaryWeaponsAvailability[ SHOT_HF_KICK_ASS_ROCKET - 100 ] = true;
item->pickedUp();
addBannerItemCollected( BANNER_ITEM_KICK_ASS_ROCKET_COLLECTED );
break;
}
case ITEM_HELLFIRE:
{
if ( shipType == LIGHT_FIGHTER ) {
secondaryWeaponsAvailability[ SHOT_HELLFIRE - 100 ] = true;
item->pickedUp();
addBannerItemCollected( BANNER_ITEM_HELLFIRE_COLLECTED );
}
break;
}
case ITEM_MACHINE_GUN:
{
if ( shipType == LIGHT_FIGHTER ) {
secondaryWeaponsAvailability[ SHOT_MACHINE_GUN - 100 ] = true;
item->pickedUp();
addBannerItemCollected( BANNER_ITEM_MACHINE_GUN_COLLECTED );
}
break;
}
case ITEM_HEALTH:
{
if ( arcadeGame ) {
repair( ITEM_HEALTH_REPAIR_AMOUNT );
} else {
if ( shipType == LIGHT_FIGHTER )
repair( ITEM_HEALTH_REPAIR_AMOUNT );
else repair( ITEM_HEALTH_REPAIR_AMOUNT * ITEM_HEALTH_REPAIR_FACTOR_HEAVY_FIGHTER );
}
item->pickedUp();
addBannerItemCollected( BANNER_ITEM_HEALTH_COLLECTED );
break;
}
case ITEM_HEATSEEKER:
{
specialsAvailability[ SPECIAL_HEATSEEKER ] += ITEM_HEATSEEKER_AMMO;
activeSpecial = SPECIAL_HEATSEEKER;
item->pickedUp();
addBannerItemCollected( BANNER_ITEM_HEATSEEKER_COLLECTED );
break;
}
case ITEM_NUKE:
{
specialsAvailability[ SPECIAL_NUKE ] += ITEM_NUKE_AMMO;
if ( activeSpecial == SPECIAL_NONE ) {
activeSpecial = SPECIAL_NUKE;
}
item->pickedUp();
addBannerItemCollected( BANNER_ITEM_NUKE_COLLECTED );
break;
}
case ITEM_DEFLECTOR:
{
if (shipType == HEAVY_FIGHTER ) {
specialsAvailability[ SPECIAL_DEFLECTOR ] += ITEM_DEFLECTOR_AMMO;
if ( activeSpecial == SPECIAL_NONE ) {
activeSpecial = SPECIAL_DEFLECTOR;
}
item->pickedUp();
addBannerItemCollected( BANNER_ITEM_DEFLECTOR_COLLECTED );
}
break;
}
case ITEM_ENERGY_BEAM:
{
if ( shipType == LIGHT_FIGHTER ) {
secondaryWeaponsAvailability[ SHOT_ENERGY_BEAM - 100 ] = true;
item->pickedUp();
addBannerItemCollected( BANNER_ITEM_ENERGY_BEAM_COLLECTED );
}
break;
}
case ITEM_LASER:
{
if ( shipType == HEAVY_FIGHTER ) {
secondaryWeaponsAvailability[ SHOT_HF_LASER - 100 ] = true;
addBannerItemCollected( BANNER_ITEM_LASER_COLLECTED );
item->pickedUp();
}
break;
}
default:
{
cout << "pickUpItems: unexpected itemType: " << item->getType() << endl;
break;
}
}
}
}
}
float Racer::getActVelMax() {
return maxVel;
}
void Racer::repair( float amount ) {
float possibleDamageAdd = maxDamage - damage;
if ( possibleDamageAdd >= amount ) {
damage += amount;
} else {
damage += possibleDamageAdd;
amount -= possibleDamageAdd;
shield += amount;
}
if ( shield > maxShield ) shield = maxShield;
}
void Racer::specialKeyDown() {
switch ( activeSpecial ) {
case SPECIAL_NUKE:
{
if ( timeLastNukeUsed + RACER_COOLDOWN_SPECIAL_NUKE < SDL_GetTicks() ) {
shots->addShot( new Shot( SPECIAL_SHOT_NUKE,
playerNr, pos,
(Vector2D( SCREEN_WIDTH / 2.0,
SCREEN_HEIGHT / 2.0 ) - pos).getDirection() ) );
specialsAvailability[ SPECIAL_NUKE ]--;
timeLastNukeUsed = SDL_GetTicks();
}
break;
}
case SPECIAL_DEFLECTOR:
{
if ( !deflectorActive ) {
deflectorActive = true;
deflectorTimeLeft = ITEM_DEFLECTOR_DURATION;
specialsAvailability[ SPECIAL_DEFLECTOR ]--;
}
break;
}
default:
{
break;
}
}
if ( specialsAvailability[ activeSpecial ] == 0 ) {
switchSpecials();
}
}
void Racer::specialKeyUp() {
if ( specialsAvailability[ activeSpecial ] == 0 ) {
switchSpecials();
}
}
void Racer::handlePlayerEvent( PlayerEvent pEvent, bool keyDown ) {
switch (pEvent) {
case PE_UP: if ( keyDown ) thrust = true; else thrust = false; break;
case PE_DOWN: if ( keyDown ) backwards = true; else backwards = false; break;
case PE_LEFT: if ( keyDown ) left = true; else left = false; break;
case PE_RIGHT: if ( keyDown ) right = true; else right = false; break;
case PE_FIRE_SPECIALS:// PE_FIRE_WEAPONS:
if ( keyDown ) fireWeapons = true; else fireWeapons = false; break;
case PE_CHOOSE_WEAPON_SECONDARY:
{
if ( !keyDown ) {
switchSecondary();
}
break;
}
case PE_CHOOSE_WEAPON_SPECIALS:
{
if ( !keyDown ) {
switchSpecials();
}
break;
}
case PE_FIRE_WEAPONS: // PE_FIRE_SPECIALS:
{
if ( keyDown ) {
useSpecial = true;
specialKeyDown();
} else {
useSpecial = false;
specialKeyUp();
break;
}
}
default: break;
}
}
void Racer::addBannerItemCollected( BannerTexts text ) {
if ( onePlayerGame ) {
banners->addBanner( text,
BANNER_MODE_ITEM_COLLECTED_SINGLE_PLAYER,
BANNER_BONUS_NONE );
} else {
if ( playerNr == 0 ) {
banners->addBanner( text,
BANNER_MODE_ITEM_COLLECTED_PLAYER_ONE,
BANNER_BONUS_NONE );
} else {
banners->addBanner( text,
BANNER_MODE_ITEM_COLLECTED_PLAYER_TWO,
BANNER_BONUS_NONE );
}
}
}