3416 lines
86 KiB
C++
3416 lines
86 KiB
C++
#include "game.h"
|
|
|
|
#define DEATH_COUNTER 350
|
|
|
|
// Constructor
|
|
Game::Game(int playerID, int currentStage, SDL_Renderer *renderer, Screen *screen, Asset *asset, Lang *lang, Input *input, bool demo, param_t *param, options_t *options, section_t *section, JA_Music_t *music)
|
|
{
|
|
// Copia los punteros
|
|
this->renderer = renderer;
|
|
this->screen = screen;
|
|
this->asset = asset;
|
|
this->lang = lang;
|
|
this->input = input;
|
|
this->param = param;
|
|
this->options = options;
|
|
this->section = section;
|
|
this->music = music;
|
|
|
|
// Pasa variables
|
|
this->demo.enabled = demo;
|
|
this->currentStage = currentStage;
|
|
lastStageReached = currentStage;
|
|
difficulty = options->game.difficulty;
|
|
|
|
// Crea los objetos
|
|
fade = new Fade(renderer, param);
|
|
eventHandler = new SDL_Event();
|
|
scoreboard = new Scoreboard(renderer, screen, asset, lang, options);
|
|
background = new Background(renderer, screen, asset, param);
|
|
|
|
// Carga los recursos
|
|
loadMedia();
|
|
|
|
// Inicializa los vectores con los datos para la demo
|
|
if (demo)
|
|
{
|
|
// Aleatoriza la asignación del fichero
|
|
const int index1 = rand() % 2;
|
|
const int index2 = (index1 + 1) % 2;
|
|
loadDemoFile(asset->get("demo1.bin"), &this->demo.dataFile[index1]);
|
|
loadDemoFile(asset->get("demo2.bin"), &this->demo.dataFile[index2]);
|
|
}
|
|
|
|
// Establece la máxima puntuación desde fichero o desde las puntuaciones online
|
|
setHiScore();
|
|
|
|
n1000Sprite = new SmartSprite(gameTextTexture, renderer);
|
|
n2500Sprite = new SmartSprite(gameTextTexture, renderer);
|
|
n5000Sprite = new SmartSprite(gameTextTexture, renderer);
|
|
|
|
gameOverSprite = new Sprite(16, 80, 128, 96, gameOverTexture, renderer);
|
|
gameOverEndSprite = new Sprite(PLAY_AREA_CENTER_X - gameOverEndTexture->getWidth() / 2, 80, 128, 96, gameOverEndTexture, renderer);
|
|
|
|
canvas = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, playArea.w, playArea.h);
|
|
SDL_SetTextureBlendMode(canvas, SDL_BLENDMODE_BLEND);
|
|
|
|
// Inicializa las variables necesarias para la sección 'Game'
|
|
init(playerID);
|
|
}
|
|
|
|
Game::~Game()
|
|
{
|
|
saveScoreFile();
|
|
#ifdef RECORDING
|
|
saveDemoFile();
|
|
#endif
|
|
|
|
// Elimina todos los objetos contenidos en vectores
|
|
deleteAllVectorObjects();
|
|
|
|
bulletTexture->unload();
|
|
delete bulletTexture;
|
|
|
|
gameTextTexture->unload();
|
|
delete gameTextTexture;
|
|
|
|
gameOverTexture->unload();
|
|
delete gameOverTexture;
|
|
|
|
gameOverEndTexture->unload();
|
|
delete gameOverEndTexture;
|
|
|
|
// Animaciones
|
|
for (auto animation : playerAnimations)
|
|
{
|
|
delete animation;
|
|
}
|
|
playerAnimations.clear();
|
|
|
|
for (auto animation : balloonAnimations)
|
|
{
|
|
delete animation;
|
|
}
|
|
balloonAnimations.clear();
|
|
|
|
for (auto animation : itemAnimations)
|
|
{
|
|
delete animation;
|
|
}
|
|
itemAnimations.clear();
|
|
|
|
// Texturas
|
|
for (auto texture : player1Textures)
|
|
{
|
|
texture->unload();
|
|
delete texture;
|
|
}
|
|
player1Textures.clear();
|
|
|
|
for (auto texture : player2Textures)
|
|
{
|
|
texture->unload();
|
|
delete texture;
|
|
}
|
|
player2Textures.clear();
|
|
|
|
for (auto texture : itemTextures)
|
|
{
|
|
texture->unload();
|
|
delete texture;
|
|
}
|
|
itemTextures.clear();
|
|
|
|
for (auto texture : balloonTextures)
|
|
{
|
|
texture->unload();
|
|
delete texture;
|
|
}
|
|
balloonTextures.clear();
|
|
|
|
delete scoreboard;
|
|
delete background;
|
|
|
|
delete text;
|
|
delete textBig;
|
|
delete textNokia2;
|
|
delete textNokiaBig2;
|
|
delete fade;
|
|
delete eventHandler;
|
|
delete n1000Sprite;
|
|
delete n2500Sprite;
|
|
delete n5000Sprite;
|
|
delete gameOverSprite;
|
|
delete gameOverEndSprite;
|
|
|
|
SDL_DestroyTexture(canvas);
|
|
|
|
JA_DeleteSound(balloonSound);
|
|
JA_DeleteSound(bulletSound);
|
|
JA_DeleteSound(playerCollisionSound);
|
|
JA_DeleteSound(hiScoreSound);
|
|
JA_DeleteSound(itemDropSound);
|
|
JA_DeleteSound(itemPickUpSound);
|
|
JA_DeleteSound(coffeeOutSound);
|
|
JA_DeleteSound(stageChangeSound);
|
|
JA_DeleteSound(bubble1Sound);
|
|
JA_DeleteSound(bubble2Sound);
|
|
JA_DeleteSound(bubble3Sound);
|
|
JA_DeleteSound(bubble4Sound);
|
|
JA_DeleteSound(clockSound);
|
|
JA_DeleteSound(powerBallSound);
|
|
JA_DeleteSound(coffeeMachineSound);
|
|
}
|
|
|
|
// Inicializa las variables necesarias para la sección 'Game'
|
|
void Game::init(int playerID)
|
|
{
|
|
ticks = 0;
|
|
ticksSpeed = 15;
|
|
|
|
// Elimina qualquier jugador que hubiese antes de crear los nuevos
|
|
for (auto player : players)
|
|
{
|
|
if (player)
|
|
{
|
|
delete player;
|
|
}
|
|
};
|
|
players.clear();
|
|
|
|
// Crea los dos jugadores
|
|
Player *player1 = new Player((PLAY_AREA_CENTER_FIRST_QUARTER_X * ((0 * 2) + 1)) - 11, PLAY_AREA_BOTTOM - 30, renderer, playerTextures[0], playerAnimations);
|
|
players.push_back(player1);
|
|
|
|
Player *player2 = new Player((PLAY_AREA_CENTER_FIRST_QUARTER_X * ((1 * 2) + 1)) - 11, PLAY_AREA_BOTTOM - 30, renderer, playerTextures[1], playerAnimations);
|
|
players.push_back(player2);
|
|
|
|
// Habilita el jugador seleccionado. playerID es player 1 o player 2
|
|
players[playerID - 1]->enable(true);
|
|
|
|
// Variables relacionadas con la dificultad
|
|
switch (difficulty)
|
|
{
|
|
case DIFFICULTY_EASY:
|
|
defaultEnemySpeed = BALLOON_SPEED_1;
|
|
difficultyScoreMultiplier = 0.5f;
|
|
difficultyColor = difficultyEasyColor;
|
|
scoreboard->setColor(difficultyColor);
|
|
break;
|
|
|
|
case DIFFICULTY_NORMAL:
|
|
defaultEnemySpeed = BALLOON_SPEED_1;
|
|
difficultyScoreMultiplier = 1.0f;
|
|
difficultyColor = difficultyNormalColor;
|
|
scoreboard->setColor(scoreboardColor);
|
|
break;
|
|
|
|
case DIFFICULTY_HARD:
|
|
defaultEnemySpeed = BALLOON_SPEED_5;
|
|
difficultyScoreMultiplier = 1.5f;
|
|
difficultyColor = difficultyHardColor;
|
|
scoreboard->setColor(difficultyColor);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Variables para el marcador
|
|
scoreboard->setPos({param->scoreboard.x, param->scoreboard.y, param->scoreboard.w, param->scoreboard.h});
|
|
|
|
// Resto de variables
|
|
paused = false;
|
|
gameCompleted = false;
|
|
gameCompletedCounter = 0;
|
|
section->name = SECTION_PROG_GAME;
|
|
section->subsection = SUBSECTION_GAME_PLAY_1P;
|
|
menaceCurrent = 0;
|
|
menaceThreshold = 0;
|
|
hiScoreAchieved = false;
|
|
stageBitmapCounter = STAGE_COUNTER;
|
|
deathCounter = DEATH_COUNTER;
|
|
timeStopped = false;
|
|
timeStoppedCounter = 0;
|
|
counter = 0;
|
|
lastEnemyDeploy = 0;
|
|
enemyDeployCounter = 0;
|
|
enemySpeed = defaultEnemySpeed;
|
|
helper.needCoffee = false;
|
|
helper.needCoffeeMachine = false;
|
|
helper.needPowerBall = false;
|
|
helper.counter = HELP_COUNTER;
|
|
helper.itemPoints1Odds = ITEM_POINTS_1_DISK_ODDS;
|
|
helper.itemPoints2Odds = ITEM_POINTS_2_GAVINA_ODDS;
|
|
helper.itemPoints3Odds = ITEM_POINTS_3_PACMAR_ODDS;
|
|
helper.itemClockOdds = ITEM_CLOCK_ODDS;
|
|
helper.itemCoffeeOdds = ITEM_COFFEE_ODDS;
|
|
helper.itemCoffeeMachineOdds = ITEM_COFFEE_MACHINE_ODDS;
|
|
powerBallEnabled = false;
|
|
powerBallCounter = 0;
|
|
coffeeMachineEnabled = false;
|
|
|
|
// Inicializa las variables para el modo demo
|
|
if (demo.enabled)
|
|
{
|
|
// Selecciona una pantalla al azar
|
|
const int num = rand() % 2;
|
|
if (num == 0)
|
|
{
|
|
balloonsPopped = 1000;
|
|
currentStage = 3;
|
|
}
|
|
else
|
|
{
|
|
balloonsPopped = 1800;
|
|
currentStage = 6;
|
|
}
|
|
|
|
// Activa o no al otro jugador
|
|
if (rand() % 3 == 0)
|
|
{
|
|
const int otherPlayer = playerID == 1 ? 2 : 1;
|
|
players[otherPlayer - 1]->enable(true);
|
|
}
|
|
|
|
// Añade 0, 1 o 2 cafes al jugador
|
|
for (int i = 0; i < rand() % 3; ++i)
|
|
{
|
|
players[0]->giveExtraHit();
|
|
}
|
|
|
|
// Deshabilita los sonidos
|
|
JA_EnableSound(false);
|
|
}
|
|
|
|
initPaths();
|
|
initEnemyFormations();
|
|
initEnemyPools();
|
|
initGameStages();
|
|
|
|
// Mas variables
|
|
balloonsPopped = 0;
|
|
for (int i = 0; i < currentStage; ++i)
|
|
{
|
|
balloonsPopped += stage[i].powerToComplete;
|
|
}
|
|
|
|
totalPowerToCompleteGame = 0;
|
|
for (int i = 0; i < 10; ++i)
|
|
{
|
|
totalPowerToCompleteGame += stage[i].powerToComplete;
|
|
}
|
|
|
|
// Modo grabar demo
|
|
#ifdef RECORDING
|
|
demo.recording = true;
|
|
#else
|
|
demo.recording = false;
|
|
#endif
|
|
demo.counter = 0;
|
|
|
|
// Inicializa el objeto para el fundido
|
|
fade->setColor(fadeColor.r, fadeColor.g, fadeColor.b);
|
|
fade->setPost(param->fadePostDuration);
|
|
fade->setType(FADE_VENETIAN);
|
|
|
|
// Con los globos creados, calcula el nivel de amenaza
|
|
evaluateAndSetMenace();
|
|
|
|
// Inicializa el bitmap de 1000 puntos
|
|
const int height = 15;
|
|
const int sprite1Width = 35;
|
|
const int sprite2Width = 38;
|
|
const int sprite3Width = 39;
|
|
n1000Sprite->setPosX(0);
|
|
n1000Sprite->setPosY(0);
|
|
n1000Sprite->setWidth(sprite1Width);
|
|
n1000Sprite->setHeight(height);
|
|
n1000Sprite->setVelX(0.0f);
|
|
n1000Sprite->setVelY(-0.5f);
|
|
n1000Sprite->setAccelX(0.0f);
|
|
n1000Sprite->setAccelY(-0.1f);
|
|
n1000Sprite->setSpriteClip(0, 0, sprite1Width, height);
|
|
n1000Sprite->setEnabled(false);
|
|
n1000Sprite->setEnabledCounter(0);
|
|
n1000Sprite->setDestX(0);
|
|
n1000Sprite->setDestY(0);
|
|
|
|
// Inicializa el bitmap de 2500 puntos
|
|
n2500Sprite->setPosX(0);
|
|
n2500Sprite->setPosY(0);
|
|
n2500Sprite->setWidth(sprite2Width);
|
|
n2500Sprite->setHeight(height);
|
|
n2500Sprite->setVelX(0.0f);
|
|
n2500Sprite->setVelY(-0.5f);
|
|
n2500Sprite->setAccelX(0.0f);
|
|
n2500Sprite->setAccelY(-0.1f);
|
|
n2500Sprite->setSpriteClip(sprite1Width, 0, sprite2Width, height);
|
|
n2500Sprite->setEnabled(false);
|
|
n2500Sprite->setEnabledCounter(0);
|
|
n2500Sprite->setDestX(0);
|
|
n2500Sprite->setDestY(0);
|
|
|
|
// Inicializa el bitmap de 5000 puntos
|
|
n5000Sprite->setPosX(0);
|
|
n5000Sprite->setPosY(0);
|
|
n5000Sprite->setWidth(sprite3Width);
|
|
n5000Sprite->setHeight(height);
|
|
n5000Sprite->setVelX(0.0f);
|
|
n5000Sprite->setVelY(-0.5f);
|
|
n5000Sprite->setAccelX(0.0f);
|
|
n5000Sprite->setAccelY(-0.1f);
|
|
n5000Sprite->setSpriteClip(sprite1Width + sprite2Width, 0, sprite3Width, height);
|
|
n5000Sprite->setEnabled(false);
|
|
n5000Sprite->setEnabledCounter(0);
|
|
n5000Sprite->setDestX(0);
|
|
n5000Sprite->setDestY(0);
|
|
}
|
|
|
|
// Carga los recursos necesarios para la sección 'Game'
|
|
void Game::loadMedia()
|
|
{
|
|
if (options->console)
|
|
{
|
|
std::cout << std::endl
|
|
<< "** LOADING RESOURCES FOR GAME SECTION" << std::endl;
|
|
}
|
|
|
|
// Texturas
|
|
bulletTexture = new Texture(renderer, asset->get("bullet.png"));
|
|
gameTextTexture = new Texture(renderer, asset->get("game_text.png"));
|
|
gameOverTexture = new Texture(renderer, asset->get("menu_game_over.png"));
|
|
gameOverEndTexture = new Texture(renderer, asset->get("menu_game_over_end.png"));
|
|
|
|
// Texturas - Globos
|
|
Texture *balloon1Texture = new Texture(renderer, asset->get("balloon1.png"));
|
|
balloonTextures.push_back(balloon1Texture);
|
|
|
|
Texture *balloon2Texture = new Texture(renderer, asset->get("balloon2.png"));
|
|
balloonTextures.push_back(balloon2Texture);
|
|
|
|
Texture *balloon3Texture = new Texture(renderer, asset->get("balloon3.png"));
|
|
balloonTextures.push_back(balloon3Texture);
|
|
|
|
Texture *balloon4Texture = new Texture(renderer, asset->get("balloon4.png"));
|
|
balloonTextures.push_back(balloon4Texture);
|
|
|
|
// Texturas - Items
|
|
Texture *item1 = new Texture(renderer, asset->get("item_points1_disk.png"));
|
|
itemTextures.push_back(item1);
|
|
|
|
Texture *item2 = new Texture(renderer, asset->get("item_points2_gavina.png"));
|
|
itemTextures.push_back(item2);
|
|
|
|
Texture *item3 = new Texture(renderer, asset->get("item_points3_pacmar.png"));
|
|
itemTextures.push_back(item3);
|
|
|
|
Texture *item4 = new Texture(renderer, asset->get("item_clock.png"));
|
|
itemTextures.push_back(item4);
|
|
|
|
Texture *item5 = new Texture(renderer, asset->get("item_coffee.png"));
|
|
itemTextures.push_back(item5);
|
|
|
|
Texture *item6 = new Texture(renderer, asset->get("item_coffee_machine.png"));
|
|
itemTextures.push_back(item6);
|
|
|
|
// Texturas - Player1
|
|
Texture *player1Head = new Texture(renderer, asset->get("player_bal1_head.png"));
|
|
player1Textures.push_back(player1Head);
|
|
|
|
Texture *player1Body = new Texture(renderer, asset->get("player_bal1_body.png"));
|
|
player1Textures.push_back(player1Body);
|
|
|
|
Texture *player1Legs = new Texture(renderer, asset->get("player_bal1_legs.png"));
|
|
player1Textures.push_back(player1Legs);
|
|
|
|
Texture *player1Death = new Texture(renderer, asset->get("player_bal1_death.png"));
|
|
player1Textures.push_back(player1Death);
|
|
|
|
Texture *player1Fire = new Texture(renderer, asset->get("player_bal1_fire.png"));
|
|
player1Textures.push_back(player1Fire);
|
|
|
|
playerTextures.push_back(player1Textures);
|
|
|
|
// Texturas - Player2
|
|
Texture *player2Head = new Texture(renderer, asset->get("player_arounder_head.png"));
|
|
player2Textures.push_back(player2Head);
|
|
|
|
Texture *player2Body = new Texture(renderer, asset->get("player_arounder_body.png"));
|
|
player2Textures.push_back(player2Body);
|
|
|
|
Texture *player2Legs = new Texture(renderer, asset->get("player_arounder_legs.png"));
|
|
player2Textures.push_back(player2Legs);
|
|
|
|
Texture *player2Death = new Texture(renderer, asset->get("player_arounder_death.png"));
|
|
player2Textures.push_back(player2Death);
|
|
|
|
Texture *player2Fire = new Texture(renderer, asset->get("player_arounder_fire.png"));
|
|
player2Textures.push_back(player2Fire);
|
|
|
|
playerTextures.push_back(player2Textures);
|
|
|
|
// Animaciones -- Jugador
|
|
std::vector<std::string> *playerHeadAnimation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("player_head.ani"), playerHeadAnimation);
|
|
playerAnimations.push_back(playerHeadAnimation);
|
|
|
|
std::vector<std::string> *playerBodyAnimation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("player_body.ani"), playerBodyAnimation);
|
|
playerAnimations.push_back(playerBodyAnimation);
|
|
|
|
std::vector<std::string> *playerLegsAnimation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("player_legs.ani"), playerLegsAnimation);
|
|
playerAnimations.push_back(playerLegsAnimation);
|
|
|
|
std::vector<std::string> *playerDeathAnimation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("player_death.ani"), playerDeathAnimation);
|
|
playerAnimations.push_back(playerDeathAnimation);
|
|
|
|
std::vector<std::string> *playerFireAnimation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("player_fire.ani"), playerFireAnimation);
|
|
playerAnimations.push_back(playerFireAnimation);
|
|
|
|
// Animaciones -- Globos
|
|
std::vector<std::string> *balloon1Animation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("balloon1.ani"), balloon1Animation);
|
|
balloonAnimations.push_back(balloon1Animation);
|
|
|
|
std::vector<std::string> *balloon2Animation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("balloon2.ani"), balloon2Animation);
|
|
balloonAnimations.push_back(balloon2Animation);
|
|
|
|
std::vector<std::string> *balloon3Animation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("balloon3.ani"), balloon3Animation);
|
|
balloonAnimations.push_back(balloon3Animation);
|
|
|
|
std::vector<std::string> *balloon4Animation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("balloon4.ani"), balloon4Animation);
|
|
balloonAnimations.push_back(balloon4Animation);
|
|
|
|
// Animaciones -- Items
|
|
std::vector<std::string> *item1Animation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("item_points1_disk.ani"), item1Animation);
|
|
itemAnimations.push_back(item1Animation);
|
|
|
|
std::vector<std::string> *item2Animation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("item_points2_gavina.ani"), item2Animation);
|
|
itemAnimations.push_back(item2Animation);
|
|
|
|
std::vector<std::string> *item3Animation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("item_points3_pacmar.ani"), item3Animation);
|
|
itemAnimations.push_back(item3Animation);
|
|
|
|
std::vector<std::string> *item4Animation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("item_clock.ani"), item4Animation);
|
|
itemAnimations.push_back(item4Animation);
|
|
|
|
std::vector<std::string> *item5Animation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("item_coffee.ani"), item5Animation);
|
|
itemAnimations.push_back(item5Animation);
|
|
|
|
std::vector<std::string> *item6Animation = new std::vector<std::string>;
|
|
loadAnimations(asset->get("item_coffee_machine.ani"), item6Animation);
|
|
itemAnimations.push_back(item6Animation);
|
|
|
|
// Texto
|
|
text = new Text(asset->get("smb2.png"), asset->get("smb2.txt"), renderer);
|
|
textBig = new Text(asset->get("smb2_big.png"), asset->get("smb2_big.txt"), renderer);
|
|
textNokia2 = new Text(asset->get("nokia2.png"), asset->get("nokia2.txt"), renderer);
|
|
textNokiaBig2 = new Text(asset->get("nokia_big2.png"), asset->get("nokia_big2.txt"), renderer);
|
|
|
|
// Sonidos
|
|
balloonSound = JA_LoadSound(asset->get("balloon.wav").c_str());
|
|
bubble1Sound = JA_LoadSound(asset->get("bubble1.wav").c_str());
|
|
bubble2Sound = JA_LoadSound(asset->get("bubble2.wav").c_str());
|
|
bubble3Sound = JA_LoadSound(asset->get("bubble3.wav").c_str());
|
|
bubble4Sound = JA_LoadSound(asset->get("bubble4.wav").c_str());
|
|
bulletSound = JA_LoadSound(asset->get("bullet.wav").c_str());
|
|
clockSound = JA_LoadSound(asset->get("clock.wav").c_str());
|
|
coffeeOutSound = JA_LoadSound(asset->get("coffeeout.wav").c_str());
|
|
hiScoreSound = JA_LoadSound(asset->get("hiscore.wav").c_str());
|
|
itemDropSound = JA_LoadSound(asset->get("itemdrop.wav").c_str());
|
|
itemPickUpSound = JA_LoadSound(asset->get("itempickup.wav").c_str());
|
|
playerCollisionSound = JA_LoadSound(asset->get("player_collision.wav").c_str());
|
|
powerBallSound = JA_LoadSound(asset->get("powerball.wav").c_str());
|
|
stageChangeSound = JA_LoadSound(asset->get("stage_change.wav").c_str());
|
|
coffeeMachineSound = JA_LoadSound(asset->get("title.wav").c_str());
|
|
|
|
if (options->console)
|
|
{
|
|
std::cout << "** RESOURCES FOR GAME SECTION LOADED" << std::endl
|
|
<< std::endl;
|
|
}
|
|
}
|
|
|
|
// Carga el fichero de puntos
|
|
bool Game::loadScoreFile()
|
|
{
|
|
// Indicador de éxito en la carga
|
|
bool success = true;
|
|
const std::string p = asset->get("score.bin");
|
|
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 == nullptr)
|
|
{
|
|
if (options->console)
|
|
{
|
|
std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl;
|
|
}
|
|
|
|
// Creamos el fichero para escritura
|
|
file = SDL_RWFromFile(p.c_str(), "w+b");
|
|
if (file != nullptr)
|
|
{
|
|
if (options->console)
|
|
{
|
|
std::cout << "New file (" << filename.c_str() << ") created!" << std::endl;
|
|
}
|
|
|
|
// Inicializamos los datos
|
|
for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
|
|
{
|
|
scoreDataFile[i] = 0;
|
|
SDL_RWwrite(file, &scoreDataFile[i], sizeof(Uint32), 1);
|
|
}
|
|
|
|
// Cerramos el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
else
|
|
{
|
|
if (options->console)
|
|
{
|
|
std::cout << "Error: Unable to create file " << filename.c_str() << std::endl;
|
|
}
|
|
success = false;
|
|
}
|
|
}
|
|
// El fichero existe
|
|
else
|
|
{
|
|
// Cargamos los datos
|
|
if (options->console)
|
|
{
|
|
std::cout << "Reading file " << filename.c_str() << std::endl;
|
|
}
|
|
for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
|
|
SDL_RWread(file, &scoreDataFile[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 (scoreDataFile[0] == 0)
|
|
{
|
|
hiScore = 10000;
|
|
}
|
|
// Comprueba el checksum para ver si se ha modificado el fichero
|
|
else if (scoreDataFile[0] % 43 == scoreDataFile[1])
|
|
{
|
|
hiScore = scoreDataFile[0];
|
|
}
|
|
else
|
|
{
|
|
hiScore = 10000;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Carga el fichero de datos para la demo
|
|
bool Game::loadDemoFile(std::string f, demoKeys_t (*dataFile)[TOTAL_DEMO_DATA])
|
|
{
|
|
// Indicador de éxito en la carga
|
|
bool success = true;
|
|
const std::string filename = f.substr(f.find_last_of("\\/") + 1);
|
|
SDL_RWops *file = SDL_RWFromFile(f.c_str(), "r+b");
|
|
|
|
// El fichero no existe
|
|
if (file == nullptr)
|
|
{
|
|
if (options->console)
|
|
{
|
|
std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl;
|
|
}
|
|
|
|
// Creamos el fichero para escritura
|
|
file = SDL_RWFromFile(f.c_str(), "w+b");
|
|
|
|
// Si no existe el fichero
|
|
if (file != nullptr)
|
|
{
|
|
if (options->console)
|
|
{
|
|
std::cout << "New file (" << filename.c_str() << ") created!" << std::endl;
|
|
}
|
|
|
|
// Inicializas los datos y los guarda en el fichero
|
|
for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
|
|
{
|
|
demoKeys_t tmp;
|
|
tmp.left = 0;
|
|
tmp.right = 0;
|
|
tmp.noInput = 0;
|
|
tmp.fire = 0;
|
|
tmp.fireLeft = 0;
|
|
tmp.fireRight = 0;
|
|
(*dataFile)[i] = tmp;
|
|
SDL_RWwrite(file, &tmp, sizeof(demoKeys_t), 1);
|
|
}
|
|
|
|
// Cerramos el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
else
|
|
{ // Si no puede crear el fichero
|
|
if (options->console)
|
|
{
|
|
std::cout << "Error: Unable to create file " << filename.c_str() << std::endl;
|
|
}
|
|
success = false;
|
|
}
|
|
}
|
|
// El fichero existe
|
|
else
|
|
{
|
|
// Mensaje de proceder a la carga de los datos
|
|
if (options->console)
|
|
{
|
|
std::cout << "Reading file " << filename.c_str() << std::endl;
|
|
}
|
|
|
|
// Lee todos los datos del fichero y los deja en el destino
|
|
for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
|
|
{
|
|
demoKeys_t tmp;
|
|
SDL_RWread(file, &tmp, sizeof(demoKeys_t), 1);
|
|
(*dataFile)[i] = tmp;
|
|
}
|
|
|
|
// Cierra el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Guarda el fichero de puntos
|
|
bool Game::saveScoreFile()
|
|
{
|
|
bool success = true;
|
|
const std::string p = asset->get("score.bin");
|
|
const std::string filename = p.substr(p.find_last_of("\\/") + 1);
|
|
SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b");
|
|
if (file != nullptr)
|
|
{
|
|
// Guardamos los datos
|
|
for (int i = 0; i < TOTAL_SCORE_DATA; ++i)
|
|
{
|
|
SDL_RWwrite(file, &scoreDataFile[i], sizeof(Uint32), 1);
|
|
}
|
|
|
|
if (options->console)
|
|
{
|
|
std::cout << "Writing file " << filename.c_str() << std::endl;
|
|
}
|
|
|
|
// Cerramos el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
else
|
|
{
|
|
if (options->console)
|
|
{
|
|
std::cout << "Error: Unable to save " << filename.c_str() << " file! " << SDL_GetError() << std::endl;
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
#ifdef RECORDING
|
|
// Guarda el fichero de datos para la demo
|
|
bool Game::saveDemoFile()
|
|
{
|
|
bool success = true;
|
|
const std::string p = asset->get("demo1.bin");
|
|
const std::string filename = p.substr(p.find_last_of("\\/") + 1);
|
|
|
|
SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b");
|
|
if (file != nullptr)
|
|
{
|
|
// Guardamos los datos
|
|
for (int i = 0; i < TOTAL_DEMO_DATA; ++i)
|
|
{
|
|
SDL_RWwrite(file, &demo.dataFile[0][i], sizeof(demoKeys_t), 1);
|
|
}
|
|
|
|
if (options->console)
|
|
{
|
|
std::cout << "Writing file " << filename.c_str() << std::endl;
|
|
}
|
|
|
|
// Cerramos el fichero
|
|
SDL_RWclose(file);
|
|
}
|
|
else
|
|
{
|
|
if (options->console)
|
|
{
|
|
std::cout << "Error: Unable to save " << filename.c_str() << " file! " << SDL_GetError() << std::endl;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
#endif
|
|
|
|
// 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++)
|
|
{
|
|
enemyFormation[i].numberOfEnemies = 0;
|
|
for (int j = 0; j < MAX_NUMBER_OF_ENEMIES_IN_A_FORMATION; j++)
|
|
{
|
|
enemyFormation[i].init[j].x = 0;
|
|
enemyFormation[i].init[j].y = 0;
|
|
enemyFormation[i].init[j].velX = 0;
|
|
enemyFormation[i].init[j].kind = 0;
|
|
enemyFormation[i].init[j].creationCounter = 0;
|
|
}
|
|
}
|
|
|
|
const int creationTime = 300;
|
|
int incX = 0;
|
|
int incTime = 0;
|
|
int j = 0;
|
|
|
|
// #00 - Dos enemigos BALLOON4 uno a cada extremo
|
|
j = 0;
|
|
enemyFormation[j].numberOfEnemies = 2;
|
|
incX = x4_100;
|
|
incTime = 0;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x4_0 + (i * incX);
|
|
enemyFormation[j].init[i].y = y4;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
|
|
enemyFormation[j].init[i].kind = BALLOON_4;
|
|
enemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
|
|
}
|
|
|
|
// #01 - Dos enemigos BALLOON4 uno a cada cuarto. Ambos van hacia el centro
|
|
j = 1;
|
|
enemyFormation[j].numberOfEnemies = 2;
|
|
incX = PLAY_AREA_CENTER_X;
|
|
incTime = 0;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = PLAY_AREA_CENTER_FIRST_QUARTER_X - (BALLOON_WIDTH_4 / 2) + (i * incX);
|
|
enemyFormation[j].init[i].y = y4;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
|
|
enemyFormation[j].init[i].kind = BALLOON_4;
|
|
enemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
|
|
}
|
|
|
|
// #02 - Cuatro enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
|
|
j = 2;
|
|
enemyFormation[j].numberOfEnemies = 4;
|
|
incX = BALLOON_WIDTH_2 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x2_0 + (i * incX);
|
|
enemyFormation[j].init[i].y = y2;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_2;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #03 - Cuatro enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
|
|
j = 3;
|
|
enemyFormation[j].numberOfEnemies = 4;
|
|
incX = BALLOON_WIDTH_2 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x2_100 - (i * incX);
|
|
enemyFormation[j].init[i].y = y2;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_2;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #04 - Tres enemigos BALLOON3. 0, 25, 50. Hacia la derecha
|
|
j = 4;
|
|
enemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_3 * 2;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
enemyFormation[j].init[i].y = y3;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_3;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #05 - Tres enemigos BALLOON3. 50, 75, 100. Hacia la izquierda
|
|
j = 5;
|
|
enemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_3 * 2;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x3_100 - (i * incX);
|
|
enemyFormation[j].init[i].y = y3;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_3;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #06 - Tres enemigos BALLOON3. 0, 0, 0. Hacia la derecha
|
|
j = 6;
|
|
enemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_3 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
enemyFormation[j].init[i].y = y3;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_3;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #07 - Tres enemigos BALLOON3. 100, 100, 100. Hacia la izquierda
|
|
j = 7;
|
|
enemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_3 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x3_100 - (i * incX);
|
|
enemyFormation[j].init[i].y = y3;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_3;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #08 - Seis enemigos BALLOON1. 0, 0, 0, 0, 0, 0. Hacia la derecha
|
|
j = 8;
|
|
enemyFormation[j].numberOfEnemies = 6;
|
|
incX = BALLOON_WIDTH_1 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x1_0 + (i * incX);
|
|
enemyFormation[j].init[i].y = 13;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_1;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #09 - Seis enemigos BALLOON1. 100, 100, 100, 100, 100, 100. Hacia la izquierda
|
|
j = 9;
|
|
enemyFormation[j].numberOfEnemies = 6;
|
|
incX = BALLOON_WIDTH_1 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x1_100 - (i * incX);
|
|
enemyFormation[j].init[i].y = 13;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_1;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #10 - Tres enemigos BALLOON4 seguidos desde la izquierda
|
|
j = 10;
|
|
enemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_4 + 1;
|
|
incTime = 15;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x4_0 + (i * incX);
|
|
enemyFormation[j].init[i].y = y4;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_4;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #11 - Tres enemigos BALLOON4 seguidos desde la derecha
|
|
j = 11;
|
|
enemyFormation[j].numberOfEnemies = 3;
|
|
incX = BALLOON_WIDTH_4 + 1;
|
|
incTime = 15;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x4_100 - (i * incX);
|
|
enemyFormation[j].init[i].y = y4;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_4;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #12 - Seis enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
|
|
j = 12;
|
|
enemyFormation[j].numberOfEnemies = 6;
|
|
incX = BALLOON_WIDTH_2 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x2_0 + (i * incX);
|
|
enemyFormation[j].init[i].y = y2;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_2;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #13 - Seis enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
|
|
j = 13;
|
|
enemyFormation[j].numberOfEnemies = 6;
|
|
incX = BALLOON_WIDTH_2 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x2_100 - (i * incX);
|
|
enemyFormation[j].init[i].y = y2;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_2;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #14 - Cinco enemigos BALLOON3. Hacia la derecha. Separados
|
|
j = 14;
|
|
enemyFormation[j].numberOfEnemies = 5;
|
|
incX = BALLOON_WIDTH_3 * 2;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
enemyFormation[j].init[i].y = y3;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_3;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #15 - Cinco enemigos BALLOON3. Hacia la izquierda. Separados
|
|
j = 15;
|
|
enemyFormation[j].numberOfEnemies = 5;
|
|
incX = BALLOON_WIDTH_3 * 2;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x3_100 - (i * incX);
|
|
enemyFormation[j].init[i].y = y3;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_3;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #16 - Cinco enemigos BALLOON3. Hacia la derecha. Juntos
|
|
j = 16;
|
|
enemyFormation[j].numberOfEnemies = 5;
|
|
incX = BALLOON_WIDTH_3 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
enemyFormation[j].init[i].y = y3;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_3;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #17 - Cinco enemigos BALLOON3. Hacia la izquierda. Juntos
|
|
j = 17;
|
|
enemyFormation[j].numberOfEnemies = 5;
|
|
incX = BALLOON_WIDTH_3 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x3_100 - (i * incX);
|
|
enemyFormation[j].init[i].y = y3;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_3;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #18 - Doce enemigos BALLOON1. Hacia la derecha. Juntos
|
|
j = 18;
|
|
enemyFormation[j].numberOfEnemies = 12;
|
|
incX = BALLOON_WIDTH_1 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x1_0 + (i * incX);
|
|
enemyFormation[j].init[i].y = y1;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_1;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #19 - Doce enemigos BALLOON1. Hacia la izquierda. Juntos
|
|
j = 19;
|
|
enemyFormation[j].numberOfEnemies = 12;
|
|
incX = BALLOON_WIDTH_1 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[j].init[i].x = x1_100 - (i * incX);
|
|
enemyFormation[j].init[i].y = y1;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].kind = BALLOON_1;
|
|
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
|
|
}
|
|
|
|
// #20 - Dos enemigos BALLOON4 seguidos desde la izquierda/derecha. Simetricos
|
|
j = 20;
|
|
enemyFormation[j].numberOfEnemies = 4;
|
|
incX = BALLOON_WIDTH_4 + 1;
|
|
incTime = 0;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
const int half = enemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
enemyFormation[j].init[i].x = x4_0 + (i * incX);
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
}
|
|
else
|
|
{
|
|
enemyFormation[j].init[i].x = x4_100 - ((i - half) * incX);
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
}
|
|
enemyFormation[j].init[i].y = y4;
|
|
enemyFormation[j].init[i].kind = BALLOON_4;
|
|
enemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
|
|
}
|
|
|
|
// #21 - Diez enemigos BALLOON2 uno detras del otro. Izquierda/derecha. Simetricos
|
|
j = 21;
|
|
enemyFormation[j].numberOfEnemies = 10;
|
|
incX = BALLOON_WIDTH_2 + 1;
|
|
incTime = 3;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
const int half = enemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
enemyFormation[j].init[i].x = x2_0 + (i * incX);
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
|
|
}
|
|
else
|
|
{
|
|
enemyFormation[j].init[i].x = x2_100 - ((i - half) * incX);
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
|
|
}
|
|
enemyFormation[j].init[i].y = y2;
|
|
enemyFormation[j].init[i].kind = BALLOON_2;
|
|
}
|
|
|
|
// #22 - Diez enemigos BALLOON3. Hacia la derecha/izquierda. Separados. Simetricos
|
|
j = 22;
|
|
enemyFormation[j].numberOfEnemies = 10;
|
|
incX = BALLOON_WIDTH_3 * 2;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
const int half = enemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
enemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
|
|
}
|
|
else
|
|
{
|
|
enemyFormation[j].init[i].x = x3_100 - ((i - half) * incX);
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
|
|
}
|
|
enemyFormation[j].init[i].y = y3;
|
|
enemyFormation[j].init[i].kind = BALLOON_3;
|
|
}
|
|
|
|
// #23 - Diez enemigos BALLOON3. Hacia la derecha. Juntos. Simetricos
|
|
j = 23;
|
|
enemyFormation[j].numberOfEnemies = 10;
|
|
incX = BALLOON_WIDTH_3 + 1;
|
|
incTime = 10;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
const int half = enemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
enemyFormation[j].init[i].x = x3_0 + (i * incX);
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
|
|
}
|
|
else
|
|
{
|
|
enemyFormation[j].init[i].x = x3_100 - ((i - half) * incX);
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
|
|
}
|
|
enemyFormation[j].init[i].y = y3;
|
|
enemyFormation[j].init[i].kind = BALLOON_3;
|
|
}
|
|
|
|
// #24 - Treinta enemigos BALLOON1. Del centro hacia los extremos. Juntos. Simetricos
|
|
j = 24;
|
|
enemyFormation[j].numberOfEnemies = 30;
|
|
incX = 0;
|
|
incTime = 5;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
const int half = enemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
enemyFormation[j].init[i].x = x1_50;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].creationCounter = (creationTime) + (incTime * i);
|
|
}
|
|
else
|
|
{
|
|
enemyFormation[j].init[i].x = x1_50;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].creationCounter = (creationTime) + (incTime * (i - half));
|
|
}
|
|
enemyFormation[j].init[i].y = y1;
|
|
enemyFormation[j].init[i].kind = BALLOON_1;
|
|
}
|
|
|
|
// #25 - Treinta enemigos BALLOON1. Del centro hacia adentro. Juntos. Simetricos
|
|
j = 25;
|
|
enemyFormation[j].numberOfEnemies = 30;
|
|
incX = BALLOON_WIDTH_1 + 1;
|
|
incTime = 5;
|
|
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
|
|
{
|
|
const int half = enemyFormation[j].numberOfEnemies / 2;
|
|
if (i < half)
|
|
{
|
|
enemyFormation[j].init[i].x = x1_50 + 20;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
|
|
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
|
|
}
|
|
else
|
|
{
|
|
enemyFormation[j].init[i].x = x1_50 - 20;
|
|
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
|
|
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
|
|
}
|
|
enemyFormation[j].init[i].y = y1;
|
|
enemyFormation[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++)
|
|
{
|
|
enemyFormation[k + 50].numberOfEnemies = enemyFormation[k].numberOfEnemies;
|
|
for (int i = 0; i < enemyFormation[k + 50].numberOfEnemies; i++)
|
|
{
|
|
enemyFormation[k + 50].init[i].x = enemyFormation[k].init[i].x;
|
|
enemyFormation[k + 50].init[i].y = enemyFormation[k].init[i].y;
|
|
enemyFormation[k + 50].init[i].velX = enemyFormation[k].init[i].velX;
|
|
enemyFormation[k + 50].init[i].creationCounter = enemyFormation[k].init[i].creationCounter;
|
|
enemyFormation[k + 50].init[i].kind = enemyFormation[k].init[i].kind + 4;
|
|
}
|
|
}
|
|
|
|
// TEST
|
|
enemyFormation[99].numberOfEnemies = 4;
|
|
|
|
enemyFormation[99].init[0].x = 10;
|
|
enemyFormation[99].init[0].y = y1;
|
|
enemyFormation[99].init[0].velX = 0;
|
|
enemyFormation[99].init[0].kind = BALLOON_1;
|
|
enemyFormation[99].init[0].creationCounter = 200;
|
|
|
|
enemyFormation[99].init[1].x = 50;
|
|
enemyFormation[99].init[1].y = y1;
|
|
enemyFormation[99].init[1].velX = 0;
|
|
enemyFormation[99].init[1].kind = BALLOON_2;
|
|
enemyFormation[99].init[1].creationCounter = 200;
|
|
|
|
enemyFormation[99].init[2].x = 90;
|
|
enemyFormation[99].init[2].y = y1;
|
|
enemyFormation[99].init[2].velX = 0;
|
|
enemyFormation[99].init[2].kind = BALLOON_3;
|
|
enemyFormation[99].init[2].creationCounter = 200;
|
|
|
|
enemyFormation[99].init[3].x = 140;
|
|
enemyFormation[99].init[3].y = y1;
|
|
enemyFormation[99].init[3].velX = 0;
|
|
enemyFormation[99].init[3].kind = BALLOON_4;
|
|
enemyFormation[99].init[3].creationCounter = 200;
|
|
}
|
|
|
|
// Inicializa los conjuntos de formaciones
|
|
void Game::initEnemyPools()
|
|
{
|
|
// EnemyPool #0
|
|
enemyPool[0].set[0] = &enemyFormation[0];
|
|
enemyPool[0].set[1] = &enemyFormation[1];
|
|
enemyPool[0].set[2] = &enemyFormation[2];
|
|
enemyPool[0].set[3] = &enemyFormation[3];
|
|
enemyPool[0].set[4] = &enemyFormation[4];
|
|
enemyPool[0].set[5] = &enemyFormation[5];
|
|
enemyPool[0].set[6] = &enemyFormation[6];
|
|
enemyPool[0].set[7] = &enemyFormation[7];
|
|
enemyPool[0].set[8] = &enemyFormation[8];
|
|
enemyPool[0].set[9] = &enemyFormation[9];
|
|
|
|
// EnemyPool #1
|
|
enemyPool[1].set[0] = &enemyFormation[10];
|
|
enemyPool[1].set[1] = &enemyFormation[11];
|
|
enemyPool[1].set[2] = &enemyFormation[12];
|
|
enemyPool[1].set[3] = &enemyFormation[13];
|
|
enemyPool[1].set[4] = &enemyFormation[14];
|
|
enemyPool[1].set[5] = &enemyFormation[15];
|
|
enemyPool[1].set[6] = &enemyFormation[16];
|
|
enemyPool[1].set[7] = &enemyFormation[17];
|
|
enemyPool[1].set[8] = &enemyFormation[18];
|
|
enemyPool[1].set[9] = &enemyFormation[19];
|
|
|
|
// EnemyPool #2
|
|
enemyPool[2].set[0] = &enemyFormation[0];
|
|
enemyPool[2].set[1] = &enemyFormation[1];
|
|
enemyPool[2].set[2] = &enemyFormation[2];
|
|
enemyPool[2].set[3] = &enemyFormation[3];
|
|
enemyPool[2].set[4] = &enemyFormation[4];
|
|
enemyPool[2].set[5] = &enemyFormation[55];
|
|
enemyPool[2].set[6] = &enemyFormation[56];
|
|
enemyPool[2].set[7] = &enemyFormation[57];
|
|
enemyPool[2].set[8] = &enemyFormation[58];
|
|
enemyPool[2].set[9] = &enemyFormation[59];
|
|
|
|
// EnemyPool #3
|
|
enemyPool[3].set[0] = &enemyFormation[50];
|
|
enemyPool[3].set[1] = &enemyFormation[51];
|
|
enemyPool[3].set[2] = &enemyFormation[52];
|
|
enemyPool[3].set[3] = &enemyFormation[53];
|
|
enemyPool[3].set[4] = &enemyFormation[54];
|
|
enemyPool[3].set[5] = &enemyFormation[5];
|
|
enemyPool[3].set[6] = &enemyFormation[6];
|
|
enemyPool[3].set[7] = &enemyFormation[7];
|
|
enemyPool[3].set[8] = &enemyFormation[8];
|
|
enemyPool[3].set[9] = &enemyFormation[9];
|
|
|
|
// EnemyPool #4
|
|
enemyPool[4].set[0] = &enemyFormation[60];
|
|
enemyPool[4].set[1] = &enemyFormation[61];
|
|
enemyPool[4].set[2] = &enemyFormation[62];
|
|
enemyPool[4].set[3] = &enemyFormation[63];
|
|
enemyPool[4].set[4] = &enemyFormation[64];
|
|
enemyPool[4].set[5] = &enemyFormation[65];
|
|
enemyPool[4].set[6] = &enemyFormation[66];
|
|
enemyPool[4].set[7] = &enemyFormation[67];
|
|
enemyPool[4].set[8] = &enemyFormation[68];
|
|
enemyPool[4].set[9] = &enemyFormation[69];
|
|
|
|
// EnemyPool #5
|
|
enemyPool[5].set[0] = &enemyFormation[10];
|
|
enemyPool[5].set[1] = &enemyFormation[61];
|
|
enemyPool[5].set[2] = &enemyFormation[12];
|
|
enemyPool[5].set[3] = &enemyFormation[63];
|
|
enemyPool[5].set[4] = &enemyFormation[14];
|
|
enemyPool[5].set[5] = &enemyFormation[65];
|
|
enemyPool[5].set[6] = &enemyFormation[16];
|
|
enemyPool[5].set[7] = &enemyFormation[67];
|
|
enemyPool[5].set[8] = &enemyFormation[18];
|
|
enemyPool[5].set[9] = &enemyFormation[69];
|
|
|
|
// EnemyPool #6
|
|
enemyPool[6].set[0] = &enemyFormation[60];
|
|
enemyPool[6].set[1] = &enemyFormation[11];
|
|
enemyPool[6].set[2] = &enemyFormation[62];
|
|
enemyPool[6].set[3] = &enemyFormation[13];
|
|
enemyPool[6].set[4] = &enemyFormation[64];
|
|
enemyPool[6].set[5] = &enemyFormation[15];
|
|
enemyPool[6].set[6] = &enemyFormation[66];
|
|
enemyPool[6].set[7] = &enemyFormation[17];
|
|
enemyPool[6].set[8] = &enemyFormation[68];
|
|
enemyPool[6].set[9] = &enemyFormation[19];
|
|
|
|
// EnemyPool #7
|
|
enemyPool[7].set[0] = &enemyFormation[20];
|
|
enemyPool[7].set[1] = &enemyFormation[21];
|
|
enemyPool[7].set[2] = &enemyFormation[22];
|
|
enemyPool[7].set[3] = &enemyFormation[23];
|
|
enemyPool[7].set[4] = &enemyFormation[24];
|
|
enemyPool[7].set[5] = &enemyFormation[65];
|
|
enemyPool[7].set[6] = &enemyFormation[66];
|
|
enemyPool[7].set[7] = &enemyFormation[67];
|
|
enemyPool[7].set[8] = &enemyFormation[68];
|
|
enemyPool[7].set[9] = &enemyFormation[69];
|
|
|
|
// EnemyPool #8
|
|
enemyPool[8].set[0] = &enemyFormation[70];
|
|
enemyPool[8].set[1] = &enemyFormation[71];
|
|
enemyPool[8].set[2] = &enemyFormation[72];
|
|
enemyPool[8].set[3] = &enemyFormation[73];
|
|
enemyPool[8].set[4] = &enemyFormation[74];
|
|
enemyPool[8].set[5] = &enemyFormation[15];
|
|
enemyPool[8].set[6] = &enemyFormation[16];
|
|
enemyPool[8].set[7] = &enemyFormation[17];
|
|
enemyPool[8].set[8] = &enemyFormation[18];
|
|
enemyPool[8].set[9] = &enemyFormation[19];
|
|
|
|
// EnemyPool #9
|
|
enemyPool[9].set[0] = &enemyFormation[20];
|
|
enemyPool[9].set[1] = &enemyFormation[21];
|
|
enemyPool[9].set[2] = &enemyFormation[22];
|
|
enemyPool[9].set[3] = &enemyFormation[23];
|
|
enemyPool[9].set[4] = &enemyFormation[24];
|
|
enemyPool[9].set[5] = &enemyFormation[70];
|
|
enemyPool[9].set[6] = &enemyFormation[71];
|
|
enemyPool[9].set[7] = &enemyFormation[72];
|
|
enemyPool[9].set[8] = &enemyFormation[73];
|
|
enemyPool[9].set[9] = &enemyFormation[74];
|
|
}
|
|
|
|
// Inicializa las fases del juego
|
|
void Game::initGameStages()
|
|
{
|
|
// STAGE 1
|
|
stage[0].number = 1;
|
|
stage[0].currentPower = 0;
|
|
stage[0].powerToComplete = 200;
|
|
stage[0].minMenace = 7 + (4 * 1);
|
|
stage[0].maxMenace = 7 + (4 * 3);
|
|
stage[0].enemyPool = &enemyPool[0];
|
|
|
|
// STAGE 2
|
|
stage[1].number = 2;
|
|
stage[1].currentPower = 0;
|
|
stage[1].powerToComplete = 300;
|
|
stage[1].minMenace = 7 + (4 * 2);
|
|
stage[1].maxMenace = 7 + (4 * 4);
|
|
stage[1].enemyPool = &enemyPool[1];
|
|
|
|
// STAGE 3
|
|
stage[2].number = 3;
|
|
stage[2].currentPower = 0;
|
|
stage[2].powerToComplete = 600;
|
|
stage[2].minMenace = 7 + (4 * 3);
|
|
stage[2].maxMenace = 7 + (4 * 5);
|
|
stage[2].enemyPool = &enemyPool[2];
|
|
|
|
// STAGE 4
|
|
stage[3].number = 4;
|
|
stage[3].currentPower = 0;
|
|
stage[3].powerToComplete = 600;
|
|
stage[3].minMenace = 7 + (4 * 3);
|
|
stage[3].maxMenace = 7 + (4 * 5);
|
|
stage[3].enemyPool = &enemyPool[3];
|
|
|
|
// STAGE 5
|
|
stage[4].number = 5;
|
|
stage[4].currentPower = 0;
|
|
stage[4].powerToComplete = 600;
|
|
stage[4].minMenace = 7 + (4 * 4);
|
|
stage[4].maxMenace = 7 + (4 * 6);
|
|
stage[4].enemyPool = &enemyPool[4];
|
|
|
|
// STAGE 6
|
|
stage[5].number = 6;
|
|
stage[5].currentPower = 0;
|
|
stage[5].powerToComplete = 600;
|
|
stage[5].minMenace = 7 + (4 * 4);
|
|
stage[5].maxMenace = 7 + (4 * 6);
|
|
stage[5].enemyPool = &enemyPool[5];
|
|
|
|
// STAGE 7
|
|
stage[6].number = 7;
|
|
stage[6].currentPower = 0;
|
|
stage[6].powerToComplete = 650;
|
|
stage[6].minMenace = 7 + (4 * 5);
|
|
stage[6].maxMenace = 7 + (4 * 7);
|
|
stage[6].enemyPool = &enemyPool[6];
|
|
|
|
// STAGE 8
|
|
stage[7].number = 8;
|
|
stage[7].currentPower = 0;
|
|
stage[7].powerToComplete = 750;
|
|
stage[7].minMenace = 7 + (4 * 5);
|
|
stage[7].maxMenace = 7 + (4 * 7);
|
|
stage[7].enemyPool = &enemyPool[7];
|
|
|
|
// STAGE 9
|
|
stage[8].number = 9;
|
|
stage[8].currentPower = 0;
|
|
stage[8].powerToComplete = 850;
|
|
stage[8].minMenace = 7 + (4 * 6);
|
|
stage[8].maxMenace = 7 + (4 * 8);
|
|
stage[8].enemyPool = &enemyPool[8];
|
|
|
|
// STAGE 10
|
|
stage[9].number = 10;
|
|
stage[9].currentPower = 0;
|
|
stage[9].powerToComplete = 950;
|
|
stage[9].minMenace = 7 + (4 * 7);
|
|
stage[9].maxMenace = 7 + (4 * 10);
|
|
stage[9].enemyPool = &enemyPool[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 (enemyDeployCounter == 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
|
|
enemyDeployCounter = 50;
|
|
}
|
|
else
|
|
{
|
|
// Decrementa el contador de despliegues enemigos de la PowerBall
|
|
powerBallCounter > 0 ? powerBallCounter-- : powerBallCounter = 0;
|
|
|
|
// Elige una formación enemiga la azar
|
|
int set = rand() % 10;
|
|
|
|
// Evita repetir la ultima formación enemiga desplegada
|
|
if (set == lastEnemyDeploy)
|
|
++set %= 10;
|
|
|
|
lastEnemyDeploy = set;
|
|
|
|
const int numEnemies = stage[currentStage].enemyPool->set[set]->numberOfEnemies;
|
|
for (int i = 0; i < numEnemies; ++i)
|
|
{
|
|
createBalloon(stage[currentStage].enemyPool->set[set]->init[i].x,
|
|
stage[currentStage].enemyPool->set[set]->init[i].y,
|
|
stage[currentStage].enemyPool->set[set]->init[i].kind,
|
|
stage[currentStage].enemyPool->set[set]->init[i].velX,
|
|
enemySpeed,
|
|
stage[currentStage].enemyPool->set[set]->init[i].creationCounter);
|
|
}
|
|
|
|
enemyDeployCounter = 300;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Aumenta el poder de la fase
|
|
void Game::increaseStageCurrentPower(int power)
|
|
{
|
|
stage[currentStage].currentPower += power;
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void Game::setHiScore(Uint32 score)
|
|
{
|
|
hiScore = score;
|
|
}
|
|
|
|
// Actualiza el valor de hiScore en caso necesario
|
|
void Game::updateHiScore()
|
|
{
|
|
// Si la puntuación actual es mayor que la máxima puntuación
|
|
for (auto player : players)
|
|
if (player->getScore() > hiScore)
|
|
{
|
|
// Actualiza la máxima puntuación
|
|
hiScore = player->getScore();
|
|
|
|
// Almacena la máxima puntuación en el fichero junto con un checksum
|
|
scoreDataFile[0] = hiScore;
|
|
scoreDataFile[1] = hiScore % 43;
|
|
|
|
// Si se supera la máxima puntuación emite sonido
|
|
if (hiScoreAchieved == false)
|
|
{
|
|
hiScoreAchieved = true;
|
|
JA_PlaySound(hiScoreSound);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza las variables del jugador
|
|
void Game::updatePlayers()
|
|
{
|
|
for (auto player : players)
|
|
{
|
|
if (player->isEnabled())
|
|
{
|
|
player->update();
|
|
|
|
// Comprueba la colisión entre el jugador y los globos
|
|
if (checkPlayerBalloonCollision(player))
|
|
{
|
|
if (player->isAlive())
|
|
{
|
|
killPlayer(player);
|
|
|
|
if (demo.enabled && allPlayersAreDead())
|
|
{
|
|
fade->setType(FADE_RANDOM_SQUARE);
|
|
fade->activate();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Comprueba las colisiones entre el jugador y los items
|
|
checkPlayerItemCollision(player);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dibuja a los jugadores
|
|
void Game::renderPlayers()
|
|
{
|
|
for (auto player : players)
|
|
{
|
|
if (player->isEnabled())
|
|
{
|
|
player->render();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza las variables de la fase
|
|
void Game::updateStage()
|
|
{
|
|
if (stage[currentStage].currentPower >= stage[currentStage].powerToComplete)
|
|
{
|
|
// Cambio de fase
|
|
currentStage++;
|
|
lastStageReached = currentStage;
|
|
if (currentStage == 10)
|
|
{ // Ha llegado al final el juego
|
|
gameCompleted = true; // Marca el juego como completado
|
|
currentStage = 9; // Deja el valor dentro de los limites
|
|
stage[currentStage].currentPower = 0; // Deja el poder a cero para que no vuelva a entrar en esta condición
|
|
destroyAllBalloons(); // Destruye a todos los enemigos
|
|
stage[currentStage].currentPower = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos lo globos
|
|
menaceCurrent = 255; // Sube el nivel de amenaza para que no cree mas globos
|
|
for (auto player : players)
|
|
{ // Añade un millon de puntos a los jugadores que queden vivos
|
|
if (player->isAlive())
|
|
{
|
|
player->addScore(1000000);
|
|
}
|
|
}
|
|
updateHiScore();
|
|
JA_StopMusic();
|
|
}
|
|
JA_PlaySound(stageChangeSound);
|
|
stageBitmapCounter = 0;
|
|
enemySpeed = defaultEnemySpeed;
|
|
setBalloonSpeed(enemySpeed);
|
|
screen->flash(flashColor, 5);
|
|
screen->shake();
|
|
}
|
|
|
|
// Incrementa el contador del bitmap que aparece mostrando el cambio de fase
|
|
if (stageBitmapCounter < STAGE_COUNTER)
|
|
{
|
|
stageBitmapCounter++;
|
|
}
|
|
|
|
// Si el juego se ha completado, el bitmap se detiene en el centro de la pantalla
|
|
if (gameCompleted)
|
|
{
|
|
if (stageBitmapCounter > 100)
|
|
{
|
|
stageBitmapCounter = 100;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza el estado de muerte
|
|
void Game::updateDeath()
|
|
{
|
|
// Comprueba si todos los jugadores estan muertos
|
|
if (allPlayersAreDead())
|
|
{
|
|
if (deathCounter > 0)
|
|
{
|
|
deathCounter--;
|
|
|
|
if ((deathCounter == 250) || (deathCounter == 200) || (deathCounter == 180) || (deathCounter == 120) || (deathCounter == 60))
|
|
{
|
|
// Hace sonar aleatoriamente uno de los 4 sonidos de burbujas
|
|
const int index = rand() % 4;
|
|
JA_Sound_t *sound[4] = {bubble1Sound, bubble2Sound, bubble3Sound, bubble4Sound};
|
|
JA_PlaySound(sound[index], 0);
|
|
}
|
|
|
|
if (deathCounter == 150)
|
|
{
|
|
fade->activate();
|
|
}
|
|
}
|
|
|
|
if (fade->hasEnded())
|
|
{
|
|
// section->subsection = SUBSECTION_GAME_GAMEOVER;
|
|
section->name = SECTION_PROG_HI_SCORE_TABLE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza los globos
|
|
void Game::updateBalloons()
|
|
{
|
|
for (auto balloon : balloons)
|
|
{
|
|
balloon->update();
|
|
}
|
|
}
|
|
|
|
// Pinta en pantalla todos los globos activos
|
|
void Game::renderBalloons()
|
|
{
|
|
for (auto balloon : balloons)
|
|
{
|
|
balloon->render();
|
|
}
|
|
}
|
|
|
|
// Crea un globo nuevo en el vector de globos
|
|
int Game::createBalloon(float x, int y, int kind, float velx, float speed, int creationtimer)
|
|
{
|
|
const int index = (kind - 1) % 4;
|
|
Balloon *b = new Balloon(x, y, kind, velx, speed, creationtimer, balloonTextures[index], balloonAnimations[index], renderer);
|
|
balloons.push_back(b);
|
|
return (int)(balloons.size() - 1);
|
|
}
|
|
|
|
// 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 luck = rand() % 3;
|
|
const int x[3] = {left, center, right};
|
|
const float vx[3] = {BALLOON_VELX_POSITIVE, BALLOON_VELX_POSITIVE, BALLOON_VELX_NEGATIVE};
|
|
|
|
Balloon *b = new Balloon(x[luck], posY, POWER_BALL, vx[luck], enemySpeed, 100, balloonTextures[3], balloonAnimations[3], renderer);
|
|
balloons.push_back(b);
|
|
|
|
powerBallEnabled = true;
|
|
powerBallCounter = POWERBALL_COUNTER;
|
|
}
|
|
|
|
// Establece la velocidad de los globos
|
|
void Game::setBalloonSpeed(float speed)
|
|
{
|
|
for (auto balloon : balloons)
|
|
{
|
|
if (balloon->isEnabled())
|
|
{
|
|
balloon->setSpeed(speed);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Incrementa la velocidad de los globos
|
|
void Game::incBalloonSpeed()
|
|
{
|
|
// La velocidad solo se incrementa en el modo normal
|
|
if (difficulty == DIFFICULTY_NORMAL)
|
|
{
|
|
if (enemySpeed == BALLOON_SPEED_1)
|
|
{
|
|
enemySpeed = BALLOON_SPEED_2;
|
|
}
|
|
|
|
else if (enemySpeed == BALLOON_SPEED_2)
|
|
{
|
|
enemySpeed = BALLOON_SPEED_3;
|
|
}
|
|
|
|
else if (enemySpeed == BALLOON_SPEED_3)
|
|
{
|
|
enemySpeed = BALLOON_SPEED_4;
|
|
}
|
|
|
|
else if (enemySpeed == BALLOON_SPEED_4)
|
|
{
|
|
enemySpeed = BALLOON_SPEED_5;
|
|
}
|
|
|
|
setBalloonSpeed(enemySpeed);
|
|
}
|
|
}
|
|
|
|
// Decrementa la velocidad de los globos
|
|
void Game::decBalloonSpeed()
|
|
{
|
|
// La velocidad solo se decrementa en el modo normal
|
|
if (difficulty == DIFFICULTY_NORMAL)
|
|
{
|
|
if (enemySpeed == BALLOON_SPEED_5)
|
|
{
|
|
enemySpeed = BALLOON_SPEED_4;
|
|
}
|
|
|
|
else if (enemySpeed == BALLOON_SPEED_4)
|
|
{
|
|
enemySpeed = BALLOON_SPEED_3;
|
|
}
|
|
|
|
else if (enemySpeed == BALLOON_SPEED_3)
|
|
{
|
|
enemySpeed = BALLOON_SPEED_2;
|
|
}
|
|
|
|
else if (enemySpeed == BALLOON_SPEED_2)
|
|
{
|
|
enemySpeed = BALLOON_SPEED_1;
|
|
}
|
|
|
|
setBalloonSpeed(enemySpeed);
|
|
}
|
|
}
|
|
|
|
// Actualiza la velocidad de los globos en funcion del poder acumulado de la fase
|
|
void Game::updateBalloonSpeed()
|
|
{
|
|
const float percent = (float)stage[currentStage].currentPower / (float)stage[currentStage].powerToComplete;
|
|
if (enemySpeed == BALLOON_SPEED_1)
|
|
{
|
|
if (percent > 0.2f)
|
|
{
|
|
incBalloonSpeed();
|
|
}
|
|
}
|
|
|
|
else if (enemySpeed == BALLOON_SPEED_2)
|
|
{
|
|
if (percent > 0.4f)
|
|
{
|
|
incBalloonSpeed();
|
|
}
|
|
}
|
|
|
|
else if (enemySpeed == BALLOON_SPEED_3)
|
|
{
|
|
if (percent > 0.6f)
|
|
{
|
|
incBalloonSpeed();
|
|
}
|
|
}
|
|
|
|
else if (enemySpeed == BALLOON_SPEED_4)
|
|
{
|
|
if (percent > 0.8f)
|
|
{
|
|
incBalloonSpeed();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Explosiona un globo. Lo destruye y crea otros dos si es el caso
|
|
void Game::popBalloon(Balloon *balloon)
|
|
{
|
|
// Aumenta el poder de la fase
|
|
increaseStageCurrentPower(1);
|
|
balloonsPopped++;
|
|
|
|
const int kind = balloon->getKind();
|
|
switch (kind)
|
|
{
|
|
// Si es del tipo más pequeño, simplemente elimina el globo
|
|
case BALLOON_1:
|
|
balloon->pop();
|
|
break;
|
|
|
|
case HEXAGON_1:
|
|
balloon->pop();
|
|
break;
|
|
|
|
// Si es del tipo PowerBall, destruye todos los globos
|
|
case POWER_BALL:
|
|
destroyAllBalloons();
|
|
powerBallEnabled = false;
|
|
enemyDeployCounter = 20;
|
|
break;
|
|
|
|
// En cualquier otro caso, crea dos globos de un tipo inferior
|
|
default:
|
|
const int index = createBalloon(0, balloon->getPosY(), balloon->getKind() - 1, BALLOON_VELX_NEGATIVE, enemySpeed, 0);
|
|
balloons[index]->allignTo(balloon->getPosX() + (balloon->getWidth() / 2));
|
|
if (balloons[index]->getClass() == BALLOON_CLASS)
|
|
{
|
|
balloons[index]->setVelY(-2.50f);
|
|
}
|
|
else
|
|
{
|
|
balloons[index]->setVelY(BALLOON_VELX_NEGATIVE);
|
|
}
|
|
|
|
const int index2 = createBalloon(0, balloon->getPosY(), balloon->getKind() - 1, BALLOON_VELX_POSITIVE, enemySpeed, 0);
|
|
balloons[index2]->allignTo(balloon->getPosX() + (balloon->getWidth() / 2));
|
|
if (balloons[index2]->getClass() == BALLOON_CLASS)
|
|
{
|
|
balloons[index2]->setVelY(-2.50f);
|
|
}
|
|
else
|
|
{
|
|
balloons[index2]->setVelY(BALLOON_VELX_NEGATIVE);
|
|
}
|
|
|
|
// Elimina el globo
|
|
balloon->pop();
|
|
break;
|
|
}
|
|
|
|
// Recalcula el nivel de amenaza
|
|
evaluateAndSetMenace();
|
|
}
|
|
|
|
// Explosiona un globo. Lo destruye
|
|
void Game::destroyBalloon(Balloon *balloon)
|
|
{
|
|
int score = 0;
|
|
int power = 0;
|
|
|
|
// Calcula la puntuación y el poder que generaria el globo en caso de romperlo a él y a sus hijos
|
|
switch (balloon->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 (auto player : players)
|
|
{
|
|
player->addScore(Uint32(score * player->getScoreMultiplier() * difficultyScoreMultiplier));
|
|
}
|
|
updateHiScore();
|
|
|
|
// Aumenta el poder de la fase
|
|
increaseStageCurrentPower(power);
|
|
balloonsPopped += power;
|
|
|
|
// Destruye el globo
|
|
balloon->pop();
|
|
|
|
// Recalcula el nivel de amenaza
|
|
evaluateAndSetMenace();
|
|
}
|
|
|
|
// Explosiona todos los globos
|
|
void Game::popAllBalloons()
|
|
{
|
|
for (auto balloon : balloons)
|
|
{
|
|
if ((balloon->isEnabled()) && (!balloon->isPopping()) && (!balloon->isBeingCreated()))
|
|
{
|
|
popBalloon(balloon);
|
|
}
|
|
}
|
|
|
|
JA_PlaySound(balloonSound);
|
|
}
|
|
|
|
// Destruye todos los globos
|
|
void Game::destroyAllBalloons()
|
|
{
|
|
for (auto balloon : balloons)
|
|
{
|
|
if ((balloon->isEnabled()) && (!balloon->isPopping()))
|
|
{
|
|
destroyBalloon(balloon);
|
|
}
|
|
}
|
|
|
|
enemyDeployCounter = 255;
|
|
JA_PlaySound(powerBallSound);
|
|
screen->flash(flashColor, 5);
|
|
screen->shake();
|
|
}
|
|
|
|
// Detiene todos los globos
|
|
void Game::stopAllBalloons(int time)
|
|
{
|
|
for (auto balloon : balloons)
|
|
{
|
|
if (balloon->isEnabled())
|
|
{
|
|
balloon->setStop(true);
|
|
balloon->setStoppedTimer(time);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pone en marcha todos los globos
|
|
void Game::startAllBalloons()
|
|
{
|
|
for (auto balloon : balloons)
|
|
{
|
|
if ((balloon->isEnabled()) && (!balloon->isBeingCreated()))
|
|
{
|
|
balloon->setStop(false);
|
|
balloon->setStoppedTimer(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Obtiene el número de globos activos
|
|
int Game::countBalloons()
|
|
{
|
|
int num = 0;
|
|
|
|
for (auto balloon : balloons)
|
|
{
|
|
if (balloon->isEnabled())
|
|
{
|
|
if (!balloon->isPopping())
|
|
{
|
|
num++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
// Vacia el vector de globos
|
|
void Game::freeBalloons()
|
|
{
|
|
if (balloons.empty() == false)
|
|
{
|
|
for (int i = balloons.size() - 1; i >= 0; --i)
|
|
{
|
|
if (balloons[i]->isEnabled() == false)
|
|
{
|
|
delete balloons[i];
|
|
balloons.erase(balloons.begin() + i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Comprueba la colisión entre el jugador y los globos activos
|
|
bool Game::checkPlayerBalloonCollision(Player *player)
|
|
{
|
|
for (auto balloon : balloons)
|
|
{
|
|
if ((balloon->isEnabled()) && !(balloon->isStopped()) && !(balloon->isInvulnerable()))
|
|
{
|
|
if (checkCollision(player->getCollider(), balloon->getCollider()))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Comprueba la colisión entre el jugador y los items
|
|
void Game::checkPlayerItemCollision(Player *player)
|
|
{
|
|
if (!player->isAlive())
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (auto item : items)
|
|
{
|
|
if (item->isEnabled())
|
|
{
|
|
if (checkCollision(player->getCollider(), item->getCollider()))
|
|
{
|
|
switch (item->getClass())
|
|
{
|
|
case ITEM_POINTS_1_DISK:
|
|
player->addScore(1000);
|
|
updateHiScore();
|
|
createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n1000Sprite->getWidth() / 2), player->getPosY(), n1000Sprite);
|
|
JA_PlaySound(itemPickUpSound);
|
|
break;
|
|
|
|
case ITEM_POINTS_2_GAVINA:
|
|
player->addScore(2500);
|
|
updateHiScore();
|
|
createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n2500Sprite->getWidth() / 2), player->getPosY(), n2500Sprite);
|
|
JA_PlaySound(itemPickUpSound);
|
|
break;
|
|
|
|
case ITEM_POINTS_3_PACMAR:
|
|
player->addScore(5000);
|
|
updateHiScore();
|
|
createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n5000Sprite->getWidth() / 2), player->getPosY(), n5000Sprite);
|
|
JA_PlaySound(itemPickUpSound);
|
|
break;
|
|
|
|
case ITEM_CLOCK:
|
|
enableTimeStopItem();
|
|
JA_PlaySound(itemPickUpSound);
|
|
break;
|
|
|
|
case ITEM_COFFEE:
|
|
if (player->getCoffees() == 2)
|
|
{
|
|
player->addScore(5000);
|
|
updateHiScore();
|
|
createItemScoreSprite(item->getPosX() + (item->getWidth() / 2) - (n5000Sprite->getWidth() / 2), player->getPosY(), n5000Sprite);
|
|
}
|
|
player->giveExtraHit();
|
|
JA_PlaySound(itemPickUpSound);
|
|
break;
|
|
|
|
case ITEM_COFFEE_MACHINE:
|
|
player->setPowerUp();
|
|
JA_PlaySound(itemPickUpSound);
|
|
coffeeMachineEnabled = false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
item->disable();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Comprueba y procesa la colisión entre las balas y los globos
|
|
void Game::checkBulletBalloonCollision()
|
|
{
|
|
for (auto bullet : bullets)
|
|
{
|
|
for (auto balloon : balloons)
|
|
{
|
|
if (balloon->isEnabled() && (!balloon->isInvulnerable()) && bullet->isEnabled())
|
|
{
|
|
if (checkCollision(balloon->getCollider(), bullet->getCollider()))
|
|
{
|
|
// Otorga los puntos correspondientes al globo al jugador que disparó la bala
|
|
int index = bullet->getOwner();
|
|
players[index]->incScoreMultiplier();
|
|
players[index]->addScore(Uint32(balloon->getScore() * players[index]->getScoreMultiplier() * difficultyScoreMultiplier));
|
|
updateHiScore();
|
|
|
|
// Explota el globo
|
|
popBalloon(balloon);
|
|
|
|
// Sonido de explosión
|
|
JA_PlaySound(balloonSound);
|
|
|
|
// Deshabilita la bala
|
|
bullet->disable();
|
|
|
|
// Suelta el item en caso de que salga uno
|
|
const int droppeditem = dropItem();
|
|
// if ((droppeditem != NO_KIND) && !(demo.enabled) && !(demo.recording))
|
|
if ((droppeditem != NO_KIND) && !(demo.recording))
|
|
{
|
|
if (droppeditem != ITEM_COFFEE_MACHINE)
|
|
{
|
|
createItem(droppeditem, balloon->getPosX(), balloon->getPosY());
|
|
JA_PlaySound(itemDropSound);
|
|
}
|
|
else
|
|
{
|
|
createItem(droppeditem, players[index]->getPosX(), 0);
|
|
coffeeMachineEnabled = true;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mueve las balas activas
|
|
void Game::moveBullets()
|
|
{
|
|
for (auto bullet : bullets)
|
|
{
|
|
if (bullet->isEnabled())
|
|
{
|
|
if (bullet->move() == BULLET_MOVE_OUT)
|
|
{
|
|
players[bullet->getOwner()]->decScoreMultiplier();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pinta las balas activas
|
|
void Game::renderBullets()
|
|
{
|
|
for (auto bullet : bullets)
|
|
{
|
|
if (bullet->isEnabled())
|
|
{
|
|
bullet->render();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Crea un objeto bala
|
|
void Game::createBullet(int x, int y, int kind, bool poweredUp, int owner)
|
|
{
|
|
Bullet *b = new Bullet(x, y, kind, poweredUp, owner, bulletTexture, renderer);
|
|
bullets.push_back(b);
|
|
}
|
|
|
|
// Vacia el vector de balas
|
|
void Game::freeBullets()
|
|
{
|
|
if (bullets.empty() == false)
|
|
{
|
|
for (int i = bullets.size() - 1; i >= 0; --i)
|
|
{
|
|
if (bullets[i]->isEnabled() == false)
|
|
{
|
|
delete bullets[i];
|
|
bullets.erase(bullets.begin() + i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza los items
|
|
void Game::updateItems()
|
|
{
|
|
for (auto item : items)
|
|
{
|
|
if (item->isEnabled())
|
|
{
|
|
item->update();
|
|
if (item->isOnFloor())
|
|
{
|
|
JA_PlaySound(coffeeMachineSound);
|
|
screen->shake();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pinta los items activos
|
|
void Game::renderItems()
|
|
{
|
|
for (auto item : items)
|
|
{
|
|
item->render();
|
|
}
|
|
}
|
|
|
|
// Devuelve un item al azar y luego segun sus probabilidades
|
|
int Game::dropItem()
|
|
{
|
|
const int luckyNumber = rand() % 100;
|
|
const int item = rand() % 6;
|
|
|
|
switch (item)
|
|
{
|
|
case 0:
|
|
if (luckyNumber < helper.itemPoints1Odds)
|
|
{
|
|
return ITEM_POINTS_1_DISK;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if (luckyNumber < helper.itemPoints2Odds)
|
|
{
|
|
return ITEM_POINTS_2_GAVINA;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
if (luckyNumber < helper.itemPoints3Odds)
|
|
{
|
|
return ITEM_POINTS_3_PACMAR;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
if (luckyNumber < helper.itemClockOdds)
|
|
{
|
|
return ITEM_CLOCK;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
if (luckyNumber < helper.itemCoffeeOdds)
|
|
{
|
|
helper.itemCoffeeOdds = ITEM_COFFEE_ODDS;
|
|
return ITEM_COFFEE;
|
|
}
|
|
else
|
|
{
|
|
if (helper.needCoffee)
|
|
{
|
|
helper.itemCoffeeOdds++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
if (luckyNumber < helper.itemCoffeeMachineOdds)
|
|
{
|
|
helper.itemCoffeeMachineOdds = ITEM_COFFEE_MACHINE_ODDS;
|
|
if ((!coffeeMachineEnabled) && (helper.needCoffeeMachine))
|
|
{
|
|
return ITEM_COFFEE_MACHINE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (helper.needCoffeeMachine)
|
|
{
|
|
helper.itemCoffeeMachineOdds++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NO_KIND;
|
|
}
|
|
|
|
// Crea un objeto item
|
|
void Game::createItem(int kind, float x, float y)
|
|
{
|
|
Item *item = new Item(kind, x, y, itemTextures[kind - 1], itemAnimations[kind - 1], renderer);
|
|
items.push_back(item);
|
|
}
|
|
|
|
// Vacia el vector de items
|
|
void Game::freeItems()
|
|
{
|
|
if (items.empty() == false)
|
|
{
|
|
for (int i = items.size() - 1; i >= 0; --i)
|
|
{
|
|
if (items[i]->isEnabled() == false)
|
|
{
|
|
delete items[i];
|
|
items.erase(items.begin() + i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Crea un objeto SmartSprite para mostrar la puntuación al coger un objeto
|
|
void Game::createItemScoreSprite(int x, int y, SmartSprite *sprite)
|
|
{
|
|
SmartSprite *ss = new SmartSprite(nullptr, renderer);
|
|
smartSprites.push_back(ss);
|
|
|
|
// Crea una copia del objeto
|
|
*ss = *sprite;
|
|
ss->setPosX(x);
|
|
ss->setPosY(y);
|
|
ss->setDestX(x);
|
|
ss->setDestY(y - 25);
|
|
ss->setEnabled(true);
|
|
ss->setEnabledCounter(100);
|
|
}
|
|
|
|
// Vacia el vector de smartsprites
|
|
void Game::freeSmartSprites()
|
|
{
|
|
if (smartSprites.empty() == false)
|
|
{
|
|
for (int i = smartSprites.size() - 1; i >= 0; --i)
|
|
{
|
|
if (smartSprites[i]->hasFinished())
|
|
{
|
|
delete smartSprites[i];
|
|
smartSprites.erase(smartSprites.begin() + i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Crea un SmartSprite para arrojar el item café al recibir un impacto
|
|
void Game::throwCoffee(int x, int y)
|
|
{
|
|
SmartSprite *ss = new SmartSprite(itemTextures[4], renderer);
|
|
smartSprites.push_back(ss);
|
|
|
|
ss->setPosX(x - 8);
|
|
ss->setPosY(y - 8);
|
|
ss->setWidth(param->itemSize);
|
|
ss->setHeight(param->itemSize);
|
|
ss->setVelX(-1.0f + ((rand() % 5) * 0.5f));
|
|
ss->setVelY(-4.0f);
|
|
ss->setAccelX(0.0f);
|
|
ss->setAccelY(0.2f);
|
|
ss->setDestX(x + (ss->getVelX() * 50));
|
|
ss->setDestY(param->gameHeight + 1);
|
|
ss->setEnabled(true);
|
|
ss->setEnabledCounter(1);
|
|
ss->setSpriteClip(0, param->itemSize, param->itemSize, param->itemSize);
|
|
ss->setRotate(true);
|
|
ss->setRotateSpeed(10);
|
|
ss->setRotateAmount(90.0);
|
|
}
|
|
|
|
// Actualiza los SmartSprites
|
|
void Game::updateSmartSprites()
|
|
{
|
|
for (auto ss : smartSprites)
|
|
{
|
|
ss->update();
|
|
}
|
|
}
|
|
|
|
// Pinta los SmartSprites activos
|
|
void Game::renderSmartSprites()
|
|
{
|
|
for (auto ss : smartSprites)
|
|
{
|
|
ss->render();
|
|
}
|
|
}
|
|
|
|
// Acciones a realizar cuando el jugador muere
|
|
void Game::killPlayer(Player *player)
|
|
{
|
|
if (!player->isEnabled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!player->isInvulnerable())
|
|
{
|
|
if (player->hasExtraHit())
|
|
{
|
|
player->removeExtraHit();
|
|
throwCoffee(player->getPosX() + (player->getWidth() / 2), player->getPosY() + (player->getHeight() / 2));
|
|
JA_PlaySound(coffeeOutSound);
|
|
screen->shake();
|
|
}
|
|
else
|
|
{
|
|
JA_PauseMusic();
|
|
stopAllBalloons(10);
|
|
JA_PlaySound(playerCollisionSound);
|
|
screen->shake();
|
|
JA_PlaySound(coffeeOutSound);
|
|
player->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()
|
|
{
|
|
menaceCurrent = 0;
|
|
for (auto balloon : balloons)
|
|
{
|
|
if (balloon->isEnabled())
|
|
{
|
|
menaceCurrent += balloon->getMenace();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Obtiene el valor de la variable
|
|
int Game::getMenace()
|
|
{
|
|
return menaceCurrent;
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void Game::setTimeStopped(bool value)
|
|
{
|
|
timeStopped = value;
|
|
}
|
|
|
|
// Obtiene el valor de la variable
|
|
bool Game::isTimeStopped()
|
|
{
|
|
return timeStopped;
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void Game::setTimeStoppedCounter(int value)
|
|
{
|
|
timeStoppedCounter = value;
|
|
}
|
|
|
|
// Incrementa el valor de la variable
|
|
void Game::incTimeStoppedCounter(int value)
|
|
{
|
|
timeStoppedCounter += value;
|
|
}
|
|
|
|
// Actualiza y comprueba el valor de la variable
|
|
void Game::updateTimeStoppedCounter()
|
|
{
|
|
if (isTimeStopped())
|
|
{
|
|
if (timeStoppedCounter > 0)
|
|
{
|
|
timeStoppedCounter--;
|
|
stopAllBalloons(TIME_STOPPED_COUNTER);
|
|
}
|
|
else
|
|
{
|
|
disableTimeStopItem();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza la variable enemyDeployCounter
|
|
void Game::updateEnemyDeployCounter()
|
|
{
|
|
if (enemyDeployCounter > 0)
|
|
{
|
|
enemyDeployCounter--;
|
|
}
|
|
}
|
|
|
|
// Actualiza el juego
|
|
void Game::update()
|
|
{
|
|
if (paused)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
|
if (SDL_GetTicks() - ticks > ticksSpeed)
|
|
{
|
|
// Actualiza el contador de ticks
|
|
ticks = SDL_GetTicks();
|
|
|
|
// Actualiza el contador de juego
|
|
counter++;
|
|
|
|
if (demo.enabled)
|
|
{
|
|
// Incrementa el contador de la demo
|
|
if (demo.counter < TOTAL_DEMO_DATA)
|
|
{
|
|
demo.counter++;
|
|
}
|
|
|
|
// Activa el fundido antes de acabar con los datos de la demo
|
|
if (demo.counter == TOTAL_DEMO_DATA - 200)
|
|
{
|
|
fade->setType(FADE_RANDOM_SQUARE);
|
|
fade->activate();
|
|
}
|
|
|
|
// Si ha terminado el fundido, cambia de sección
|
|
if (fade->hasEnded())
|
|
{
|
|
section->name = SECTION_PROG_HI_SCORE_TABLE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifdef RECORDING
|
|
// Solo mira y guarda el input en cada update
|
|
checkInput();
|
|
|
|
// Incrementa el contador de la demo
|
|
if (demo.counter < TOTAL_DEMO_DATA)
|
|
{
|
|
demo.counter++;
|
|
}
|
|
|
|
// Si se ha llenado el vector con datos, sale del programa
|
|
else
|
|
{
|
|
section->name = SECTION_PROG_QUIT;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// Comprueba si la música ha de estar sonando
|
|
checkMusicStatus();
|
|
|
|
// Actualiza el objeto screen
|
|
screen->update();
|
|
|
|
// Actualiza el objeto fade
|
|
fade->update();
|
|
|
|
// Actualiza las variables del jugador
|
|
updatePlayers();
|
|
|
|
// Actualiza el marcador
|
|
updateScoreboard();
|
|
|
|
// Actualiza el fondo
|
|
updateBackground();
|
|
|
|
// Mueve los globos
|
|
updateBalloons();
|
|
|
|
// Mueve las balas
|
|
moveBullets();
|
|
|
|
// Actualiza los items
|
|
updateItems();
|
|
|
|
// Actualiza el valor de currentStage
|
|
updateStage();
|
|
|
|
// Actualiza el estado de muerte
|
|
updateDeath();
|
|
|
|
// Actualiza los SmartSprites
|
|
updateSmartSprites();
|
|
|
|
// Actualiza los contadores de estado y efectos
|
|
updateTimeStoppedCounter();
|
|
updateEnemyDeployCounter();
|
|
|
|
// 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
|
|
updateMenace();
|
|
|
|
// Actualiza la velocidad de los enemigos
|
|
updateBalloonSpeed();
|
|
|
|
// Actualiza el tramo final de juego, una vez completado
|
|
updateGameCompleted();
|
|
|
|
// Vacia los vectores
|
|
freeBullets();
|
|
freeBalloons();
|
|
freeItems();
|
|
freeSmartSprites();
|
|
}
|
|
}
|
|
|
|
// Actualiza el fondo
|
|
void Game::updateBackground()
|
|
{
|
|
// Si el juego está completado, se reduce la velocidad de las nubes
|
|
if (gameCompleted)
|
|
{
|
|
if (balloonsPopped > 400)
|
|
{
|
|
balloonsPopped -= 25;
|
|
}
|
|
else
|
|
{
|
|
balloonsPopped = 200;
|
|
}
|
|
}
|
|
|
|
// Calcula la velocidad en función de los globos explotados y el total de globos a explotar para acabar el juego
|
|
const float speed = (-0.2f) + (-3.00f * ((float)balloonsPopped / (float)totalPowerToCompleteGame));
|
|
|
|
// Aplica la velocidad calculada para las nubes
|
|
background->setCloudsSpeed(speed);
|
|
const float gradientNumber = std::min(((float)balloonsPopped / 1250.0f), 3.0f);
|
|
const float percent = gradientNumber - (int)gradientNumber;
|
|
background->setGradientNumber((int)gradientNumber);
|
|
background->setTransition(percent);
|
|
|
|
// Actualiza el objeto
|
|
background->update();
|
|
}
|
|
|
|
// Dibuja la linea que separa la zona ade juego del marcador
|
|
void Game::renderSeparator()
|
|
{
|
|
// Dibuja la linea que separa el marcador de la zona de juego
|
|
SDL_SetRenderDrawColor(renderer, separator.r, separator.g, separator.b, 255);
|
|
SDL_RenderDrawLine(renderer, param->scoreboard.x, param->scoreboard.y, param->scoreboard.x + param->scoreboard.w, param->scoreboard.y);
|
|
}
|
|
|
|
// Dibuja los elementos de la zona de juego en su textura
|
|
void Game::fillCanvas()
|
|
{
|
|
// Dibujamos el contenido de la zona de juego en su textura
|
|
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
|
|
SDL_SetRenderTarget(renderer, canvas);
|
|
|
|
// Dibuja los objetos
|
|
background->render();
|
|
renderItems();
|
|
renderSmartSprites();
|
|
renderBalloons();
|
|
renderBullets();
|
|
renderMessages();
|
|
renderPlayers();
|
|
|
|
// Deja el renderizador apuntando donde estaba
|
|
SDL_SetRenderTarget(renderer, temp);
|
|
}
|
|
|
|
// Dibuja el juego
|
|
void Game::render()
|
|
{
|
|
// Dibuja los graficos de la zona de juego en la textura
|
|
fillCanvas();
|
|
|
|
// Prepara para empezar a dibujar en la textura de juego
|
|
screen->start();
|
|
|
|
// Copia la textura con la zona de juego a la pantalla
|
|
SDL_RenderCopy(renderer, canvas, nullptr, &playArea);
|
|
|
|
// Dibuja el marcador
|
|
scoreboard->render();
|
|
|
|
// Dibuja el separador del marcador de la zona de juego
|
|
renderSeparator();
|
|
|
|
// Dibuja el fade
|
|
fade->render();
|
|
|
|
// Vuelca el contenido del renderizador en pantalla
|
|
screen->blit();
|
|
}
|
|
|
|
// Gestiona el nivel de amenaza
|
|
void Game::updateMenace()
|
|
{
|
|
if (gameCompleted)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const float percent = stage[currentStage].currentPower / stage[currentStage].powerToComplete;
|
|
const int difference = stage[currentStage].maxMenace - stage[currentStage].minMenace;
|
|
|
|
// Aumenta el nivel de amenaza en función de la puntuación
|
|
menaceThreshold = stage[currentStage].minMenace + (difference * percent);
|
|
|
|
// Si el nivel de amenza es inferior al umbral
|
|
if (menaceCurrent < menaceThreshold)
|
|
{
|
|
// 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::checkInput()
|
|
{
|
|
// Comprueba las teclas que afectan al programa (solo para el primer jugador)
|
|
if (input->checkInput(input_exit, DO_NOT_ALLOW_REPEAT))
|
|
{
|
|
section->name = SECTION_PROG_QUIT;
|
|
return;
|
|
}
|
|
|
|
else if (input->checkInput(input_pause, DO_NOT_ALLOW_REPEAT))
|
|
{
|
|
pause(!paused);
|
|
}
|
|
|
|
// Modo Demo activo
|
|
if (demo.enabled)
|
|
{
|
|
int i = 0;
|
|
for (auto player : players)
|
|
{
|
|
if (player->isAlive() && player->isEnabled())
|
|
{
|
|
// Comprueba direcciones
|
|
if (demo.dataFile[i][demo.counter].left == 1)
|
|
{
|
|
player->setInput(input_left);
|
|
}
|
|
|
|
else if (demo.dataFile[i][demo.counter].right == 1)
|
|
{
|
|
player->setInput(input_right);
|
|
}
|
|
|
|
else if (demo.dataFile[i][demo.counter].noInput == 1)
|
|
{
|
|
player->setInput(input_null);
|
|
}
|
|
|
|
// Comprueba botones
|
|
if (demo.dataFile[i][demo.counter].fire == 1)
|
|
{
|
|
if (player->canFire())
|
|
{
|
|
player->setInput(input_fire_center);
|
|
createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_UP, player->isPowerUp(), i);
|
|
player->setFireCooldown(10);
|
|
}
|
|
}
|
|
|
|
else if (demo.dataFile[i][demo.counter].fireLeft == 1)
|
|
{
|
|
if (player->canFire())
|
|
{
|
|
player->setInput(input_fire_left);
|
|
createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_LEFT, player->isPowerUp(), i);
|
|
player->setFireCooldown(10);
|
|
}
|
|
}
|
|
|
|
else if (demo.dataFile[i][demo.counter].fireRight == 1)
|
|
{
|
|
if (player->canFire())
|
|
{
|
|
player->setInput(input_fire_right);
|
|
createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_RIGHT, player->isPowerUp(), i);
|
|
player->setFireCooldown(10);
|
|
}
|
|
}
|
|
|
|
// Si se pulsa cualquier tecla, se sale del modo demo
|
|
if (input->checkAnyButtonPressed())
|
|
{
|
|
section->name = SECTION_PROG_TITLE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
// Modo Demo no activo
|
|
else
|
|
{
|
|
#ifdef RECORDING
|
|
// Resetea el teclado
|
|
demo.keys.left = 0;
|
|
demo.keys.right = 0;
|
|
demo.keys.noInput = 0;
|
|
demo.keys.fire = 0;
|
|
demo.keys.fireLeft = 0;
|
|
demo.keys.fireRight = 0;
|
|
#endif
|
|
int i = 0;
|
|
for (auto player : players)
|
|
{
|
|
if (player->isAlive() && player->isEnabled())
|
|
{
|
|
// Input a la izquierda
|
|
if (input->checkInput(input_left, ALLOW_REPEAT, options->controller[i].deviceType, options->controller[i].index))
|
|
{
|
|
player->setInput(input_left);
|
|
#ifdef RECORDING
|
|
demo.keys.left = 1;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Input a la derecha
|
|
if (input->checkInput(input_right, ALLOW_REPEAT, options->controller[i].deviceType, options->controller[i].index))
|
|
{
|
|
player->setInput(input_right);
|
|
#ifdef RECORDING
|
|
demo.keys.right = 1;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Ninguno de los dos inputs anteriores
|
|
player->setInput(input_null);
|
|
#ifdef RECORDING
|
|
demo.keys.noInput = 1;
|
|
#endif
|
|
}
|
|
}
|
|
// Comprueba el input de disparar al centro
|
|
if (input->checkInput(input_fire_center, ALLOW_REPEAT, options->controller[i].deviceType, options->controller[i].index))
|
|
{
|
|
if (player->canFire())
|
|
{
|
|
player->setInput(input_fire_center);
|
|
createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_UP, player->isPowerUp(), i);
|
|
player->setFireCooldown(10);
|
|
|
|
// Reproduce el sonido de disparo
|
|
JA_PlaySound(bulletSound);
|
|
#ifdef RECORDING
|
|
demo.keys.fire = 1;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Comprueba el input de disparar a la izquierda
|
|
else if (input->checkInput(input_fire_left, ALLOW_REPEAT, options->controller[i].deviceType, options->controller[i].index))
|
|
{
|
|
if (player->canFire())
|
|
{
|
|
player->setInput(input_fire_left);
|
|
createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_LEFT, player->isPowerUp(), i);
|
|
player->setFireCooldown(10);
|
|
|
|
// Reproduce el sonido de disparo
|
|
JA_PlaySound(bulletSound);
|
|
#ifdef RECORDING
|
|
demo.keys.fireLeft = 1;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Comprueba el input de disparar a la derecha
|
|
else if (input->checkInput(input_fire_right, ALLOW_REPEAT, options->controller[i].deviceType, options->controller[i].index))
|
|
{
|
|
if (player->canFire())
|
|
{
|
|
player->setInput(input_fire_right);
|
|
createBullet(player->getPosX() + (player->getWidth() / 2) - 4, player->getPosY() + (player->getHeight() / 2), BULLET_RIGHT, player->isPowerUp(), i);
|
|
player->setFireCooldown(10);
|
|
|
|
// Reproduce el sonido de disparo
|
|
JA_PlaySound(bulletSound);
|
|
#ifdef RECORDING
|
|
demo.keys.fireRight = 1;
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef RECORDING
|
|
if (demo.recording)
|
|
{
|
|
if (demo.counter < TOTAL_DEMO_DATA)
|
|
{
|
|
demo.dataFile[0][demo.counter] = demo.keys;
|
|
}
|
|
}
|
|
#endif
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
if (input->checkInput(input_start, ALLOW_REPEAT, options->controller[i].deviceType, options->controller[i].index))
|
|
{
|
|
player->enable(true);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Comprueba el input para el resto de objetos
|
|
screen->checkInput();
|
|
}
|
|
|
|
// Pinta diferentes mensajes en la pantalla
|
|
void Game::renderMessages()
|
|
{
|
|
// GetReady
|
|
if ((counter < STAGE_COUNTER) && (!demo.enabled))
|
|
{
|
|
textNokiaBig2->write((int)getReadyBitmapPath[counter], PLAY_AREA_CENTER_Y - 8, lang->getText(75), -2);
|
|
}
|
|
|
|
// Time Stopped
|
|
if (timeStopped)
|
|
{
|
|
if ((timeStoppedCounter > 100) || (timeStoppedCounter % 10 > 4))
|
|
{
|
|
textNokia2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, lang->getText(36) + std::to_string(timeStoppedCounter / 10), -1, noColor, 1, shdwTxtColor);
|
|
}
|
|
|
|
if (timeStoppedCounter > 100)
|
|
{
|
|
if (timeStoppedCounter % 30 == 0)
|
|
{
|
|
// JA_PlaySound(clockSound, false);
|
|
JA_PlaySound(clockSound);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (timeStoppedCounter % 15 == 0)
|
|
{
|
|
// JA_PlaySound(clockSound, false);
|
|
JA_PlaySound(clockSound);
|
|
}
|
|
}
|
|
}
|
|
|
|
// D E M O
|
|
if (demo.enabled)
|
|
{
|
|
if (demo.counter % 30 > 8)
|
|
{
|
|
textNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, lang->getText(37), 0, noColor, 2, shdwTxtColor);
|
|
}
|
|
}
|
|
|
|
// STAGE NUMBER
|
|
if (stageBitmapCounter < STAGE_COUNTER)
|
|
{
|
|
const int stageNum = stage[currentStage].number;
|
|
std::string text;
|
|
|
|
if (stageNum == 10)
|
|
{ // Ultima fase
|
|
text = lang->getText(79);
|
|
}
|
|
else
|
|
{ // X fases restantes
|
|
text = std::to_string(11 - stage[currentStage].number) + lang->getText(38);
|
|
}
|
|
|
|
if (!gameCompleted)
|
|
{ // Escribe el número de fases restantes
|
|
textNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, stageBitmapPath[stageBitmapCounter], text, -2, noColor, 2, shdwTxtColor);
|
|
}
|
|
else
|
|
{ // Escribe el texto de juego completado
|
|
text = lang->getText(50);
|
|
textNokiaBig2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, stageBitmapPath[stageBitmapCounter], text, -2, noColor, 1, shdwTxtColor);
|
|
textNokia2->writeDX(TXT_CENTER, PLAY_AREA_CENTER_X, stageBitmapPath[stageBitmapCounter] + textNokiaBig2->getCharacterSize() + 2, lang->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 && !demo.enabled)
|
|
{
|
|
JA_PauseMusic();
|
|
}
|
|
}
|
|
|
|
// Deshabilita el efecto del item de detener el tiempo
|
|
void Game::disableTimeStopItem()
|
|
{
|
|
timeStopped = false;
|
|
setTimeStoppedCounter(0);
|
|
startAllBalloons();
|
|
if (JA_GetMusicState() == JA_MUSIC_PAUSED && !demo.enabled)
|
|
{
|
|
JA_ResumeMusic();
|
|
}
|
|
}
|
|
|
|
// Comprueba si la música ha de estar sonando
|
|
void Game::checkMusicStatus()
|
|
{
|
|
// Si la música no está sonando
|
|
if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED))
|
|
{
|
|
// Reproduce la música
|
|
if (!gameCompleted)
|
|
{
|
|
if (players[0]->isAlive() || players[1]->isAlive())
|
|
{
|
|
JA_PlayMusic(music);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Bucle para el juego
|
|
void Game::run()
|
|
{
|
|
while (section->name == SECTION_PROG_GAME)
|
|
{
|
|
#ifndef RECORDING
|
|
checkInput();
|
|
#endif
|
|
update();
|
|
checkEvents(); // Tiene que ir antes del render
|
|
render();
|
|
}
|
|
|
|
// Vuelve a dejar el sonido como estaba
|
|
if (demo.enabled)
|
|
{
|
|
JA_EnableSound(options->audio.sound.enabled);
|
|
}
|
|
}
|
|
|
|
// Indica si se puede crear una powerball
|
|
bool Game::canPowerBallBeCreated()
|
|
{
|
|
if ((!powerBallEnabled) && (calculateScreenPower() > POWERBALL_SCREENPOWER_MINIMUM) && (powerBallCounter == 0))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Calcula el poder actual de los globos en pantalla
|
|
int Game::calculateScreenPower()
|
|
{
|
|
int power = 0;
|
|
|
|
for (auto balloon : balloons)
|
|
{
|
|
if (balloon->isEnabled())
|
|
{
|
|
power += balloon->getPower();
|
|
}
|
|
}
|
|
|
|
return power;
|
|
}
|
|
|
|
// Inicializa las variables que contienen puntos de ruta para mover objetos
|
|
void Game::initPaths()
|
|
{
|
|
// Vector con los valores del seno para 360 grados
|
|
float sin[360];
|
|
for (int i = 0; i < 360; ++i)
|
|
{
|
|
sin[i] = SDL_sinf((float)i * 3.14f / 180.0f);
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
stageBitmapPath[i] = (sin[(int)((i * 1.8f) + 90)] * (distance) + centerPoint);
|
|
}
|
|
|
|
else if (i < secondPart)
|
|
{
|
|
stageBitmapPath[i] = (int)centerPoint;
|
|
}
|
|
|
|
else
|
|
{
|
|
stageBitmapPath[i] = (sin[(int)(((i - 149) * 1.8f) + 90)] * (centerPoint + 17) - 17);
|
|
}
|
|
}
|
|
|
|
// Letrero de GetReady
|
|
const int size = textNokiaBig2->lenght(lang->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)
|
|
{
|
|
getReadyBitmapPath[i] = sin[(int)(i * 1.8f)];
|
|
getReadyBitmapPath[i] *= distance1;
|
|
getReadyBitmapPath[i] -= size;
|
|
}
|
|
|
|
else if (i < secondPart)
|
|
{
|
|
getReadyBitmapPath[i] = (int)finish1;
|
|
}
|
|
|
|
else
|
|
{
|
|
getReadyBitmapPath[i] = sin[(int)((i - 150) * 1.8f)];
|
|
getReadyBitmapPath[i] *= distance2;
|
|
getReadyBitmapPath[i] += finish1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza el tramo final de juego, una vez completado
|
|
void Game::updateGameCompleted()
|
|
{
|
|
if (gameCompleted)
|
|
{
|
|
gameCompletedCounter++;
|
|
}
|
|
|
|
if (gameCompletedCounter == GAME_COMPLETED_END)
|
|
{
|
|
// section->subsection = SUBSECTION_GAME_GAMEOVER;
|
|
section->name = SECTION_PROG_TITLE;
|
|
section->subsection = SUBSECTION_TITLE_1;
|
|
}
|
|
}
|
|
|
|
// Actualiza las variables de ayuda
|
|
void Game::updateHelper()
|
|
{
|
|
// Solo ofrece ayuda cuando la amenaza es elevada
|
|
if (menaceCurrent > 15)
|
|
{
|
|
for (auto player : players)
|
|
{
|
|
if (player->getCoffees() == 0)
|
|
{
|
|
helper.needCoffee = true;
|
|
}
|
|
else
|
|
{
|
|
helper.needCoffee = false;
|
|
}
|
|
|
|
if (!player->isPowerUp())
|
|
{
|
|
helper.needCoffeeMachine = true;
|
|
}
|
|
else
|
|
{
|
|
helper.needCoffeeMachine = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
helper.needCoffee = false;
|
|
helper.needCoffeeMachine = false;
|
|
}
|
|
}
|
|
|
|
// Comprueba si todos los jugadores han muerto
|
|
bool Game::allPlayersAreDead()
|
|
{
|
|
bool success = true;
|
|
for (auto player : players)
|
|
{
|
|
success &= (!player->isAlive() || !player->isEnabled());
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Comprueba los eventos que hay en cola
|
|
void Game::checkEvents()
|
|
{
|
|
const Uint8 *keyStates = SDL_GetKeyboardState(nullptr);
|
|
|
|
if (keyStates[SDL_SCANCODE_H] != 0)
|
|
{
|
|
createItemScoreSprite(param->gameWidth / 2, param->gameWidth / 2, n1000Sprite);
|
|
}
|
|
|
|
while (SDL_PollEvent(eventHandler) != 0)
|
|
{
|
|
// Evento de salida de la aplicación
|
|
if (eventHandler->type == SDL_QUIT)
|
|
{
|
|
section->name = SECTION_PROG_QUIT;
|
|
break;
|
|
}
|
|
|
|
else if (eventHandler->type == SDL_WINDOWEVENT)
|
|
{
|
|
if (eventHandler->window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
|
{
|
|
if (!demo.enabled)
|
|
{
|
|
pause(true);
|
|
}
|
|
}
|
|
|
|
if (eventHandler->window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
|
{
|
|
pause(false);
|
|
}
|
|
|
|
if (eventHandler->window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
|
|
{
|
|
reloadTextures();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Carga las animaciones
|
|
void Game::loadAnimations(std::string filePath, std::vector<std::string> *buffer)
|
|
{
|
|
std::ifstream file(filePath);
|
|
std::string line;
|
|
|
|
if (file)
|
|
{
|
|
if (options->console)
|
|
{
|
|
std::cout << "Animation loaded: " << filePath.substr(filePath.find_last_of("\\/") + 1).c_str() << std::endl;
|
|
}
|
|
while (std::getline(file, line))
|
|
{
|
|
buffer->push_back(line);
|
|
}
|
|
file.close();
|
|
}
|
|
}
|
|
|
|
// Elimina todos los objetos contenidos en vectores
|
|
void Game::deleteAllVectorObjects()
|
|
{
|
|
for (auto player : players)
|
|
{
|
|
delete player;
|
|
};
|
|
players.clear();
|
|
|
|
for (auto ballon : balloons)
|
|
{
|
|
delete ballon;
|
|
};
|
|
balloons.clear();
|
|
|
|
for (auto bullet : bullets)
|
|
{
|
|
delete bullet;
|
|
};
|
|
bullets.clear();
|
|
|
|
for (auto item : items)
|
|
{
|
|
delete item;
|
|
};
|
|
items.clear();
|
|
|
|
for (auto smartSprite : smartSprites)
|
|
{
|
|
delete smartSprite;
|
|
};
|
|
smartSprites.clear();
|
|
}
|
|
|
|
// Recarga las texturas
|
|
void Game::reloadTextures()
|
|
{
|
|
for (auto texture : itemTextures)
|
|
{
|
|
texture->reLoad();
|
|
}
|
|
|
|
for (auto texture : balloonTextures)
|
|
{
|
|
texture->reLoad();
|
|
}
|
|
|
|
for (auto texture : player1Textures)
|
|
{
|
|
texture->reLoad();
|
|
}
|
|
|
|
for (auto texture : player2Textures)
|
|
{
|
|
texture->reLoad();
|
|
}
|
|
|
|
bulletTexture->reLoad();
|
|
gameTextTexture->reLoad();
|
|
background->reloadTextures();
|
|
}
|
|
|
|
// Establece la máxima puntuación desde fichero o desde las puntuaciones online
|
|
void Game::setHiScore()
|
|
{
|
|
// Carga el fichero de puntos
|
|
loadScoreFile();
|
|
|
|
hiScoreName = "";
|
|
}
|
|
|
|
// Actualiza el marcador
|
|
void Game::updateScoreboard()
|
|
{
|
|
// Jugador 1
|
|
scoreboard->setScore1(players[0]->getScore());
|
|
scoreboard->setMult1(players[0]->getScoreMultiplier());
|
|
|
|
// Jugador 2
|
|
scoreboard->setScore2(players[1]->getScore());
|
|
scoreboard->setMult2(players[1]->getScoreMultiplier());
|
|
|
|
// Resto de marcador
|
|
scoreboard->setStage(stage[currentStage].number);
|
|
scoreboard->setPower((float)stage[currentStage].currentPower / (float)stage[currentStage].powerToComplete);
|
|
scoreboard->setHiScore(hiScore);
|
|
scoreboard->setHiScoreName(hiScoreName);
|
|
}
|
|
|
|
// Pausa el juego
|
|
void Game::pause(bool value)
|
|
{
|
|
paused = value;
|
|
screen->attenuate(paused);
|
|
} |