538 lines
16 KiB
C++
538 lines
16 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.
|
|
***************************************************************************/
|
|
#include "enemy.h"
|
|
#include "SDL.h"
|
|
#include "surfaceDB.h"
|
|
#include "boundingBox.h"
|
|
#include "mixer.h"
|
|
#include "shots.h"
|
|
#include "shot.h"
|
|
#include "racers.h"
|
|
#include "racer.h"
|
|
#include "items.h"
|
|
#include "item.h"
|
|
#include "wrecks.h"
|
|
#include "wreck.h"
|
|
#include "global.h"
|
|
#include "explosions.h"
|
|
#include "explosion.h"
|
|
#include "options.h"
|
|
|
|
Enemy::Enemy( Vector2D pos, Vector2D vel, EnemyTypes whichEnemyType,
|
|
bool isInFormation, bool fireByFormation ) {
|
|
|
|
this->isInFormation = isInFormation;
|
|
this->fireByFormation = fireByFormation;
|
|
enemyType = whichEnemyType;
|
|
hitpoints = ENEMY_HITPOINTS[ enemyType ];
|
|
|
|
this->pos = pos;
|
|
this->vel = vel;
|
|
relTargetPos = Vector2D(0,0);
|
|
|
|
switch ( enemyType ) {
|
|
case FIGHTER:
|
|
{
|
|
string fn = LVL_ENEMY_FIGHTER;
|
|
levelConf->getStr( LVL_ENEMY_FIGHTER, fn );
|
|
spriteEnemy = surfaceDB.loadSurface( fn );
|
|
|
|
fn = LVL_ENEMY_FIGHTER_SHADOW;
|
|
levelConf->getStr( LVL_ENEMY_FIGHTER_SHADOW, fn );
|
|
spriteShadow = surfaceDB.loadSurface( fn, true );
|
|
break;
|
|
}
|
|
case BOMBER:
|
|
{
|
|
string fn = LVL_ENEMY_BOMBER;
|
|
levelConf->getStr( LVL_ENEMY_BOMBER, fn );
|
|
spriteEnemy = surfaceDB.loadSurface( fn );
|
|
|
|
fn = LVL_ENEMY_BOMBER_SHADOW;
|
|
levelConf->getStr( LVL_ENEMY_BOMBER_SHADOW, fn );
|
|
spriteShadow = surfaceDB.loadSurface( fn, true );
|
|
break;
|
|
}
|
|
case TANK:
|
|
{
|
|
string fn = LVL_ENEMY_TANK;
|
|
levelConf->getStr( LVL_ENEMY_TANK, fn );
|
|
spriteEnemy = surfaceDB.loadSurface( fn );
|
|
break;
|
|
}
|
|
|
|
case BOSS_1_MAIN_GUN:
|
|
{
|
|
string fn = LVL_ENEMY_BOSS_1_MAIN_GUN;
|
|
levelConf->getStr( LVL_ENEMY_BOSS_1_MAIN_GUN, fn );
|
|
spriteEnemy = surfaceDB.loadSurface( fn );
|
|
break;
|
|
}
|
|
case BOSS_1_ROCKET_LAUNCHER:
|
|
{
|
|
string fn = LVL_ENEMY_BOSS_1_ROCKET_LAUNCHER;
|
|
levelConf->getStr( LVL_ENEMY_BOSS_1_ROCKET_LAUNCHER, fn );
|
|
spriteEnemy = surfaceDB.loadSurface( fn );
|
|
break;
|
|
}
|
|
case BOSS_1_SHOT_BATTERY_LEFT:
|
|
{
|
|
string fn = LVL_ENEMY_BOSS_1_SHOT_BATTERY_LEFT;
|
|
levelConf->getStr( LVL_ENEMY_BOSS_1_SHOT_BATTERY_LEFT, fn );
|
|
spriteEnemy = surfaceDB.loadSurface( fn );
|
|
break;
|
|
}
|
|
case BOSS_1_SHOT_BATTERY_RIGHT:
|
|
{
|
|
string fn = LVL_ENEMY_BOSS_1_SHOT_BATTERY_RIGHT;
|
|
levelConf->getStr( LVL_ENEMY_BOSS_1_SHOT_BATTERY_RIGHT, fn );
|
|
spriteEnemy = surfaceDB.loadSurface( fn );
|
|
break;
|
|
}
|
|
case BOSS_2:
|
|
{
|
|
spriteEnemy = surfaceDB.loadSurface( FN_ENEMY_BOSS_2 );
|
|
spriteShadow = surfaceDB.loadSurface( FN_ENEMY_BOSS_2_SHADOW, true );
|
|
boss2PointReached = false;
|
|
boss2TargetPos = Vector2D(SCREEN_WIDTH / 2, 100);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
string fn = LVL_ENEMY_FIGHTER;
|
|
levelConf->getStr( LVL_ENEMY_FIGHTER, fn );
|
|
spriteEnemy = surfaceDB.loadSurface( fn );
|
|
break;
|
|
}
|
|
}
|
|
|
|
boundingBox = new BoundingBox( lroundf(pos.getX() - spriteEnemy->w * 0.45),
|
|
lroundf(pos.getY() - spriteEnemy->h * 0.45),
|
|
lroundf(spriteEnemy->w * 0.9),
|
|
lroundf(spriteEnemy->h * 0.9) );
|
|
nextShotPrimary = rand() % (ENEMY_RAND_WAIT_PRIMARY[ enemyType ]+1);
|
|
nextShotSecondary = rand() % (ENEMY_RAND_WAIT_SECONDARY[ enemyType ]+1);
|
|
|
|
sndShotPrimary = Mixer::mixer().loadSample( FN_SOUND_SHOT_PRIMARY );
|
|
sndShotSecondary = Mixer::mixer().loadSample( FN_SOUND_SHOT_SECONDARY );
|
|
}
|
|
|
|
Enemy::~Enemy() {
|
|
delete boundingBox;
|
|
}
|
|
|
|
|
|
bool Enemy::isExpired() {
|
|
return ( hitpoints <= 0 ||
|
|
pos.getY() < -500 ||
|
|
pos.getY() > SCREEN_HEIGHT + 500 ||
|
|
pos.getX() < -500 ||
|
|
pos.getX() > SCREEN_WIDTH + 500 );
|
|
}
|
|
|
|
|
|
void Enemy::expire() {
|
|
hitpoints = -1;
|
|
}
|
|
|
|
Circle Enemy::getBoundingCircle() {
|
|
return Circle( pos, min(spriteEnemy->w / 2, spriteEnemy->h / 2) );
|
|
}
|
|
|
|
BoundingBox *Enemy::getBoundingBox() {
|
|
return boundingBox;
|
|
}
|
|
|
|
bool Enemy::collidesWith( const Vector2D &shotPosOld, const Vector2D &shotPosNew ) {
|
|
return boundingBox->overlaps(shotPosOld, shotPosNew);
|
|
}
|
|
|
|
bool Enemy::collidesWith( BoundingBox *box ) {
|
|
return boundingBox->overlaps( box );
|
|
}
|
|
|
|
bool Enemy::collidesWith( const Circle &circle ) {
|
|
return boundingBox->overlaps( circle );
|
|
}
|
|
|
|
bool Enemy::collidesWithAsCircle( const Circle &circle ) {
|
|
return ( circle.getRadius() + spriteEnemy->w / 2 > circle.getCenter().distanceTo( pos ) );
|
|
}
|
|
|
|
bool Enemy::collidesWithAsCircle( BoundingBox *box ) {
|
|
return ( box->overlaps( Circle( pos, min( spriteEnemy->h / 2, spriteEnemy->w / 2 ) ) ) );
|
|
}
|
|
|
|
|
|
void Enemy::update( int dT ) {
|
|
move( dT );
|
|
if ( !fireByFormation ) {
|
|
shootPrimary( dT );
|
|
shootSecondary( dT );
|
|
}
|
|
}
|
|
|
|
void Enemy::move( int dT ) {
|
|
switch ( enemyType ) {
|
|
case FIGHTER:
|
|
case BOMBER:
|
|
{
|
|
if ( scrollingOn ) pos += vel * dT / 1000.0;
|
|
else pos += (vel - SCROLL_SPEED) * dT / 1000.0;
|
|
if ( isInFormation && relTargetPos != Vector2D(0,0) ) {
|
|
Vector2D addMovement =
|
|
Vector2D( 40, relTargetPos.getDirection(), POLAR ) * dT / 1000.0;
|
|
if ( addMovement.getLength() > relTargetPos.getLength() ) {
|
|
addMovement.setLength( relTargetPos.getLength() );
|
|
}
|
|
pos += addMovement;
|
|
relTargetPos -= addMovement;
|
|
}
|
|
updateBoundingBox();
|
|
break;
|
|
}
|
|
case TANK: {
|
|
if ( scrollingOn ) pos += vel * dT / 1000.0;
|
|
updateBoundingBox();
|
|
break;
|
|
}
|
|
case BOSS_1_MAIN_GUN:
|
|
case BOSS_1_ROCKET_LAUNCHER:
|
|
case BOSS_1_SHOT_BATTERY_LEFT:
|
|
case BOSS_1_SHOT_BATTERY_RIGHT: {
|
|
if ( scrollingOn ) {
|
|
pos += Vector2D( 0, SCROLL_SPEED * dT / 1000.0 );
|
|
updateBoundingBox();
|
|
if ( pos.getY() >= BOSS_1_END_Y ) {
|
|
scrollingOn = false;
|
|
pos.setY( BOSS_1_END_Y );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case BOSS_2: {
|
|
if ( boss2PointReached ) {
|
|
boss2TargetPos = Vector2D( (rand() % (SCREEN_WIDTH - spriteEnemy->w)) + spriteEnemy->w / 2, rand() % 100 + spriteEnemy->h );
|
|
boss2PointReached = false;
|
|
} else {
|
|
pos += (boss2TargetPos - pos) / 50;
|
|
}
|
|
if ( pos.distanceTo(boss2TargetPos) < 15.0 ) boss2PointReached = true;
|
|
updateBoundingBox();
|
|
break;
|
|
}
|
|
default: cout << "enemys.cc::move(): unknown enemyType" << endl; break;
|
|
}
|
|
}
|
|
|
|
void Enemy::updateBoundingBox() {
|
|
boundingBox->moveUpperBound( lroundf(pos.getY() - spriteEnemy->h * 0.45) );
|
|
boundingBox->moveLeftBound( lroundf(pos.getX() - spriteEnemy->w * 0.45) );
|
|
}
|
|
|
|
|
|
void Enemy::firePrimary() {
|
|
switch (enemyType) {
|
|
case FIGHTER:
|
|
{
|
|
Shot *shot =
|
|
new Shot( ENEMY_SHOT_NORMAL, 666,
|
|
pos + Vector2D( 0, spriteEnemy->h / 2 ),
|
|
90 );
|
|
shots->addShot( shot );
|
|
Mixer::mixer().playSample( sndShotPrimary, 0 );
|
|
break;
|
|
}
|
|
case BOMBER:
|
|
{
|
|
Shot *shot =
|
|
new Shot( ENEMY_SHOT_NORMAL, 666,
|
|
pos + Vector2D( -7, spriteEnemy->h / 2 ),
|
|
100 );
|
|
shots->addShot( shot );
|
|
shot =
|
|
new Shot( ENEMY_SHOT_NORMAL, 666,
|
|
pos + Vector2D( +7, spriteEnemy->h / 2 ),
|
|
80 );
|
|
shots->addShot( shot );
|
|
Mixer::mixer().playSample( sndShotPrimary, 0 );
|
|
break;
|
|
}
|
|
case TANK:
|
|
{
|
|
Shot *shot =
|
|
new Shot( ENEMY_SHOT_NORMAL, 666,
|
|
pos,
|
|
(rand() % 360) - 180 );
|
|
shots->addShot( shot );
|
|
Mixer::mixer().playSample( sndShotPrimary, 0 );
|
|
break;
|
|
}
|
|
case BOSS_1_MAIN_GUN:
|
|
{
|
|
Shot *shot =
|
|
new Shot( ENEMY_SHOT_NORMAL, 666,
|
|
pos,
|
|
(rand() % 20) + 80 );
|
|
shots->addShot( shot );
|
|
Mixer::mixer().playSample( sndShotPrimary, 0 );
|
|
break;
|
|
}
|
|
case BOSS_1_SHOT_BATTERY_LEFT:
|
|
{
|
|
Shot *shot =
|
|
new Shot( ENEMY_SHOT_NORMAL, 666,
|
|
pos,
|
|
(rand() % 120) + 30 );
|
|
shots->addShot( shot );
|
|
Mixer::mixer().playSample( sndShotPrimary, 0 );
|
|
break;
|
|
}
|
|
case BOSS_1_SHOT_BATTERY_RIGHT:
|
|
{
|
|
Shot *shot =
|
|
new Shot( ENEMY_SHOT_NORMAL, 666,
|
|
pos,
|
|
(rand() % 120) + 30 );
|
|
shots->addShot( shot );
|
|
Mixer::mixer().playSample( sndShotPrimary, 0 );
|
|
break;
|
|
}
|
|
case BOSS_1_ROCKET_LAUNCHER:
|
|
{
|
|
unsigned int racerIdx = rand() % racers->getNrRacers();
|
|
float angle = (racers->getRacer( racerIdx )->getPos() - pos).getDirection();
|
|
Shot *shot =
|
|
new Shot( ENEMY_SHOT_TANK_ROCKET, 666, pos, angle );
|
|
shots->addShot( shot );
|
|
Mixer::mixer().playSample( sndShotSecondary, 0 );
|
|
break;
|
|
}
|
|
case BOSS_2:
|
|
{
|
|
unsigned int racerIdx = rand() % racers->getNrRacers();
|
|
float angle = (racers->getRacer( racerIdx )->getPos() - pos).getDirection();
|
|
Shot *shot = new Shot( ENEMY_SHOT_NORMAL, 666, pos, angle );
|
|
shots->addShot( shot );
|
|
Mixer::mixer().playSample( sndShotPrimary, 0 );
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Enemy::shootPrimary( int dT ) {
|
|
nextShotPrimary -= dT;
|
|
if ( nextShotPrimary < 0 ) {
|
|
firePrimary();
|
|
nextShotPrimary =
|
|
(rand() % (ENEMY_RAND_WAIT_PRIMARY[ enemyType ]+1)) + ENEMY_COOLDOWN_PRIMARY[ enemyType ];
|
|
}
|
|
}
|
|
|
|
|
|
void Enemy::fireSecondary() {
|
|
switch (enemyType) {
|
|
case TANK:
|
|
{
|
|
unsigned int racerIdx = rand() % racers->getNrRacers();
|
|
float angle = (racers->getRacer( racerIdx )->getPos() - pos).getDirection();
|
|
|
|
Shot *shot =
|
|
new Shot( ENEMY_SHOT_TANK_ROCKET, 666, pos, angle );
|
|
shots->addShot( shot );
|
|
Mixer::mixer().playSample( sndShotSecondary, 0 );
|
|
break;
|
|
}
|
|
case BOSS_2:
|
|
{
|
|
unsigned int racerIdx = rand() % racers->getNrRacers();
|
|
float angle = (racers->getRacer( racerIdx )->getPos() - pos).getDirection();
|
|
Shot *shot = new Shot( ENEMY_SHOT_TANK_ROCKET, 666, pos - Vector2D(-80,0), angle );
|
|
shots->addShot( shot );
|
|
shot = new Shot( ENEMY_SHOT_TANK_ROCKET, 666, pos - Vector2D(+80,0), angle );
|
|
shots->addShot( shot );
|
|
Mixer::mixer().playSample( sndShotSecondary, 0 );
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Enemy::shootSecondary( int dT ) {
|
|
nextShotSecondary -= dT;
|
|
if ( nextShotSecondary < 0 ) {
|
|
fireSecondary();
|
|
nextShotSecondary =
|
|
(rand() % (ENEMY_RAND_WAIT_SECONDARY[ enemyType ]+1)) +
|
|
ENEMY_COOLDOWN_SECONDARY[ enemyType ];
|
|
}
|
|
}
|
|
|
|
|
|
void Enemy::doDamage( ShotTypes shotType, int fromWhichPlayer ) {
|
|
bool allreadyDead = isExpired();
|
|
|
|
switch (shotType) {
|
|
case SHOT_NORMAL: hitpoints -= DAMAGE_SHOT_NORMAL; break;
|
|
case SHOT_NORMAL_HEAVY: hitpoints -= DAMAGE_SHOT_NORMAL_HEAVY; break;
|
|
case SHOT_DOUBLE: hitpoints -= DAMAGE_SHOT_DOUBLE; break;
|
|
case SHOT_DOUBLE_HEAVY: hitpoints -= DAMAGE_SHOT_DOUBLE_HEAVY; break;
|
|
case SHOT_TRIPLE: hitpoints -= DAMAGE_SHOT_TRIPLE; break;
|
|
|
|
case SHOT_HF_NORMAL: hitpoints -= DAMAGE_SHOT_HF_NORMAL; break;
|
|
case SHOT_HF_DOUBLE: hitpoints -= DAMAGE_SHOT_HF_DOUBLE; break;
|
|
case SHOT_HF_TRIPLE: hitpoints -= DAMAGE_SHOT_HF_TRIPLE; break;
|
|
case SHOT_HF_QUATTRO: hitpoints -= DAMAGE_SHOT_HF_QUATTRO; break;
|
|
case SHOT_HF_QUINTO: hitpoints -= DAMAGE_SHOT_HF_QUINTO; break;
|
|
|
|
case SHOT_DUMBFIRE: hitpoints -= DAMAGE_SHOT_DUMBFIRE; break;
|
|
case SHOT_DUMBFIRE_DOUBLE: hitpoints -= DAMAGE_SHOT_DUMBFIRE_DOUBLE; break;
|
|
case SHOT_KICK_ASS_ROCKET: hitpoints -= DAMAGE_SHOT_KICK_ASS_ROCKET; break;
|
|
case SHOT_HELLFIRE: hitpoints -= DAMAGE_SHOT_HELLFIRE; break;
|
|
case SHOT_MACHINE_GUN: hitpoints -= DAMAGE_SHOT_MACHINE_GUN; break;
|
|
case SHOT_ENERGY_BEAM: hitpoints -= DAMAGE_SHOT_ENERGY_BEAM; break;
|
|
|
|
case SHOT_HF_DUMBFIRE: hitpoints -= DAMAGE_SHOT_HF_DUMBFIRE; break;
|
|
case SHOT_HF_DUMBFIRE_DOUBLE: hitpoints -= DAMAGE_SHOT_HF_DUMBFIRE_DOUBLE; break;
|
|
case SHOT_HF_KICK_ASS_ROCKET: hitpoints -= DAMAGE_SHOT_HF_KICK_ASS_ROCKET; break;
|
|
case SHOT_HF_LASER: hitpoints -= DAMAGE_SHOT_HF_LASER; break;
|
|
|
|
case SPECIAL_SHOT_HEATSEEKER: hitpoints -= DAMAGE_SPECIAL_SHOT_HEATSEEKER; break;
|
|
case SPECIAL_SHOT_NUKE: hitpoints -= DAMAGE_SPECIAL_SHOT_NUKE; break;
|
|
default:
|
|
{
|
|
cout << "Enemy::doDamage: unexpected shotType: " << shotType << endl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( enemyType < NR_ENEMY_TYPES_NORMAL ) {
|
|
// the enemy just died -> explode, generate item,
|
|
if ( (!allreadyDead) && isExpired() ) {
|
|
// the player gets points, who did the final shot
|
|
if ( 0 <= fromWhichPlayer && fromWhichPlayer < (int)racers->getNrRacers() ) {
|
|
racers->getRacer( fromWhichPlayer )->receivePoints( ENEMY_POINTS_FOR_DEST[ enemyType ]);
|
|
}
|
|
// explode
|
|
Explosion *newExplosion =
|
|
new Explosion( FN_EXPLOSION_ENEMY, pos, vel, EXPLOSION_NORMAL_AIR );
|
|
explosions->addExplosion( newExplosion );
|
|
// generate wreck
|
|
Wreck *newWreck = new Wreck( pos, WRECK_FOR_ENEMYTYPE[ enemyType ]);
|
|
wrecks->addWreck( newWreck );
|
|
// generate item
|
|
if ( rand() % ENEMY_DIES_ITEM_APPEAR_CHANCE[ enemyType ] == 0 ) {
|
|
items->generateItemNow( pos, vel / 10.0 );
|
|
}
|
|
}
|
|
}
|
|
// it's a boss!!!
|
|
else {
|
|
if ( (!allreadyDead) && isExpired() ) {
|
|
// explode
|
|
Explosion *newExplosion;
|
|
for(int i = 0; i < 10; i++){
|
|
newExplosion = new Explosion(
|
|
FN_EXPLOSION_ENEMY,
|
|
pos + Vector2D(rand() % spriteEnemy->w - spriteEnemy->w / 2, rand() % spriteEnemy->h - spriteEnemy->h / 2),
|
|
vel + Vector2D(rand() % 100 - 50, rand() % 100 - 50) / 5.0,
|
|
EXPLOSION_NORMAL_GROUND );
|
|
explosions->addExplosion( newExplosion );
|
|
}
|
|
|
|
// generate wreck
|
|
Wreck *newWreck = new Wreck( pos, WRECK_FOR_ENEMYTYPE[ enemyType ]);
|
|
wrecks->addWreck( newWreck );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Enemy::drawGroundEnemy( SdlCompat_AcceleratedSurface *screen ) {
|
|
if ( ENEMY_FLYING[ enemyType ] ) return;
|
|
|
|
SDL_Rect destR;
|
|
|
|
destR.x = lroundf(pos.getX()) - spriteEnemy->w / 2;
|
|
destR.y = lroundf(pos.getY()) - spriteEnemy->h / 2;
|
|
destR.w = spriteEnemy->w;
|
|
destR.h = spriteEnemy->h;
|
|
|
|
SDL_BlitSurface( spriteEnemy, 0, screen, &destR );
|
|
}
|
|
|
|
void Enemy::drawAirEnemy( SdlCompat_AcceleratedSurface *screen ) {
|
|
if ( !ENEMY_FLYING[ enemyType ] ) return;
|
|
|
|
SDL_Rect destR;
|
|
|
|
destR.x = lroundf(pos.getX()) - spriteEnemy->w / 2;
|
|
destR.y = lroundf(pos.getY()) - spriteEnemy->h / 2;
|
|
destR.w = spriteEnemy->w;
|
|
destR.h = spriteEnemy->h;
|
|
|
|
SDL_BlitSurface( spriteEnemy, 0, screen, &destR );
|
|
}
|
|
|
|
void Enemy::drawShadow( SdlCompat_AcceleratedSurface *screen ) {
|
|
if ( !ENEMY_FLYING[ enemyType ] ) return;
|
|
|
|
SDL_Rect destR;
|
|
|
|
destR.x = lroundf(pos.getX()) - spriteShadow->w / 2 - ENEMY_FLYING_HEIGHT[ enemyType ];
|
|
destR.y = lroundf(pos.getY()) - spriteShadow->h / 2 + ENEMY_FLYING_HEIGHT[ enemyType ];
|
|
destR.w = spriteShadow->w;
|
|
destR.h = spriteShadow->h;
|
|
|
|
SDL_BlitSurface( spriteShadow, 0, screen, &destR );
|
|
}
|
|
|
|
|
|
void Enemy::drawStats( SdlCompat_AcceleratedSurface *screen ) {
|
|
// draw status of the bosses
|
|
float pixPerHP = spriteEnemy->w / (float)(ENEMY_HITPOINTS[ enemyType ]);
|
|
SDL_Rect destR;
|
|
// draw damage
|
|
destR.x = lroundf(pos.getX()) - spriteEnemy->w / 2;
|
|
destR.y = lroundf(pos.getY()) - spriteEnemy->h / 2 - 4;
|
|
float damageToDraw = min( (float)ENEMY_HITPOINTS[ enemyType ] / 2, hitpoints );
|
|
destR.w = lroundf(pixPerHP * damageToDraw);
|
|
destR.h = 3;
|
|
SDL_FillRect( screen, &destR, SDL_MapRGB(screen->format, 255, 0, 0) );
|
|
// draw shields
|
|
destR.x = lroundf(pos.getX());
|
|
destR.y = lroundf(pos.getY()) - spriteEnemy->h / 2 - 4;
|
|
float shieldToDraw = min( (float)ENEMY_HITPOINTS[ enemyType ] / 2,
|
|
hitpoints - ENEMY_HITPOINTS[ enemyType ] / 2 );
|
|
if ( shieldToDraw < 1 ) destR.w = 0;
|
|
else destR.w = lroundf(pixPerHP * shieldToDraw);
|
|
destR.h = 3;
|
|
SDL_FillRect(screen, &destR, SDL_MapRGB(screen->format, 0, 255, 0) );
|
|
}
|