3439 lines
97 KiB
C++
3439 lines
97 KiB
C++
#include "game.h"
|
|
#ifdef __MIPSEL__
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
#endif
|
|
|
|
// Constructor
|
|
Game::Game(int numPlayers, SDL_Renderer *renderer, Screen *screen, std::string *filelist, Lang *lang, Input *input, bool demo, options_t *options)
|
|
{
|
|
// Copia los punteros
|
|
mRenderer = renderer;
|
|
mScreen = screen;
|
|
mFileList = filelist;
|
|
mLang = lang;
|
|
mInput = input;
|
|
mOptions = options;
|
|
mOnePlayerControl = mOptions->input[0].deviceType;
|
|
|
|
// Pasa variables
|
|
mDemo.enabled = demo;
|
|
mNumPlayers = numPlayers;
|
|
if (mNumPlayers == 1)
|
|
mOptions->input[0].deviceType = INPUT_USE_ANY;
|
|
mDifficulty = mOptions->difficulty;
|
|
|
|
// Crea los objetos
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
mPlayer[i] = new Player();
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
mBalloon[i] = new Balloon();
|
|
for (int i = 0; i < MAX_BULLETS; i++)
|
|
mBullet[i] = new Bullet();
|
|
for (int i = 0; i < MAX_ITEMS; i++)
|
|
mItem[i] = new Item();
|
|
for (int i = 0; i < MAX_SMART_SPRITES; i++)
|
|
mSmartSprite[i] = new SmartSprite();
|
|
|
|
mTextureBalloon = new LTexture();
|
|
mTextureBullet = new LTexture();
|
|
mTextureGameBG = new LTexture();
|
|
mTextureGameText = new LTexture();
|
|
mTextureItems = new LTexture();
|
|
mTexturePlayer1Head = new LTexture();
|
|
mTexturePlayer1Body = new LTexture();
|
|
mTexturePlayer1Death = new LTexture();
|
|
mTexturePlayer1Legs = new LTexture();
|
|
mTexturePlayer2Head = new LTexture();
|
|
mTexturePlayer2Body = new LTexture();
|
|
mTexturePlayer2Death = new LTexture();
|
|
mTexturePlayer2Legs = new LTexture();
|
|
mTextureText = new LTexture();
|
|
mTextureTextScoreBoard = new LTexture();
|
|
mTextureTextBig = new LTexture();
|
|
mTextureTextNokia2 = new LTexture();
|
|
mTextureTextNokiaBig2 = new LTexture();
|
|
|
|
mText = new Text(mFileList[48], mTextureText, mRenderer);
|
|
mTextScoreBoard = new Text(mFileList[46], mTextureTextScoreBoard, mRenderer);
|
|
mTextBig = new Text(mFileList[47], mTextureTextBig, mRenderer);
|
|
mTextNokia2 = new Text(mFileList[57], mTextureTextNokia2, mRenderer);
|
|
mTextNokiaBig2 = new Text(mFileList[55], mTextureTextNokiaBig2, mRenderer);
|
|
|
|
mMenuGameOver = new Menu(mRenderer, mText, mInput, mFileList);
|
|
mMenuPause = new Menu(mRenderer, mText, mInput, mFileList);
|
|
|
|
mFade = new Fade(mRenderer);
|
|
mEventHandler = new SDL_Event();
|
|
|
|
mClouds1a = new MovingSprite();
|
|
mClouds1b = new MovingSprite();
|
|
mClouds2a = new MovingSprite();
|
|
mClouds2b = new MovingSprite();
|
|
m1000Bitmap = new SmartSprite();
|
|
m2500Bitmap = new SmartSprite();
|
|
m5000Bitmap = new SmartSprite();
|
|
mSpriteBackground = new Sprite();
|
|
mSpriteGetReady = new Sprite();
|
|
mSpriteGradient = new Sprite();
|
|
mSpriteGrass = new Sprite();
|
|
mSpritePowerMeter = new Sprite();
|
|
mSpriteScoreBoard = new Sprite();
|
|
|
|
#ifdef __MIPSEL__
|
|
DIR *dir = opendir("/media/data/local/home/.coffee_crisis");
|
|
if (dir)
|
|
{
|
|
closedir(dir);
|
|
}
|
|
else if (ENOENT == errno)
|
|
{
|
|
int status = mkdir("/media/data/local/home/.coffee_crisis", 755);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
Game::~Game()
|
|
{
|
|
saveScoreFile();
|
|
saveDemoFile();
|
|
|
|
mOptions->input[0].deviceType = mOnePlayerControl;
|
|
|
|
mRenderer = nullptr;
|
|
mScreen = nullptr;
|
|
mFileList = nullptr;
|
|
mLang = nullptr;
|
|
mInput = nullptr;
|
|
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
{
|
|
delete mPlayer[i];
|
|
mPlayer[i] = nullptr;
|
|
}
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
{
|
|
delete mBalloon[i];
|
|
mBalloon[i] = nullptr;
|
|
}
|
|
for (int i = 0; i < MAX_BULLETS; i++)
|
|
{
|
|
delete mBullet[i];
|
|
mBullet[i] = nullptr;
|
|
}
|
|
for (int i = 0; i < MAX_ITEMS; i++)
|
|
{
|
|
delete mItem[i];
|
|
mItem[i] = nullptr;
|
|
}
|
|
for (int i = 0; i < MAX_SMART_SPRITES; i++)
|
|
{
|
|
delete mSmartSprite[i];
|
|
mSmartSprite[i] = nullptr;
|
|
}
|
|
|
|
mTextureBalloon->unload();
|
|
delete mTextureBalloon;
|
|
mTextureBalloon = nullptr;
|
|
|
|
mTextureBullet->unload();
|
|
delete mTextureBullet;
|
|
mTextureBullet = nullptr;
|
|
|
|
mTextureGameBG->unload();
|
|
delete mTextureGameBG;
|
|
mTextureGameBG = nullptr;
|
|
|
|
mTextureGameText->unload();
|
|
delete mTextureGameText;
|
|
mTextureGameText = nullptr;
|
|
|
|
mTextureItems->unload();
|
|
delete mTextureItems;
|
|
mTextureItems = nullptr;
|
|
|
|
mTexturePlayer1Head->unload();
|
|
delete mTexturePlayer1Head;
|
|
mTexturePlayer1Head = nullptr;
|
|
|
|
mTexturePlayer1Body->unload();
|
|
delete mTexturePlayer1Body;
|
|
mTexturePlayer1Body = nullptr;
|
|
|
|
mTexturePlayer1Death->unload();
|
|
delete mTexturePlayer1Death;
|
|
mTexturePlayer1Death = nullptr;
|
|
|
|
mTexturePlayer1Legs->unload();
|
|
delete mTexturePlayer1Legs;
|
|
mTexturePlayer1Legs = nullptr;
|
|
|
|
mTexturePlayer2Head->unload();
|
|
delete mTexturePlayer2Head;
|
|
mTexturePlayer2Head = nullptr;
|
|
|
|
mTexturePlayer2Body->unload();
|
|
delete mTexturePlayer2Body;
|
|
mTexturePlayer2Body = nullptr;
|
|
|
|
mTexturePlayer2Death->unload();
|
|
delete mTexturePlayer2Death;
|
|
mTexturePlayer2Death = nullptr;
|
|
|
|
mTexturePlayer2Legs->unload();
|
|
delete mTexturePlayer2Legs;
|
|
mTexturePlayer2Legs = nullptr;
|
|
|
|
mTextureText->unload();
|
|
delete mTextureText;
|
|
mTextureText = nullptr;
|
|
|
|
mTextureTextScoreBoard->unload();
|
|
delete mTextureTextScoreBoard;
|
|
mTextureTextScoreBoard = nullptr;
|
|
|
|
mTextureTextBig->unload();
|
|
delete mTextureTextBig;
|
|
mTextureTextBig = nullptr;
|
|
|
|
mTextureTextNokia2->unload();
|
|
delete mTextureTextNokia2;
|
|
mTextureTextNokia2 = nullptr;
|
|
|
|
mTextureTextNokiaBig2->unload();
|
|
delete mTextureTextNokiaBig2;
|
|
mTextureTextNokiaBig2 = nullptr;
|
|
|
|
delete mText;
|
|
mText = nullptr;
|
|
|
|
delete mTextBig;
|
|
mTextBig = nullptr;
|
|
|
|
delete mTextScoreBoard;
|
|
mTextScoreBoard = nullptr;
|
|
|
|
delete mTextNokia2;
|
|
mTextNokia2 = nullptr;
|
|
|
|
delete mTextNokiaBig2;
|
|
mTextNokiaBig2 = nullptr;
|
|
|
|
delete mMenuGameOver;
|
|
mMenuGameOver = nullptr;
|
|
|
|
delete mMenuPause;
|
|
mMenuPause = nullptr;
|
|
|
|
delete mFade;
|
|
mFade = nullptr;
|
|
|
|
delete mEventHandler;
|
|
mEventHandler = nullptr;
|
|
|
|
delete mClouds1a;
|
|
mClouds1a = nullptr;
|
|
|
|
delete mClouds1b;
|
|
mClouds1b = nullptr;
|
|
|
|
delete mClouds2a;
|
|
mClouds2a = nullptr;
|
|
|
|
delete mClouds2b;
|
|
mClouds2b = nullptr;
|
|
|
|
delete m1000Bitmap;
|
|
m1000Bitmap = nullptr;
|
|
|
|
delete m2500Bitmap;
|
|
m2500Bitmap = nullptr;
|
|
|
|
delete m5000Bitmap;
|
|
m5000Bitmap = nullptr;
|
|
|
|
delete mSpriteBackground;
|
|
mSpriteBackground = nullptr;
|
|
|
|
delete mSpriteGetReady;
|
|
mSpriteGetReady = nullptr;
|
|
|
|
delete mSpriteGradient;
|
|
mSpriteGradient = nullptr;
|
|
|
|
delete mSpriteGrass;
|
|
mSpriteGrass = nullptr;
|
|
|
|
delete mSpritePowerMeter;
|
|
mSpritePowerMeter = nullptr;
|
|
|
|
delete mSpriteScoreBoard;
|
|
mSpriteScoreBoard = nullptr;
|
|
|
|
JA_DeleteSound(mSoundBalloon);
|
|
JA_DeleteSound(mSoundBullet);
|
|
JA_DeleteSound(mSoundPlayerCollision);
|
|
JA_DeleteSound(mSoundHiScore);
|
|
JA_DeleteSound(mSoundItemDrop);
|
|
JA_DeleteSound(mSoundItemPickup);
|
|
JA_DeleteSound(mSoundCoffeeOut);
|
|
JA_DeleteSound(mSoundStageChange);
|
|
JA_DeleteSound(mSoundBubble1);
|
|
JA_DeleteSound(mSoundBubble2);
|
|
JA_DeleteSound(mSoundBubble3);
|
|
JA_DeleteSound(mSoundBubble4);
|
|
JA_DeleteSound(mSoundClock);
|
|
JA_DeleteSound(mSoundPowerBall);
|
|
JA_DeleteSound(mSoundCollision);
|
|
|
|
JA_DeleteMusic(mMusicPlaying);
|
|
}
|
|
|
|
// Inicializa el vector con los valores del seno
|
|
void Game::initSin()
|
|
{
|
|
// Vector con los valores del seno para 360 grados
|
|
for (int i = 0; i < 360; i++)
|
|
mSin[i] = SDL_sinf((float)i * 3.14f / 180.0f);
|
|
}
|
|
|
|
// Inicializa las variables necesarias para la sección 'Game'
|
|
void Game::init()
|
|
{
|
|
// Carga los recursos
|
|
loadMedia();
|
|
|
|
// Carga ficheros
|
|
loadScoreFile();
|
|
loadDemoFile();
|
|
|
|
mTicks = 0;
|
|
mTicksSpeed = 15;
|
|
|
|
// Inicializa las variables
|
|
switch (mDifficulty)
|
|
{
|
|
case DIFFICULTY_EASY:
|
|
mDefaultEnemySpeed = BALLOON_SPEED_1;
|
|
mDifficultyScoreMultiplier = 0.5f;
|
|
break;
|
|
|
|
case DIFFICULTY_NORMAL:
|
|
mDefaultEnemySpeed = BALLOON_SPEED_1;
|
|
mDifficultyScoreMultiplier = 1.0f;
|
|
break;
|
|
|
|
case DIFFICULTY_HARD:
|
|
mDefaultEnemySpeed = BALLOON_SPEED_5;
|
|
mDifficultyScoreMultiplier = 1.5f;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
mGameCompleted = false;
|
|
mGameCompletedCounter = 0;
|
|
mSection.name = PROG_SECTION_GAME;
|
|
mSection.subsection = GAME_SECTION_PLAY_1P;
|
|
mMenaceCurrent = 0;
|
|
mMenaceThreshold = 0;
|
|
mHiScoreAchieved = false;
|
|
mCurrentStage = 0;
|
|
mStageBitmapCounter = STAGE_COUNTER;
|
|
mDeathCounter = DEATH_COUNTER;
|
|
mExplosionTime = false;
|
|
mRemainingExplosions = REMAINING_EXPLOSIONS;
|
|
mRemainingExplosionsCounter = REMAINING_EXPLOSIONS_COUNTER;
|
|
mTimeStopped = false;
|
|
mTimeStoppedCounter = 0;
|
|
mCounter = 0;
|
|
mBalloonsPopped = 0;
|
|
mLastEnemyDeploy = 0;
|
|
mEnemyDeployCounter = 0;
|
|
mEnemySpeed = mDefaultEnemySpeed;
|
|
mEffect.flash = false;
|
|
mEffect.shake = false;
|
|
mEffect.shakeCounter = SHAKE_COUNTER;
|
|
mHelper.needCoffee = false;
|
|
mHelper.needCoffeeMachine = false;
|
|
mHelper.needPowerBall = false;
|
|
mHelper.counter = HELP_COUNTER;
|
|
mHelper.itemPoints1Odds = ITEM_POINTS_1_DISK_ODDS;
|
|
mHelper.itemPoints2Odds = ITEM_POINTS_2_GAVINA_ODDS;
|
|
mHelper.itemPoints3Odds = ITEM_POINTS_3_PACMAR_ODDS;
|
|
mHelper.itemClockOdds = ITEM_CLOCK_ODDS;
|
|
mHelper.itemCoffeeOdds = ITEM_COFFEE_ODDS;
|
|
mHelper.itemCoffeeMachineOdds = ITEM_COFFEE_MACHINE_ODDS;
|
|
mPowerBallEnabled = false;
|
|
mPowerBallCounter = 0;
|
|
mCoffeeMachineEnabled = false;
|
|
mPostFade = 0;
|
|
|
|
if (mDemo.enabled)
|
|
{
|
|
int num = rand() % 2;
|
|
if (num == 0)
|
|
{
|
|
mBalloonsPopped = 1000;
|
|
mCurrentStage = 3;
|
|
}
|
|
else
|
|
{
|
|
mBalloonsPopped = 1800;
|
|
mCurrentStage = 6;
|
|
}
|
|
}
|
|
|
|
initSin();
|
|
initPaths();
|
|
initEnemyFormations();
|
|
initEnemyPools();
|
|
initGameStages();
|
|
|
|
// Modo debug
|
|
mDebug.enabled = false;
|
|
mDebug.enemySet = 0;
|
|
mDebug.gradR = mDebug.gradG = mDebug.gradB = 0;
|
|
|
|
// Modo demo
|
|
mDemo.recording = false;
|
|
mDemo.counter = 0;
|
|
|
|
// Inicializa el objeto para el fundido
|
|
mFade->init(0x27, 0x27, 0x36);
|
|
|
|
// Inicializa el objeto con el menu de pausa
|
|
mMenuPause->init("PAUSE", 0, 12 * BLOCK, MENU_BACKGROUND_SOLID);
|
|
mMenuPause->addItem(mLang->getText(46), 2);
|
|
mMenuPause->addItem(mLang->getText(47), 0);
|
|
mMenuPause->setDefaultActionWhenCancel(0);
|
|
mMenuPause->setBackgroundColor(0x29, 0x39, 0x41, 240);
|
|
mMenuPause->setSelectorColor(0xFF, 0x7A, 0x00, 255);
|
|
mMenuPause->setSelectorTextColor(0xFF, 0xFF, 0xFF);
|
|
mMenuPause->centerMenuOnX(SCREEN_CENTER_X);
|
|
mMenuPause->centerMenuElementsOnX();
|
|
|
|
// Inicializa el objeto con el menu de la pantalla de game over
|
|
mMenuGameOver->init("GAME OVER", 0, PLAY_AREA_CENTER_Y + BLOCK * 4, MENU_BACKGROUND_TRANSPARENT);
|
|
mMenuGameOver->addItem(mLang->getText(48), 2);
|
|
mMenuGameOver->addItem(mLang->getText(49));
|
|
mMenuGameOver->setDefaultActionWhenCancel(1);
|
|
mMenuGameOver->setBackgroundColor(0, 0, 0, 255);
|
|
mMenuGameOver->setSelectorColor(0x54, 0x6e, 0x7a, 255);
|
|
mMenuGameOver->setSelectorColor(0x54, 0x6e, 0x7a, 0);
|
|
mMenuGameOver->setSelectorTextColor(0xFF, 0xFF, 0xFF);
|
|
mMenuGameOver->setSelectorTextColor(0xFF, 0xF1, 0x76);
|
|
mMenuGameOver->setSelectorTextColor(0xFF, 0x7A, 0x00);
|
|
mMenuGameOver->centerMenuOnX(SCREEN_CENTER_X);
|
|
mMenuGameOver->centerMenuElementsOnX();
|
|
|
|
// Sprites
|
|
mClouds1a->init(0, 0, 256, 52, -0.4f, 0.0f, 0.0f, 0.0f, mTextureGameBG, mRenderer);
|
|
mClouds1a->setSpriteClip(256, 0, 256, 52);
|
|
|
|
mClouds1b->init(256, 0, 256, 52, -0.4f, 0.0f, 0.0f, 0.0f, mTextureGameBG, mRenderer);
|
|
mClouds1b->setSpriteClip(256, 0, 256, 52);
|
|
|
|
mClouds2a->init(0, 52, 256, 32, -0.2f, 0.0f, 0.0f, 0.0f, mTextureGameBG, mRenderer);
|
|
mClouds2a->setSpriteClip(256, 52, 256, 32);
|
|
|
|
mClouds2b->init(256, 52, 256, 32, -0.2f, 0.0f, 0.0f, 0.0f, mTextureGameBG, mRenderer);
|
|
mClouds2b->setSpriteClip(256, 52, 256, 32);
|
|
|
|
mSpriteGrass->init(0, 85, SCREEN_WIDTH, 6, mTextureGameBG, mRenderer);
|
|
mSpriteGrass->setPosY(154);
|
|
|
|
mSpriteScoreBoard->init(0, 160, SCREEN_WIDTH, 32, mTextureGameBG, mRenderer);
|
|
mSpriteScoreBoard->setSpriteClip(0, 160, 256, 32);
|
|
|
|
mSpritePowerMeter->init(PLAY_AREA_CENTER_X - 20, 170, 40, 8, mTextureGameBG, mRenderer);
|
|
mSpritePowerMeter->setSpriteClip(256, 192 - 8, 40, 8);
|
|
|
|
// Vector de jugadores
|
|
if (mNumPlayers == 1)
|
|
mPlayer[0]->init(PLAY_AREA_CENTER_X - 11, PLAY_AREA_BOTTOM - 24, mTexturePlayer1Legs, mTexturePlayer1Body, mTexturePlayer1Head, mTexturePlayer1Death, mRenderer);
|
|
if (mNumPlayers == 2)
|
|
{
|
|
mPlayer[0]->init((PLAY_AREA_CENTER_FIRST_QUARTER_X * ((0 * 2) + 1)) - 11, PLAY_AREA_BOTTOM - 24, mTexturePlayer1Legs, mTexturePlayer1Body, mTexturePlayer1Head, mTexturePlayer1Death, mRenderer);
|
|
mPlayer[1]->init((PLAY_AREA_CENTER_FIRST_QUARTER_X * ((1 * 2) + 1)) - 11, PLAY_AREA_BOTTOM - 24, mTexturePlayer2Legs, mTexturePlayer2Body, mTexturePlayer2Head, mTexturePlayer2Death, mRenderer);
|
|
}
|
|
|
|
// Establece a cero todos los valores del vector de objetos globo
|
|
resetBalloons();
|
|
|
|
// Con los globos creados, calcula el nivel de amenaza
|
|
evaluateAndSetMenace();
|
|
|
|
// Establece a cero todos los valores del vector de objetos bala
|
|
resetBullets();
|
|
|
|
// Establece a cero todos los valores del vector de objetos item
|
|
resetItems();
|
|
|
|
// Establece a cero todos los valores del vector de objetos SmafrtSprite
|
|
resetSmartSprites();
|
|
|
|
// Inicializa el bitmap de GetReady!
|
|
mSpriteGetReady->init(0, PLAY_AREA_CENTER_Y - 10, 109, 20, mTextureGameText, mRenderer);
|
|
mSpriteGetReady->setSpriteClip(0, 0, 109, 20);
|
|
|
|
// Inicializa el bitmap de 1000 puntos
|
|
m1000Bitmap->init(mTextureGameText, mRenderer);
|
|
m1000Bitmap->setPosX(0);
|
|
m1000Bitmap->setPosY(0);
|
|
m1000Bitmap->setWidth(26);
|
|
m1000Bitmap->setHeight(9);
|
|
m1000Bitmap->setVelX(0.0f);
|
|
m1000Bitmap->setVelY(-0.5f);
|
|
m1000Bitmap->setAccelX(0.0f);
|
|
m1000Bitmap->setAccelY(-0.1f);
|
|
m1000Bitmap->setSpriteClip(0, 20, 26, 9);
|
|
m1000Bitmap->setEnabled(false);
|
|
m1000Bitmap->setEnabledTimer(0);
|
|
m1000Bitmap->setDestX(0);
|
|
m1000Bitmap->setDestY(0);
|
|
|
|
// Inicializa el bitmap de 2500 puntos
|
|
m2500Bitmap->init(mTextureGameText, mRenderer);
|
|
m2500Bitmap->setPosX(0);
|
|
m2500Bitmap->setPosY(0);
|
|
m2500Bitmap->setWidth(28);
|
|
m2500Bitmap->setHeight(9);
|
|
m2500Bitmap->setVelX(0.0f);
|
|
m2500Bitmap->setVelY(-0.5f);
|
|
m2500Bitmap->setAccelX(0.0f);
|
|
m2500Bitmap->setAccelY(-0.1f);
|
|
m2500Bitmap->setSpriteClip(26, 20, 28, 9);
|
|
m2500Bitmap->setEnabled(false);
|
|
m2500Bitmap->setEnabledTimer(0);
|
|
m2500Bitmap->setDestX(0);
|
|
m2500Bitmap->setDestY(0);
|
|
|
|
// Inicializa el bitmap de 5000 puntos
|
|
m5000Bitmap->init(mTextureGameText, mRenderer);
|
|
m5000Bitmap->setPosX(0);
|
|
m5000Bitmap->setPosY(0);
|
|
m5000Bitmap->setWidth(28);
|
|
m5000Bitmap->setHeight(9);
|
|
m5000Bitmap->setVelX(0.0f);
|
|
m5000Bitmap->setVelY(-0.5f);
|
|
m5000Bitmap->setAccelX(0.0f);
|
|
m5000Bitmap->setAccelY(-0.1f);
|
|
m5000Bitmap->setSpriteClip(54, 20, 28, 9);
|
|
m5000Bitmap->setEnabled(false);
|
|
m5000Bitmap->setEnabledTimer(0);
|
|
m5000Bitmap->setDestX(0);
|
|
m5000Bitmap->setDestY(0);
|
|
|
|
// Los fondos
|
|
mSpriteBackground->init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, mTextureGameBG, mRenderer);
|
|
mSpriteGradient->init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, mTextureGameBG, mRenderer);
|
|
mGradientRect[0] = {0, 192, SCREEN_WIDTH, SCREEN_HEIGHT};
|
|
mGradientRect[1] = {256, 192, SCREEN_WIDTH, SCREEN_HEIGHT};
|
|
mGradientRect[2] = {0, 384, SCREEN_WIDTH, SCREEN_HEIGHT};
|
|
mGradientRect[3] = {256, 384, SCREEN_WIDTH, SCREEN_HEIGHT};
|
|
}
|
|
|
|
// Carga los recursos necesarios para la sección 'Game'
|
|
bool Game::loadMedia()
|
|
{
|
|
bool success = true;
|
|
|
|
// Texturas
|
|
success &= loadTextureFromFile(mTextureText, mFileList[30], mRenderer);
|
|
success &= loadTextureFromFile(mTextureTextScoreBoard, mFileList[27], mRenderer);
|
|
success &= loadTextureFromFile(mTextureTextBig, mFileList[29], mRenderer);
|
|
success &= loadTextureFromFile(mTextureTextNokia2, mFileList[56], mRenderer);
|
|
success &= loadTextureFromFile(mTextureTextNokiaBig2, mFileList[54], mRenderer);
|
|
|
|
success &= loadTextureFromFile(mTexturePlayer1Legs, mFileList[39], mRenderer);
|
|
success &= loadTextureFromFile(mTexturePlayer1Head, mFileList[41], mRenderer);
|
|
success &= loadTextureFromFile(mTexturePlayer1Body, mFileList[37], mRenderer);
|
|
success &= loadTextureFromFile(mTexturePlayer1Death, mFileList[38], mRenderer);
|
|
|
|
success &= loadTextureFromFile(mTexturePlayer2Legs, mFileList[44], mRenderer);
|
|
success &= loadTextureFromFile(mTexturePlayer2Head, mFileList[45], mRenderer);
|
|
success &= loadTextureFromFile(mTexturePlayer2Body, mFileList[42], mRenderer);
|
|
success &= loadTextureFromFile(mTexturePlayer2Death, mFileList[43], mRenderer);
|
|
|
|
success &= loadTextureFromFile(mTextureBalloon, mFileList[24], mRenderer);
|
|
success &= loadTextureFromFile(mTextureBullet, mFileList[25], mRenderer);
|
|
success &= loadTextureFromFile(mTextureGameBG, mFileList[31], mRenderer);
|
|
success &= loadTextureFromFile(mTextureItems, mFileList[34], mRenderer);
|
|
success &= loadTextureFromFile(mTextureGameText, mFileList[32], mRenderer);
|
|
|
|
// Sonidos
|
|
mSoundBalloon = JA_LoadSound(mFileList[6].c_str());
|
|
mSoundBubble1 = JA_LoadSound(mFileList[7].c_str());
|
|
mSoundBubble2 = JA_LoadSound(mFileList[8].c_str());
|
|
mSoundBubble3 = JA_LoadSound(mFileList[9].c_str());
|
|
mSoundBubble4 = JA_LoadSound(mFileList[10].c_str());
|
|
mSoundBullet = JA_LoadSound(mFileList[11].c_str());
|
|
mSoundClock = JA_LoadSound(mFileList[22].c_str());
|
|
mSoundCoffeeOut = JA_LoadSound(mFileList[12].c_str());
|
|
mSoundHiScore = JA_LoadSound(mFileList[13].c_str());
|
|
mSoundItemDrop = JA_LoadSound(mFileList[14].c_str());
|
|
mSoundItemPickup = JA_LoadSound(mFileList[15].c_str());
|
|
mSoundPlayerCollision = JA_LoadSound(mFileList[19].c_str());
|
|
mSoundPowerBall = JA_LoadSound(mFileList[23].c_str());
|
|
mSoundStageChange = JA_LoadSound(mFileList[20].c_str());
|
|
mSoundCollision = JA_LoadSound(mFileList[21].c_str());
|
|
|
|
// Musicas
|
|
mMusicPlaying = JA_LoadMusic(mFileList[4].c_str());
|
|
|
|
return success;
|
|
}
|
|
|
|
// Carga el fichero de puntos
|
|
bool Game::loadScoreFile()
|
|
{
|
|
// Indicador de éxito en la carga
|
|
bool success = true;
|
|
const std::string p = mFileList[0];
|
|
const std::string filename = p.substr(p.find_last_of("\\/") + 1);
|
|
SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b");
|
|
|
|
// El fichero no existe
|
|
if (file == NULL)
|
|
{
|
|
printf("Warning: Unable to open %s file\n", filename.c_str());
|
|
|
|
// Creamos el fichero para escritura
|
|
file = SDL_RWFromFile(p.c_str(), "w+b");
|
|
if (file != NULL)
|
|
{
|
|
printf("New file (%s) created!\n", filename.c_str());
|
|
|
|
// Inicializamos los datos
|
|
for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
|
|
{
|
|
mScoreDataFile[i] = 0;
|
|
SDL_RWwrite(file, &mScoreDataFile[i], sizeof(Uint32), 1);
|
|
}
|
|
|
|
// Cerramos el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
else
|
|
{
|
|
printf("Error: Unable to create file %s\n", filename.c_str());
|
|
success = false;
|
|
}
|
|
}
|
|
// El fichero existe
|
|
else
|
|
{
|
|
// Cargamos los datos
|
|
printf("Reading file %s\n", filename.c_str());
|
|
for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
|
|
SDL_RWread(file, &mScoreDataFile[i], sizeof(Uint32), 1);
|
|
|
|
// Cierra el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
|
|
// Establece el valor de la máxima puntuación a partir del vector con los datos
|
|
if (mScoreDataFile[0] == 0)
|
|
mHiScore = 10000;
|
|
// Comprueba el checksum para ver si se ha modificado el fichero
|
|
else if (mScoreDataFile[0] % 43 == mScoreDataFile[1])
|
|
mHiScore = mScoreDataFile[0];
|
|
else
|
|
mHiScore = 10000;
|
|
|
|
return success;
|
|
}
|
|
|
|
// Carga el fichero de datos para la demo
|
|
bool Game::loadDemoFile()
|
|
{
|
|
// Indicador de éxito en la carga
|
|
bool success = true;
|
|
const std::string p = mFileList[1];
|
|
const std::string filename = p.substr(p.find_last_of("\\/") + 1);
|
|
SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b");
|
|
|
|
// El fichero no existe
|
|
if (file == NULL)
|
|
{
|
|
printf("Warning: Unable to open %s file\n", filename.c_str());
|
|
|
|
// Creamos el fichero para escritura
|
|
file = SDL_RWFromFile(p.c_str(), "w+b");
|
|
if (file != NULL)
|
|
{
|
|
printf("New file (%s) created!\n", filename.c_str());
|
|
|
|
// Inicializamos los datos
|
|
for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
|
|
{
|
|
mDemo.keys.left = 0;
|
|
mDemo.keys.right = 0;
|
|
mDemo.keys.noInput = 0;
|
|
mDemo.keys.fire = 0;
|
|
mDemo.keys.fireLeft = 0;
|
|
mDemo.keys.fireRight = 0;
|
|
mDemo.dataFile[i] = mDemo.keys;
|
|
SDL_RWwrite(file, &mDemo.dataFile[i], sizeof(demoKeys_t), 1);
|
|
}
|
|
|
|
// Cerramos el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
else
|
|
{
|
|
printf("Error: Unable to create file %s\n", filename.c_str());
|
|
success = false;
|
|
}
|
|
}
|
|
// El fichero existe
|
|
else
|
|
{
|
|
// Cargamos los datos
|
|
printf("Reading file %s\n", filename.c_str());
|
|
for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
|
|
SDL_RWread(file, &mDemo.dataFile[i], sizeof(demoKeys_t), 1);
|
|
|
|
// Cierra el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Guarda el fichero de puntos
|
|
bool Game::saveScoreFile()
|
|
{
|
|
bool success = true;
|
|
const std::string p = mFileList[0];
|
|
const std::string filename = p.substr(p.find_last_of("\\/") + 1);
|
|
SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b");
|
|
if (file != NULL)
|
|
{
|
|
// Guardamos los datos
|
|
for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
|
|
{
|
|
SDL_RWwrite(file, &mScoreDataFile[i], sizeof(Uint32), 1);
|
|
}
|
|
|
|
printf("Writing file %s\n", filename.c_str());
|
|
|
|
// Cerramos el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
else
|
|
{
|
|
printf("Error: Unable to save %s file! %s\n", filename.c_str(), SDL_GetError());
|
|
}
|
|
return success;
|
|
}
|
|
|
|
// Guarda el fichero de datos para la demo
|
|
bool Game::saveDemoFile()
|
|
{
|
|
bool success = true;
|
|
const std::string p = mFileList[1];
|
|
const std::string filename = p.substr(p.find_last_of("\\/") + 1);
|
|
if (mDemo.recording)
|
|
{
|
|
SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b");
|
|
if (file != NULL)
|
|
{
|
|
// Guardamos los datos
|
|
for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
|
|
{
|
|
SDL_RWwrite(file, &mDemo.dataFile[i], sizeof(demoKeys_t), 1);
|
|
}
|
|
|
|
printf("Writing file %s\n", filename.c_str());
|
|
|
|
// Cerramos el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
else
|
|
{
|
|
printf("Error: Unable to save %s file! %s\n", filename.c_str(), SDL_GetError());
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
// Inicializa las formaciones enemigas
|
|
void Game::initEnemyFormations()
|
|
{
|
|
const int y4 = (PLAY_AREA_TOP - BLOCK);
|
|
const int x4_0 = PLAY_AREA_LEFT;
|
|
const int x4_100 = (PLAY_AREA_RIGHT)-BALLOON_WIDTH_4;
|
|
|
|
const int y3 = (PLAY_AREA_TOP - BLOCK);
|
|
const int x3_0 = PLAY_AREA_LEFT;
|
|
const int x3_100 = (PLAY_AREA_RIGHT)-BALLOON_WIDTH_3;
|
|
|
|
const int y2 = (PLAY_AREA_TOP - BLOCK);
|
|
const int x2_0 = PLAY_AREA_LEFT;
|
|
const int x2_100 = (PLAY_AREA_RIGHT)-BALLOON_WIDTH_2;
|
|
|
|
const int y1 = (PLAY_AREA_TOP - BLOCK);
|
|
const int x1_0 = PLAY_AREA_LEFT;
|
|
const int x1_50 = PLAY_AREA_CENTER_X - (BALLOON_WIDTH_1 / 2);
|
|
const int x1_100 = (PLAY_AREA_RIGHT)-BALLOON_WIDTH_1;
|
|
|
|
// Inicializa a cero las variables
|
|
for (int i = 0; i < NUMBER_OF_ENEMY_FORMATIONS; i++)
|
|
{
|
|
mEnemyFormation[i].numberOfEnemies = 0;
|
|
for (int j = 0; j < MAX_NUMBER_OF_ENEMIES_IN_A_FORMATION; j++)
|
|
{
|
|
mEnemyFormation[i].init[j].x = 0;
|
|
mEnemyFormation[i].init[j].y = 0;
|
|
mEnemyFormation[i].init[j].velX = 0;
|
|
mEnemyFormation[i].init[j].kind = 0;
|
|
mEnemyFormation[i].init[j].creationCounter = 0;
|
|
}
|
|
}
|
|
|
|
const Uint16 creationTime = 300;
|
|
int incX = 0;
|
|
Uint8 incTime = 0;
|
|
Uint8 j = 0;
|
|
|
|
// #00 - Dos enemigos BALLOON4 uno a cada extremo
|
|
j = 0;
|
|
mEnemyFormation[j].numberOfEnemies = 2;
|
|
incX = x4_100;
|
|
incTime = 0;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x4_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].y = y4;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
|
|
mEnemyFormation[j].init[i].kind = BALLOON_4;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
|
|
}
|
|
|
|
// #01 - Dos enemigos BALLOON4 uno a cada cuarto. Ambos van hacia el centro
|
|
j = 1;
|
|
mEnemyFormation[j].numberOfEnemies = 2;
|
|
incX = PLAY_AREA_CENTER_X;
|
|
incTime = 0;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = PLAY_AREA_CENTER_FIRST_QUARTER_X - (BALLOON_WIDTH_4 / 2) + (i * incX);
|
|
mEnemyFormation[j].init[i].y = y4;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
|
|
mEnemyFormation[j].init[i].kind = BALLOON_4;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
|
|
}
|
|
|
|
// #02 - Cuatro enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
|
|
j = 2;
|
|
mEnemyFormation[j].numberOfEnemies = 4;
|
|
incX = BALLOON_WIDTH_2 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x2_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].y = y2;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_2;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #03 - Cuatro enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
|
|
j = 3;
|
|
mEnemyFormation[j].numberOfEnemies = 4;
|
|
incX = BALLOON_WIDTH_2 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x2_100 - (i * incX);
|
|
mEnemyFormation[j].init[i].y = y2;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_2;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #04 - Tres enemigos BALLOON3. 0, 25, 50. Hacia la derecha
|
|
j = 4;
|
|
mEnemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_3 * 2;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].y = y3;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_3;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #05 - Tres enemigos BALLOON3. 50, 75, 100. Hacia la izquierda
|
|
j = 5;
|
|
mEnemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_3 * 2;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_100 - (i * incX);
|
|
mEnemyFormation[j].init[i].y = y3;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_3;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #06 - Tres enemigos BALLOON3. 0, 0, 0. Hacia la derecha
|
|
j = 6;
|
|
mEnemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_3 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].y = y3;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_3;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #07 - Tres enemigos BALLOON3. 100, 100, 100. Hacia la izquierda
|
|
j = 7;
|
|
mEnemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_3 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_100 - (i * incX);
|
|
mEnemyFormation[j].init[i].y = y3;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_3;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #08 - Seis enemigos BALLOON1. 0, 0, 0, 0, 0, 0. Hacia la derecha
|
|
j = 8;
|
|
mEnemyFormation[j].numberOfEnemies = 6;
|
|
incX = BALLOON_WIDTH_1 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x1_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].y = 13;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_1;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #09 - Seis enemigos BALLOON1. 100, 100, 100, 100, 100, 100. Hacia la izquierda
|
|
j = 9;
|
|
mEnemyFormation[j].numberOfEnemies = 6;
|
|
incX = BALLOON_WIDTH_1 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x1_100 - (i * incX);
|
|
mEnemyFormation[j].init[i].y = 13;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_1;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #10 - Tres enemigos BALLOON4 seguidos desde la izquierda
|
|
j = 10;
|
|
mEnemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_4 + 1;
|
|
incTime = 15;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x4_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].y = y4;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_4;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #11 - Tres enemigos BALLOON4 seguidos desde la derecha
|
|
j = 11;
|
|
mEnemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_4 + 1;
|
|
incTime = 15;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x4_100 - (i * incX);
|
|
mEnemyFormation[j].init[i].y = y4;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_4;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #12 - Seis enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
|
|
j = 12;
|
|
mEnemyFormation[j].numberOfEnemies = 6;
|
|
incX = BALLOON_WIDTH_2 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x2_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].y = y2;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_2;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #13 - Seis enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
|
|
j = 13;
|
|
mEnemyFormation[j].numberOfEnemies = 6;
|
|
incX = BALLOON_WIDTH_2 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x2_100 - (i * incX);
|
|
mEnemyFormation[j].init[i].y = y2;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_2;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #14 - Cinco enemigos BALLOON3. Hacia la derecha. Separados
|
|
j = 14;
|
|
mEnemyFormation[j].numberOfEnemies = 5;
|
|
incX = BALLOON_WIDTH_3 * 2;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].y = y3;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_3;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #15 - Cinco enemigos BALLOON3. Hacia la izquierda. Separados
|
|
j = 15;
|
|
mEnemyFormation[j].numberOfEnemies = 5;
|
|
incX = BALLOON_WIDTH_3 * 2;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_100 - (i * incX);
|
|
mEnemyFormation[j].init[i].y = y3;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_3;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #16 - Cinco enemigos BALLOON3. Hacia la derecha. Juntos
|
|
j = 16;
|
|
mEnemyFormation[j].numberOfEnemies = 5;
|
|
incX = BALLOON_WIDTH_3 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].y = y3;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_3;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #17 - Cinco enemigos BALLOON3. Hacia la izquierda. Juntos
|
|
j = 17;
|
|
mEnemyFormation[j].numberOfEnemies = 5;
|
|
incX = BALLOON_WIDTH_3 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_100 - (i * incX);
|
|
mEnemyFormation[j].init[i].y = y3;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_3;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #18 - Doce enemigos BALLOON1. Hacia la derecha. Juntos
|
|
j = 18;
|
|
mEnemyFormation[j].numberOfEnemies = 12;
|
|
incX = BALLOON_WIDTH_1 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x1_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].y = y1;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_1;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #19 - Doce enemigos BALLOON1. Hacia la izquierda. Juntos
|
|
j = 19;
|
|
mEnemyFormation[j].numberOfEnemies = 12;
|
|
incX = BALLOON_WIDTH_1 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x1_100 - (i * incX);
|
|
mEnemyFormation[j].init[i].y = y1;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_1;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #20 - Dos enemigos BALLOON4 seguidos desde la izquierda/derecha. Simetricos
|
|
j = 20;
|
|
mEnemyFormation[j].numberOfEnemies = 4;
|
|
incX = BALLOON_WIDTH_4 + 1;
|
|
incTime = 0;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
Uint8 half = mEnemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x4_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
}
|
|
else
|
|
{
|
|
mEnemyFormation[j].init[i].x = x4_100 - ((i - half) * incX);
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
}
|
|
mEnemyFormation[j].init[i].y = y4;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_4;
|
|
mEnemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
|
|
}
|
|
|
|
// #21 - Diez enemigos BALLOON2 uno detras del otro. Izquierda/derecha. Simetricos
|
|
j = 21;
|
|
mEnemyFormation[j].numberOfEnemies = 10;
|
|
incX = BALLOON_WIDTH_2 + 1;
|
|
incTime = 3;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
Uint8 half = mEnemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x2_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
|
|
}
|
|
else
|
|
{
|
|
mEnemyFormation[j].init[i].x = x2_100 - ((i - half) * incX);
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
|
|
}
|
|
mEnemyFormation[j].init[i].y = y2;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_2;
|
|
}
|
|
|
|
// #22 - Diez enemigos BALLOON3. Hacia la derecha/izquierda. Separados. Simetricos
|
|
j = 22;
|
|
mEnemyFormation[j].numberOfEnemies = 10;
|
|
incX = BALLOON_WIDTH_3 * 2;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
Uint8 half = mEnemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
|
|
}
|
|
else
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_100 - ((i - half) * incX);
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
|
|
}
|
|
mEnemyFormation[j].init[i].y = y3;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_3;
|
|
}
|
|
|
|
// #23 - Diez enemigos BALLOON3. Hacia la derecha. Juntos. Simetricos
|
|
j = 23;
|
|
mEnemyFormation[j].numberOfEnemies = 10;
|
|
incX = BALLOON_WIDTH_3 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
Uint8 half = mEnemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
|
|
}
|
|
else
|
|
{
|
|
mEnemyFormation[j].init[i].x = x3_100 - ((i - half) * incX);
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
|
|
}
|
|
mEnemyFormation[j].init[i].y = y3;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_3;
|
|
}
|
|
|
|
// #24 - Treinta enemigos BALLOON1. Del centro hacia los extremos. Juntos. Simetricos
|
|
j = 24;
|
|
mEnemyFormation[j].numberOfEnemies = 30;
|
|
incX = 0;
|
|
incTime = 5;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
Uint8 half = mEnemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x1_50;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].creationCounter = (creationTime) + (incTime * i);
|
|
}
|
|
else
|
|
{
|
|
mEnemyFormation[j].init[i].x = x1_50;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].creationCounter = (creationTime) + (incTime * (i - half));
|
|
}
|
|
mEnemyFormation[j].init[i].y = y1;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_1;
|
|
}
|
|
|
|
// #25 - Treinta enemigos BALLOON1. Del centro hacia adentro. Juntos. Simetricos
|
|
j = 25;
|
|
mEnemyFormation[j].numberOfEnemies = 30;
|
|
incX = BALLOON_WIDTH_1 + 1;
|
|
incTime = 5;
|
|
for (int i = 0; i < mEnemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
Uint8 half = mEnemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
mEnemyFormation[j].init[i].x = x1_50 + 20;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
mEnemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
|
|
}
|
|
else
|
|
{
|
|
mEnemyFormation[j].init[i].x = x1_50 - 20;
|
|
mEnemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
mEnemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
|
|
}
|
|
mEnemyFormation[j].init[i].y = y1;
|
|
mEnemyFormation[j].init[i].kind = BALLOON_1;
|
|
}
|
|
|
|
// Crea las mismas formaciones pero con hexagonos a partir de la posición 50 del vector
|
|
for (int k = 0; k < j + 1; k++)
|
|
{
|
|
mEnemyFormation[k + 50].numberOfEnemies = mEnemyFormation[k].numberOfEnemies;
|
|
for (int i = 0; i < mEnemyFormation[k + 50].numberOfEnemies; i++)
|
|
{
|
|
mEnemyFormation[k + 50].init[i].x = mEnemyFormation[k].init[i].x;
|
|
mEnemyFormation[k + 50].init[i].y = mEnemyFormation[k].init[i].y;
|
|
mEnemyFormation[k + 50].init[i].velX = mEnemyFormation[k].init[i].velX;
|
|
mEnemyFormation[k + 50].init[i].creationCounter = mEnemyFormation[k].init[i].creationCounter;
|
|
mEnemyFormation[k + 50].init[i].kind = mEnemyFormation[k].init[i].kind + 4;
|
|
}
|
|
}
|
|
|
|
// TEST
|
|
mEnemyFormation[99].numberOfEnemies = 4;
|
|
|
|
mEnemyFormation[99].init[0].x = 10;
|
|
mEnemyFormation[99].init[0].y = y1;
|
|
mEnemyFormation[99].init[0].velX = 0;
|
|
mEnemyFormation[99].init[0].kind = BALLOON_1;
|
|
mEnemyFormation[99].init[0].creationCounter = 200;
|
|
|
|
mEnemyFormation[99].init[1].x = 50;
|
|
mEnemyFormation[99].init[1].y = y1;
|
|
mEnemyFormation[99].init[1].velX = 0;
|
|
mEnemyFormation[99].init[1].kind = BALLOON_2;
|
|
mEnemyFormation[99].init[1].creationCounter = 200;
|
|
|
|
mEnemyFormation[99].init[2].x = 90;
|
|
mEnemyFormation[99].init[2].y = y1;
|
|
mEnemyFormation[99].init[2].velX = 0;
|
|
mEnemyFormation[99].init[2].kind = BALLOON_3;
|
|
mEnemyFormation[99].init[2].creationCounter = 200;
|
|
|
|
mEnemyFormation[99].init[3].x = 140;
|
|
mEnemyFormation[99].init[3].y = y1;
|
|
mEnemyFormation[99].init[3].velX = 0;
|
|
mEnemyFormation[99].init[3].kind = BALLOON_4;
|
|
mEnemyFormation[99].init[3].creationCounter = 200;
|
|
}
|
|
|
|
// Inicializa los conjuntos de formaciones
|
|
void Game::initEnemyPools()
|
|
{
|
|
// EnemyPool #0
|
|
mEnemyPool[0].set[0] = &mEnemyFormation[0];
|
|
mEnemyPool[0].set[1] = &mEnemyFormation[1];
|
|
mEnemyPool[0].set[2] = &mEnemyFormation[2];
|
|
mEnemyPool[0].set[3] = &mEnemyFormation[3];
|
|
mEnemyPool[0].set[4] = &mEnemyFormation[4];
|
|
mEnemyPool[0].set[5] = &mEnemyFormation[5];
|
|
mEnemyPool[0].set[6] = &mEnemyFormation[6];
|
|
mEnemyPool[0].set[7] = &mEnemyFormation[7];
|
|
mEnemyPool[0].set[8] = &mEnemyFormation[8];
|
|
mEnemyPool[0].set[9] = &mEnemyFormation[9];
|
|
|
|
// EnemyPool #1
|
|
mEnemyPool[1].set[0] = &mEnemyFormation[10];
|
|
mEnemyPool[1].set[1] = &mEnemyFormation[11];
|
|
mEnemyPool[1].set[2] = &mEnemyFormation[12];
|
|
mEnemyPool[1].set[3] = &mEnemyFormation[13];
|
|
mEnemyPool[1].set[4] = &mEnemyFormation[14];
|
|
mEnemyPool[1].set[5] = &mEnemyFormation[15];
|
|
mEnemyPool[1].set[6] = &mEnemyFormation[16];
|
|
mEnemyPool[1].set[7] = &mEnemyFormation[17];
|
|
mEnemyPool[1].set[8] = &mEnemyFormation[18];
|
|
mEnemyPool[1].set[9] = &mEnemyFormation[19];
|
|
|
|
// EnemyPool #2
|
|
mEnemyPool[2].set[0] = &mEnemyFormation[0];
|
|
mEnemyPool[2].set[1] = &mEnemyFormation[1];
|
|
mEnemyPool[2].set[2] = &mEnemyFormation[2];
|
|
mEnemyPool[2].set[3] = &mEnemyFormation[3];
|
|
mEnemyPool[2].set[4] = &mEnemyFormation[4];
|
|
mEnemyPool[2].set[5] = &mEnemyFormation[55];
|
|
mEnemyPool[2].set[6] = &mEnemyFormation[56];
|
|
mEnemyPool[2].set[7] = &mEnemyFormation[57];
|
|
mEnemyPool[2].set[8] = &mEnemyFormation[58];
|
|
mEnemyPool[2].set[9] = &mEnemyFormation[59];
|
|
|
|
// EnemyPool #3
|
|
mEnemyPool[3].set[0] = &mEnemyFormation[50];
|
|
mEnemyPool[3].set[1] = &mEnemyFormation[51];
|
|
mEnemyPool[3].set[2] = &mEnemyFormation[52];
|
|
mEnemyPool[3].set[3] = &mEnemyFormation[53];
|
|
mEnemyPool[3].set[4] = &mEnemyFormation[54];
|
|
mEnemyPool[3].set[5] = &mEnemyFormation[5];
|
|
mEnemyPool[3].set[6] = &mEnemyFormation[6];
|
|
mEnemyPool[3].set[7] = &mEnemyFormation[7];
|
|
mEnemyPool[3].set[8] = &mEnemyFormation[8];
|
|
mEnemyPool[3].set[9] = &mEnemyFormation[9];
|
|
|
|
// EnemyPool #4
|
|
mEnemyPool[4].set[0] = &mEnemyFormation[60];
|
|
mEnemyPool[4].set[1] = &mEnemyFormation[61];
|
|
mEnemyPool[4].set[2] = &mEnemyFormation[62];
|
|
mEnemyPool[4].set[3] = &mEnemyFormation[63];
|
|
mEnemyPool[4].set[4] = &mEnemyFormation[64];
|
|
mEnemyPool[4].set[5] = &mEnemyFormation[65];
|
|
mEnemyPool[4].set[6] = &mEnemyFormation[66];
|
|
mEnemyPool[4].set[7] = &mEnemyFormation[67];
|
|
mEnemyPool[4].set[8] = &mEnemyFormation[68];
|
|
mEnemyPool[4].set[9] = &mEnemyFormation[69];
|
|
|
|
// EnemyPool #5
|
|
mEnemyPool[5].set[0] = &mEnemyFormation[10];
|
|
mEnemyPool[5].set[1] = &mEnemyFormation[61];
|
|
mEnemyPool[5].set[2] = &mEnemyFormation[12];
|
|
mEnemyPool[5].set[3] = &mEnemyFormation[63];
|
|
mEnemyPool[5].set[4] = &mEnemyFormation[14];
|
|
mEnemyPool[5].set[5] = &mEnemyFormation[65];
|
|
mEnemyPool[5].set[6] = &mEnemyFormation[16];
|
|
mEnemyPool[5].set[7] = &mEnemyFormation[67];
|
|
mEnemyPool[5].set[8] = &mEnemyFormation[18];
|
|
mEnemyPool[5].set[9] = &mEnemyFormation[69];
|
|
|
|
// EnemyPool #6
|
|
mEnemyPool[6].set[0] = &mEnemyFormation[60];
|
|
mEnemyPool[6].set[1] = &mEnemyFormation[11];
|
|
mEnemyPool[6].set[2] = &mEnemyFormation[62];
|
|
mEnemyPool[6].set[3] = &mEnemyFormation[13];
|
|
mEnemyPool[6].set[4] = &mEnemyFormation[64];
|
|
mEnemyPool[6].set[5] = &mEnemyFormation[15];
|
|
mEnemyPool[6].set[6] = &mEnemyFormation[66];
|
|
mEnemyPool[6].set[7] = &mEnemyFormation[17];
|
|
mEnemyPool[6].set[8] = &mEnemyFormation[68];
|
|
mEnemyPool[6].set[9] = &mEnemyFormation[19];
|
|
|
|
// EnemyPool #7
|
|
mEnemyPool[7].set[0] = &mEnemyFormation[20];
|
|
mEnemyPool[7].set[1] = &mEnemyFormation[21];
|
|
mEnemyPool[7].set[2] = &mEnemyFormation[22];
|
|
mEnemyPool[7].set[3] = &mEnemyFormation[23];
|
|
mEnemyPool[7].set[4] = &mEnemyFormation[24];
|
|
mEnemyPool[7].set[5] = &mEnemyFormation[65];
|
|
mEnemyPool[7].set[6] = &mEnemyFormation[66];
|
|
mEnemyPool[7].set[7] = &mEnemyFormation[67];
|
|
mEnemyPool[7].set[8] = &mEnemyFormation[68];
|
|
mEnemyPool[7].set[9] = &mEnemyFormation[69];
|
|
|
|
// EnemyPool #8
|
|
mEnemyPool[8].set[0] = &mEnemyFormation[70];
|
|
mEnemyPool[8].set[1] = &mEnemyFormation[71];
|
|
mEnemyPool[8].set[2] = &mEnemyFormation[72];
|
|
mEnemyPool[8].set[3] = &mEnemyFormation[73];
|
|
mEnemyPool[8].set[4] = &mEnemyFormation[74];
|
|
mEnemyPool[8].set[5] = &mEnemyFormation[15];
|
|
mEnemyPool[8].set[6] = &mEnemyFormation[16];
|
|
mEnemyPool[8].set[7] = &mEnemyFormation[17];
|
|
mEnemyPool[8].set[8] = &mEnemyFormation[18];
|
|
mEnemyPool[8].set[9] = &mEnemyFormation[19];
|
|
|
|
// EnemyPool #9
|
|
mEnemyPool[9].set[0] = &mEnemyFormation[20];
|
|
mEnemyPool[9].set[1] = &mEnemyFormation[21];
|
|
mEnemyPool[9].set[2] = &mEnemyFormation[22];
|
|
mEnemyPool[9].set[3] = &mEnemyFormation[23];
|
|
mEnemyPool[9].set[4] = &mEnemyFormation[24];
|
|
mEnemyPool[9].set[5] = &mEnemyFormation[70];
|
|
mEnemyPool[9].set[6] = &mEnemyFormation[71];
|
|
mEnemyPool[9].set[7] = &mEnemyFormation[72];
|
|
mEnemyPool[9].set[8] = &mEnemyFormation[73];
|
|
mEnemyPool[9].set[9] = &mEnemyFormation[74];
|
|
}
|
|
|
|
// Inicializa las fases del juego
|
|
void Game::initGameStages()
|
|
{
|
|
// STAGE 1
|
|
mStage[0].number = 1;
|
|
mStage[0].currentPower = 0;
|
|
mStage[0].powerToComplete = 200;
|
|
mStage[0].minMenace = 7 + (4 * 1);
|
|
mStage[0].maxMenace = 7 + (4 * 3);
|
|
mStage[0].enemyPool = &mEnemyPool[0];
|
|
|
|
// STAGE 2
|
|
mStage[1].number = 2;
|
|
mStage[1].currentPower = 0;
|
|
mStage[1].powerToComplete = 300;
|
|
mStage[1].minMenace = 7 + (4 * 2);
|
|
mStage[1].maxMenace = 7 + (4 * 4);
|
|
mStage[1].enemyPool = &mEnemyPool[1];
|
|
|
|
// STAGE 3
|
|
mStage[2].number = 3;
|
|
mStage[2].currentPower = 0;
|
|
mStage[2].powerToComplete = 600;
|
|
mStage[2].minMenace = 7 + (4 * 3);
|
|
mStage[2].maxMenace = 7 + (4 * 5);
|
|
mStage[2].enemyPool = &mEnemyPool[2];
|
|
|
|
// STAGE 4
|
|
mStage[3].number = 4;
|
|
mStage[3].currentPower = 0;
|
|
mStage[3].powerToComplete = 600;
|
|
mStage[3].minMenace = 7 + (4 * 3);
|
|
mStage[3].maxMenace = 7 + (4 * 5);
|
|
mStage[3].enemyPool = &mEnemyPool[3];
|
|
|
|
// STAGE 5
|
|
mStage[4].number = 5;
|
|
mStage[4].currentPower = 0;
|
|
mStage[4].powerToComplete = 600;
|
|
mStage[4].minMenace = 7 + (4 * 4);
|
|
mStage[4].maxMenace = 7 + (4 * 6);
|
|
mStage[4].enemyPool = &mEnemyPool[4];
|
|
|
|
// STAGE 6
|
|
mStage[5].number = 6;
|
|
mStage[5].currentPower = 0;
|
|
mStage[5].powerToComplete = 600;
|
|
mStage[5].minMenace = 7 + (4 * 4);
|
|
mStage[5].maxMenace = 7 + (4 * 6);
|
|
mStage[5].enemyPool = &mEnemyPool[5];
|
|
|
|
// STAGE 7
|
|
mStage[6].number = 7;
|
|
mStage[6].currentPower = 0;
|
|
mStage[6].powerToComplete = 650;
|
|
mStage[6].minMenace = 7 + (4 * 5);
|
|
mStage[6].maxMenace = 7 + (4 * 7);
|
|
mStage[6].enemyPool = &mEnemyPool[6];
|
|
|
|
// STAGE 8
|
|
mStage[7].number = 8;
|
|
mStage[7].currentPower = 0;
|
|
mStage[7].powerToComplete = 750;
|
|
mStage[7].minMenace = 7 + (4 * 5);
|
|
mStage[7].maxMenace = 7 + (4 * 7);
|
|
mStage[7].enemyPool = &mEnemyPool[7];
|
|
|
|
// STAGE 9
|
|
mStage[8].number = 9;
|
|
mStage[8].currentPower = 0;
|
|
mStage[8].powerToComplete = 850;
|
|
mStage[8].minMenace = 7 + (4 * 6);
|
|
mStage[8].maxMenace = 7 + (4 * 8);
|
|
mStage[8].enemyPool = &mEnemyPool[8];
|
|
|
|
// STAGE 10
|
|
mStage[9].number = 10;
|
|
mStage[9].currentPower = 0;
|
|
mStage[9].powerToComplete = 950;
|
|
mStage[9].minMenace = 7 + (4 * 7);
|
|
mStage[9].maxMenace = 7 + (4 * 10);
|
|
mStage[9].enemyPool = &mEnemyPool[9];
|
|
}
|
|
|
|
// Crea una formación de enemigos
|
|
void Game::deployEnemyFormation()
|
|
{
|
|
// Solo despliega una formación enemiga si ha pasado cierto tiempo desde la última
|
|
if (mEnemyDeployCounter == 0)
|
|
{
|
|
|
|
// En este punto se decide entre crear una powerball o una formación enemiga
|
|
if ((rand() % 100 < 15) && (canPowerBallBeCreated()))
|
|
{
|
|
// Crea una powerball
|
|
createPowerBall();
|
|
|
|
// Da un poco de margen para que se creen mas enemigos
|
|
mEnemyDeployCounter = 50;
|
|
}
|
|
else
|
|
{
|
|
// Decrementa el contador de despliegues enemigos de la PowerBall
|
|
mPowerBallCounter > 0 ? mPowerBallCounter-- : mPowerBallCounter = 0;
|
|
|
|
// Elige una formación enemiga la azar
|
|
Uint8 set = (rand() % 10);
|
|
|
|
// Evita repetir la ultima formación enemiga desplegada
|
|
if (set == mLastEnemyDeploy)
|
|
++set %= 10;
|
|
|
|
mLastEnemyDeploy = set;
|
|
|
|
if (mDebug.enabled)
|
|
set = mDebug.enemySet;
|
|
|
|
Uint8 numEnemies = mStage[mCurrentStage].enemyPool->set[set]->numberOfEnemies;
|
|
for (int i = 0; i < numEnemies; i++)
|
|
createNewBalloon(mStage[mCurrentStage].enemyPool->set[set]->init[i].x,
|
|
mStage[mCurrentStage].enemyPool->set[set]->init[i].y,
|
|
mStage[mCurrentStage].enemyPool->set[set]->init[i].kind,
|
|
mStage[mCurrentStage].enemyPool->set[set]->init[i].velX,
|
|
mEnemySpeed,
|
|
mStage[mCurrentStage].enemyPool->set[set]->init[i].creationCounter,
|
|
mTextureBalloon);
|
|
|
|
mEnemyDeployCounter = 300;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Aumenta el poder de la fase
|
|
void Game::increaseStageCurrentPower(Uint8 power)
|
|
{
|
|
mStage[mCurrentStage].currentPower += power;
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void Game::setHiScore(Uint32 score)
|
|
{
|
|
mHiScore = score;
|
|
}
|
|
|
|
// Actualiza el valor de mHiScore en caso necesario
|
|
void Game::updateHiScore()
|
|
{
|
|
// Si la puntuación actual es mayor que la máxima puntuación
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
if (mPlayer[i]->getScore() > mHiScore)
|
|
{
|
|
// Actualiza la máxima puntuación
|
|
mHiScore = mPlayer[i]->getScore();
|
|
|
|
// Almacena la máxima puntuación en el fichero junto con un checksum
|
|
mScoreDataFile[0] = mHiScore;
|
|
mScoreDataFile[1] = mHiScore % 43;
|
|
|
|
// Si se supera la máxima puntuación emite sonido
|
|
if (mHiScoreAchieved == false)
|
|
{
|
|
mHiScoreAchieved = true;
|
|
JA_PlaySound(mSoundHiScore);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Transforma un valor numérico en una cadena de 6 cifras
|
|
std::string Game::updateScoreText(Uint32 num)
|
|
{
|
|
//return (std::to_string(num));
|
|
|
|
if ((num >= 0) && (num <= 9))
|
|
{
|
|
return ("000000" + std::to_string(num));
|
|
}
|
|
|
|
if ((num >= 10) && (num <= 99))
|
|
{
|
|
return ("00000" + std::to_string(num));
|
|
}
|
|
|
|
if ((num >= 100) && (num <= 999))
|
|
{
|
|
return ("0000" + std::to_string(num));
|
|
}
|
|
|
|
if ((num >= 1000) && (num <= 9999))
|
|
{
|
|
return ("000" + std::to_string(num));
|
|
}
|
|
|
|
if ((num >= 010000) && (num <= 99999))
|
|
{
|
|
return ("00" + std::to_string(num));
|
|
}
|
|
|
|
if ((num >= 100000) && (num <= 999999))
|
|
{
|
|
return ("0" + std::to_string(num));
|
|
}
|
|
|
|
if ((num >= 1000000) && (num <= 9999999))
|
|
{
|
|
return (std::to_string(num));
|
|
}
|
|
|
|
return (std::to_string(num));
|
|
}
|
|
|
|
// Pinta el marcador en pantalla usando un objeto texto
|
|
void Game::renderScoreBoard()
|
|
{
|
|
mSpriteScoreBoard->render();
|
|
|
|
const int offset1 = 162;
|
|
const int offset2 = offset1 + 7;
|
|
const int offset3 = offset2 + 7;
|
|
const int offset4 = offset3 + 7;
|
|
|
|
const int offsetLeft = PLAY_AREA_LEFT + 45;
|
|
const int offsetRight = PLAY_AREA_RIGHT - 45;
|
|
|
|
// PLAYER1 - SCORE
|
|
mTextScoreBoard->writeCentered(offsetLeft, offset1, mLang->getText(53));
|
|
mTextScoreBoard->writeCentered(offsetLeft, offset2, updateScoreText(mPlayer[0]->getScore()));
|
|
|
|
// PLAYER1 - MULT
|
|
mTextScoreBoard->writeCentered(offsetLeft, offset3, mLang->getText(55));
|
|
mTextScoreBoard->writeCentered(offsetLeft, offset4, std::to_string(mPlayer[0]->getScoreMultiplier()).substr(0, 3));
|
|
|
|
if (mNumPlayers == 2)
|
|
{
|
|
// PLAYER2 - SCORE
|
|
mTextScoreBoard->writeCentered(offsetRight, offset1, mLang->getText(54));
|
|
mTextScoreBoard->writeCentered(offsetRight, offset2, updateScoreText(mPlayer[1]->getScore()));
|
|
|
|
// PLAYER2 - MULT
|
|
mTextScoreBoard->writeCentered(offsetRight, offset3, mLang->getText(55));
|
|
mTextScoreBoard->writeCentered(offsetRight, offset4, std::to_string(mPlayer[1]->getScoreMultiplier()).substr(0, 3));
|
|
}
|
|
else
|
|
{
|
|
// PLAYER2 - SCORE
|
|
mTextScoreBoard->writeCentered(offsetRight, offset1, mLang->getText(54));
|
|
mTextScoreBoard->writeCentered(offsetRight, offset2, "0000000");
|
|
|
|
// PLAYER2 - MULT
|
|
mTextScoreBoard->writeCentered(offsetRight, offset3, mLang->getText(55));
|
|
mTextScoreBoard->writeCentered(offsetRight, offset4, "1.0");
|
|
}
|
|
|
|
// STAGE
|
|
mTextScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset1, mLang->getText(57) + std::to_string(mStage[mCurrentStage].number));
|
|
|
|
// POWER
|
|
mSpritePowerMeter->setPosY(offset2);
|
|
mSpritePowerMeter->setSpriteClip(256, 184, 40, 8);
|
|
mSpritePowerMeter->render();
|
|
const float percent = (mStage[mCurrentStage].currentPower * 40.0f) / mStage[mCurrentStage].powerToComplete;
|
|
mSpritePowerMeter->setSpriteClip(296, 184, (int)percent, 8);
|
|
mSpritePowerMeter->render();
|
|
|
|
// HI-SCORE
|
|
mTextScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset3, mLang->getText(56));
|
|
mTextScoreBoard->writeCentered(PLAY_AREA_CENTER_X, offset4, updateScoreText(mHiScore));
|
|
}
|
|
|
|
// Actualiza las variables del jugador
|
|
void Game::updatePlayer()
|
|
{
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
{
|
|
mPlayer[i]->update();
|
|
|
|
// Comprueba la colisión entre el jugador y los globos
|
|
if (checkPlayerBalloonCollision(i))
|
|
{
|
|
if (mPlayer[i]->isAlive())
|
|
{
|
|
if (mDemo.enabled)
|
|
mSection = {PROG_SECTION_TITLE, TITLE_SECTION_INSTRUCTIONS};
|
|
else
|
|
killPlayer(i);
|
|
}
|
|
}
|
|
|
|
// Comprueba las colisiones entre el jugador y los items
|
|
checkPlayerItemCollision(i);
|
|
}
|
|
}
|
|
|
|
// Actualiza las variables de la fase
|
|
void Game::updateStage()
|
|
{
|
|
if (mStage[mCurrentStage].currentPower >= mStage[mCurrentStage].powerToComplete)
|
|
{
|
|
// Cambio de fase
|
|
mCurrentStage++;
|
|
if (mCurrentStage == 10) // Ha llegado al final el juego
|
|
{
|
|
mGameCompleted = true; // Marca el juego como completado
|
|
mCurrentStage = 9; // Deja el valor dentro de los limites
|
|
mStage[mCurrentStage].currentPower = 0; // Deja el poder a cero para que no vuelva a entrar en esta condición
|
|
destroyAllBalloons(); // Destruye a todos los enemigos
|
|
mStage[mCurrentStage].currentPower = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos lo globos
|
|
mMenaceCurrent = 255; // Sube el nivel de amenaza para que no cree mas globos
|
|
for (int i = 0; i < mNumPlayers; i++) // Añade un millon de puntos a los jugadores que queden vivos
|
|
if (mPlayer[i]->isAlive())
|
|
mPlayer[i]->addScore(1000000);
|
|
updateHiScore();
|
|
JA_StopMusic();
|
|
}
|
|
JA_PlaySound(mSoundStageChange);
|
|
mStageBitmapCounter = 0;
|
|
mEnemySpeed = mDefaultEnemySpeed;
|
|
setBalloonSpeed(mEnemySpeed);
|
|
mEffect.flash = true;
|
|
mEffect.shake = true;
|
|
}
|
|
|
|
// Incrementa el contador del bitmap que aparece mostrando el cambio de fase
|
|
if (mStageBitmapCounter < STAGE_COUNTER)
|
|
mStageBitmapCounter++;
|
|
|
|
// Si el juego se ha completado, el bitmap se detiene en el centro de la pantalla
|
|
if (mGameCompleted)
|
|
if (mStageBitmapCounter > 100)
|
|
mStageBitmapCounter = 100;
|
|
}
|
|
|
|
// Actualiza el estado de muerte
|
|
void Game::updateDeath()
|
|
{
|
|
// Comprueba si todos los jugadores estan muertos
|
|
bool allAreDead = true;
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
{
|
|
allAreDead &= (!mPlayer[i]->isAlive());
|
|
|
|
if (!mPlayer[i]->isAlive())
|
|
{
|
|
// Animación
|
|
if ((mPlayer[i]->getDeathCounter() / 5) % 4 == 0)
|
|
mSmartSprite[mPlayer[i]->mDeathIndex]->setSpriteClip(24 * 0, 24, 24, 24);
|
|
else if ((mPlayer[i]->getDeathCounter() / 5) % 4 == 1)
|
|
mSmartSprite[mPlayer[i]->mDeathIndex]->setSpriteClip(24 * 1, 24, 24, 24);
|
|
else if ((mPlayer[i]->getDeathCounter() / 5) % 4 == 2)
|
|
mSmartSprite[mPlayer[i]->mDeathIndex]->setSpriteClip(24 * 2, 24, 24, 24);
|
|
else if ((mPlayer[i]->getDeathCounter() / 5) % 4 == 3)
|
|
mSmartSprite[mPlayer[i]->mDeathIndex]->setSpriteClip(24 * 3, 24, 24, 24);
|
|
|
|
// Rebote en los laterales
|
|
if (mSmartSprite[mPlayer[i]->mDeathIndex]->getVelX() > 0)
|
|
{
|
|
if (mSmartSprite[mPlayer[i]->mDeathIndex]->getPosX() > (SCREEN_WIDTH - mSmartSprite[mPlayer[i]->mDeathIndex]->getWidth()))
|
|
{
|
|
mSmartSprite[mPlayer[i]->mDeathIndex]->setPosX(SCREEN_WIDTH - mSmartSprite[mPlayer[i]->mDeathIndex]->getWidth());
|
|
mSmartSprite[mPlayer[i]->mDeathIndex]->setVelX(mSmartSprite[mPlayer[i]->mDeathIndex]->getVelX() * (-1));
|
|
mSmartSprite[mPlayer[i]->mDeathIndex]->setDestX(mSmartSprite[mPlayer[i]->mDeathIndex]->getDestX() * (-1));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mSmartSprite[mPlayer[i]->mDeathIndex]->getPosX() < 0)
|
|
{
|
|
mSmartSprite[mPlayer[i]->mDeathIndex]->setPosX(0);
|
|
mSmartSprite[mPlayer[i]->mDeathIndex]->setVelX(mSmartSprite[mPlayer[i]->mDeathIndex]->getVelX() * (-1));
|
|
mSmartSprite[mPlayer[i]->mDeathIndex]->setDestX(mSmartSprite[mPlayer[i]->mDeathIndex]->getDestX() * (-1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (allAreDead)
|
|
{
|
|
if (mDeathCounter > 0)
|
|
{
|
|
mDeathCounter--;
|
|
if ((mDeathCounter == 250) || (mDeathCounter == 200) || (mDeathCounter == 180) || (mDeathCounter == 120) || (mDeathCounter == 60))
|
|
{
|
|
Uint8 sound = rand() % 4;
|
|
switch (sound)
|
|
{
|
|
case 0:
|
|
JA_PlaySound(mSoundBubble1, 0);
|
|
break;
|
|
case 1:
|
|
JA_PlaySound(mSoundBubble2, 0);
|
|
break;
|
|
case 2:
|
|
JA_PlaySound(mSoundBubble3, 0);
|
|
break;
|
|
case 3:
|
|
JA_PlaySound(mSoundBubble4, 0);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mSection.subsection = GAME_SECTION_GAMEOVER;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Renderiza el fade final cuando se acaba la partida
|
|
void Game::renderDeathFade(int counter)
|
|
// Counter debe ir de 0 a 150
|
|
{
|
|
SDL_SetRenderDrawColor(mRenderer, 0x27, 0x27, 0x36, 255);
|
|
|
|
if (counter < 150)
|
|
{
|
|
// 192 / 6 = 32, 6 cuadrados de 32 pixeles
|
|
SDL_Rect rect[12];
|
|
Uint8 h = counter / 3;
|
|
for (int i = 0; i < 12; i++)
|
|
{
|
|
rect[i].x = 0;
|
|
rect[i].y = i * 16;
|
|
rect[i].w = SCREEN_WIDTH;
|
|
if (i == 0)
|
|
rect[i].h = h;
|
|
else
|
|
rect[i].h = std::max(rect[i - 1].h - 3, 0);
|
|
SDL_RenderFillRect(mRenderer, &rect[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SDL_Rect rect = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
|
|
SDL_RenderFillRect(mRenderer, &rect);
|
|
}
|
|
}
|
|
|
|
// Actualiza los globos
|
|
void Game::updateBalloons()
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
mBalloon[i]->update();
|
|
}
|
|
|
|
// Pinta en pantalla todos los globos activos
|
|
void Game::renderBalloons()
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
{
|
|
mBalloon[i]->render();
|
|
if ((mDebug.enabled) && (mBalloon[i]->isPopping() == false))
|
|
mText->writeCentered(mBalloon[i]->getPosX() + (mBalloon[i]->getWidth() / 2), mBalloon[i]->getPosY() - 8, std::to_string(i));
|
|
}
|
|
}
|
|
|
|
// Devuelve el primer indice no activo del vector de globos
|
|
Uint8 Game::getBalloonFreeIndex()
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
if (!mBalloon[i]->isEnabled())
|
|
return i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Crea un globo nuevo en el vector de globos
|
|
Uint8 Game::createNewBalloon(float x, int y, Uint8 kind, float velx, float speed, Uint16 creationtimer, LTexture *texture)
|
|
{
|
|
const Uint8 index = getBalloonFreeIndex();
|
|
mBalloon[index]->init(x, y, kind, velx, speed, creationtimer, texture, mRenderer);
|
|
return index;
|
|
}
|
|
|
|
// Crea una PowerBall
|
|
void Game::createPowerBall()
|
|
{
|
|
const int posY = PLAY_AREA_TOP;
|
|
|
|
const int left = PLAY_AREA_LEFT;
|
|
const int center = PLAY_AREA_CENTER_X - (BALLOON_WIDTH_4 / 2);
|
|
const int right = PLAY_AREA_RIGHT - BALLOON_WIDTH_4;
|
|
|
|
const int x[3] = {left, center, right};
|
|
const int posX = x[rand() % 3];
|
|
|
|
mBalloon[getBalloonFreeIndex()]->init(posX, posY, POWER_BALL, BALLOON_VELX_POSITIVE * (((rand() % 2) * 2) - 1), mEnemySpeed, 100, mTextureBalloon, mRenderer);
|
|
mPowerBallEnabled = true;
|
|
mPowerBallCounter = POWERBALL_COUNTER;
|
|
}
|
|
|
|
// Establece a cero todos los valores del vector de objetos globo
|
|
void Game::resetBalloons()
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
mBalloon[i]->disable();
|
|
}
|
|
|
|
// Establece la velocidad de los globos
|
|
void Game::setBalloonSpeed(float speed)
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
if (mBalloon[i]->isEnabled())
|
|
mBalloon[i]->setSpeed(speed);
|
|
}
|
|
|
|
// Incrementa la velocidad de los globos
|
|
void Game::incBalloonSpeed()
|
|
{
|
|
// La velocidad solo se incrementa en el modo normal
|
|
if (mDifficulty == DIFFICULTY_NORMAL)
|
|
{
|
|
if (mEnemySpeed == BALLOON_SPEED_1)
|
|
mEnemySpeed = BALLOON_SPEED_2;
|
|
else if (mEnemySpeed == BALLOON_SPEED_2)
|
|
mEnemySpeed = BALLOON_SPEED_3;
|
|
else if (mEnemySpeed == BALLOON_SPEED_3)
|
|
mEnemySpeed = BALLOON_SPEED_4;
|
|
else if (mEnemySpeed == BALLOON_SPEED_4)
|
|
mEnemySpeed = BALLOON_SPEED_5;
|
|
|
|
setBalloonSpeed(mEnemySpeed);
|
|
}
|
|
}
|
|
|
|
// Decrementa la velocidad de los globos
|
|
void Game::decBalloonSpeed()
|
|
{
|
|
// La velocidad solo se decrementa en el modo normal
|
|
if (mDifficulty == DIFFICULTY_NORMAL)
|
|
{
|
|
if (mEnemySpeed == BALLOON_SPEED_5)
|
|
mEnemySpeed = BALLOON_SPEED_4;
|
|
else if (mEnemySpeed == BALLOON_SPEED_4)
|
|
mEnemySpeed = BALLOON_SPEED_3;
|
|
else if (mEnemySpeed == BALLOON_SPEED_3)
|
|
mEnemySpeed = BALLOON_SPEED_2;
|
|
else if (mEnemySpeed == BALLOON_SPEED_2)
|
|
mEnemySpeed = BALLOON_SPEED_1;
|
|
|
|
setBalloonSpeed(mEnemySpeed);
|
|
}
|
|
}
|
|
|
|
// Actualiza la velocidad de los globos en funcion del poder acumulado de la fase
|
|
void Game::updateBalloonSpeed()
|
|
{
|
|
const float percent = (float)mStage[mCurrentStage].currentPower / (float)mStage[mCurrentStage].powerToComplete;
|
|
if (mEnemySpeed == BALLOON_SPEED_1)
|
|
{
|
|
if (percent > 0.2f)
|
|
incBalloonSpeed();
|
|
}
|
|
else if (mEnemySpeed == BALLOON_SPEED_2)
|
|
{
|
|
if (percent > 0.4f)
|
|
incBalloonSpeed();
|
|
}
|
|
else if (mEnemySpeed == BALLOON_SPEED_3)
|
|
{
|
|
if (percent > 0.6f)
|
|
incBalloonSpeed();
|
|
}
|
|
else if (mEnemySpeed == BALLOON_SPEED_4)
|
|
{
|
|
if (percent > 0.8f)
|
|
incBalloonSpeed();
|
|
}
|
|
}
|
|
|
|
// Explosiona un globo. Lo destruye y crea otros dos si es el caso
|
|
void Game::popBalloon(Uint8 index)
|
|
{
|
|
// Aumenta el poder de la fase
|
|
increaseStageCurrentPower(1);
|
|
mBalloonsPopped++;
|
|
|
|
const Uint8 kind = mBalloon[index]->getKind();
|
|
Uint8 freeIndex = 0;
|
|
switch (kind)
|
|
{
|
|
// Si es del tipo más pequeño, simplemente elimina el globo
|
|
case BALLOON_1:
|
|
mBalloon[index]->pop();
|
|
break;
|
|
|
|
case HEXAGON_1:
|
|
mBalloon[index]->pop();
|
|
break;
|
|
|
|
// Si es del tipo PowerBall, destruye todos los globos
|
|
case POWER_BALL:
|
|
destroyAllBalloons();
|
|
mPowerBallEnabled = false;
|
|
mEnemyDeployCounter = 20;
|
|
break;
|
|
|
|
// En cualquier otro caso, crea dos globos de un tipo inferior
|
|
default:
|
|
freeIndex = getBalloonFreeIndex();
|
|
mBalloon[freeIndex]->init(0, mBalloon[index]->getPosY(), mBalloon[index]->getKind() - 1, BALLOON_VELX_NEGATIVE, mEnemySpeed, 0, mTextureBalloon, mRenderer);
|
|
mBalloon[freeIndex]->allignTo(mBalloon[index]->getPosX() + (mBalloon[index]->getWidth() / 2));
|
|
if (mBalloon[freeIndex]->getClass() == BALLOON_CLASS)
|
|
mBalloon[freeIndex]->setVelY(-2.50f);
|
|
else if (mBalloon[freeIndex]->getClass() == HEXAGON_CLASS)
|
|
mBalloon[freeIndex]->setVelY(BALLOON_VELX_NEGATIVE);
|
|
|
|
freeIndex = getBalloonFreeIndex();
|
|
mBalloon[freeIndex]->init(0, mBalloon[index]->getPosY(), mBalloon[index]->getKind() - 1, BALLOON_VELX_POSITIVE, mEnemySpeed, 0, mTextureBalloon, mRenderer);
|
|
mBalloon[freeIndex]->allignTo(mBalloon[index]->getPosX() + (mBalloon[index]->getWidth() / 2));
|
|
if (mBalloon[freeIndex]->getClass() == BALLOON_CLASS)
|
|
mBalloon[freeIndex]->setVelY(-2.50f);
|
|
else if (mBalloon[freeIndex]->getClass() == HEXAGON_CLASS)
|
|
mBalloon[freeIndex]->setVelY(BALLOON_VELX_NEGATIVE);
|
|
|
|
// Elimina el globo
|
|
mBalloon[index]->pop();
|
|
break;
|
|
}
|
|
|
|
// Recalcula el nivel de amenaza
|
|
evaluateAndSetMenace();
|
|
}
|
|
|
|
// Explosiona un globo. Lo destruye
|
|
void Game::destroyBalloon(Uint8 index)
|
|
{
|
|
int score = 0;
|
|
Uint8 power = 0;
|
|
|
|
// Calcula la puntuación y el poder que generaria el globo en caso de romperlo a él y a sus hijos
|
|
switch (mBalloon[index]->getSize())
|
|
{
|
|
case BALLOON_SIZE_4:
|
|
score = BALLOON_SCORE_4 + (2 * BALLOON_SCORE_3) + (4 * BALLOON_SCORE_2) + (8 * BALLOON_SCORE_1);
|
|
power = 15;
|
|
break;
|
|
|
|
case BALLOON_SIZE_3:
|
|
score = BALLOON_SCORE_3 + (2 * BALLOON_SCORE_2) + (4 * BALLOON_SCORE_1);
|
|
power = 7;
|
|
break;
|
|
|
|
case BALLOON_SIZE_2:
|
|
score = BALLOON_SCORE_2 + (2 * BALLOON_SCORE_1);
|
|
power = 3;
|
|
break;
|
|
|
|
case BALLOON_SIZE_1:
|
|
score = BALLOON_SCORE_1;
|
|
power = 1;
|
|
break;
|
|
|
|
default:
|
|
score = 0;
|
|
power = 0;
|
|
break;
|
|
}
|
|
|
|
// Otorga los puntos correspondientes al globo
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
mPlayer[i]->addScore(Uint32(score * mPlayer[i]->getScoreMultiplier() * mDifficultyScoreMultiplier));
|
|
updateHiScore();
|
|
|
|
// Aumenta el poder de la fase
|
|
increaseStageCurrentPower(power);
|
|
mBalloonsPopped += power;
|
|
|
|
// Destruye el globo
|
|
mBalloon[index]->pop();
|
|
|
|
// Recalcula el nivel de amenaza
|
|
evaluateAndSetMenace();
|
|
}
|
|
|
|
// Explosiona todos los globos
|
|
void Game::popAllBalloons()
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
if ((mBalloon[i]->isEnabled()) && (!mBalloon[i]->isPopping()) && (!mBalloon[i]->isBeingCreated()))
|
|
popBalloon(i);
|
|
|
|
JA_PlaySound(mSoundBalloon);
|
|
}
|
|
|
|
// Destruye todos los globos
|
|
void Game::destroyAllBalloons()
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
//if ((mBalloon[i]->isEnabled()) && (!mBalloon[i]->isPopping()) && (!mBalloon[i]->isBeingCreated()))
|
|
if ((mBalloon[i]->isEnabled()) && (!mBalloon[i]->isPopping()))
|
|
destroyBalloon(i);
|
|
|
|
mEnemyDeployCounter = 255;
|
|
JA_PlaySound(mSoundPowerBall);
|
|
mEffect.flash = true;
|
|
mEffect.shake = true;
|
|
}
|
|
|
|
// Detiene todos los globos
|
|
void Game::stopAllBalloons(Uint16 time)
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
if (mBalloon[i]->isEnabled())
|
|
{
|
|
mBalloon[i]->setStop(true);
|
|
mBalloon[i]->setStoppedTimer(time);
|
|
}
|
|
}
|
|
|
|
// Pone en marcha todos los globos
|
|
void Game::startAllBalloons()
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
if ((mBalloon[i]->isEnabled()) && (!mBalloon[i]->isBeingCreated()))
|
|
{
|
|
mBalloon[i]->setStop(false);
|
|
mBalloon[i]->setStoppedTimer(0);
|
|
}
|
|
}
|
|
|
|
// Obtiene el numero de globos activos
|
|
Uint8 Game::countBalloons()
|
|
{
|
|
Uint8 num = 0;
|
|
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
if (mBalloon[i]->isEnabled())
|
|
if (!mBalloon[i]->isPopping())
|
|
num++;
|
|
|
|
return num;
|
|
}
|
|
|
|
// Comprueba la colisión entre el jugador y los globos activos
|
|
bool Game::checkPlayerBalloonCollision(int index)
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
if ((mBalloon[i]->isEnabled()) && !(mBalloon[i]->isStopped()) && !(mBalloon[i]->isInvulnerable()))
|
|
if (checkCollision(mPlayer[index]->getCollider(), mBalloon[i]->getCollider()))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// Comprueba la colisión entre el jugador y los items
|
|
void Game::checkPlayerItemCollision(int index)
|
|
{
|
|
if (mPlayer[index]->isAlive())
|
|
for (int i = 0; i < MAX_ITEMS; i++)
|
|
{
|
|
if (mItem[i]->isEnabled())
|
|
{
|
|
if (checkCollision(mPlayer[index]->getCollider(), mItem[i]->getCollider()))
|
|
{
|
|
switch (mItem[i]->getClass())
|
|
{
|
|
case ITEM_POINTS_1_DISK:
|
|
mPlayer[index]->addScore(1000);
|
|
updateHiScore();
|
|
createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m1000Bitmap->getWidth() / 2), mPlayer[index]->getPosY(), m1000Bitmap);
|
|
JA_PlaySound(mSoundItemPickup);
|
|
break;
|
|
case ITEM_POINTS_2_GAVINA:
|
|
mPlayer[index]->addScore(2500);
|
|
updateHiScore();
|
|
createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m2500Bitmap->getWidth() / 2), mPlayer[index]->getPosY(), m2500Bitmap);
|
|
JA_PlaySound(mSoundItemPickup);
|
|
break;
|
|
case ITEM_POINTS_3_PACMAR:
|
|
mPlayer[index]->addScore(5000);
|
|
updateHiScore();
|
|
createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m5000Bitmap->getWidth() / 2), mPlayer[index]->getPosY(), m5000Bitmap);
|
|
JA_PlaySound(mSoundItemPickup);
|
|
break;
|
|
case ITEM_CLOCK:
|
|
enableTimeStopItem();
|
|
JA_PlaySound(mSoundItemPickup);
|
|
break;
|
|
case ITEM_COFFEE:
|
|
if (mPlayer[index]->getCoffees() == 2)
|
|
{
|
|
mPlayer[index]->addScore(5000);
|
|
updateHiScore();
|
|
createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m5000Bitmap->getWidth() / 2), mPlayer[index]->getPosY(), m5000Bitmap);
|
|
}
|
|
mPlayer[index]->giveExtraHit();
|
|
JA_PlaySound(mSoundItemPickup);
|
|
break;
|
|
case ITEM_COFFEE_MACHINE:
|
|
mPlayer[index]->setPowerUp(true);
|
|
JA_PlaySound(mSoundItemPickup);
|
|
mCoffeeMachineEnabled = false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
mItem[i]->erase();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Comprueba y procesa la colisión entre las balas y los globos
|
|
void Game::checkBulletBalloonCollision()
|
|
{
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
for (int j = 0; j < MAX_BULLETS; j++)
|
|
if (mBalloon[i]->isEnabled() && (!mBalloon[i]->isInvulnerable()) && mBullet[j]->isActive())
|
|
if (checkCollision(mBalloon[i]->getCollider(), mBullet[j]->getCollider()))
|
|
{
|
|
// Otorga los puntos correspondientes al globo al jugador que disparó la bala
|
|
int index = mBullet[j]->getOwner();
|
|
mPlayer[index]->incScoreMultiplier();
|
|
mPlayer[index]->addScore(Uint32(mBalloon[i]->getScore() * mPlayer[index]->getScoreMultiplier() * mDifficultyScoreMultiplier));
|
|
updateHiScore();
|
|
|
|
// Explota el globo
|
|
popBalloon(i);
|
|
|
|
// Si no es el modo demo, genera un sonido
|
|
if (!mDemo.enabled)
|
|
JA_PlaySound(mSoundBalloon);
|
|
|
|
// Destruye la bala
|
|
mBullet[j]->erase();
|
|
|
|
// Suelta el item en caso de que salga uno
|
|
const Uint8 droppeditem = dropItem();
|
|
if ((droppeditem != NO_KIND) && !(mDemo.enabled) && !(mDemo.recording))
|
|
{
|
|
if (droppeditem != ITEM_COFFEE_MACHINE)
|
|
{
|
|
createItem(mBalloon[i]->getPosX(), mBalloon[i]->getPosY(), droppeditem);
|
|
JA_PlaySound(mSoundItemDrop);
|
|
}
|
|
else
|
|
{
|
|
createItem(mPlayer[index]->getPosX(), 0, droppeditem);
|
|
mCoffeeMachineEnabled = true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Mueve las balas activas
|
|
void Game::moveBullets()
|
|
{
|
|
for (int i = 0; i < MAX_BULLETS; i++)
|
|
if (mBullet[i]->isActive())
|
|
if (mBullet[i]->move() == BULLET_MOVE_OUT)
|
|
mPlayer[mBullet[i]->getOwner()]->decScoreMultiplier();
|
|
}
|
|
|
|
// Pinta las balas activas
|
|
void Game::renderBullets()
|
|
{
|
|
for (int i = 0; i < MAX_BULLETS; i++)
|
|
if (mBullet[i]->isActive())
|
|
mBullet[i]->render();
|
|
}
|
|
|
|
// Devuelve el primer indice no activo del vector de balas
|
|
Uint8 Game::getBulletFreeIndex()
|
|
{
|
|
for (int i = 0; i < MAX_BULLETS; i++)
|
|
if (mBullet[i]->isActive() == false)
|
|
return i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Establece a cero todos los valores del vector de objetos bala
|
|
void Game::resetBullets()
|
|
{
|
|
for (int i = 0; i < MAX_BULLETS; i++)
|
|
mBullet[i]->erase();
|
|
}
|
|
|
|
// Crea un objeto bala
|
|
void Game::createBullet(int x, int y, Uint8 kind, bool poweredUp, int owner)
|
|
{
|
|
mBullet[getBulletFreeIndex()]->init(x, y, kind, poweredUp, owner, mTextureBullet, mRenderer);
|
|
}
|
|
|
|
// Actualiza los items
|
|
void Game::updateItems()
|
|
{
|
|
for (int i = 0; i < MAX_ITEMS; i++)
|
|
{
|
|
mItem[i]->update();
|
|
if (mItem[i]->floorCollision())
|
|
{
|
|
JA_PlaySound(mSoundCollision);
|
|
mEffect.shake = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pinta los items activos
|
|
void Game::renderItems()
|
|
{
|
|
for (int i = 0; i < MAX_ITEMS; i++)
|
|
mItem[i]->render();
|
|
}
|
|
|
|
// Devuelve el primer indice no activo del vector de items
|
|
Uint8 Game::getItemFreeIndex()
|
|
{
|
|
for (int i = 0; i < MAX_ITEMS; i++)
|
|
if (mItem[i]->getClass() == NO_KIND)
|
|
return i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Establece a cero todos los valores del vector de objetos item
|
|
void Game::resetItems()
|
|
{
|
|
for (int i = 0; i < MAX_ITEMS; i++)
|
|
mItem[i]->erase();
|
|
}
|
|
|
|
// Devuelve un item en función del azar
|
|
Uint8 Game::dropItem()
|
|
{
|
|
const Uint8 luckyNumber = rand() % 100;
|
|
const Uint8 item = rand() % 6;
|
|
|
|
switch (item)
|
|
{
|
|
case 0:
|
|
if (luckyNumber < mHelper.itemPoints1Odds)
|
|
return ITEM_POINTS_1_DISK;
|
|
break;
|
|
case 1:
|
|
if (luckyNumber < mHelper.itemPoints2Odds)
|
|
return ITEM_POINTS_2_GAVINA;
|
|
break;
|
|
case 2:
|
|
if (luckyNumber < mHelper.itemPoints3Odds)
|
|
return ITEM_POINTS_3_PACMAR;
|
|
break;
|
|
case 3:
|
|
if (luckyNumber < mHelper.itemClockOdds)
|
|
return ITEM_CLOCK;
|
|
break;
|
|
case 4:
|
|
if (luckyNumber < mHelper.itemCoffeeOdds)
|
|
{
|
|
mHelper.itemCoffeeOdds = ITEM_COFFEE_ODDS;
|
|
return ITEM_COFFEE;
|
|
}
|
|
else
|
|
{
|
|
if (mHelper.needCoffee)
|
|
mHelper.itemCoffeeOdds++;
|
|
}
|
|
break;
|
|
case 5:
|
|
if (luckyNumber < mHelper.itemCoffeeMachineOdds)
|
|
{
|
|
mHelper.itemCoffeeMachineOdds = ITEM_COFFEE_MACHINE_ODDS;
|
|
if ((!mCoffeeMachineEnabled) && (mHelper.needCoffeeMachine))
|
|
return ITEM_COFFEE_MACHINE;
|
|
}
|
|
else
|
|
{
|
|
if (mHelper.needCoffeeMachine)
|
|
mHelper.itemCoffeeMachineOdds++;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NO_KIND;
|
|
}
|
|
|
|
// Crea un objeto item
|
|
void Game::createItem(int x, int y, Uint8 kind)
|
|
{
|
|
mItem[getItemFreeIndex()]->init(kind, x, y, mTextureItems, mRenderer);
|
|
}
|
|
|
|
// Crea un objeto SmartSprite para mostrar la puntuación al coger un objeto
|
|
void Game::createItemScoreSprite(int x, int y, SmartSprite *sprite)
|
|
{
|
|
const Uint8 index = getSmartSpriteFreeIndex();
|
|
|
|
// Crea una copia del objeto
|
|
*mSmartSprite[index] = *sprite;
|
|
mSmartSprite[index]->setPosX(x);
|
|
mSmartSprite[index]->setPosY(y);
|
|
mSmartSprite[index]->setDestX(x);
|
|
mSmartSprite[index]->setDestY(y - 15);
|
|
mSmartSprite[index]->setEnabled(true);
|
|
mSmartSprite[index]->setEnabledTimer(100);
|
|
}
|
|
|
|
// Dibuja el efecto de flash
|
|
void Game::renderFlashEffect()
|
|
{
|
|
if (mEffect.flash)
|
|
{
|
|
// Pantallazo blanco
|
|
SDL_SetRenderDrawColor(mRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
|
|
SDL_RenderClear(mRenderer);
|
|
|
|
mEffect.flash = false;
|
|
}
|
|
}
|
|
|
|
// Actualiza el efecto de agitar la pantalla
|
|
void Game::updateShakeEffect()
|
|
{
|
|
if (mEffect.shake)
|
|
{
|
|
if (mEffect.shakeCounter > 0)
|
|
mEffect.shakeCounter--;
|
|
else
|
|
{
|
|
mEffect.shake = false;
|
|
mEffect.shakeCounter = SHAKE_COUNTER;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Crea un SmartSprite para arrojar el item café al recibir un impacto
|
|
void Game::throwCoffee(int x, int y)
|
|
{
|
|
const Uint8 index = getSmartSpriteFreeIndex();
|
|
|
|
mSmartSprite[index]->init(mTextureItems, mRenderer);
|
|
mSmartSprite[index]->setPosX(x - 8);
|
|
mSmartSprite[index]->setPosY(y - 8);
|
|
mSmartSprite[index]->setWidth(16);
|
|
mSmartSprite[index]->setHeight(16);
|
|
mSmartSprite[index]->setVelX(-1.0f + ((rand() % 5) * 0.5f));
|
|
mSmartSprite[index]->setVelY(-4.0f);
|
|
mSmartSprite[index]->setAccelX(0.0f);
|
|
mSmartSprite[index]->setAccelY(0.2f);
|
|
mSmartSprite[index]->setDestX(x + (mSmartSprite[index]->getVelX() * 50));
|
|
mSmartSprite[index]->setDestY(SCREEN_HEIGHT + 1);
|
|
mSmartSprite[index]->setEnabled(true);
|
|
mSmartSprite[index]->setEnabledTimer(1);
|
|
mSmartSprite[index]->setSpriteClip(80, 16, 16, 16);
|
|
mSmartSprite[index]->setRotate(true);
|
|
mSmartSprite[index]->setRotateSpeed(10);
|
|
mSmartSprite[index]->setRotateAmount(90.0);
|
|
}
|
|
|
|
// Crea un SmartSprite para arrojar al jugador al morir
|
|
void Game::throwPlayer(int x, int y, int index)
|
|
{
|
|
const int sentit = ((rand() % 2) ? 1 : -1);
|
|
|
|
mPlayer[index]->mDeathIndex = getSmartSpriteFreeIndex();
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->init(mPlayer[index]->getDeadTexture(), mRenderer);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setPosX(x);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setPosY(y);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setWidth(24);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setHeight(24);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setVelX(2.0f * sentit);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setVelY(-5.0f);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setAccelX(0.0f);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setAccelY(0.2f);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setDestX(SCREEN_WIDTH * sentit);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setDestY(SCREEN_HEIGHT + 1);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setEnabled(true);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setEnabledTimer(1);
|
|
mSmartSprite[mPlayer[index]->mDeathIndex]->setSpriteClip(0, 0, 24, 24);
|
|
}
|
|
|
|
// Actualiza los SmartSprites
|
|
void Game::updateSmartSprites()
|
|
{
|
|
for (int i = 0; i < MAX_SMART_SPRITES; i++)
|
|
mSmartSprite[i]->update();
|
|
}
|
|
|
|
// Pinta los SmartSprites activos
|
|
void Game::renderSmartSprites()
|
|
{
|
|
for (int i = 0; i < MAX_SMART_SPRITES; i++)
|
|
mSmartSprite[i]->render();
|
|
}
|
|
|
|
// Devuelve el primer indice no activo del vector de SmartSprites
|
|
Uint8 Game::getSmartSpriteFreeIndex()
|
|
{
|
|
for (int i = 0; i < MAX_SMART_SPRITES; i++)
|
|
if (!mSmartSprite[i]->isEnabled())
|
|
return i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Establece a cero todos los valores del vector de objetos SmafrtSprite
|
|
void Game::resetSmartSprites()
|
|
{
|
|
for (int i = 0; i < MAX_SMART_SPRITES; i++)
|
|
mSmartSprite[i]->erase();
|
|
}
|
|
|
|
// Acciones a realizar cuando el jugador muere
|
|
void Game::killPlayer(int index)
|
|
{
|
|
if (!mPlayer[index]->isInvulnerable())
|
|
{
|
|
if (mPlayer[index]->hasExtraHit())
|
|
{
|
|
mPlayer[index]->removeExtraHit();
|
|
throwCoffee(mPlayer[index]->getPosX() + (mPlayer[index]->getWidth() / 2), mPlayer[index]->getPosY() + (mPlayer[index]->getHeight() / 2));
|
|
JA_PlaySound(mSoundCoffeeOut);
|
|
}
|
|
else
|
|
{
|
|
JA_PauseMusic();
|
|
stopAllBalloons(10);
|
|
JA_PlaySound(mSoundPlayerCollision);
|
|
shakeScreen();
|
|
SDL_Delay(500);
|
|
JA_PlaySound(mSoundCoffeeOut);
|
|
throwPlayer(mPlayer[index]->getPosX(), mPlayer[index]->getPosY(), index);
|
|
mPlayer[index]->setAlive(false);
|
|
if (allPlayersAreDead())
|
|
JA_StopMusic();
|
|
else
|
|
JA_ResumeMusic();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calcula y establece el valor de amenaza en funcion de los globos activos
|
|
void Game::evaluateAndSetMenace()
|
|
{
|
|
mMenaceCurrent = 0;
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
if (mBalloon[i]->isEnabled())
|
|
mMenaceCurrent += mBalloon[i]->getMenace();
|
|
}
|
|
|
|
// Obtiene el valor de la variable
|
|
Uint8 Game::getMenace()
|
|
{
|
|
return mMenaceCurrent;
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void Game::setTimeStopped(bool value)
|
|
{
|
|
mTimeStopped = value;
|
|
}
|
|
|
|
// Obtiene el valor de la variable
|
|
bool Game::isTimeStopped()
|
|
{
|
|
return mTimeStopped;
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void Game::setTimeStoppedCounter(Uint16 value)
|
|
{
|
|
mTimeStoppedCounter = value;
|
|
}
|
|
|
|
// Incrementa el valor de la variable
|
|
void Game::incTimeStoppedCounter(Uint16 value)
|
|
{
|
|
mTimeStoppedCounter += value;
|
|
}
|
|
|
|
// Actualiza y comprueba el valor de la variable
|
|
void Game::updateTimeStoppedCounter()
|
|
{
|
|
if (isTimeStopped())
|
|
{
|
|
if (mTimeStoppedCounter > 0)
|
|
{
|
|
mTimeStoppedCounter--;
|
|
stopAllBalloons(TIME_STOPPED_COUNTER);
|
|
}
|
|
else
|
|
{
|
|
disableTimeStopItem();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void Game::setExplosionTime(bool value)
|
|
{
|
|
mExplosionTime = value;
|
|
}
|
|
|
|
// Obtiene el valor de la variable
|
|
bool Game::isExplosionTime()
|
|
{
|
|
return mExplosionTime;
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void Game::setRemainingExplosions(Uint8 value)
|
|
{
|
|
mRemainingExplosions = value;
|
|
}
|
|
|
|
// Actualiza y comprueba el valor de la variable
|
|
void Game::updateRemainingExplosionsCounter()
|
|
{
|
|
if (isExplosionTime())
|
|
{
|
|
if (mRemainingExplosionsCounter > 0)
|
|
{
|
|
mRemainingExplosionsCounter--;
|
|
}
|
|
else if (mRemainingExplosions > 0)
|
|
{
|
|
popAllBalloons();
|
|
mRemainingExplosions--;
|
|
mRemainingExplosionsCounter = REMAINING_EXPLOSIONS_COUNTER;
|
|
}
|
|
else
|
|
{
|
|
mExplosionTime = false;
|
|
mRemainingExplosions = REMAINING_EXPLOSIONS;
|
|
mRemainingExplosionsCounter = REMAINING_EXPLOSIONS_COUNTER;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza la variable mEnemyDeployCounter
|
|
void Game::updateEnemyDeployCounter()
|
|
{
|
|
if (mEnemyDeployCounter > 0)
|
|
mEnemyDeployCounter--;
|
|
}
|
|
|
|
// Actualiza el campo de juego
|
|
void Game::updatePlayField()
|
|
{
|
|
// Comprueba el teclado/mando
|
|
checkGameInput();
|
|
|
|
// Actualiza las variables del jugador
|
|
updatePlayer();
|
|
|
|
// Actualiza el fondo
|
|
updateBackground();
|
|
|
|
// Mueve los globos
|
|
updateBalloons();
|
|
|
|
// Mueve las balas
|
|
moveBullets();
|
|
|
|
// Actualiza los items
|
|
updateItems();
|
|
|
|
// Actualiza el valor de mCurrentStage
|
|
updateStage();
|
|
|
|
// Actualiza el estado de muerte
|
|
updateDeath();
|
|
|
|
// Actualiza los SmartSprites
|
|
updateSmartSprites();
|
|
|
|
// Actualiza los contadores de estado y efectos
|
|
updateTimeStoppedCounter();
|
|
updateRemainingExplosionsCounter();
|
|
updateEnemyDeployCounter();
|
|
updateShakeEffect();
|
|
|
|
// Actualiza el ayudante
|
|
updateHelper();
|
|
|
|
// Comprueba las colisiones entre globos y balas
|
|
checkBulletBalloonCollision();
|
|
|
|
// Comprueba el nivel de amenaza para ver si se han de crear nuevos enemigos
|
|
if (!mGameCompleted)
|
|
updateMenace();
|
|
|
|
// Actualiza la velocidad de los enemigos
|
|
updateBalloonSpeed();
|
|
|
|
// Actualiza el tramo final de juego, una vez completado
|
|
updateGameCompleted();
|
|
}
|
|
|
|
// Actualiza el fondo
|
|
void Game::updateBackground()
|
|
{
|
|
mClouds1a->move();
|
|
mClouds1b->move();
|
|
mClouds2a->move();
|
|
mClouds2b->move();
|
|
|
|
if (mClouds1a->getPosX() < -mClouds1a->getWidth())
|
|
mClouds1a->setPosX(mClouds1a->getWidth());
|
|
|
|
if (mClouds1b->getPosX() < -mClouds1b->getWidth())
|
|
mClouds1b->setPosX(mClouds1b->getWidth());
|
|
|
|
if (mClouds2a->getPosX() < -mClouds2a->getWidth())
|
|
mClouds2a->setPosX(mClouds2a->getWidth());
|
|
|
|
if (mClouds2b->getPosX() < -mClouds2b->getWidth())
|
|
mClouds2b->setPosX(mClouds2b->getWidth());
|
|
|
|
mSpriteGrass->setSpriteClip(256, 85 + (6 * (mCounter / 20 % 2)), SCREEN_WIDTH, 6);
|
|
|
|
if (mEffect.shake)
|
|
mSpriteBackground->setPosX(((mEffect.shakeCounter % 2) * 2) - 1);
|
|
else
|
|
mSpriteBackground->setPosX(0);
|
|
}
|
|
|
|
// Dibuja el fondo
|
|
void Game::renderBackground()
|
|
{
|
|
const float gradientNumber = std::min(((float)mBalloonsPopped / 1000.0f), 3.0f);
|
|
const float percent = gradientNumber - (int)gradientNumber;
|
|
const int alpha = std::max((255 - (int)(255 * percent)), 0);
|
|
|
|
// Dibuja el gradiente 2
|
|
mSpriteGradient->setSpriteClip(mGradientRect[((int)gradientNumber + 1) % 4]);
|
|
mSpriteGradient->render();
|
|
|
|
// Dibuja el gradiente 1 con una opacidad cada vez menor
|
|
mSpriteGradient->setSpriteClip(mGradientRect[(int)gradientNumber]);
|
|
mTextureGameBG->setAlpha(alpha);
|
|
mSpriteGradient->render();
|
|
mTextureGameBG->setAlpha(255);
|
|
|
|
mClouds1a->render();
|
|
mClouds1b->render();
|
|
mClouds2a->render();
|
|
mClouds2b->render();
|
|
|
|
mSpriteBackground->render();
|
|
|
|
mSpriteGrass->render();
|
|
}
|
|
|
|
// Dibuja el campo de juego
|
|
void Game::renderPlayField()
|
|
{
|
|
renderBackground();
|
|
renderBalloons();
|
|
renderBullets();
|
|
renderMessages();
|
|
renderItems();
|
|
renderSmartSprites();
|
|
renderScoreBoard();
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
mPlayer[i]->render();
|
|
if ((mDeathCounter <= 150) && !mPlayer[0]->isAlive())
|
|
renderDeathFade(150 - mDeathCounter);
|
|
if ((mGameCompleted) && (mGameCompletedCounter >= 300))
|
|
renderDeathFade(mGameCompletedCounter - 300);
|
|
renderFlashEffect();
|
|
}
|
|
|
|
// Gestiona el nivel de amenaza
|
|
void Game::updateMenace()
|
|
{
|
|
const float percent = mStage[mCurrentStage].currentPower / mStage[mCurrentStage].powerToComplete;
|
|
const Uint8 difference = mStage[mCurrentStage].maxMenace - mStage[mCurrentStage].minMenace;
|
|
|
|
// Aumenta el nivel de amenaza en función de la puntuación
|
|
mMenaceThreshold = mStage[mCurrentStage].minMenace + (difference * percent);
|
|
|
|
// Si el nivel de amenza es inferior al umbral
|
|
if (mMenaceCurrent < mMenaceThreshold)
|
|
{
|
|
// Crea una formación de enemigos
|
|
deployEnemyFormation();
|
|
|
|
// Recalcula el nivel de amenaza con el nuevo globo
|
|
evaluateAndSetMenace();
|
|
}
|
|
}
|
|
|
|
// Gestiona la entrada durante el juego
|
|
void Game::checkGameInput()
|
|
{
|
|
mDemo.keys.left = 0;
|
|
mDemo.keys.right = 0;
|
|
mDemo.keys.noInput = 0;
|
|
mDemo.keys.fire = 0;
|
|
mDemo.keys.fireLeft = 0;
|
|
mDemo.keys.fireRight = 0;
|
|
|
|
// Modo Demo activo
|
|
if (mDemo.enabled)
|
|
{
|
|
const int index = 0;
|
|
if (mDemo.dataFile[mDemo.counter].left == 1)
|
|
mPlayer[index]->setInput(INPUT_LEFT);
|
|
|
|
if (mDemo.dataFile[mDemo.counter].right == 1)
|
|
mPlayer[index]->setInput(INPUT_RIGHT);
|
|
|
|
if (mDemo.dataFile[mDemo.counter].noInput == 1)
|
|
mPlayer[index]->setInput(INPUT_NULL);
|
|
|
|
if (mDemo.dataFile[mDemo.counter].fire == 1)
|
|
if (mPlayer[index]->canFire())
|
|
{
|
|
mPlayer[index]->setInput(INPUT_BUTTON_2);
|
|
createBullet(mPlayer[index]->getPosX() + (mPlayer[index]->getWidth() / 2) - 4, mPlayer[index]->getPosY() + (mPlayer[index]->getHeight() / 2), BULLET_UP, mPlayer[index]->isPowerUp(), index);
|
|
mPlayer[index]->setFireCooldown(10);
|
|
}
|
|
|
|
if (mDemo.dataFile[mDemo.counter].fireLeft == 1)
|
|
if (mPlayer[index]->canFire())
|
|
{
|
|
mPlayer[index]->setInput(INPUT_BUTTON_1);
|
|
createBullet(mPlayer[index]->getPosX() + (mPlayer[index]->getWidth() / 2) - 4, mPlayer[index]->getPosY() + (mPlayer[index]->getHeight() / 2), BULLET_UP, mPlayer[index]->isPowerUp(), index);
|
|
mPlayer[index]->setFireCooldown(10);
|
|
}
|
|
|
|
if (mDemo.dataFile[mDemo.counter].fireRight == 1)
|
|
if (mPlayer[index]->canFire())
|
|
{
|
|
mPlayer[index]->setInput(INPUT_BUTTON_3);
|
|
createBullet(mPlayer[index]->getPosX() + (mPlayer[index]->getWidth() / 2) - 4, mPlayer[index]->getPosY() + (mPlayer[index]->getHeight() / 2), BULLET_UP, mPlayer[index]->isPowerUp(), index);
|
|
mPlayer[index]->setFireCooldown(10);
|
|
}
|
|
|
|
// Comprueba el input de pausa
|
|
if (mInput->checkInput(INPUT_BUTTON_PAUSE, REPEAT_FALSE))
|
|
mSection.name = PROG_SECTION_TITLE;
|
|
|
|
// Incrementa el contador de la demo
|
|
if (mDemo.counter < TOTAL_DEMO_DATA)
|
|
mDemo.counter++;
|
|
else
|
|
mSection = {PROG_SECTION_TITLE, TITLE_SECTION_INSTRUCTIONS};
|
|
}
|
|
// Modo Demo no activo
|
|
else
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
if (mPlayer[i]->isAlive())
|
|
{
|
|
// Input a la izquierda
|
|
if (mInput->checkInput(INPUT_LEFT, REPEAT_TRUE, mOptions->input[i].deviceType, mOptions->input[i].id))
|
|
{
|
|
mPlayer[i]->setInput(INPUT_LEFT);
|
|
mDemo.keys.left = 1;
|
|
}
|
|
else
|
|
{
|
|
// Input a la derecha
|
|
if (mInput->checkInput(INPUT_RIGHT, REPEAT_TRUE, mOptions->input[i].deviceType, mOptions->input[i].id))
|
|
{
|
|
mPlayer[i]->setInput(INPUT_RIGHT);
|
|
mDemo.keys.right = 1;
|
|
}
|
|
else
|
|
{
|
|
// Ninguno de los dos inputs anteriores
|
|
mPlayer[i]->setInput(INPUT_NULL);
|
|
mDemo.keys.noInput = 1;
|
|
}
|
|
}
|
|
// Comprueba el input de disparar al centro
|
|
if (mInput->checkInput(INPUT_BUTTON_2, REPEAT_TRUE, mOptions->input[i].deviceType, mOptions->input[i].id))
|
|
{
|
|
if (mPlayer[i]->canFire())
|
|
{
|
|
mPlayer[i]->setInput(INPUT_BUTTON_2);
|
|
createBullet(mPlayer[i]->getPosX() + (mPlayer[i]->getWidth() / 2) - 4, mPlayer[i]->getPosY() + (mPlayer[i]->getHeight() / 2), BULLET_UP, mPlayer[i]->isPowerUp(), i);
|
|
mPlayer[i]->setFireCooldown(10);
|
|
|
|
// Reproduce el sonido de disparo
|
|
JA_PlaySound(mSoundBullet);
|
|
|
|
mDemo.keys.fire = 1;
|
|
}
|
|
}
|
|
|
|
// Comprueba el input de disparar a la izquierda
|
|
if (mInput->checkInput(INPUT_BUTTON_1, REPEAT_TRUE, mOptions->input[i].deviceType, mOptions->input[i].id))
|
|
{
|
|
if (mPlayer[i]->canFire())
|
|
{
|
|
mPlayer[i]->setInput(INPUT_BUTTON_1);
|
|
createBullet(mPlayer[i]->getPosX() + (mPlayer[i]->getWidth() / 2) - 4, mPlayer[i]->getPosY() + (mPlayer[i]->getHeight() / 2), BULLET_LEFT, mPlayer[i]->isPowerUp(), i);
|
|
mPlayer[i]->setFireCooldown(10);
|
|
|
|
// Reproduce el sonido de disparo
|
|
JA_PlaySound(mSoundBullet);
|
|
|
|
mDemo.keys.fireLeft = 1;
|
|
}
|
|
}
|
|
|
|
// Comprueba el input de disparar a la derecha
|
|
if (mInput->checkInput(INPUT_BUTTON_3, REPEAT_TRUE, mOptions->input[i].deviceType, mOptions->input[i].id))
|
|
{
|
|
if (mPlayer[i]->canFire())
|
|
{
|
|
mPlayer[i]->setInput(INPUT_BUTTON_3);
|
|
createBullet(mPlayer[i]->getPosX() + (mPlayer[i]->getWidth() / 2) - 4, mPlayer[i]->getPosY() + (mPlayer[i]->getHeight() / 2), BULLET_RIGHT, mPlayer[i]->isPowerUp(), i);
|
|
mPlayer[i]->setFireCooldown(10);
|
|
|
|
// Reproduce el sonido de disparo
|
|
JA_PlaySound(mSoundBullet);
|
|
|
|
mDemo.keys.fireRight = 1;
|
|
}
|
|
}
|
|
|
|
// Comprueba el input de pausa
|
|
if (mInput->checkInput(INPUT_CANCEL, REPEAT_FALSE, mOptions->input[i].deviceType, mOptions->input[i].id))
|
|
{
|
|
mSection.subsection = GAME_SECTION_PAUSE;
|
|
|
|
if (JA_GetMusicState() == JA_MUSIC_PLAYING)
|
|
JA_PauseMusic();
|
|
}
|
|
|
|
if (mDemo.counter < TOTAL_DEMO_DATA)
|
|
{
|
|
if (mDemo.recording)
|
|
mDemo.dataFile[mDemo.counter] = mDemo.keys;
|
|
mDemo.counter++;
|
|
}
|
|
else if (mDemo.recording)
|
|
{
|
|
mSection.name = PROG_SECTION_QUIT;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pinta diferentes mensajes en la pantalla
|
|
void Game::renderMessages()
|
|
{
|
|
// GetReady
|
|
if ((mCounter < STAGE_COUNTER) && (!mDemo.enabled))
|
|
{
|
|
mSpriteGetReady->setPosX((int)mGetReadyBitmapPath[mCounter]);
|
|
mTextNokiaBig2->write((int)mGetReadyBitmapPath[mCounter], PLAY_AREA_CENTER_Y - 8, mLang->getText(75), -2);
|
|
}
|
|
|
|
// Time Stopped
|
|
if (mTimeStopped)
|
|
{
|
|
if ((mTimeStoppedCounter > 100) || (mTimeStoppedCounter % 10 > 4))
|
|
mTextNokia2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, mLang->getText(36) + std::to_string(mTimeStoppedCounter / 10), -1, noColor, 1, shdwTxtColor);
|
|
|
|
if (mTimeStoppedCounter > 100)
|
|
{
|
|
if (mTimeStoppedCounter % 30 == 0)
|
|
JA_PlaySound(mSoundClock, false);
|
|
}
|
|
else
|
|
{
|
|
if (mTimeStoppedCounter % 15 == 0)
|
|
JA_PlaySound(mSoundClock, false);
|
|
}
|
|
}
|
|
|
|
// D E M O
|
|
if (mDemo.enabled)
|
|
if (mDemo.counter % 30 > 14)
|
|
mTextNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, mLang->getText(37), 0, noColor, 2, shdwTxtColor);
|
|
|
|
// STAGE NUMBER
|
|
if (mStageBitmapCounter < STAGE_COUNTER)
|
|
{
|
|
std::string text = mLang->getText(38) + std::to_string(mStage[mCurrentStage].number);
|
|
if (!mGameCompleted)
|
|
{
|
|
mTextNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, mStageBitmapPath[mStageBitmapCounter], text, -2, noColor, 2, shdwTxtColor);
|
|
}
|
|
else
|
|
{ // Texto de juego completado
|
|
text = mLang->getText(50);
|
|
mTextNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, mStageBitmapPath[mStageBitmapCounter], text, -2, noColor, 1, shdwTxtColor);
|
|
mTextNokia2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, mStageBitmapPath[mStageBitmapCounter] + mTextNokiaBig2->getCharacterWidth() + 2, mLang->getText(76), -1, noColor, 1, shdwTxtColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Habilita el efecto del item de detener el tiempo
|
|
void Game::enableTimeStopItem()
|
|
{
|
|
stopAllBalloons(TIME_STOPPED_COUNTER);
|
|
setTimeStopped(true);
|
|
incTimeStoppedCounter(TIME_STOPPED_COUNTER);
|
|
if (JA_GetMusicState() == JA_MUSIC_PLAYING)
|
|
JA_PauseMusic();
|
|
}
|
|
|
|
// Deshabilita el efecto del item de detener el tiempo
|
|
void Game::disableTimeStopItem()
|
|
{
|
|
mTimeStopped = false;
|
|
setTimeStoppedCounter(0);
|
|
startAllBalloons();
|
|
if (JA_GetMusicState() == JA_MUSIC_PAUSED)
|
|
JA_ResumeMusic();
|
|
}
|
|
|
|
// Agita la pantalla
|
|
void Game::shakeScreen()
|
|
{
|
|
const int v[] = {-1, 1, -1, 1, -1, 1, -1, 0};
|
|
for (int n = 0; n < 8; n++)
|
|
{
|
|
// Limpia la pantalla
|
|
//SDL_SetRenderDrawColor(mRenderer, 0x00, 0x00, 0x00, 0xFF);
|
|
//SDL_RenderClear(mRenderer);
|
|
|
|
// Prepara para empezar a dibujar en la textura de juego
|
|
mScreen->start();
|
|
|
|
// Limpia la pantalla
|
|
mScreen->clean(bgColor);
|
|
|
|
// Dibuja los objetos
|
|
mSpriteBackground->setPosX(0);
|
|
mSpriteBackground->setWidth(1);
|
|
mSpriteBackground->setSpriteClip(0, 0, 1, 192);
|
|
renderBackground();
|
|
|
|
mSpriteBackground->setPosX(255);
|
|
mSpriteBackground->setSpriteClip(255, 0, 1, 192);
|
|
mSpriteBackground->render();
|
|
|
|
mSpriteBackground->setPosX(v[n]);
|
|
mSpriteBackground->setWidth(256);
|
|
mSpriteBackground->setSpriteClip(0, 0, 256, 192);
|
|
mSpriteBackground->render();
|
|
|
|
mSpriteGrass->render();
|
|
renderBalloons();
|
|
renderBullets();
|
|
renderItems();
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
mPlayer[i]->render();
|
|
renderScoreBoard();
|
|
|
|
// Actualiza la pantalla
|
|
//SDL_RenderPresent(mRenderer);
|
|
|
|
// Vuelca el contenido del renderizador en pantalla
|
|
mScreen->blit();
|
|
SDL_Delay(50);
|
|
}
|
|
}
|
|
|
|
// Bucle para el juego
|
|
section_t Game::run()
|
|
{
|
|
init();
|
|
|
|
while (mSection.name == PROG_SECTION_GAME)
|
|
{
|
|
// Sección juego en pausa
|
|
if (mSection.subsection == GAME_SECTION_PAUSE)
|
|
runPausedGame();
|
|
|
|
// Sección Game Over
|
|
if (mSection.subsection == GAME_SECTION_GAMEOVER)
|
|
runGameOverScreen();
|
|
|
|
// Sección juego jugando
|
|
if ((mSection.subsection == GAME_SECTION_PLAY_1P) || (mSection.subsection == GAME_SECTION_PLAY_2P))
|
|
{
|
|
// Si la música no está sonando
|
|
if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED))
|
|
{
|
|
// Reproduce la música
|
|
if (!mGameCompleted)
|
|
if (mPlayer[0]->isAlive())
|
|
JA_PlayMusic(mMusicPlaying);
|
|
}
|
|
|
|
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
|
if (SDL_GetTicks() - mTicks > mTicksSpeed)
|
|
{
|
|
// Actualiza el contador de ticks
|
|
mTicks = SDL_GetTicks();
|
|
|
|
// Actualiza el contador de juego
|
|
mCounter++;
|
|
|
|
// Comprueba los eventos que hay en la cola
|
|
while (SDL_PollEvent(mEventHandler) != 0)
|
|
{
|
|
// Evento de salida de la aplicación
|
|
if (mEventHandler->type == SDL_QUIT)
|
|
{
|
|
mSection.name = PROG_SECTION_QUIT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Actualiza la lógica del juego
|
|
updatePlayField();
|
|
}
|
|
|
|
// Prepara para empezar a dibujar en la textura de juego
|
|
mScreen->start();
|
|
|
|
// Limpia la pantalla
|
|
mScreen->clean(bgColor);
|
|
|
|
// Dibuja los objetos
|
|
renderPlayField();
|
|
|
|
// Pinta la informacion de debug
|
|
renderDebugInfo();
|
|
|
|
// Vuelca el contenido del renderizador en pantalla
|
|
mScreen->blit();
|
|
}
|
|
}
|
|
|
|
return mSection;
|
|
}
|
|
|
|
// Bucle para el menu de pausa del juego
|
|
void Game::runPausedGame()
|
|
{
|
|
// Reinicia el menu
|
|
mMenuPause->reset();
|
|
|
|
while ((mSection.subsection == GAME_SECTION_PAUSE) && (mSection.name == PROG_SECTION_GAME))
|
|
{
|
|
// Comprueba los eventos que hay en la cola
|
|
while (SDL_PollEvent(mEventHandler) != 0)
|
|
{
|
|
// Evento de salida de la aplicación
|
|
if (mEventHandler->type == SDL_QUIT)
|
|
{
|
|
mSection.name = PROG_SECTION_QUIT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Calcula la lógica de los objetos
|
|
if (SDL_GetTicks() - mTicks > mTicksSpeed)
|
|
{
|
|
// Actualiza el contador de ticks
|
|
mTicks = SDL_GetTicks();
|
|
|
|
// Actualiza la lógica del menu
|
|
mMenuPause->update();
|
|
mFade->update();
|
|
if (mFade->hasEnded())
|
|
{
|
|
mSection.name = PROG_SECTION_TITLE;
|
|
mSection.subsection = TITLE_SECTION_1;
|
|
JA_StopMusic();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Prepara para empezar a dibujar en la textura de juego
|
|
mScreen->start();
|
|
|
|
// Limpia la pantalla
|
|
mScreen->clean(bgColor);
|
|
|
|
// Pinta el escenario
|
|
renderPlayField();
|
|
mMenuPause->render();
|
|
mFade->render();
|
|
|
|
// Vuelca el contenido del renderizador en pantalla
|
|
mScreen->blit();
|
|
|
|
// Comprueba las entradas para el menu
|
|
mMenuPause->checkInput();
|
|
|
|
// Comprueba si se ha seleccionado algún item del menú
|
|
switch (mMenuPause->getItemSelected())
|
|
{
|
|
case 0:
|
|
mSection.name = PROG_SECTION_GAME;
|
|
if (mNumPlayers == 1)
|
|
mSection.subsection = GAME_SECTION_PLAY_1P;
|
|
else
|
|
mSection.subsection = GAME_SECTION_PLAY_2P;
|
|
if (JA_GetMusicState() == JA_MUSIC_PAUSED)
|
|
JA_ResumeMusic();
|
|
break;
|
|
|
|
case 1:
|
|
mFade->setFadeType(FADE_CENTER);
|
|
mFade->activateFade();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Bucle para la pantalla de game over
|
|
void Game::runGameOverScreen()
|
|
{
|
|
// Guarda los puntos
|
|
saveScoreFile();
|
|
|
|
// Reinicia el menu
|
|
mMenuGameOver->reset();
|
|
|
|
while ((mSection.subsection == GAME_SECTION_GAMEOVER) && (mSection.name == PROG_SECTION_GAME))
|
|
{
|
|
// Comprueba los eventos que hay en la cola
|
|
while (SDL_PollEvent(mEventHandler) != 0)
|
|
{
|
|
// Evento de salida de la aplicación
|
|
if (mEventHandler->type == SDL_QUIT)
|
|
{
|
|
mSection.name = PROG_SECTION_QUIT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Calcula la lógica de los objetos
|
|
if (SDL_GetTicks() - mTicks > mTicksSpeed)
|
|
{
|
|
// Actualiza el contador de ticks
|
|
mTicks = SDL_GetTicks();
|
|
|
|
// Actualiza la lógica del menu
|
|
mMenuGameOver->update();
|
|
mFade->update();
|
|
if (mFade->hasEnded())
|
|
{
|
|
switch (mPostFade)
|
|
{
|
|
case 0: // YES
|
|
mSection.name = PROG_SECTION_GAME;
|
|
if (mNumPlayers == 1)
|
|
mSection.subsection = GAME_SECTION_PLAY_1P;
|
|
else
|
|
mSection.subsection = GAME_SECTION_PLAY_2P;
|
|
init();
|
|
break;
|
|
|
|
case 1: // NO
|
|
mSection.name = PROG_SECTION_TITLE;
|
|
mSection.subsection = TITLE_SECTION_1;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Prepara para empezar a dibujar en la textura de juego
|
|
mScreen->start();
|
|
|
|
// Limpia la pantalla
|
|
mScreen->clean(bgColor);
|
|
|
|
// Dibuja los objetos
|
|
if (mNumPlayers == 1)
|
|
{
|
|
mTextBig->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 4), mLang->getText(43));
|
|
mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - (BLOCK * 1), mLang->getText(44) + std::to_string(mPlayer[0]->getScore()));
|
|
}
|
|
else
|
|
{
|
|
mTextBig->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - 36, mLang->getText(43));
|
|
mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y - 12, mLang->getText(77) + std::to_string(mPlayer[0]->getScore()));
|
|
mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y, mLang->getText(78) + std::to_string(mPlayer[1]->getScore()));
|
|
}
|
|
mText->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_CENTER_Y + BLOCK * 2, mLang->getText(45));
|
|
mMenuGameOver->render();
|
|
mFade->render();
|
|
|
|
// Vuelca el contenido del renderizador en pantalla
|
|
mScreen->blit();
|
|
|
|
// Comprueba las entradas para el menu
|
|
mMenuGameOver->checkInput();
|
|
|
|
// Comprueba si se ha seleccionado algún item del menú
|
|
switch (mMenuGameOver->getItemSelected())
|
|
{
|
|
case 0: // YES
|
|
mPostFade = 0;
|
|
mFade->activateFade();
|
|
break;
|
|
|
|
case 1: // NO
|
|
mPostFade = 1;
|
|
mFade->activateFade();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dibuja la informacion de debug en pantalla
|
|
void Game::renderDebugInfo()
|
|
{
|
|
const color_t color = {0xFF, 0x20, 0x20};
|
|
|
|
if (mDebug.enabled)
|
|
{
|
|
mText->writeShadowed(2, 2 + 0 * BLOCK, "menace(umb): " + std::to_string(mMenaceCurrent) + "(" + std::to_string(mMenaceThreshold) + ")", color);
|
|
mText->writeShadowed(2, 2 + 1 * BLOCK, "currentPower: " + std::to_string(mStage[mCurrentStage].currentPower), color);
|
|
mText->writeShadowed(2, 2 + 2 * BLOCK, "mCurrentStage:" + std::to_string(mCurrentStage), color);
|
|
mText->writeShadowed(2, 2 + 3 * BLOCK, "mCounter: " + std::to_string(mCounter), color);
|
|
mText->writeShadowed(2, 2 + 4 * BLOCK, "(R)enemyset: " + std::to_string(mDebug.enemySet), color);
|
|
mText->writeShadowed(2, 2 + 5 * BLOCK, "RGB: " + std::to_string(mDebug.gradR) + "," + std::to_string(mDebug.gradG) + "," + std::to_string(mDebug.gradB), color);
|
|
mText->writeShadowed(2, 2 + 6 * BLOCK, "(I)invuln: " + std::to_string(mPlayer[0]->getInvulnerableCounter()), color);
|
|
mText->writeShadowed(2, 2 + 7 * BLOCK, "balloons: " + std::to_string(countBalloons()), color);
|
|
mText->writeShadowed(2, 2 + 8 * BLOCK, "balloonsPop: " + std::to_string(mBalloonsPopped), color);
|
|
mText->writeShadowed(2, 2 + 9 * BLOCK, "(Z-X)ballSped:" + std::to_string(mEnemySpeed), color);
|
|
mText->writeShadowed(2, 2 + 10 * BLOCK, "EGcounter: " + std::to_string(mGameCompletedCounter), color);
|
|
}
|
|
}
|
|
|
|
// Indica si se puede crear una powerball
|
|
bool Game::canPowerBallBeCreated()
|
|
{
|
|
if ((!mPowerBallEnabled) && (calculateScreenPower() > POWERBALL_SCREENPOWER_MINIMUM) && (mPowerBallCounter == 0))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// Calcula el poder actual de los globos en pantalla
|
|
int Game::calculateScreenPower()
|
|
{
|
|
int power = 0;
|
|
|
|
for (int i = 0; i < MAX_BALLOONS; i++)
|
|
if (mBalloon[i]->isEnabled())
|
|
power += mBalloon[i]->getPower();
|
|
|
|
return power;
|
|
}
|
|
|
|
// Inicializa las variables que contienen puntos de ruta para mover objetos
|
|
void Game::initPaths()
|
|
{
|
|
// Letrero de STAGE #
|
|
const int firstPart = STAGE_COUNTER / 4; // 50
|
|
const int secondPart = firstPart * 3; // 150
|
|
const int centerPoint = PLAY_AREA_CENTER_Y - (BLOCK * 2);
|
|
const int distance = (PLAY_AREA_BOTTOM) - (PLAY_AREA_CENTER_Y - 16);
|
|
|
|
for (int i = 0; i < STAGE_COUNTER; i++)
|
|
{
|
|
if (i < firstPart)
|
|
mStageBitmapPath[i] = (mSin[(int)((i * 1.8f) + 90)] * (distance) + centerPoint);
|
|
else if (i < secondPart)
|
|
mStageBitmapPath[i] = (int)centerPoint;
|
|
else
|
|
mStageBitmapPath[i] = (mSin[(int)(((i - 149) * 1.8f) + 90)] * (centerPoint + 17) - 17);
|
|
}
|
|
|
|
// Letrero de GetReady
|
|
const int size = mTextNokiaBig2->lenght(mLang->getText(75), -2);
|
|
|
|
const float start1 = PLAY_AREA_LEFT - size;
|
|
const float finish1 = PLAY_AREA_CENTER_X - (size / 2);
|
|
|
|
const float start2 = finish1;
|
|
const float finish2 = PLAY_AREA_RIGHT;
|
|
|
|
const float distance1 = finish1 - start1;
|
|
const float distance2 = finish2 - start2;
|
|
|
|
for (int i = 0; i < STAGE_COUNTER; i++)
|
|
{
|
|
if (i < firstPart)
|
|
{
|
|
mGetReadyBitmapPath[i] = mSin[(int)(i * 1.8f)];
|
|
mGetReadyBitmapPath[i] *= distance1;
|
|
mGetReadyBitmapPath[i] -= size;
|
|
}
|
|
else if (i < secondPart)
|
|
mGetReadyBitmapPath[i] = (int)finish1;
|
|
else
|
|
{
|
|
mGetReadyBitmapPath[i] = mSin[(int)((i - 150) * 1.8f)];
|
|
mGetReadyBitmapPath[i] *= distance2;
|
|
mGetReadyBitmapPath[i] += finish1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza el tramo final de juego, una vez completado
|
|
void Game::updateGameCompleted()
|
|
{
|
|
if (mGameCompleted)
|
|
mGameCompletedCounter++;
|
|
|
|
if (mGameCompletedCounter == 500)
|
|
mSection.subsection = GAME_SECTION_GAMEOVER;
|
|
}
|
|
|
|
// Actualiza las variables de ayuda
|
|
void Game::updateHelper()
|
|
{
|
|
// Solo ofrece ayuda cuando la amenaza es elevada
|
|
if (mMenaceCurrent > 15)
|
|
{
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
{
|
|
if (mPlayer[i]->getCoffees() == 0)
|
|
mHelper.needCoffee = true;
|
|
else
|
|
mHelper.needCoffee = false;
|
|
|
|
if (!mPlayer[i]->isPowerUp())
|
|
mHelper.needCoffeeMachine = true;
|
|
else
|
|
mHelper.needCoffeeMachine = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mHelper.needCoffee = false;
|
|
mHelper.needCoffeeMachine = false;
|
|
}
|
|
}
|
|
|
|
// Comprueba si todos los jugadores han muerto
|
|
bool Game::allPlayersAreDead()
|
|
{
|
|
bool success = true;
|
|
for (int i = 0; i < mNumPlayers; i++)
|
|
success &= (!mPlayer[i]->isAlive());
|
|
|
|
return success;
|
|
} |