Files
commandergenius/alienblaster/project/jni/application/src/shot.cpp
pelya 99698187cf True HW acceleration for Alien Blaster - it now runs 45 FPS on ADP1,
and 30 FPS on HTC Evo (it could run faster but they limited max FPS in GL renderer).
See file SdlForwardCompat.h to have an idea how to make your SDL 1.2 app HW accelerated with SDL 1.3 -
it's a compilation of hacks but whatever.
2010-07-06 13:57:58 +03:00

858 lines
23 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 <iostream>
#include "shot.h"
#include "surfaceDB.h"
#include "racers.h"
#include "racer.h"
#include "explosions.h"
#include "explosion.h"
#include "enemys.h"
#include "enemy.h"
#include "smokePuffs.h"
#include "boundingBox.h"
Shot::Shot( ShotTypes shotType, int playerNr, Vector2D position, float angle ) {
this->shotType = shotType;
fromWhichPlayer = playerNr;
pos = position;
collidedWithGround = false;
deflectedBySonicFromPlayer1 = false;
deflectedBySonicFromPlayer2 = false;
generatesSmokePuffs = false;
timeToNextSmokePuff = 100;
switch (shotType) {
// primary shots
case SHOT_NORMAL:
{
vel = Vector2D( VEL_SHOT_NORMAL, angle, POLAR);
timeToLive = LIFETIME_SHOT_NORMAL;
sprite = surfaceDB.loadSurface( FN_SHOT_NORMAL );
break;
}
case SHOT_NORMAL_HEAVY:
{
vel = Vector2D( VEL_SHOT_NORMAL_HEAVY, angle, POLAR);
timeToLive = LIFETIME_SHOT_NORMAL_HEAVY;
sprite = surfaceDB.loadSurface( FN_SHOT_NORMAL_HEAVY );
break;
}
case SHOT_DOUBLE:
{
vel = Vector2D(VEL_SHOT_DOUBLE, angle, POLAR);
timeToLive = LIFETIME_SHOT_DOUBLE;
sprite = surfaceDB.loadSurface( FN_SHOT_DOUBLE );
break;
}
case SHOT_DOUBLE_HEAVY:
{
vel = Vector2D(VEL_SHOT_DOUBLE_HEAVY, angle, POLAR);
timeToLive = LIFETIME_SHOT_DOUBLE_HEAVY;
sprite = surfaceDB.loadSurface( FN_SHOT_DOUBLE_HEAVY );
break;
}
case SHOT_TRIPLE:
{
vel = Vector2D(VEL_SHOT_TRIPLE, angle, POLAR);
timeToLive = LIFETIME_SHOT_TRIPLE;
sprite = surfaceDB.loadSurface( FN_SHOT_TRIPLE );
break;
}
// primary shots heavy fighter
case SHOT_HF_NORMAL:
{
vel = Vector2D( VEL_SHOT_HF_NORMAL, angle, POLAR);
timeToLive = LIFETIME_SHOT_HF_NORMAL;
sprite = surfaceDB.loadSurface( FN_SHOT_HF_NORMAL );
break;
}
case SHOT_HF_DOUBLE:
{
vel = Vector2D( VEL_SHOT_HF_DOUBLE, angle, POLAR);
timeToLive = LIFETIME_SHOT_HF_DOUBLE;
sprite = surfaceDB.loadSurface( FN_SHOT_HF_DOUBLE );
break;
}
case SHOT_HF_TRIPLE:
{
vel = Vector2D(VEL_SHOT_HF_TRIPLE, angle, POLAR);
timeToLive = LIFETIME_SHOT_HF_TRIPLE;
sprite = surfaceDB.loadSurface( FN_SHOT_HF_TRIPLE );
break;
}
case SHOT_HF_QUATTRO:
{
vel = Vector2D(VEL_SHOT_HF_QUATTRO, angle, POLAR);
timeToLive = LIFETIME_SHOT_HF_QUATTRO;
sprite = surfaceDB.loadSurface( FN_SHOT_HF_QUATTRO );
break;
}
case SHOT_HF_QUINTO:
{
vel = Vector2D(VEL_SHOT_HF_QUINTO, angle, POLAR);
timeToLive = LIFETIME_SHOT_HF_QUINTO;
sprite = surfaceDB.loadSurface( FN_SHOT_HF_QUINTO );
break;
}
// secondary shots
case SHOT_DUMBFIRE:
{
vel = Vector2D(VEL_SHOT_DUMBFIRE, angle, POLAR);
timeToLive = LIFETIME_SHOT_DUMBFIRE;
sprite = surfaceDB.loadSurface( FN_SHOT_DUMBFIRE );
generatesSmokePuffs = true;
break;
}
case SHOT_DUMBFIRE_DOUBLE:
{
vel = Vector2D(VEL_SHOT_DUMBFIRE_DOUBLE, angle, POLAR);
timeToLive = LIFETIME_SHOT_DUMBFIRE_DOUBLE;
sprite = surfaceDB.loadSurface( FN_SHOT_DUMBFIRE_DOUBLE );
generatesSmokePuffs = true;
break;
}
case SHOT_KICK_ASS_ROCKET:
{
vel = Vector2D(VEL_SHOT_KICK_ASS_ROCKET, angle, POLAR);
timeToLive = LIFETIME_SHOT_KICK_ASS_ROCKET;
sprite = surfaceDB.loadSurface( FN_SHOT_KICK_ASS_ROCKET );
spriteShadow = surfaceDB.loadSurface( FN_SHOT_KICK_ASS_ROCKET_SHADOW, true );
break;
}
case SHOT_HELLFIRE:
{
vel = Vector2D(VEL_SHOT_HELLFIRE / 2.0, angle, POLAR);
timeToLive = LIFETIME_SHOT_HELLFIRE;
sprite = surfaceDB.loadSurface( FN_SHOT_HELLFIRE );
spriteShadow = surfaceDB.loadSurface( FN_SHOT_HELLFIRE_SHADOW, true );
generatesSmokePuffs = true;
break;
}
case SHOT_MACHINE_GUN:
{
vel = Vector2D(VEL_SHOT_MACHINE_GUN, angle, POLAR);
timeToLive = LIFETIME_SHOT_MACHINE_GUN;
sprite = surfaceDB.loadSurface( FN_SHOT_MACHINE_GUN );
break;
}
case SHOT_ENERGY_BEAM:
{
vel = Vector2D(VEL_SHOT_ENERGY_BEAM, angle, POLAR);
timeToLive = LIFETIME_SHOT_ENERY_BEAM;
sprite = surfaceDB.loadSurface( FN_SHOT_ENERGY_BEAM, true );
break;
}
// secondary shots heavy fighter
case SHOT_HF_DUMBFIRE:
{
vel = Vector2D(VEL_SHOT_HF_DUMBFIRE, angle, POLAR);
timeToLive = LIFETIME_SHOT_HF_DUMBFIRE;
sprite = surfaceDB.loadSurface( FN_SHOT_HF_DUMBFIRE );
generatesSmokePuffs = true;
break;
}
case SHOT_HF_DUMBFIRE_DOUBLE:
{
vel = Vector2D(VEL_SHOT_HF_DUMBFIRE_DOUBLE, angle, POLAR);
timeToLive = LIFETIME_SHOT_HF_DUMBFIRE_DOUBLE;
sprite = surfaceDB.loadSurface( FN_SHOT_HF_DUMBFIRE_DOUBLE );
generatesSmokePuffs = true;
break;
}
case SHOT_HF_KICK_ASS_ROCKET:
{
vel = Vector2D(VEL_SHOT_HF_KICK_ASS_ROCKET, angle, POLAR);
timeToLive = LIFETIME_SHOT_HF_KICK_ASS_ROCKET;
sprite = surfaceDB.loadSurface( FN_SHOT_HF_KICK_ASS_ROCKET );
spriteShadow = surfaceDB.loadSurface( FN_SHOT_HF_KICK_ASS_ROCKET_SHADOW, true );
break;
}
case SHOT_HF_LASER:
{
vel = Vector2D(VEL_SHOT_HF_LASER, angle, POLAR);
timeToLive = LIFETIME_SHOT_HF_LASER;
sprite = surfaceDB.loadSurface( FN_SHOT_HF_LASER );
break;
}
// special shots
case SPECIAL_SHOT_HEATSEEKER:
{
vel = Vector2D(VEL_SPECIAL_SHOT_HEATSEEKER, angle, POLAR);
timeToLive = LIFETIME_SPECIAL_SHOT_HEATSEEKER;
sprite = surfaceDB.loadSurface( FN_SPECIAL_SHOT_HEATSEEKER );
generatesSmokePuffs = true;
break;
}
case SPECIAL_SHOT_NUKE:
{
vel = Vector2D( VEL_SPECIAL_SHOT_NUKE, angle, POLAR );
timeToLive = LIFETIME_SPECIAL_SHOT_NUKE;
sprite = surfaceDB.loadSurface( FN_SPECIAL_SHOT_NUKE );
spriteShadow = surfaceDB.loadSurface( FN_SPECIAL_SHOT_NUKE_SHADOW, true );
break;
}
// enemy shots
case ENEMY_SHOT_NORMAL:
{
vel = Vector2D(VEL_ENEMY_SHOT_NORMAL, angle, POLAR);
timeToLive = LIFETIME_ENEMY_SHOT_NORMAL;
sprite = surfaceDB.loadSurface( FN_ENEMY_SHOT_NORMAL );
break;
}
case ENEMY_SHOT_TANK_ROCKET:
{
vel = Vector2D(VEL_ENEMY_SHOT_TANK_ROCKET, angle, POLAR);
timeToLive = LIFETIME_ENEMY_SHOT_TANK_ROCKET;
sprite = surfaceDB.loadSurface( FN_ENEMY_SHOT_TANK_ROCKET );
spriteShadow = surfaceDB.loadSurface( FN_ENEMY_SHOT_TANK_ROCKET_SHADOW, true );
generatesSmokePuffs = true;
break;
}
default:
{
vel = Vector2D(0,0);
timeToLive = 0;
sprite = surfaceDB.loadSurface( FN_SHOT_NORMAL );
break;
}
}
}
void Shot::moveAndCollide( int dT ) {
if ( fromWhichPlayer == 666 ) {
moveAndCollideEnemyShot( dT );
} else {
moveAndCollidePlayerShot( dT );
}
generateSmokePuff( dT );
timeToLive -= dT;
}
void Shot::moveAndCollidePlayerShot( int dT ) {
Vector2D posOld = pos;
// move the shot
movePlayerShot( dT );
if ( !isExpired() && collidePlayerShot( posOld ) ) {
addExplosion();
}
}
void Shot::movePlayerShot( int dT ) {
switch (shotType) {
case SHOT_NORMAL:
case SHOT_NORMAL_HEAVY:
case SHOT_DOUBLE:
case SHOT_DOUBLE_HEAVY:
case SHOT_TRIPLE:
case SHOT_HF_NORMAL:
case SHOT_HF_DOUBLE:
case SHOT_HF_TRIPLE:
case SHOT_HF_QUATTRO:
case SHOT_HF_QUINTO:
case SHOT_DUMBFIRE:
case SHOT_DUMBFIRE_DOUBLE:
case SHOT_KICK_ASS_ROCKET:
case SHOT_MACHINE_GUN:
case SHOT_ENERGY_BEAM:
case SHOT_HF_DUMBFIRE:
case SHOT_HF_DUMBFIRE_DOUBLE:
case SHOT_HF_KICK_ASS_ROCKET:
case SHOT_HF_LASER:
{
pos = pos + vel * dT / 1000.0;
break;
}
case SHOT_HELLFIRE:
{
pos = pos + vel * dT / 1000.0;
if ( timeToLive < LIFETIME_SHOT_HELLFIRE - 100 ) {
vel = Vector2D( 0, -VEL_SHOT_HELLFIRE );
}
break;
}
case SPECIAL_SHOT_HEATSEEKER:
{
pos = pos + vel * dT / 1000.0;
if ( timeToLive >= LIFETIME_SPECIAL_SHOT_HEATSEEKER - 200 ) break;
int idxNearestEnemy = 0;
float distNearest = 10000;
for ( unsigned int i = 0; i < enemys->getNrEnemys(); i++ ) {
// vector from the shotPosition to the enemy
Vector2D v = enemys->getEnemy(i)->getPos() - pos;
if ( getAbsAngleDifference( vel.getDirection(), v.getDirection() ) < 180 ) {
float dist = (enemys->getEnemy(i)->getPos() - pos).getLength();
if ( dist < distNearest ) {
distNearest = dist;
idxNearestEnemy = i;
}
}
}
if ( distNearest != 10000 ) {
float angle =
getAngleDifference( (enemys->getEnemy(idxNearestEnemy)->getPos()-pos).getDirection(),
vel.getDirection() );
if ( fabs(angle) < 80 * dT / 1000.0 ) {
vel.rotate(angle);
} else if ( angle < 0 ) {
vel.rotate( -80 * dT / 1000.0 );
} else {
vel.rotate( 80 * dT / 1000.0 );
}
}
break;
}
case SPECIAL_SHOT_NUKE:
{
pos = pos + vel * dT / 1000.0;
// Nuke is in its place!
if ( (pos - Vector2D( SCREEN_WIDTH / 2.0, SCREEN_HEIGHT / 2.0 )).getLength()
<= (vel * dT / 1000.0).getLength() ) {
nukeIsInPlace = true;
}
break;
}
default:
{
cout << "movePlayerShot: unexpected shotType: " << shotType << endl;
break;
}
}
// clip at the outside of the window
if ( !RectangleGeo( Vector2D( -SHOT_SCREEN_BORDER, -SHOT_SCREEN_BORDER ),
Vector2D( SCREEN_WIDTH + SHOT_SCREEN_BORDER,
SCREEN_HEIGHT + SHOT_SCREEN_BORDER )).isInside(pos) ) {
timeToLive = 0;
}
}
bool Shot::collidePlayerShot( Vector2D posOld ) {
switch (shotType) {
// only against air
case SHOT_ENERGY_BEAM:
{
BoundingBox box( lroundf(posOld.getX()) - sprite->w / 2,
lroundf(pos.getY()) - sprite->w / 2,
sprite->w,
lroundf((posOld-pos).getY()) + sprite->h );
for ( unsigned int i = 0; i < enemys->getNrEnemys(); i++ ) {
if ( ENEMY_FLYING[ enemys->getEnemy(i)->getType() ] &&
enemys->getEnemy(i)->collidesWith( &box ) ) {
enemys->getEnemy(i)->doDamage( shotType, fromWhichPlayer );
timeToLive = 0;
collidedWithGround = !ENEMY_FLYING[ enemys->getEnemy(i)->getType() ];
return true;
}
}
break;
}
//only against air
case SHOT_HF_LASER:
{
for ( unsigned int i = 0; i < enemys->getNrEnemys(); i++ ) {
if ( ENEMY_FLYING[ enemys->getEnemy(i)->getType() ] &&
enemys->getEnemy(i)->collidesWith( posOld, pos ) ) {
enemys->getEnemy(i)->doDamage( shotType, fromWhichPlayer );
timeToLive = 0;
collidedWithGround = false;
return true;
}
}
break;
}
// against air and ground
case SHOT_NORMAL:
case SHOT_NORMAL_HEAVY:
case SHOT_DOUBLE:
case SHOT_DOUBLE_HEAVY:
case SHOT_TRIPLE:
case SHOT_HF_NORMAL:
case SHOT_HF_DOUBLE:
case SHOT_HF_TRIPLE:
case SHOT_HF_QUATTRO:
case SHOT_HF_QUINTO:
{
for ( unsigned int i = 0; i < enemys->getNrEnemys(); i++ ) {
if ( //ENEMY_FLYING[ enemys->getEnemy(i)->getType() ] &&
enemys->getEnemy(i)->collidesWith( posOld, pos ) ) {
enemys->getEnemy(i)->doDamage( shotType, fromWhichPlayer );
timeToLive = 0;
collidedWithGround = !ENEMY_FLYING[ enemys->getEnemy(i)->getType() ];
return true;
}
}
break;
}
// against air and ground
case SHOT_DUMBFIRE:
case SHOT_DUMBFIRE_DOUBLE:
case SHOT_HF_DUMBFIRE:
case SHOT_HF_DUMBFIRE_DOUBLE:
{
for ( unsigned int i = 0; i < enemys->getNrEnemys(); i++ ) {
if ( enemys->getEnemy(i)->collidesWith( Circle(pos, 15) ) ) {
enemys->getEnemy(i)->doDamage( shotType, fromWhichPlayer );
timeToLive = 0;
collidedWithGround = !ENEMY_FLYING[ enemys->getEnemy(i)->getType() ];
return true;
}
}
break;
}
// only against ground
case SHOT_KICK_ASS_ROCKET:
case SHOT_HF_KICK_ASS_ROCKET:
{
for ( unsigned int i = 0; i < enemys->getNrEnemys(); i++ ) {
if ( (!ENEMY_FLYING[ enemys->getEnemy(i)->getType() ]) &&
enemys->getEnemy(i)->collidesWith( Circle(pos, 15) ) ) {
enemys->getEnemy(i)->doDamage( shotType, fromWhichPlayer );
timeToLive = 0;
collidedWithGround = true;
return true;
}
}
break;
}
// only against ground, but has to hit more exactly than kickAssRocket
case SHOT_HELLFIRE:
{
for ( unsigned int i = 0; i < enemys->getNrEnemys(); i++ ) {
if ( (!ENEMY_FLYING[ enemys->getEnemy(i)->getType() ]) &&
enemys->getEnemy(i)->collidesWith( Circle(pos, 5) ) ) {
enemys->getEnemy(i)->doDamage( shotType, fromWhichPlayer );
timeToLive = 0;
collidedWithGround = true;
return true;
}
}
break;
}
// against air and ground
case SHOT_MACHINE_GUN:
{
for ( unsigned int i = 0; i < enemys->getNrEnemys(); i++ ) {
if ( enemys->getEnemy(i)->collidesWith( posOld, pos ) ) {
enemys->getEnemy(i)->doDamage( shotType, fromWhichPlayer );
timeToLive = 0;
collidedWithGround = !ENEMY_FLYING[ enemys->getEnemy(i)->getType() ];
return true;
}
}
break;
}
// against air and ground
case SPECIAL_SHOT_HEATSEEKER:
{
for ( unsigned int i = 0; i < enemys->getNrEnemys(); i++ ) {
if ( enemys->getEnemy(i)->collidesWith( Circle(pos, 5) ) ) {
enemys->getEnemy(i)->doDamage( shotType, fromWhichPlayer );
timeToLive = 0;
collidedWithGround = !ENEMY_FLYING[ enemys->getEnemy(i)->getType() ];
return true;
}
}
break;
}
case SPECIAL_SHOT_NUKE: break;
default:
{
cout << "collidePlayerShot: unexpected shotType: " << shotType << endl;
return false;
}
}
return false;
}
///////////////////////////
void Shot::moveAndCollideEnemyShot( int dT ) {
Vector2D posOld = pos;
moveEnemyShot( dT );
if ( !isExpired() && collideEnemyShot( posOld ) ) {
addExplosion();
}
}
void Shot::moveEnemyShot( int dT ) {
switch (shotType) {
case ENEMY_SHOT_NORMAL: {
// is this shot near the deflector of a racer?
for ( unsigned int i = 0; i < racers->getNrRacers(); i++) {
if ( racers->getRacer(i)->getShipType() == HEAVY_FIGHTER ) {
Vector2D racerToShot = pos - racers->getRacer(i)->getPos();
if ( racerToShot.getLength() < RACER_DEFLECTOR_ACTIVATION_DIST ) {
vel += Vector2D( RACER_DEFLECTOR_POWER * (dT / 1000.0),
racerToShot.getDirection(), POLAR );
}
if ( racers->getRacer(i)->isDeflectorSpecialActive() ) {
if ( racerToShot.getLength() < ITEM_DEFLECTOR_ACTIVATION_DIST ) {
vel += Vector2D( ITEM_DEFLECTOR_POWER * (dT / 1000.0),
racerToShot.getDirection(), POLAR );
}
}
}
}
pos = pos + vel * dT / 1000.0;
break;
}
case ENEMY_SHOT_TANK_ROCKET: {
if ( deflectedBySonicFromPlayer1 ) {
Vector2D racerToShot = pos - racers->getRacer(0)->getPos();
if ( racerToShot.getLength() < RACER_SONIC_ACTIVATION_DIST ) {
vel += Vector2D( RACER_SONIC_POWER * (dT / 1000.0),
racerToShot.getDirection(), POLAR );
deflectedBySonicFromPlayer1 = false;
}
}
if ( deflectedBySonicFromPlayer2 ) {
Vector2D racerToShot = pos - racers->getRacer(1)->getPos();
if ( racerToShot.getLength() < RACER_SONIC_ACTIVATION_DIST ) {
vel += Vector2D( RACER_SONIC_POWER * (dT / 1000.0),
racerToShot.getDirection(), POLAR );
deflectedBySonicFromPlayer2 = false;
}
}
pos = pos + vel * dT / 1000.0;
break;
}
default: {
cout << "moveEnemyShot: unexpected shotType: " << shotType << endl;
break;
}
}
// clip at the outside of the window
if ( !RectangleGeo(Vector2D( -SHOT_SCREEN_BORDER, -SHOT_SCREEN_BORDER ),
Vector2D( SCREEN_WIDTH + SHOT_SCREEN_BORDER,
SCREEN_HEIGHT + SHOT_SCREEN_BORDER )).isInside(pos) ) {
timeToLive = 0;
}
}
bool Shot::collideEnemyShot( Vector2D posOld ) {
switch (shotType) {
case ENEMY_SHOT_NORMAL:
{
for ( unsigned int i = 0; i < racers->getNrRacers(); i++ ) {
if ( racers->getRacer(i)->collidesWith( posOld, pos ) ) {
racers->getRacer(i)->doDamage( shotType );
timeToLive = 0;
collidedWithGround = false;
return true;
}
}
break;
}
case ENEMY_SHOT_TANK_ROCKET:
{
for ( unsigned int i = 0; i < racers->getNrRacers(); i++ ) {
if ( racers->getRacer(i)->collidesWith( Circle(pos, 5) ) ) {
racers->getRacer(i)->doDamage( shotType );
timeToLive = 0;
collidedWithGround = false;
return true;
}
}
break;
}
default:
{
cout << "collideEnemyShot: unexpected shotType: " << shotType << endl;
return false;
}
}
return false;
}
/////////////
void Shot::addExplosion() {
Explosion *explosion;
switch (shotType) {
default:
{
if ( collidedWithGround ) {
explosion = new Explosion( FN_EXPLOSION_NORMAL, pos,
vel / 10.0, EXPLOSION_NORMAL_GROUND );
} else {
if ( shotType == SHOT_HF_LASER ) {
// Laser is too fast...
explosion = new Explosion( FN_EXPLOSION_NORMAL, pos,
vel / 30.0, EXPLOSION_NORMAL_AIR );
} else {
explosion = new Explosion( FN_EXPLOSION_NORMAL, pos,
vel / 10.0, EXPLOSION_NORMAL_AIR );
}
}
break;
}
}
explosions->addExplosion( explosion );
}
////////////////////
void Shot::drawShadow(SdlCompat_AcceleratedSurface *screen) {
switch (shotType) {
case SHOT_KICK_ASS_ROCKET:
case SHOT_HF_KICK_ASS_ROCKET:
case SHOT_HELLFIRE:
case SPECIAL_SHOT_NUKE:
{
SDL_Rect shadowR;
shadowR.x = lroundf(pos.getX()) - spriteShadow->w / 2 - 7;
shadowR.y = lroundf(pos.getY()) - spriteShadow->h / 2 + 7;
shadowR.w = spriteShadow->w;
shadowR.h = spriteShadow->h;
SDL_BlitSurface( spriteShadow, 0, screen, &shadowR );
break;
}
case ENEMY_SHOT_TANK_ROCKET:
{
SDL_Rect destR;
SDL_Rect srcR;
destR.x = lroundf(pos.getX()) - spriteShadow->w / 16 - 10;
destR.y = lroundf(pos.getY()) - spriteShadow->h / 2 + 10;
destR.w = spriteShadow->w / 8;
destR.h = spriteShadow->h;
float angle = vel.getDirection() + 202.5;
int idx = lroundf(angle) % 360;
idx = idx / 45;
srcR.x = idx * spriteShadow->w / 8;
srcR.y = 0;
srcR.w = spriteShadow->w / 8;
srcR.h = spriteShadow->h;
SDL_BlitSurface( spriteShadow, &srcR, screen, &destR );
break;
}
default: break;
}
}
void Shot::drawGroundShot(SdlCompat_AcceleratedSurface *screen) {
switch (shotType) {
case SHOT_KICK_ASS_ROCKET:
case SHOT_HF_KICK_ASS_ROCKET:
case SHOT_HELLFIRE:
{
SDL_Rect destR;
SDL_Rect srcR;
destR.x = lroundf(pos.getX()) - sprite->w / 2;
destR.y = lroundf(pos.getY()) - sprite->h / 2;
destR.w = sprite->w;
destR.h = sprite->h;
srcR.x = 0;
srcR.y = 0;
srcR.w = sprite->w;
srcR.h = sprite->h;
SDL_BlitSurface( sprite, &srcR, screen, &destR );
break;
}
default: break;
}
}
void Shot::drawGroundAirShot(SdlCompat_AcceleratedSurface *screen) {
switch (shotType) {
case SHOT_DUMBFIRE:
case SHOT_DUMBFIRE_DOUBLE:
case SHOT_HF_DUMBFIRE:
case SHOT_HF_DUMBFIRE_DOUBLE:
{
SDL_Rect destR;
SDL_Rect srcR;
destR.x = lroundf(pos.getX()) - sprite->w / 16;
destR.y = lroundf(pos.getY()) - sprite->h / 2;
destR.w = sprite->w / 8;
destR.h = sprite->h;
// TODO: eight directions are outdated for dumbfire, but existent in the image
float angle = vel.getDirection() + 202.5;
int idx = lroundf(angle) % 360;
idx = idx / 45;
srcR.x = idx * 8;
srcR.y = 0;
srcR.w = 8;
srcR.h = 8;
SDL_BlitSurface( sprite, &srcR, screen, &destR );
break;
}
case SHOT_MACHINE_GUN:
case SHOT_HF_LASER:
{
SDL_Rect destR;
destR.x = lroundf(pos.getX()) - sprite->w / 2;
destR.y = lroundf(pos.getY()) - sprite->h / 2;
destR.w = sprite->w;
destR.h = sprite->h;
SDL_BlitSurface( sprite, 0, screen, &destR );
break;
}
case SHOT_ENERGY_BEAM:
{
SDL_Rect destR;
destR.x = lroundf(pos.getX()) - sprite->w / 2;
destR.y = lroundf(pos.getY()) - sprite->h / 2;
destR.w = sprite->w;
destR.h = sprite->h;
SDL_BlitSurface( sprite, 0, screen, &destR );
destR.x = lroundf(pos.getX()) - sprite->w / 2;
destR.y = lroundf(pos.getY()) - sprite->h / 2;
SDL_BlitSurface( sprite, 0, screen, &destR );
break;
}
case SPECIAL_SHOT_HEATSEEKER:
{
SDL_Rect destR;
SDL_Rect srcR;
destR.x = lroundf(pos.getX()) - sprite->w / 16;
destR.y = lroundf(pos.getY()) - sprite->h / 2;
destR.w = sprite->w / 8;
destR.h = sprite->h;
float angle = vel.getDirection() + 202.5;
int idx = lroundf(angle) % 360;
idx = idx / 45;
srcR.x = idx * 8;
srcR.y = 0;
srcR.w = 8;
srcR.h = 8;
SDL_BlitSurface( sprite, &srcR, screen, &destR );
break;
}
case ENEMY_SHOT_TANK_ROCKET:
{
SDL_Rect destR;
SDL_Rect srcR;
destR.x = lroundf(pos.getX()) - sprite->w / 16;
destR.y = lroundf(pos.getY()) - sprite->h / 2;
destR.w = sprite->w / 8;
destR.h = sprite->h;
float angle = vel.getDirection() + 202.5;
int idx = lroundf(angle) % 360;
idx = idx / 45;
srcR.x = idx * sprite->w / 8;
srcR.y = 0;
srcR.w = sprite->w / 8;
srcR.h = sprite->h;
SDL_BlitSurface( sprite, &srcR, screen, &destR );
break;
}
default: break;
}
}
void Shot::drawAirShot(SdlCompat_AcceleratedSurface *screen) {
switch (shotType) {
case SHOT_NORMAL:
case SHOT_NORMAL_HEAVY:
case SHOT_DOUBLE:
case SHOT_DOUBLE_HEAVY:
case SHOT_TRIPLE:
case SHOT_HF_NORMAL:
case SHOT_HF_DOUBLE:
case SHOT_HF_TRIPLE:
case SHOT_HF_QUATTRO:
case SHOT_HF_QUINTO:
case SPECIAL_SHOT_NUKE:
case ENEMY_SHOT_NORMAL:
{
SDL_Rect destR;
destR.x = lroundf(pos.getX()) - sprite->w / 2;
destR.y = lroundf(pos.getY()) - sprite->h / 2;
destR.w = sprite->w;
destR.h = sprite->h;
SDL_BlitSurface( sprite, 0, screen, &destR );
break;
}
default: break;
}
}
ShotTypes Shot::getShotType() {
return shotType;
}
void Shot::generateSmokePuff( int dT) {
if ( ! generatesSmokePuffs ) return;
timeToNextSmokePuff -= dT;
if ( timeToNextSmokePuff < 0 ) {
Vector2D relPos = -vel;
relPos.setLength( sprite->h / 2 );
if ( shotType == SHOT_HELLFIRE ||
shotType == ENEMY_SHOT_TANK_ROCKET ) {
smokePuffs->addSmokePuff( pos + relPos,
vel * SMOKE_PUFF_VELOCITY_FACTOR,
SMOKE_PUFF_MEDIUM );
timeToNextSmokePuff += SMOKE_PUFF_DELAY_TO_NEXT_PUFF[ SMOKE_PUFF_MEDIUM ];
} else {
smokePuffs->addSmokePuff( pos + relPos,
vel * SMOKE_PUFF_VELOCITY_FACTOR,
SMOKE_PUFF_SMALL );
timeToNextSmokePuff += SMOKE_PUFF_DELAY_TO_NEXT_PUFF[ SMOKE_PUFF_SMALL ];
}
}
}