source/code/main.cpp
browsing at commit = c3a7fe3c7c0fd53f31f11be92b5435bdcf3ff048
/*
===========================================================================
blockattack - Block Attack - Rise of the Blocks
Copyright (C) 2005-2012 Poul Sander
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/
Source information and contacts persons can be found at
http://blockattack.sf.net
===========================================================================
*/
#include "common.h"
#include "global.hpp"
#include "scopeHelpers.hpp"
#include <string.h>
#ifndef VERSION_NUMBER
#define VERSION_NUMBER "version 1.5.0 BETA"
#endif
//If DEBUG is defined: AI info and FPS will be written to screen
#ifndef DEBUG
#define DEBUG 1
#endif
#define WITH_SDL 1
#include "sago/SagoSpriteHolder.hpp"
#include <iostream>
#include <stdlib.h>
#include <time.h> //Used for srand()
#include <sstream> //Still used by itoa2
#include <string>
#include "SDL.h" //The SDL libary, used for most things
#include <SDL_mixer.h> //Used for sound & music
#include <SDL_image.h> //To load PNG images!
#include <physfs.h> //Abstract file system. To use containers
#include "physfs_stream.hpp" //To use C++ style file streams
#include "Libs/NFont.h"
//#include "ttfont.h" //To use True Type Fonts in SDL
//#include "config.h"
#include <vector>
#include <SDL/SDL_video.h>
#include "MenuSystem.h"
#include "puzzlehandler.hpp"
#include <memory>
//if SHAREDIR is not used we look in current directory
#ifndef SHAREDIR
#define SHAREDIR "."
#endif
#ifndef LOCALEDIR
#define LOCALEDIR SHAREDIR"/locale"
#endif
#ifndef PACKAGE
#define PACKAGE "blockattack_roftb"
#endif
#include "highscore.h" //Stores highscores
#include "ReadKeyboard.h" //Reads text from keyboard
#include "joypad.h" //Used for joypads
#include "listFiles.h" //Used to show files on screen
#include "stats.h" //Saves general stats
//#include "uploadReplay.h" //Takes care of everything libcurl related
#include "common.h"
/*******************************************************************************
* All variables and constant has been moved to mainVars.hpp for the overview. *
*******************************************************************************/
#include "mainVars.hpp"
using namespace std;
static int InitImages(sago::SagoSpriteHolder& holder);
static string oldThemePath = "default";
void loadTheme(sago::SagoSpriteHolder& holder, const string& themeName) {
#if defined(__unix__)
string home = (string)getenv("HOME")+(string)"/.gamesaves/blockattack";
#elif defined(_WIN32)
string home = (string)getMyDocumentsPath()+(string)"/My Games/blockattack";
#endif
//Remove old theme
PHYSFS_removeFromSearchPath(oldThemePath.c_str());
//Look in blockattack.data
PHYSFS_addToSearchPath(((string)SHAREDIR+"/blockattack.data").c_str(), 1);
//Look in folder
PHYSFS_addToSearchPath( ((string) PHYSFS_getBaseDir()+"/data").c_str(), 1);
//Look in home folder
#if defined(__unix__) || defined(_WIN32)
PHYSFS_addToSearchPath(home.c_str(), 1);
#endif
if (themeName == Config::getInstance()->getString("themename")) {
//If this is a theme different from the saved one. Remember it!
Config::getInstance()->setString("themename", themeName);
}
if (themeName.compare("default")==0 || (themeName.compare("start")==0)) {
InitImages(holder);
return; //Nothing more to do
}
oldThemePath = "themes/"+themeName;
PHYSFS_addToSearchPath(oldThemePath.c_str(),0);
#if defined(__unix__) || defined(_WIN32)
PHYSFS_addToSearchPath((home+(string)"/"+oldThemePath).c_str(), 0);
#endif
InitImages(holder);
}
//Load all image files to memory
static int InitImages(sago::SagoSpriteHolder& holder) {
bricks[0] = holder.GetSprite("blue");
bricks[1] = holder.GetSprite("green");
bricks[2] = holder.GetSprite("purple");
bricks[3] = holder.GetSprite("red");
bricks[4] = holder.GetSprite("turkish");
bricks[5] = holder.GetSprite("yellow");
bricks[6] = holder.GetSprite("grey");
bomb = holder.GetSprite("block_bomb");
backgroundImage = holder.GetSprite("background");
bHighScore = holder.GetSprite("b_highscore");
bBack = holder.GetSprite("b_blank");
bForward = holder.GetSprite("b_forward");
blackLine = holder.GetSprite("black_line");
stageBobble = holder.GetSprite("i_stage_clear_limit");
crossover = holder.GetSprite("crossover");
balls[0] = holder.GetSprite("ball_blue");
balls[1] = holder.GetSprite("ball_green");
balls[2] = holder.GetSprite("ball_purple");
balls[3] = holder.GetSprite("ball_red");
balls[4] = holder.GetSprite("ball_turkish");
balls[5] = holder.GetSprite("ball_yellow");
balls[6] = holder.GetSprite("ball_gray");
cursor = holder.GetSprite("cursor");
ready = holder.GetSprite("ready");
explosion[0] = holder.GetSprite("explosion0");
explosion[1] = holder.GetSprite("explosion1");
explosion[2] = holder.GetSprite("explosion2");
explosion[3] = holder.GetSprite("explosion3");
counter[0] = holder.GetSprite("counter_1");
counter[1] = holder.GetSprite("counter_2");
counter[2] = holder.GetSprite("counter_3");
iGameOver = holder.GetSprite("i_game_over");
iWinner = holder.GetSprite("i_winner");
iDraw = holder.GetSprite("i_draw");
iLoser = holder.GetSprite("i_loser");
iChainFrame = holder.GetSprite("chain_frame");
dialogBox = holder.GetSprite("dialogbox");
iLevelCheck = holder.GetSprite("i_level_check");
iLevelCheckBox = holder.GetSprite("i_level_check_box");
iLevelCheckBoxMarked = holder.GetSprite("i_level_check_box_marked");
iCheckBoxArea = holder.GetSprite("i_check_box_area");
boardBackBack = holder.GetSprite("board_back_back");
garbageTL = holder.GetSprite("garbage_tl");
garbageT = holder.GetSprite("garbage_t");
garbageTR = holder.GetSprite("garbage_tr");
garbageR = holder.GetSprite("garbage_r");
garbageBR = holder.GetSprite("garbage_br");
garbageB = holder.GetSprite("garbage_b");
garbageBL = holder.GetSprite("garbage_bl");
garbageL = holder.GetSprite("garbage_l");
garbageFill = holder.GetSprite("garbage_fill");
garbageML = holder.GetSprite("garbage_ml");
garbageM = holder.GetSprite("garbage_m");
garbageMR = holder.GetSprite("garbage_mr");
garbageGM = holder.GetSprite("garbage_gm");
garbageGML = holder.GetSprite("garbage_gml");
garbageGMR = holder.GetSprite("garbage_gmr");
smiley[0] = holder.GetSprite("smileys0");
smiley[1] = holder.GetSprite("smileys1");
smiley[2] = holder.GetSprite("smileys2");
smiley[3] = holder.GetSprite("smileys3");
transCover = holder.GetSprite("trans_cover");
bSkip = holder.GetSprite("b_blank");
bNext = holder.GetSprite("b_blank");
bRetry = holder.GetSprite("b_blank");
mouse = holder.GetSprite("mouse");
menuMarked = holder.GetSprite("menu_marked");
menuUnmarked = holder.GetSprite("menu_unmarked");
backBoard = holder.GetSprite("back_board");
SDL_Color nf_button_color, nf_standard_blue_color, nf_standard_small_color;
memset(&nf_button_color,0,sizeof(SDL_Color));
nf_button_color.b = 255;
nf_button_color.g = 255;
nf_button_color.r = 255;
nf_button_color.a = 255;
nf_standard_blue_color.b = 255;
nf_standard_blue_color.g = 0;
nf_standard_blue_color.r = 0;
nf_standard_blue_color.a = 255;
nf_standard_small_color.b = 0;
nf_standard_small_color.g = 0;
nf_standard_small_color.r = 200;
nf_standard_small_color.a = 255;
nf_button_font.load(screen, holder.GetDataHolder().getFontPtr("freeserif", 24), nf_button_color);
nf_standard_blue_font.load(screen, holder.GetDataHolder().getFontPtr("freeserif", 30), nf_standard_blue_color);
nf_standard_small_font.load(screen, holder.GetDataHolder().getFontPtr("freeserif", 16), nf_standard_small_color);
nf_scoreboard_font.load(screen, holder.GetDataHolder().getFontPtr("penguinattack", 20), nf_button_color);
//Loads the sound if sound present
if (!NoSound) {
//And here the music:
bgMusic = holder.GetDataHolder().getMusicPtr("bgmusic");
highbeatMusic = holder.GetDataHolder().getMusicPtr("highbeat");
//the music... we just hope it exists, else the user won't hear anything
//Same goes for the sounds
boing = holder.GetDataHolder().getSoundPtr("pop");
applause = holder.GetDataHolder().getSoundPtr("applause");
photoClick = holder.GetDataHolder().getSoundPtr("cameraclick");
typingChunk = holder.GetDataHolder().getSoundPtr("typing");
counterChunk = holder.GetDataHolder().getSoundPtr("counter");
counterFinalChunk = holder.GetDataHolder().getSoundPtr("counter_final");
} //All sound has been loaded or not
return 0;
} //InitImages()
static stringstream converter;
//Function to convert numbers to string (2 diget)
static string itoa2(int num) {
converter.str(std::string());
converter.clear();
if (num<10) {
converter << "0";
}
converter << num;
return converter.str();
}
/*Draws a image from on a given Surface. Takes source image, destination surface and coordinates*/
void DrawIMG(sago::SagoSprite& sprite, SDL_Renderer* target, int x, int y) {
sprite.Draw(target, SDL_GetTicks() ,x,y);
}
void DrawIMG_Bounded(sago::SagoSprite& sprite, SDL_Renderer* target, int x, int y, int minx, int miny, int maxx, int maxy) {
SDL_Rect bounds;
bounds.x = minx;
bounds.y = miny;
bounds.w = maxx-minx;
bounds.h = maxy-miny;
sprite.DrawBounded(target, SDL_GetTicks(),x,y,bounds);
}
void NFont_Write(SDL_Renderer* target, int x, int y, const string& text) {
nf_standard_blue_font.draw(target, x, y, "%s", text.c_str());
}
void ResetFullscreen() {
#if defined(_WIN32)
/* if (bFullscreen) {
screen=SDL_SetVideoMode(xsize,ysize,32,SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ANYFORMAT);
}
else {
screen=SDL_SetVideoMode(xsize,ysize,32,SDL_SWSURFACE|SDL_ANYFORMAT);
}
DrawIMG(background, screen, 0, 0);
*/
#else
//TODO: Find SDL2 alternative
//SDL_WM_ToggleFullScreen(screen); //Will only work in Linux
#endif
SDL_ShowCursor(SDL_DISABLE);
}
//The small things that are faaling when you clear something
class aBall {
private:
double x;
double y;
double velocityY;
double velocityX;
int color;
unsigned long int lastTime;
public:
aBall() {
}
//constructor:
aBall(int X, int Y, bool right, int coulor) {
double tal = 1.0+((double)rand()/((double)RAND_MAX));
velocityY = -tal*startVelocityY;
lastTime = currentTime;
x = (double)X;
y = (double)Y;
color = coulor;
if (right) {
velocityX = tal*VelocityX;
}
else {
velocityX = -tal*VelocityX;
}
} //constructor
void update() {
double timePassed = (((double)(currentTime-lastTime))/1000.0); //time passed in seconds
x = x+timePassed*velocityX;
y = y+timePassed*velocityY;
velocityY = velocityY + gravity*timePassed;
if (y<1.0) {
velocityY=10.0;
}
if ((velocityY>minVelocity) && (y>(double)(768-ballSize)) && (y<768.0)) {
velocityY = -0.70*velocityY;
y = 768.0-ballSize;
}
lastTime = currentTime;
}
int getX() {
return (int)x;
}
int getY() {
return (int)y;
}
int getColor() {
return color;
}
}; //aBall
static const int maxNumberOfBalls = 6*12*2*2;
class ballManeger {
public:
aBall ballArray[maxNumberOfBalls];
bool ballUsed[maxNumberOfBalls];
ballManeger() {
for (int i=0; i<maxNumberOfBalls; i++) {
ballUsed[i] = false;
}
}
//Adds a ball to the screen at given coordiantes, traveling right or not with color
int addBall(int x, int y,bool right,int color) {
int ballNumber = 0;
//Find a free ball
while ((ballUsed[ballNumber])&&(ballNumber<maxNumberOfBalls)) {
ballNumber++;
}
//Could not find a free ball, return -1
if (ballNumber==maxNumberOfBalls) {
return -1;
}
currentTime = SDL_GetTicks();
ballArray[ballNumber] = aBall(x,y,right,color);
ballUsed[ballNumber] = true;
return 1;
} //addBall
void update() {
currentTime = SDL_GetTicks();
for (int i = 0; i<maxNumberOfBalls; i++) {
if (ballUsed[i]) {
ballArray[i].update();
if (ballArray[i].getY()>800 || ballArray[i].getX()>xsize || ballArray[i].getX()<-ballSize) {
ballUsed[i] = false;
}
}
}
} //update
}; //theBallManeger
static ballManeger theBallManeger;
//a explosions, non moving
class anExplosion {
private:
int x;
int y;
Uint8 frameNumber;
#define frameLength 80
//How long an image in an animation should be showed
#define maxFrame 4
//How many images there are in the animation
unsigned long int placeTime; //Then the explosion occored
public:
anExplosion() {
}
//constructor:
anExplosion(int X, int Y) {
placeTime = currentTime;
x = X;
y = Y;
frameNumber=0;
} //constructor
//true if animation has played and object should be removed from the screen
bool removeMe() {
frameNumber = (currentTime-placeTime)/frameLength;
return (!(frameNumber<maxFrame));
}
int getX() {
return (int)x;
}
int getY() {
return (int)y;
}
int getFrame() {
return frameNumber;
}
}; //nExplosion
class explosionManeger {
public:
anExplosion explosionArray[maxNumberOfBalls];
bool explosionUsed[maxNumberOfBalls];
explosionManeger() {
for (int i=0; i<maxNumberOfBalls; i++) {
explosionUsed[i] = false;
}
}
int addExplosion(int x, int y) {
int explosionNumber = 0;
while ((explosionUsed[explosionNumber])&&(explosionNumber<maxNumberOfBalls)) {
explosionNumber++;
}
if (explosionNumber==maxNumberOfBalls) {
return -1;
}
currentTime = SDL_GetTicks();
explosionArray[explosionNumber] = anExplosion(x,y);
explosionUsed[explosionNumber] = true;
return 1;
} //addBall
void update() {
currentTime = SDL_GetTicks();
for (int i = 0; i<maxNumberOfBalls; i++) {
if (explosionUsed[i]) {
if (explosionArray[i].removeMe()) {
explosionUsed[i] = false;
}
}
}
} //update
}; //explosionManeger
static explosionManeger theExplosionManeger;
//text pop-up
class textMessage {
private:
int x;
int y;
string textt;
unsigned long int time;
unsigned long int placeTime; //Then the text was placed
public:
textMessage() {
}
//constructor:
textMessage(int X, int Y,const char* Text,unsigned int Time) {
placeTime = currentTime;
x = X;
y = Y;
textt = Text;
time = Time;
} //constructor
//true if the text has expired
bool removeMe() {
return currentTime-placeTime>time;
}
int getX() {
return x;
}
int getY() {
return y;
}
const char* getText() {
return textt.c_str();
}
}; //text popup
class textManeger {
public:
textMessage textArray[maxNumberOfBalls];
bool textUsed[maxNumberOfBalls];
textManeger() {
for (int i=0; i<maxNumberOfBalls; i++) {
textUsed[i] = false;
}
}
int addText(int x, int y,string Text,unsigned int Time) {
int textNumber = 0;
while (textNumber<maxNumberOfBalls && textUsed[textNumber]) {
textNumber++;
}
if (textNumber==maxNumberOfBalls) {
return -1;
}
currentTime = SDL_GetTicks();
textArray[textNumber] = textMessage(x,y,Text.c_str(),Time);
textUsed[textNumber] = true;
return 1;
} //addText
void update() {
currentTime = SDL_GetTicks();
for (int i = 0; i<maxNumberOfBalls; i++) {
if (textUsed[i]) {
if (textArray[i].removeMe()) {
textUsed[i] = false;
}
}
}
} //update
}; //textManeger
static textManeger theTextManeger;
//Here comes the Block Game object
#include "BlockGame.hpp"
#include "BlockGame.cpp"
class BlockGameSdl : public BlockGame {
public:
BlockGameSdl(int tx, int ty) {
topx = tx;
topy = ty;
}
void DrawImgBoard(sago::SagoSprite& img, int x, int y) const {
DrawIMG(img, screen, x+topx, y+topy);
}
void DrawImgBoardBounded(sago::SagoSprite& img, int x, int y) const {
DrawIMG_Bounded(img, screen, x+topx, y+topy, topx, topy, topx + backBoard.GetWidth(), topy + backBoard.GetHeight());
}
void PrintTextCenteredBoard(int x, int y, const char* text) {
nf_button_font.draw(screen, x+topx+60, y+topy+10, NFont::CENTER, "%s", text);
}
int GetTopX() const {
return topx;
}
int GetTopY() const {
return topy;
}
void AddText(int x, int y, const std::string& text, int time) const override {
theTextManeger.addText(topx-10+x*bsize, topy+12*bsize-y*bsize, text, time);
}
void AddBall(int x, int y, bool right, int color) const override {
theBallManeger.addBall(topx+40+x*bsize, topy+bsize*12-y*bsize, right, color);
}
void AddExplosion(int x, int y) const override {
theExplosionManeger.addExplosion(topx-10+x*bsize, topy+bsize*12-10-y*bsize);
}
void PlayerWonEvent() const override {
if (!SoundEnabled) {
return;
}
Mix_PlayChannel(1, applause, 0);
}
void DrawEvent() const override {
Mix_HaltChannel(1);
}
void BlockPopEvent() const override {
if (!SoundEnabled) {
return;
}
Mix_PlayChannel(0, boing, 0);
}
void LongChainDoneEvent() const override {
if (!SoundEnabled) {
return;
}
Mix_PlayChannel(1, applause, 0);
}
void TimeTrialEndEvent() const override {
if (!NoSound && SoundEnabled) {
Mix_PlayChannel(1,counterFinalChunk,0);
}
}
void EndlessHighscoreEvent() const override {
if (!SoundEnabled) {
return;
}
Mix_PlayChannel(1, applause, 0);
}
private:
//Draws all the bricks to the board (including garbage)
void PaintBricks() const {
for (int i=0; ((i<13)&&(i<30)); i++)
for (int j=0; j<6; j++) {
if ((board[j][i]%10 != -1) && (board[j][i]%10 < 7) && ((board[j][i]/1000000)%10==0)) {
DrawImgBoardBounded(bricks[board[j][i]%10], j*bsize, bsize*12-i*bsize-pixels);
if ((board[j][i]/BLOCKWAIT)%10==1) {
DrawImgBoard(bomb, j*bsize, bsize*12-i*bsize-pixels);
}
if ((board[j][i]/BLOCKHANG)%10==1) {
DrawImgBoardBounded(ready, j*bsize, bsize*12-i*bsize-pixels);
}
}
if ((board[j][i]/1000000)%10==1) {
int left, right, over, under;
int number = board[j][i];
if (j<1) {
left = -1;
}
else {
left = board[j-1][i];
}
if (j>5) {
right = -1;
}
else {
right = board[j+1][i];
}
if (i>28) {
over = -1;
}
else {
over = board[j][i+1];
}
if (i<1) {
under = -1;
}
else {
under = board[j][i-1];
}
if ((left == number)&&(right == number)&&(over == number)&&(under == number)) {
DrawImgBoardBounded(garbageFill, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left != number)&&(right == number)&&(over == number)&&(under == number)) {
DrawImgBoardBounded(garbageL, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left == number)&&(right != number)&&(over == number)&&(under == number)) {
DrawImgBoardBounded(garbageR, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left == number)&&(right == number)&&(over != number)&&(under == number)) {
DrawImgBoardBounded(garbageT, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left == number)&&(right == number)&&(over == number)&&(under != number)) {
DrawImgBoardBounded(garbageB, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left != number)&&(right == number)&&(over != number)&&(under == number)) {
DrawImgBoardBounded(garbageTL, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left != number)&&(right == number)&&(over == number)&&(under != number)) {
DrawImgBoardBounded(garbageBL, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left == number)&&(right != number)&&(over != number)&&(under == number)) {
DrawImgBoardBounded(garbageTR, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left == number)&&(right != number)&&(over == number)&&(under != number)) {
DrawImgBoardBounded(garbageBR, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left == number)&&(right != number)&&(over != number)&&(under != number)) {
DrawImgBoardBounded(garbageMR, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left == number)&&(right == number)&&(over != number)&&(under != number)) {
DrawImgBoardBounded(garbageM, j*bsize, bsize*12-i*bsize-pixels);
}
if ((left != number)&&(right == number)&&(over != number)&&(under != number)) {
DrawImgBoardBounded(garbageML, j*bsize, bsize*12-i*bsize-pixels);
}
}
if ((board[j][i]/1000000)%10==2) {
if (j==0) {
DrawImgBoardBounded(garbageGML, j*bsize, bsize*12-i*bsize-pixels);
}
else if (j==5) {
DrawImgBoardBounded(garbageGMR, j*bsize, bsize*12-i*bsize-pixels);
}
else {
DrawImgBoardBounded(garbageGM, j*bsize, bsize*12-i*bsize-pixels);
}
}
}
const int j = 0;
int garbageSize=0;
for (int i=0; i<20; i++) {
if ((board[j][i]/1000000)%10==1) {
int left, right, over, under;
int number = board[j][i];
if (j<1) {
left = -1;
}
else {
left = board[j-1][i];
}
if (j>5) {
right = -1;
}
else {
right = board[j+1][i];
}
if (i>28) {
over = -1;
}
else {
over = board[j][i+1];
}
if (i<1) {
under = -1;
}
else {
under = board[j][i-1];
}
if (((left != number)&&(right == number)&&(over != number)&&(under == number))&&(garbageSize>0)) {
DrawImgBoardBounded(smiley[board[j][i]%4], 2*bsize, 12*bsize-i*bsize-pixels+(bsize/2)*garbageSize);
}
if (!((left != number)&&(right == number)&&(over == number)&&(under == number))) { //not in garbage
garbageSize=0;
}
else {
garbageSize++;
}
}
}
for (int i=0; i<6; i++) {
if (board[i][0]!=-1) {
DrawImgBoardBounded(transCover, i*bsize, 12*bsize-pixels); //Make the appering blocks transperant
}
}
}
public:
//Draws everything
void DoPaintJob() {
DrawIMG(boardBackBack,screen,this->GetTopX()-60,this->GetTopY()-68);
nf_scoreboard_font.draw(screen, this->GetTopX()+310,this->GetTopY()-68+148,_("Score:") );
nf_scoreboard_font.draw(screen, this->GetTopX()+310,this->GetTopY()-68+197,_("Time:") );
nf_scoreboard_font.draw(screen, this->GetTopX()+310,this->GetTopY()-68+246,_("Chain:") );
nf_scoreboard_font.draw(screen, this->GetTopX()+310,this->GetTopY()-68+295,_("Speed:") );
DrawImgBoard(backBoard, 0, 0);
PaintBricks();
if (stageClear) {
DrawImgBoard(blackLine, 0, bsize*(12+2)+bsize*(stageClearLimit-linesCleared)-pixels-1);
}
if (puzzleMode&&(!bGameOver)) {
//We need to write nr. of moves left!
strHolder = "Moves left: " + itoa(MovesLeft);
nf_standard_blue_font.draw(screen, topx+5, topy+5, "%s",strHolder.c_str());
}
if (puzzleMode && stageButtonStatus == SBpuzzleMode) {
DrawImgBoard(bRetry, cordRetryButton.x, cordRetryButton.y);
PrintTextCenteredBoard(cordRetryButton.x, cordRetryButton.y, _("Retry"));
if (Level<PuzzleGetNumberOfPuzzles()-1) {
if (hasWonTheGame) {
DrawImgBoard(bNext,cordNextButton.x, cordNextButton.y);
PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, _("Next"));
}
else {
DrawImgBoard(bSkip,cordNextButton.x, cordNextButton.y);
PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, _("Skip"));
}
}
else {
strHolder = "Last puzzle";
nf_standard_blue_font.draw(screen, topx+5, topy+5, "%s",strHolder.c_str());
}
}
if (stageClear && stageButtonStatus == SBstageClear) {
DrawImgBoard(bRetry, cordRetryButton.x, cordRetryButton.y);
PrintTextCenteredBoard(cordRetryButton.x, cordRetryButton.y, _("Retry"));
if (Level<50-1) {
if (hasWonTheGame) {
DrawImgBoard(bNext,cordNextButton.x, cordNextButton.y);
PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, _("Next"));
}
else {
DrawImgBoard(bSkip,cordNextButton.x, cordNextButton.y);
PrintTextCenteredBoard(cordNextButton.x, cordNextButton.y, _("Skip"));
}
}
else {
strHolder = "Last stage";
nf_standard_blue_font.draw(screen, topx+5, topy+5, "%s",strHolder.c_str());
}
}
#if DEBUG
if (AI_Enabled&&(!bGameOver)) {
strHolder = "AI_status: " + itoa(AIstatus)+ ", "+ itoa(AIlineToClear);
//NFont_Write( 5, 5, strHolder.c_str());
nf_standard_blue_font.draw(screen, topx+5, topy+5, "%s",strHolder.c_str());
}
#endif
if (!bGameOver) {
DrawImgBoard(cursor,cursorx*bsize-4,11*bsize-cursory*bsize-pixels-4);
}
if (ticks<gameStartedAt) {
int currentCounter = abs((int)ticks-(int)gameStartedAt)/1000;
if ( (currentCounter!=lastCounter) && (SoundEnabled)&&(!NoSound)) {
Mix_PlayChannel(1,counterChunk,0);
}
lastCounter = currentCounter;
switch (currentCounter) {
case 2:
DrawImgBoard(counter[2], 2*bsize, 5*bsize);
break;
case 1:
DrawImgBoard(counter[1], 2*bsize, 5*bsize);
break;
case 0:
DrawImgBoard(counter[0], 2*bsize, 5*bsize);
break;
default:
break;
}
}
else {
if (SoundEnabled&&(!NoSound)&&(timetrial)&&(ticks>gameStartedAt+10000)&&(!bGameOver)) {
int currentCounter = (ticks-(int)gameStartedAt)/1000;
if (currentCounter!=lastCounter) {
if (currentCounter>115 && currentCounter<120) {
Mix_PlayChannel(1,counterChunk,0);
}
}
lastCounter = currentCounter;
}
else {
if ( (0==lastCounter) && (SoundEnabled)&&(!NoSound)) {
Mix_PlayChannel(1,counterFinalChunk,0);
}
lastCounter = -1;
}
}
if ((bGameOver)&&(!editorMode)) {
if (hasWonTheGame) {
DrawImgBoard(iWinner, 0, 5*bsize);
}
else {
if (bDraw) {
DrawImgBoard(iDraw, 0, 5*bsize);
}
else {
DrawImgBoard(iGameOver, 0, 5*bsize);
}
}
}
}
void Update(int newtick) {
BlockGame::Update(newtick);
}
private:
int topx, topy;
};
//writeScreenShot saves the screen as a bmp file, it uses the time to get a unique filename
void writeScreenShot() {
if (verboseLevel) {
cout << "Saving screenshot" << endl;
}
int rightNow = (int)time(nullptr);
/*#if defined(__unix__)
char buf[514];
snprintf( buf, sizeof(buf), "%s/.gamesaves/blockattack/screenshots/screenshot%i.bmp", getenv("HOME"), rightNow );
#elif defined(__win32__)
char buf[MAX_PATH];
snprintf( buf, sizeof(buf), "%s\\My Games\\blockattack\\screenshots\\screenshot%i.bmp", (getMyDocumentsPath()).c_str(), rightNow );
#else
char buf[MAX_PATH];
snprintf( buf, sizeof(buf), "screenshot%i.bmp", rightNow );
#endif*/
#if defined(__unix__)
string buf = (string)getenv("HOME")+"/.gamesaves/blockattack/screenshots/screenshot"+itoa(rightNow)+".bmp";
#elif defined(__win32__)
string buf = getMyDocumentsPath()+"\\My Games\\blockattack\\screenshots\\screenshot"+itoa(rightNow)+".bmp";
#else
string buf = "screenshot"+itoa(rightNow)+".bmp";
#endif
//SDL_SaveBMP( screen, buf.c_str() );
//TODO: Write screenshot
if (!NoSound) {
if (SoundEnabled) {
Mix_PlayChannel(1,photoClick,0);
}
}
}
//Function to return the name of a key, to be displayed...
static string getKeyName(SDL_Keycode key) {
string keyname(SDL_GetKeyName(key));
return keyname;
}
//Dialogbox
bool OpenDialogbox(int x, int y, std::string& name) {
bool done = false; //We are done!
bool accept = false; //New name is accepted! (not Cancelled)
SDL_TextInput textInputScope;
ReadKeyboard rk = ReadKeyboard(name.c_str());
string strHolder;
DrawIMG(backgroundImage,screen,0,0);
while (!done && !Config::getInstance()->isShuttingDown()) {
DrawIMG(dialogBox,screen,x,y);
NFont_Write(screen, x+40,y+76,rk.GetString());
strHolder = rk.GetString();
strHolder.erase((int)rk.CharsBeforeCursor());
if (((SDL_GetTicks()/600)%2)==1) {
NFont_Write(screen, x+40+nf_standard_blue_font.getWidth( "%s", strHolder.c_str()),y+76,"|");
}
SDL_Event event;
while ( SDL_PollEvent(&event) ) {
if ( event.type == SDL_QUIT ) {
Config::getInstance()->setShuttingDown(5);
done = true;
accept = false;
}
if (event.type == SDL_TEXTINPUT) {
if ((rk.ReadKey(event))&&(SoundEnabled)&&(!NoSound)) {
Mix_PlayChannel(1,typingChunk,0);
}
}
if ( event.type == SDL_KEYDOWN ) {
if ( (event.key.keysym.sym == SDLK_RETURN)||(event.key.keysym.sym == SDLK_KP_ENTER) ) {
done = true;
accept = true;
}
else if ( (event.key.keysym.sym == SDLK_ESCAPE) ) {
done = true;
accept = false;
}
else {
if ((rk.ReadKey(event))&&(SoundEnabled)&&(!NoSound)) {
Mix_PlayChannel(1,typingChunk,0);
}
}
}
} //while(event)
SDL_RenderPresent(screen); //Update screen
} //while(!done)
name = rk.GetString();
bScreenLocked = false;
showDialog = false;
return accept;
}
//Draws the highscores
void DrawHighscores(int x, int y, bool endless) {
DrawIMG(backgroundImage,screen,0,0);
if (endless) {
nf_standard_blue_font.draw(screen, x+100,y+100, "%s",_("Endless:") );
}
else {
nf_standard_blue_font.draw(screen, x+100,y+100, "%s",_("Time Trial:") );
}
for (int i =0; i<10; i++) {
char playerScore[32];
char playerName[32];
if (endless) {
snprintf(playerScore, sizeof(playerScore), "%i", theTopScoresEndless.getScoreNumber(i));
}
else {
snprintf(playerScore, sizeof(playerScore), "%i", theTopScoresTimeTrial.getScoreNumber(i));
}
if (endless) {
strcpy(playerName,theTopScoresEndless.getScoreName(i));
}
else {
strcpy(playerName,theTopScoresTimeTrial.getScoreName(i));
}
nf_standard_blue_font.draw(screen, x+420,y+150+i*35, "%s",playerScore);
nf_standard_blue_font.draw(screen, x+60,y+150+i*35, "%s",playerName);
}
}
void DrawStats() {
DrawIMG(backgroundImage,screen,0,0);
int y = 5;
const int y_spacing = 30;
NFont_Write(screen, 10,y,_("Stats") );
y+=y_spacing*2;
NFont_Write(screen, 10,y,_("Chains") );
for (int i=2; i<13; i++) {
y+=y_spacing;
NFont_Write(screen, 10,y,(itoa(i)+"X").c_str());
string numberAsString = itoa(Stats::getInstance()->getNumberOf("chainX"+itoa(i)));
NFont_Write(screen, 300,y,numberAsString.c_str());
}
y+=y_spacing*2;
NFont_Write(screen, 10,y,_("Lines Pushed: ") );
string numberAsString = itoa(Stats::getInstance()->getNumberOf("linesPushed"));
NFont_Write(screen, 300,y,numberAsString.c_str());
y+=y_spacing;
NFont_Write(screen, 10,y, _("Puzzles solved: ") );
numberAsString = itoa(Stats::getInstance()->getNumberOf("puzzlesSolved"));
NFont_Write(screen, 300,y,numberAsString.c_str());
y+=y_spacing*2;
NFont_Write(screen, 10,y, _("Run time: ") );
commonTime ct = TimeHandler::peekTime("totalTime",TimeHandler::ms2ct(SDL_GetTicks()));
y+=y_spacing;
NFont_Write(screen, 10,y,((string)( _("Days: ")+itoa(ct.days))).c_str());
y+=y_spacing;
NFont_Write(screen, 10,y,((string)( _("Hours: ")+itoa(ct.hours))).c_str());
y+=y_spacing;
NFont_Write(screen, 10,y,((string)( _("Minutes: ")+itoa(ct.minutes))).c_str());
y+=y_spacing;
NFont_Write(screen, 10,y,((string)( _("Seconds: ")+itoa(ct.seconds))).c_str());
y-=y_spacing*4; //Four rows back
const int x_offset3 = xsize/3+10; //Ofset for three rows
NFont_Write(screen, x_offset3,y, _("Play time: ") );
ct = TimeHandler::getTime("playTime");
y+=y_spacing;
NFont_Write(screen, x_offset3,y,((string)( _("Days: ")+itoa(ct.days))).c_str());
y+=y_spacing;
NFont_Write(screen, x_offset3,y,((string)( _("Hours: ")+itoa(ct.hours))).c_str());
y+=y_spacing;
NFont_Write(screen, x_offset3,y,((string)( _("Minutes: ")+itoa(ct.minutes))).c_str());
y+=y_spacing;
NFont_Write(screen, x_offset3,y,((string)( _("Seconds: ")+itoa(ct.seconds))).c_str());
const int x_offset = xsize/2+10;
y = 5+y_spacing*2;
NFont_Write(screen, x_offset,y, _("VS CPU (win/loss)") );
for (int i=0; i<7; i++) {
y += y_spacing;
NFont_Write(screen, x_offset,y,string("AI "+itoa(i+1)).c_str());
numberAsString = itoa(Stats::getInstance()->getNumberOf("defeatedAI"+itoa(i)));
string numberAsString2 = itoa(Stats::getInstance()->getNumberOf("defeatedByAI"+itoa(i)));
string toPrint = numberAsString + "/" + numberAsString2;
NFont_Write(screen, x_offset+230,y,toPrint.c_str());
}
}
void OpenScoresDisplay() {
int mousex,mousey;
bool done = false; //We are done!
int page = 0;
const int numberOfPages = 3;
//button coodinates:
const int scoreX = buttonXsize*2;
const int scoreY = 0;
const int backX = 20;
const int backY = ysize-buttonYsize-20;
const int nextX = xsize-buttonXsize-20;
const int nextY = backY;
while (!done && !Config::getInstance()->isShuttingDown()) {
switch (page) {
case 0:
//Highscores, endless
DrawHighscores(100,100,true);
break;
case 1:
//Highscores, Time Trial
DrawHighscores(100,100,false);
break;
case 2:
default:
DrawStats();
};
//Draw buttons:
DrawIMG(bHighScore,screen,scoreX,scoreY);
DrawIMG(bBack,screen,backX,backY);
nf_button_font.draw(screen, backX+60,backY+10, NFont::CENTER ,_("Back"));
DrawIMG(bNext,screen,nextX,nextY);
nf_button_font.draw(screen, nextX+60,nextY+10, NFont::CENTER,_("Next"));
//Draw page number
string pageXofY = (boost::format(_("Page %1% of %2%") )%(page+1)%numberOfPages).str();
NFont_Write(screen, xsize/2-nf_standard_blue_font.getWidth( "%s", pageXofY.c_str())/2,ysize-60,pageXofY.c_str());
SDL_Delay(1);
SDL_Event event;
SDL_GetMouseState(&mousex,&mousey);
while ( SDL_PollEvent(&event) ) {
if ( event.type == SDL_QUIT ) {
Config::getInstance()->setShuttingDown(5);
done = true;
}
if ( event.type == SDL_KEYDOWN ) {
if ( (event.key.keysym.sym == SDLK_RIGHT)) {
page++;
if (page>=numberOfPages) {
page = 0;
}
}
else if ( (event.key.keysym.sym == SDLK_LEFT)) {
page--;
if (page<0) {
page = numberOfPages-1;
}
}
else {
done = true;
}
if ( event.key.keysym.sym == SDLK_F9 ) {
writeScreenShot();
}
if ( (event.key.keysym.sym == SDLK_RETURN)||(event.key.keysym.sym == SDLK_KP_ENTER) ) {
done = true;
}
else if ( (event.key.keysym.sym == SDLK_ESCAPE) ) {
done = true;
}
}
} //while(event)
// If the mouse button is released, make bMouseUp equal true
if (!SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) {
bMouseUp=true;
}
if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
bMouseUp = false;
//The Score button:
if ((mousex>scoreX) && (mousex<scoreX+buttonXsize) && (mousey>scoreY) && (mousey<scoreY+buttonYsize)) {
done =true;
}
//The back button:
if ((mousex>backX) && (mousex<backX+buttonXsize) && (mousey>backY) && (mousey<backY+buttonYsize)) {
page--;
if (page<0) {
page = numberOfPages-1;
}
}
//The next button:
if ((mousex>nextX) && (mousex<nextX+buttonXsize) && (mousey>nextY) && (mousey<nextY+buttonYsize)) {
page++;
if (page>=numberOfPages) {
page = 0;
}
}
}
mouse.Draw(screen, SDL_GetTicks(), mousex, mousey);
SDL_RenderPresent(screen);
}
}
//Open a puzzle file
bool OpenFileDialogbox(int x, int y, char* name) {
bool done = false; //We are done!
int mousex, mousey;
ListFiles lf = ListFiles();
string folder = (string)SHAREDIR+(string)"/puzzles";
if (verboseLevel) {
cout << "Looking in " << folder << endl;
}
lf.setDirectory(folder.c_str());
#ifdef __unix__
string homeFolder = (string)getenv("HOME")+(string)"/.gamesaves/blockattack/puzzles";
lf.setDirectory2(homeFolder.c_str());
#endif
while (!done && !Config::getInstance()->isShuttingDown()) {
DrawIMG(backgroundImage,screen,0,0);
DrawIMG(bForward,screen,x+460,y+420);
nf_button_font.draw(screen, x+20+60, y+420+10, NFont::CENTER, _("Forward"));
DrawIMG(bBack,screen,x+20,y+420);
nf_button_font.draw(screen, x+20+60, y+420+10, NFont::CENTER, _("Back"));
const int nrOfFiles = 10;
for (int i=0; i<nrOfFiles; i++) {
NFont_Write(screen, x+10,y+10+36*i,lf.getFileName(i).c_str());
}
SDL_Event event;
while ( SDL_PollEvent(&event) ) {
if ( event.type == SDL_QUIT ) {
Config::getInstance()->setShuttingDown(5);
done = true;
}
if ( event.type == SDL_KEYDOWN ) {
if ( (event.key.keysym.sym == SDLK_ESCAPE) ) {
done = true;
}
if ( (event.key.keysym.sym == SDLK_RIGHT) ) {
lf.forward();
}
if ( (event.key.keysym.sym == SDLK_LEFT) ) {
lf.back();
}
}
} //while(event)
SDL_GetMouseState(&mousex,&mousey);
// If the mouse button is released, make bMouseUp equal true
if (!SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) {
bMouseUp=true;
}
if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
bMouseUp = false;
//The Forward Button:
if ( (mousex>x+460) && (mousex<x+460+buttonXsize) && (mousey>y+420) && (mousey<y+420+40) ) {
lf.forward();
}
//The back button:
if ( (mousex>x+20) && (mousex<x+20+buttonXsize) && (mousey>y+420) && (mousey<y+420+40) ) {
lf.back();
}
for (int i=0; i<10; i++) {
if ( (mousex>x+10) && (mousex<x+480) && (mousey>y+10+i*36) && (mousey<y+10+i*36+32) ) {
if (lf.fileExists(i)) {
strncpy(name,lf.getFileName(i).c_str(),28); //Problems occurs then larger than 28 (maybe 29)
done=true; //The user have, clicked the purpose of this function is now complete
}
}
}
}
mouse.Draw(screen, SDL_GetTicks(), mousex, mousey);
SDL_RenderPresent(screen); //Update screen
}
return true;
}
//Draws the balls and explosions
static void DrawBalls() {
for (int i = 0; i< maxNumberOfBalls; i++) {
if (theBallManeger.ballUsed[i]) {
DrawIMG(balls[theBallManeger.ballArray[i].getColor()],screen,theBallManeger.ballArray[i].getX(),theBallManeger.ballArray[i].getY());
} //if used
if (theExplosionManeger.explosionUsed[i]) {
DrawIMG(explosion[theExplosionManeger.explosionArray[i].getFrame()],screen,theExplosionManeger.explosionArray[i].getX(),theExplosionManeger.explosionArray[i].getY());
}
if (theTextManeger.textUsed[i]) {
//cout << "Printing text: " << theTextManeger.textArray[i].getText() << endl;
int x = theTextManeger.textArray[i].getX()-12;
int y = theTextManeger.textArray[i].getY()-12;
DrawIMG(iChainFrame,screen,x,y);
nf_standard_small_font.draw(screen, x+12,y+7, NFont::CENTER, "%s",theTextManeger.textArray[i].getText());
}
} //for
} //DrawBalls
//draws everything
void DrawEverything(int xsize, int ysize,BlockGameSdl* theGame, BlockGameSdl* theGame2) {
SDL_ShowCursor(SDL_DISABLE);
DrawIMG(backgroundImage,screen,0,0);
theGame->DoPaintJob();
theGame2->DoPaintJob();
string strHolder;
strHolder = itoa(theGame->GetScore()+theGame->GetHandicap());
NFont_Write(screen, theGame->GetTopX()+310,theGame->GetTopY()+100,strHolder.c_str());
if (theGame->GetAIenabled()) {
NFont_Write(screen, theGame->GetTopX()+10,theGame->GetTopY()-34,_("AI") );
}
else if (editorMode) {
NFont_Write(screen, theGame->GetTopX()+10,theGame->GetTopY()-34,_("Playing field") );
}
else if (!singlePuzzle) {
NFont_Write(screen, theGame->GetTopX()+10,theGame->GetTopY()-34,player1name);
}
if (theGame->isTimeTrial()) {
int tid = (int)SDL_GetTicks()-theGame->GetGameStartedAt();
int minutes;
int seconds;
if (tid>=0) {
minutes = (2*60*1000-(abs((int)SDL_GetTicks()-(int)theGame->GetGameStartedAt())))/60/1000;
seconds = ((2*60*1000-(abs((int)SDL_GetTicks()-(int)theGame->GetGameStartedAt())))%(60*1000))/1000;
}
else {
minutes = ((abs((int)SDL_GetTicks()-(int)theGame->GetGameStartedAt())))/60/1000;
seconds = (((abs((int)SDL_GetTicks()-(int)theGame->GetGameStartedAt())))%(60*1000))/1000;
}
if (theGame->isGameOver()) {
minutes=0;
}
if (theGame->isGameOver()) {
seconds=0;
}
if (seconds>9) {
strHolder = itoa(minutes)+":"+itoa(seconds);
}
else {
strHolder = itoa(minutes)+":0"+itoa(seconds);
}
//if ((SoundEnabled)&&(!NoSound)&&(tid>0)&&(seconds<5)&&(minutes == 0)&&(seconds>1)&&(!(Mix_Playing(6)))) Mix_PlayChannel(6,heartBeat,0);
NFont_Write(screen, theGame->GetTopX()+310,theGame->GetTopY()+150,strHolder.c_str());
}
else {
int minutes = ((abs((int)SDL_GetTicks()-(int)theGame->GetGameStartedAt())))/60/1000;
int seconds = (((abs((int)SDL_GetTicks()-(int)theGame->GetGameStartedAt())))%(60*1000))/1000;
if (theGame->isGameOver()) {
minutes=(theGame->GetGameEndedAt()/1000/60)%100;
}
if (theGame->isGameOver()) {
seconds=(theGame->GetGameEndedAt()/1000)%60;
}
if (seconds>9) {
strHolder = itoa(minutes)+":"+itoa(seconds);
}
else {
strHolder = itoa(minutes)+":0"+itoa(seconds);
}
NFont_Write(screen, theGame->GetTopX()+310,theGame->GetTopY()+150,strHolder.c_str());
}
strHolder = itoa(theGame->GetChains());
NFont_Write(screen, theGame->GetTopX()+310,theGame->GetTopY()+200,strHolder.c_str());
//drawspeedLevel:
strHolder = itoa(theGame->GetSpeedLevel());
NFont_Write(screen, theGame->GetTopX()+310,theGame->GetTopY()+250,strHolder.c_str());
if ((theGame->isStageClear()) &&(theGame->GetTopY()+700+50*(theGame->GetStageClearLimit()-theGame->GetLinesCleared())-theGame->GetPixels()-1<600+theGame->GetTopY())) {
oldBubleX = theGame->GetTopX()+280;
oldBubleY = theGame->GetTopY()+650+50*(theGame->GetStageClearLimit()-theGame->GetLinesCleared())-theGame->GetPixels()-1;
DrawIMG(stageBobble,screen,theGame->GetTopX()+280,theGame->GetTopY()+650+50*(theGame->GetStageClearLimit()-theGame->GetLinesCleared())-theGame->GetPixels()-1);
}
//player1 finnish, player2 start
//DrawIMG(boardBackBack,screen,theGame2->GetTopX()-60,theGame2->GetTopY()-68);
if (!editorMode) {
/*
*If single player mode (and not VS)
*/
if (!twoPlayers && !theGame->isGameOver()) {
//Blank player2's board:
DrawIMG(backBoard,screen,theGame2->GetTopX(),theGame2->GetTopY());
//Write a description:
if (theGame->isTimeTrial()) {
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+10,"Time Trial");
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+160,"Objective:");
string infostring = _("Score as much as \npossible in 2 minutes");
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+160+32,infostring);
}
else if (theGame->isStageClear()) {
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+10,"Stage Clear");
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+160,"Objective:");
string infostring = _("You must clear a \nnumber of lines.\nSpeed is rapidly \nincreased.");
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+160+32,infostring);
}
else if (theGame->isPuzzleMode()) {
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+10,"Puzzle");
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+160,"Objective:");
string infostring = _("Clear the entire board \nwith a limited number \nof moves.");
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+160+32,infostring);
}
else {
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+10,"Endless");
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+160,"Objective:");
string infostring = _("Score as much as \npossible. No time limit.");
NFont_Write(screen, theGame2->GetTopX()+7,theGame2->GetTopY()+160+32,infostring);
}
//Write the keys that are in use
int y = theGame2->GetTopY()+400;
NFont_Write(screen, theGame2->GetTopX()+7,y,_("Movement keys:") );
NFont_Write(screen, theGame2->GetTopX()+7,y+40,(getKeyName(keySettings[0].left)+", "+getKeyName(keySettings[0].right)+"," ).c_str() );
NFont_Write(screen, theGame2->GetTopX()+7,y+76,(getKeyName(keySettings[0].up)+", "+getKeyName(keySettings[0].down)).c_str() );
NFont_Write(screen, theGame2->GetTopX()+7,y+120,( _("Switch: ")+getKeyName(keySettings[0].change) ).c_str() );
if (theGame->isPuzzleMode()) {
NFont_Write(screen, theGame2->GetTopX()+7,y+160,( _("Restart: ")+getKeyName(keySettings[0].push) ).c_str() );
}
else {
NFont_Write(screen, theGame2->GetTopX()+7,y+160,( _("Push line: ")+getKeyName(keySettings[0].push) ).c_str() );
}
}
strHolder = itoa(theGame2->GetScore()+theGame2->GetHandicap());
NFont_Write(screen, theGame2->GetTopX()+310,theGame2->GetTopY()+100,strHolder.c_str());
if (theGame2->GetAIenabled()) {
NFont_Write(screen, theGame2->GetTopX()+10,theGame2->GetTopY()-34,_("AI") );
}
else {
NFont_Write(screen, theGame2->GetTopX()+10,theGame2->GetTopY()-34,theGame2->name);
}
if (theGame2->isTimeTrial()) {
int tid = (int)SDL_GetTicks()-theGame2->GetGameStartedAt();
int minutes;
int seconds;
if (tid>=0) {
minutes = (2*60*1000-(abs((int)SDL_GetTicks()-(int)theGame2->GetGameStartedAt())))/60/1000;
seconds = ((2*60*1000-(abs((int)SDL_GetTicks()-(int)theGame2->GetGameStartedAt())))%(60*1000))/1000;
}
else {
minutes = ((abs((int)SDL_GetTicks()-(int)theGame2->GetGameStartedAt())))/60/1000;
seconds = (((abs((int)SDL_GetTicks()-(int)theGame2->GetGameStartedAt())))%(60*1000))/1000;
}
if (theGame2->isGameOver()) {
minutes=0;
}
if (theGame2->isGameOver()) {
seconds=0;
}
if (seconds>9) {
strHolder = itoa(minutes)+":"+itoa(seconds);
}
else {
strHolder = itoa(minutes)+":0"+itoa(seconds);
}
//if ((SoundEnabled)&&(!NoSound)&&(tid>0)&&(seconds<5)&&(minutes == 0)&&(seconds>1)&&(!(Mix_Playing(6)))) Mix_PlayChannel(6,heartBeat,0);
NFont_Write(screen, theGame2->GetTopX()+310,theGame2->GetTopY()+150,strHolder.c_str());
}
else {
int minutes = (abs((int)SDL_GetTicks()-(int)theGame2->GetGameStartedAt()))/60/1000;
int seconds = (abs((int)SDL_GetTicks()-(int)theGame2->GetGameStartedAt())%(60*1000))/1000;
if (theGame2->isGameOver()) {
minutes=(theGame2->GetGameEndedAt()/1000/60)%100;
}
if (theGame2->isGameOver()) {
seconds=(theGame2->GetGameEndedAt()/1000)%60;
}
if (seconds>9) {
strHolder = itoa(minutes)+":"+itoa(seconds);
}
else {
strHolder = itoa(minutes)+":0"+itoa(seconds);
}
NFont_Write(screen, theGame2->GetTopX()+310,theGame2->GetTopY()+150,strHolder.c_str());
}
strHolder = itoa(theGame2->GetChains());
NFont_Write(screen, theGame2->GetTopX()+310,theGame2->GetTopY()+200,strHolder.c_str());
strHolder = itoa(theGame2->GetSpeedLevel());
NFont_Write(screen, theGame2->GetTopX()+310,theGame2->GetTopY()+250,strHolder.c_str());
}
//player2 finnish
DrawBalls();
#if DEBUG
Frames++;
if (SDL_GetTicks() >= Ticks + 1000) {
if (Frames > 999) {
Frames=999;
}
snprintf(FPS, sizeof(FPS), "%lu fps", Frames);
Frames = 0;
Ticks = SDL_GetTicks();
}
//NFont_Write(screen, 800,4,FPS);
nf_standard_blue_font.draw(screen, 800, 4, "%s", FPS);
#endif
//SDL_RenderPresent(screen); Update screen is now called outside DrawEvrything, bacause the mouse needs to be painted
}
//The function that allows the player to choose PuzzleLevel
int PuzzleLevelSelect(int Type) {
const int xplace = 200;
const int yplace = 300;
int levelNr = 0;
int mousex, mousey;
int oldmousex = 0;
int oldmousey = 0;
bool levelSelected = false;
bool tempBool;
int nrOfLevels = 0;
Uint32 tempUInt32;
Uint32 totalScore = 0;
Uint32 totalTime = 0;
int selected = 0;
//Loads the levels, if they havn't been loaded:
if (Type == 0) {
LoadPuzzleStages();
}
//Keeps track of background;
SDL_GetTicks();
if (Type == 0) {
nrOfLevels = PuzzleGetNumberOfPuzzles();
}
if (Type == 1) {
ifstream stageFile(stageClearSavePath.c_str(),ios::binary);
if (stageFile) {
for (int i = 0; i<nrOfStageLevels; i++) {
stageFile.read(reinterpret_cast<char*>(&tempBool),sizeof(bool));
stageCleared[i]=tempBool;
}
if (!stageFile.eof()) {
for (int i=0; i<nrOfStageLevels; i++) {
tempUInt32 = 0;
if (!stageFile.eof()) {
stageFile.read(reinterpret_cast<char*>(&tempUInt32),sizeof(Uint32));
}
stageScores[i]=tempUInt32;
totalScore+=tempUInt32;
}
for (int i=0; i<nrOfStageLevels; i++) {
tempUInt32 = 0;
if (!stageFile.eof()) {
stageFile.read(reinterpret_cast<char*>(&tempUInt32),sizeof(Uint32));
}
stageTimes[i]=tempUInt32;
totalTime += tempUInt32;
}
}
else {
for (int i=0; i<nrOfStageLevels; i++) {
stageScores[i]=0;
stageTimes[i]=0;
}
}
stageFile.close();
}
else {
for (int i=0; i<nrOfStageLevels; i++) {
stageCleared[i]= false;
stageScores[i]=0;
stageTimes[i]=0;
}
}
nrOfLevels = nrOfStageLevels;
}
while (!levelSelected) {
SDL_GetTicks();
DrawIMG(backgroundImage, screen, 0, 0);
DrawIMG(iCheckBoxArea,screen,xplace,yplace);
if (Type == 0) {
NFont_Write(screen, xplace+12,yplace+2,_("Select Puzzle") );
}
if (Type == 1) {
NFont_Write(screen, xplace+12,yplace+2, _("Stage Clear Level Select") );
}
//Now drow the fields you click in (and a V if clicked):
for (int i = 0; i < nrOfLevels; i++) {
DrawIMG(iLevelCheckBox,screen,xplace+10+(i%10)*50, yplace+60+(i/10)*50);
if (i==selected) {
DrawIMG(iLevelCheckBoxMarked,screen,xplace+10+(i%10)*50, yplace+60+(i/10)*50);
}
if (Type == 0 && PuzzleIsCleared(i)) {
DrawIMG(iLevelCheck,screen,xplace+10+(i%10)*50, yplace+60+(i/10)*50);
}
if (Type == 1 && stageCleared.at(i)==true) {
DrawIMG(iLevelCheck,screen,xplace+10+(i%10)*50, yplace+60+(i/10)*50);
}
}
SDL_Event event;
while ( SDL_PollEvent(&event) )
if ( event.type == SDL_KEYDOWN ) {
if ( event.key.keysym.sym == SDLK_ESCAPE ) {
levelNr = -1;
levelSelected = true;
}
if ( event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER ) {
levelNr = selected;
levelSelected = true;
}
if ( event.key.keysym.sym == SDLK_RIGHT ) {
++selected;
if (selected >= nrOfLevels) {
selected = 0;
}
}
if ( event.key.keysym.sym == SDLK_LEFT ) {
--selected;
if (selected < 0) {
selected = nrOfLevels-1;
}
}
if ( event.key.keysym.sym == SDLK_DOWN ) {
selected+=10;
if (selected >= nrOfLevels) {
selected-=10;
}
}
if ( event.key.keysym.sym == SDLK_UP ) {
selected-=10;
if (selected < 0) {
selected+=10;
}
}
}
SDL_GetKeyboardState(nullptr);
SDL_GetMouseState(&mousex,&mousey);
if (mousex != oldmousex || mousey != oldmousey) {
int tmpSelected = -1;
int j;
for (j = 0; (tmpSelected == -1) && ( (j<nrOfLevels/10)||((j<nrOfLevels/10+1)&&(nrOfLevels%10 != 0)) ); j++)
if ((60+j*50<mousey-yplace)&&(mousey-yplace<j*50+92)) {
tmpSelected = j*10;
}
if (tmpSelected != -1)
for (int k = 0; (( (!(nrOfLevels%10) || k<nrOfLevels-10*(j-1)) )&&(k<10)); k++)
if ((10+k*50<mousex-xplace)&&(mousex-xplace<k*50+42)) {
tmpSelected +=k;
selected = tmpSelected;
}
}
oldmousey = mousey;
oldmousex= mousex;
// If the mouse button is released, make bMouseUp equal true
if (!SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) {
bMouseUp=true;
}
if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
bMouseUp = false;
int levelClicked = -1;
int i;
for (i = 0; (i<nrOfLevels/10)||((i<nrOfLevels/10+1)&&(nrOfLevels%10 != 0)); i++)
if ((60+i*50<mousey-yplace)&&(mousey-yplace<i*50+92)) {
levelClicked = i*10;
}
i++;
if (levelClicked != -1)
for (int j = 0; ((j<nrOfStageLevels%(i*10))&&(j<10)); j++)
if ((10+j*50<mousex-xplace)&&(mousex-xplace<j*50+42)) {
levelClicked +=j;
levelSelected = true;
levelNr = levelClicked;
}
}
if (Type == 1) {
string scoreString = _("Best score: 0");
string timeString = _("Time used: -- : --");
if (stageScores.at(selected)>0) {
scoreString = _("Best score: ")+itoa(stageScores.at(selected));
}
if (stageTimes.at(selected)>0) {
timeString = _("Time used: ")+itoa(stageTimes.at(selected)/1000/60)+" : "+itoa2((stageTimes.at(selected)/1000)%60);
}
NFont_Write(screen, 200,200,scoreString.c_str());
NFont_Write(screen, 200,250,timeString.c_str());
string totalString = (boost::format("Total score: %1% in %2%:%3%")%totalScore%(totalTime/1000/60)%((totalTime/1000)%60)).str(); //"Total score: " +itoa(totalScore) + " in " + itoa(totalTime/1000/60) + " : " + itoa2((totalTime/1000)%60);
NFont_Write(screen, 200,600,totalString.c_str());
}
mouse.Draw(screen, SDL_GetTicks(), mousex, mousey);
SDL_RenderPresent(screen); //draws it all to the screen
}
DrawIMG(backgroundImage, screen, 0, 0);
return levelNr;
}
//This function will promt for the user to select another file for puzzle mode
void changePuzzleLevels() {
char theFileName[30];
strcpy(theFileName, PuzzleGetName().c_str());
for (int i=PuzzleGetName().length(); i<30; i++) {
theFileName[i]=' ';
}
theFileName[29]=0;
if (OpenFileDialogbox(200,100,theFileName)) {
for (int i=28; ((theFileName[i]==' ')&&(i>0)); i--) {
theFileName[i]=0;
}
PuzzleSetName(theFileName);
#if defined(__unix__)
string home = getenv("HOME");
PuzzleSetSavePath(home+"/.gamesaves/blockattack/"+PuzzleGetName()+".save");
#elif defined(_WIN32)
string home = getMyDocumentsPath();
PuzzleSetSavePath(home+"/My Games/blockattack/"+PuzzleGetName()+".save");
#else
PuzzleSetSavePath(PuzzleGetName()+".save");
#endif
}
}
static BlockGameSdl* player1;
static BlockGameSdl* player2;
static bool registerEndlessHighscore = false;
static bool registerTTHighscorePlayer1 = false;
static bool registerTTHighscorePlayer2 = false;
static void StartSinglePlayerEndless() {
//1 player - endless
player1->NewGame(SDL_GetTicks());
player1->putStartBlocks(time(0));
twoPlayers =false;
player2->SetGameOver();
player1->name = player1name;
player2->name = player2name;
registerEndlessHighscore = true;
}
static void StartSinglePlayerTimeTrial() {
player1->NewTimeTrialGame(SDL_GetTicks());
twoPlayers =false;
player2->SetGameOver();
//vsMode = false;
player1->name = player1name;
player2->name = player2name;
registerTTHighscorePlayer1 = true;
}
static int StartSinglePlayerPuzzle(int level) {
int myLevel = PuzzleLevelSelect(0);
if (myLevel == -1) {
return 1;
}
player1->NewPuzzleGame(myLevel,SDL_GetTicks());
DrawIMG(backgroundImage, screen, 0, 0);
twoPlayers = false;
player2->SetGameOver();
//vsMode = true;
player1->name = player1name;
player2->name = player2name;
return 0;
}
static void StarTwoPlayerTimeTrial() {
player1->NewTimeTrialGame(SDL_GetTicks());
player2->NewTimeTrialGame(SDL_GetTicks());
int theTime = time(0);
player1->putStartBlocks(theTime);
player2->putStartBlocks(theTime);
twoPlayers = true;
player1->setGameSpeed(player1Speed);
player2->setGameSpeed(player2Speed);
player1->setHandicap(player1handicap);
player2->setHandicap(player2handicap);
registerTTHighscorePlayer1 = true;
registerTTHighscorePlayer2 = true;
if (player1AI) {
player1->setAIlevel(player1AIlevel);
registerTTHighscorePlayer1 = false;
}
if (player2AI) {
player2->setAIlevel(player2AIlevel);
registerTTHighscorePlayer2 = false;
}
player1->name = player1name;
player2->name = player2name;
}
static void StartTwoPlayerVs() {
//2 player - VsMode
player1->NewVsGame(player2,SDL_GetTicks());
player2->NewVsGame(player1,SDL_GetTicks());
//vsMode = true;
twoPlayers = true;
player1->setGameSpeed(player1Speed);
player2->setGameSpeed(player2Speed);
player1->setHandicap(player1handicap);
player2->setHandicap(player2handicap);
if (player1AI) {
player1->setAIlevel(player1AIlevel);
}
if (player2AI) {
player2->setAIlevel(player2AIlevel);
}
int theTime = time(0);
player1->putStartBlocks(theTime);
player2->putStartBlocks(theTime);
player1->name = player1name;
player2->name = player2name;
}
//The main function, quite big... too big
int main(int argc, char* argv[]) {
//We first create the folder there we will save (only on UNIX systems)
//we call the external command "mkdir"... the user might have renamed this, but we hope he hasn't
#if defined(__unix__)
//Compiler warns about unused result. The users envisonment should normally give the user all the information he needs
if (system("mkdir -p ~/.gamesaves/blockattack/screenshots")) {
cerr << "mkdir error creating ~/.gamesaves/blockattack/screenshots" << endl;
}
if (system("mkdir -p ~/.gamesaves/blockattack/replays")) {
cerr << "mkdir error creating ~/.gamesaves/blockattack/replays" << endl;
}
if (system("mkdir -p ~/.gamesaves/blockattack/puzzles")) {
cerr << "mkdir error creating ~/.gamesaves/blockattack/puzzles" << endl;
}
#elif defined(_WIN32)
//Now for Windows NT/2k/xp/2k3 etc.
string tempA = getMyDocumentsPath()+"\\My Games";
CreateDirectory(tempA.c_str(),nullptr);
tempA = getMyDocumentsPath()+"\\My Games\\blockattack";
CreateDirectory(tempA.c_str(),nullptr);
tempA = getMyDocumentsPath()+"\\My Games\\blockattack\\replays";
CreateDirectory(tempA.c_str(),nullptr);
tempA = getMyDocumentsPath()+"\\My Games\\blockattack\\screenshots";
CreateDirectory(tempA.c_str(),nullptr);
#endif
highPriority = false; //if true the game will take most resources, but increase framerate.
bFullscreen = false;
//Set default Config variables:
Config::getInstance()->setDefault("themename","default");
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
if (argc > 1) {
int argumentNr = 1;
while (argc>argumentNr) {
const char helpString[] = "--help";
const char priorityString[] = "-priority";
const char singlePuzzleString[] = "-SP";
const char noSoundAtAll[] = "-nosound";
const char selectTheme[] = "-theme";
const char verbose[] = "-v";
if (strequals(argv[argumentNr],helpString)) {
cout << "Block Attack Help" << endl << helpString << " " << _("Displays this message") <<
endl << "-priority " << _("Starts game in high priority") << endl <<
"-nosound " << _("No sound will be played at all, and sound hardware will not be loaded (use this if game crashes because of sound)") << endl <<
"-theme <" << _("THEMENAME") << "> " << _("Changes to the theme <THEMENAME> on startup") << endl;
#ifdef WIN32
system("Pause");
#endif
return 0;
}
if (strequals(argv[argumentNr],priorityString)) {
if (verboseLevel) {
cout << "Priority mode" << endl;
}
highPriority = true;
}
if (strequals(argv[argumentNr],singlePuzzleString)) {
singlePuzzle = true; //We will just have one puzzle
if (argv[argumentNr+1][1]!=0) {
singlePuzzleNr = (argv[argumentNr+1][1]-'0')+(argv[argumentNr+1][0]-'0')*10;
}
else {
singlePuzzleNr = (argv[argumentNr+1][0]-'0');
}
singlePuzzleFile = argv[argumentNr+2];
argumentNr+=2;
if (verboseLevel) {
cout << "SinglePuzzleMode, File: " << singlePuzzleFile << " and Level: " << singlePuzzleNr << endl;
}
}
if (strequals(argv[argumentNr],noSoundAtAll)) {
NoSound = true;
}
if (strequals(argv[argumentNr],selectTheme)) {
argumentNr++; //Go to themename (the next argument)
if (verboseLevel) {
cout << "Theme set to \"" << argv[argumentNr] << '"' << endl;
}
Config::getInstance()->setString("themename",argv[argumentNr]);
}
if (strequals(argv[argumentNr],verbose)) {
verboseLevel++;
}
argumentNr++;
} //while
} //if
SoundEnabled = true;
MusicEnabled = true;
bScreenLocked = false;
twoPlayers = false; //true if two players splitscreen
theTopScoresEndless = Highscore(1);
theTopScoresTimeTrial = Highscore(2);
drawBalls = true;
puzzleLoaded = false;
theBallManeger = ballManeger();
theExplosionManeger = explosionManeger();
//We now set the paths were we are saving, we are using the keyword __unix__ . I hope that all UNIX systems has a home folder
#if defined(__unix__)
string home = getenv("HOME");
string optionsPath = home+"/.gamesaves/blockattack/options.dat";
#elif defined(_WIN32)
string home = getMyDocumentsPath();
string optionsPath;
if (&home!=nullptr) { //Null if no APPDATA dir exists (win 9x)
optionsPath = home+"/My Games/blockattack/options.dat";
}
else {
optionsPath = "options.dat";
}
#else
string optionsPath = "options.dat";
#endif
#if defined(__unix__)
stageClearSavePath = home+"/.gamesaves/blockattack/stageClear.SCsave";
PuzzleSetSavePath(home+"/.gamesaves/blockattack/puzzle.levels.save");
#elif defined(_WIN32)
if (&home!=nullptr) {
stageClearSavePath = home+"/My Games/blockattack/stageClear.SCsave";
PuzzleSetSavePath(home+"/My Games/blockattack/puzzle.levels.save");
}
else {
stageClearSavePath = "stageClear.SCsave";
PuzzleSetSavePath("puzzle.levels.save");
}
#else
stageClearSavePath = "stageClear.SCsave";
PuzzleSetSavePath("puzzle.levels.save");
#endif
PuzzleSetName("puzzle.levels");
//Init SDL
if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
cerr << "Unable to init SDL: " << SDL_GetError() << endl;
exit(1);
}
TTF_Init();
atexit(SDL_Quit); //quits SDL when the game stops for some reason (like you hit exit or Esc)
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
Joypad_init(); //Prepare the joysticks
Joypad joypad1 = Joypad(); //Creates a joypad
Joypad joypad2 = Joypad(); //Creates a joypad
theTextManeger = textManeger();
//Open Audio
if (!NoSound) //If sound has not been disabled, then load the sound system
if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 2048) < 0) {
cerr << "Warning: Couldn't set 44100 Hz 16-bit audio - Reason: " << SDL_GetError() << endl
<< "Sound will be disabled!" << endl;
NoSound = true; //Tries to stop all sound from playing/loading
}
//SDL_WM_SetCaption("Block Attack - Rise of the Blocks", nullptr); //Sets title line
if (verboseLevel) {
//Copyright notice:
cout << "Block Attack - Rise of the Blocks (" << VERSION_NUMBER << ")" << endl << "http://blockattack.sf.net" << endl << "Copyright 2004-2011 Poul Sander" << endl <<
"A SDL based game (see www.libsdl.org)" << endl <<
"The game is availeble under the GPL, see COPYING for details." << endl;
#if defined(_WIN32)
cout << "Windows build" << endl;
#elif defined(__linux__)
cout << "Linux build" << endl;
#elif defined(__unix__)
cout << "Unix build" << endl;
#else
cout << "Alternative build" << endl;
#endif
cout << "-------------------------------------------" << endl;
}
keySettings[0].up= SDLK_UP;
keySettings[0].down = SDLK_DOWN;
keySettings[0].left = SDLK_LEFT;
keySettings[0].right = SDLK_RIGHT;
keySettings[0].change = SDLK_RCTRL;
keySettings[0].push = SDLK_RSHIFT;
keySettings[2].up= SDLK_w;
keySettings[2].down = SDLK_s;
keySettings[2].left = SDLK_a;
keySettings[2].right = SDLK_d;
keySettings[2].change = SDLK_LCTRL;
keySettings[2].push = SDLK_LSHIFT;
player1keys=0;
player2keys=2;
player1name = "Player 1";
player2name = "Player 2";
Config* configSettings = Config::getInstance();
//configSettings->setString("aNumber"," A string");
//configSettings->save();
if (configSettings->exists("fullscreen")) { //Test if an configFile exists
bFullscreen = (bool)configSettings->getInt("fullscreen");
MusicEnabled = (bool)configSettings->getInt("musicenabled");
SoundEnabled = (bool)configSettings->getInt("soundenabled");
mouseplay1 = (bool)configSettings->getInt("mouseplay1");
mouseplay2 = (bool)configSettings->getInt("mouseplay2");
joyplay1 = (bool)configSettings->getInt("joypad1");
joyplay2 = (bool)configSettings->getInt("joypad2");
if (configSettings->exists("player1keyup")) {
keySettings[0].up = (SDL_Keycode)configSettings->getInt("player1keyup");
}
if (configSettings->exists("player1keydown")) {
keySettings[0].down = (SDL_Keycode)configSettings->getInt("player1keydown");
}
if (configSettings->exists("player1keyleft")) {
keySettings[0].left = (SDL_Keycode)configSettings->getInt("player1keyleft");
}
if (configSettings->exists("player1keyright")) {
keySettings[0].right = (SDL_Keycode)configSettings->getInt("player1keyright");
}
if (configSettings->exists("player1keychange")) {
keySettings[0].change = (SDL_Keycode)configSettings->getInt("player1keychange");
}
if (configSettings->exists("player1keypush")) {
keySettings[0].push = (SDL_Keycode)configSettings->getInt("player1keypush");
}
if (configSettings->exists("player2keyup")) {
keySettings[2].up = (SDL_Keycode)configSettings->getInt("player2keyup");
}
if (configSettings->exists("player2keydown")) {
keySettings[2].down = (SDL_Keycode)configSettings->getInt("player2keydown");
}
if (configSettings->exists("player2keyleft")) {
keySettings[2].left = (SDL_Keycode)configSettings->getInt("player2keyleft");
}
if (configSettings->exists("player2keyright")) {
keySettings[2].right = (SDL_Keycode)configSettings->getInt("player2keyright");
}
if (configSettings->exists("player2keychange")) {
keySettings[2].change = (SDL_Keycode)configSettings->getInt("player2keychange");
}
if (configSettings->exists("player2keypush")) {
keySettings[2].push = (SDL_Keycode)configSettings->getInt("player2keypush");
}
if (configSettings->exists("player1name")) {
player1name = configSettings->getString("player1name");
}
if (configSettings->exists("player2name")) {
player2name = configSettings->getString("player2name");
}
if (verboseLevel) {
cout << "Data loaded from config file" << endl;
}
}
else {
if (verboseLevel) {
cout << "Unable to load options file, using default values" << endl;
}
}
#if NETWORK
Config::getInstance()->setDefault("portv4","42200");
strcpy(serverAddress, "192.168.0.2 \0");
if (configSettings->exists("address0")) {
strcpy(serverAddress, " \0");
strncpy(serverAddress,configSettings->getString("address0").c_str(),sizeof(serverAddress)-1);
}
#endif
if (singlePuzzle) {
xsize=300;
ysize=600;
}
// "Block Attack - Rise of the Blocks"
//Open video
int createWindowParams = 0;
if ((bFullscreen)&&(!singlePuzzle)) {
createWindowParams |= SDL_WINDOW_FULLSCREEN_DESKTOP;
}
SDL_Window* sdlWindow = SDL_CreateWindow("Block Attack - Rise of the BlocksMy Game Window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
xsize, ysize,
createWindowParams );
dieOnNullptr(sdlWindow, "Unable to create window");
SDL_Renderer* renderer = SDL_CreateRenderer(sdlWindow, -1, 0);
dieOnNullptr(renderer, "Unable to create render");
screen = renderer;
//Init the file system abstraction layer
PHYSFS_init(argv[0]);
PHYSFS_addToSearchPath( ((string) PHYSFS_getBaseDir()+"/data").c_str(), 1);
//Load default theme
sago::SagoDataHolder d(renderer);
sago::SagoSpriteHolder spriteholder(d);
loadTheme(spriteholder, Config::getInstance()->getString("themename"));
//Now sets the icon:
//SDL_Surface* icon = IMG_Load2("gfx/icon.png");
//SDL_WM_SetIcon(icon,nullptr);
if (verboseLevel) {
cout << "Images loaded" << endl;
}
//InitMenues();
BlockGameSdl theGame = BlockGameSdl(50,100); //creates game objects
BlockGameSdl theGame2 = BlockGameSdl(xsize-500,100);
player1 = &theGame;
player2 = &theGame2;
/*if (singlePuzzle)
{
theGame.GetTopY()=0;
theGame.GetTopX()=0;
theGame2.GetTopY()=10000;
theGame2.GetTopX()=10000;
}*/
theGame.SetGameOver(); //sets the game over in the beginning
theGame2.SetGameOver();
//Takes names from file instead
theGame.name = player1name;
theGame2.name = player2name;
if (singlePuzzle) {
LoadPuzzleStages();
theGame.NewPuzzleGame(singlePuzzleNr, SDL_GetTicks());
}
DrawIMG(backgroundImage, screen, 0, 0);
DrawEverything(xsize,ysize,&theGame,&theGame2);
SDL_RenderPresent(screen);
//game loop
MainMenu();
//Saves options
if (!editorMode) {
configSettings->setInt("fullscreen",(int)bFullscreen);
configSettings->setInt("musicenabled",(int)MusicEnabled);
configSettings->setInt("soundenabled",(int)SoundEnabled);
configSettings->setInt("mouseplay1",(int)mouseplay1);
configSettings->setInt("mouseplay2",(int)mouseplay2);
configSettings->setInt("joypad1",(int)joyplay1);
configSettings->setInt("joypad2",(int)joyplay2);
configSettings->setInt("player1keyup",(int)keySettings[0].up);
configSettings->setInt("player1keydown",(int)keySettings[0].down);
configSettings->setInt("player1keyleft",(int)keySettings[0].left);
configSettings->setInt("player1keyright",(int)keySettings[0].right);
configSettings->setInt("player1keychange",(int)keySettings[0].change);
configSettings->setInt("player1keypush",(int)keySettings[0].push);
configSettings->setInt("player2keyup",(int)keySettings[2].up);
configSettings->setInt("player2keydown",(int)keySettings[2].down);
configSettings->setInt("player2keyleft",(int)keySettings[2].left);
configSettings->setInt("player2keyright",(int)keySettings[2].right);
configSettings->setInt("player2keychange",(int)keySettings[2].change);
configSettings->setInt("player2keypush",(int)keySettings[2].push);
configSettings->setString("player1name",player1name);
configSettings->setString("player2name",player2name);
configSettings->save();
}
//calculate uptime:
//int hours, mins, secs,
commonTime ct = TimeHandler::ms2ct(SDL_GetTicks());
if (verboseLevel) {
cout << boost::format("Block Attack - Rise of the Blocks ran for: %1% hours %2% mins and %3% secs") % ct.hours % ct.minutes % ct.seconds << endl;
}
ct = TimeHandler::addTime("totalTime",ct);
if (verboseLevel) {
cout << "Total run time is now: " << ct.days << " days " << ct.hours << " hours " << ct.minutes << " mins and " << ct.seconds << " secs" << endl;
}
Stats::getInstance()->save();
Config::getInstance()->save();
//Close file system Apstraction layer!
PHYSFS_deinit();
return 0;
}
int runGame(int gametype, int level) {
int mousex, mousey; //Mouse coordinates
bScreenLocked = false;
theTopScoresEndless = Highscore(1);
theTopScoresTimeTrial = Highscore(2);
drawBalls = true;
puzzleLoaded = false;
bool weWhereConnected = false;
bool bNearDeath = false; //Play music faster or louder while tru
theBallManeger = ballManeger();
theExplosionManeger = explosionManeger();
BlockGameSdl theGame = BlockGameSdl(50,100); //creates game objects
BlockGameSdl theGame2 = BlockGameSdl(xsize-500,100);
player1 = &theGame;
player2 = &theGame2;
theGame.DoPaintJob(); //Makes sure what there is something to paint
theGame2.DoPaintJob();
theGame.SetGameOver(); //sets the game over in the beginning
theGame2.SetGameOver();
//Takes names from file instead
theGame.name = player1name;
theGame2.name = player2name;
Joypad joypad1 = Joypad(); //Creates a joypad
Joypad joypad2 = Joypad(); //Creates a joypad
if (singlePuzzle) {
LoadPuzzleStages();
theGame.NewPuzzleGame(singlePuzzleNr, SDL_GetTicks());
}
//game loop
int done = 0;
if (verboseLevel) {
cout << "Starting game loop" << endl;
}
bool mustsetupgame = true;
while (done == 0) {
if (mustsetupgame) {
registerEndlessHighscore = false;
registerTTHighscorePlayer1 = false;
registerTTHighscorePlayer2 = false;
switch (gametype) {
case 1:
StartSinglePlayerTimeTrial();
break;
case 2: {
int myLevel = PuzzleLevelSelect(1);
if (myLevel == -1) {
return 1;
}
theGame.NewStageGame(myLevel,SDL_GetTicks());
DrawIMG(backgroundImage, screen, 0, 0);
twoPlayers =false;
theGame2.SetGameOver();
theGame.name = player1name;
theGame2.name = player2name;
}
break;
case 3:
if (StartSinglePlayerPuzzle(level)) {
return 1;
}
break;
case 4: {
//1 player - Vs mode
int theAIlevel = level; //startSingleVs();
theGame.NewVsGame(&theGame2, SDL_GetTicks());
theGame2.NewVsGame(&theGame, SDL_GetTicks());
DrawIMG(backgroundImage, screen, 0, 0);
twoPlayers = true; //Single player, but AI plays
theGame2.setAIlevel((Uint8)theAIlevel);
int theTime = time(0);
theGame.putStartBlocks(theTime);
theGame2.putStartBlocks(theTime);
theGame.name = player1name;
theGame2.name = player2name;
}
break;
case 10:
StarTwoPlayerTimeTrial();
break;
case 11:
StartTwoPlayerVs();
break;
case 0:
default:
StartSinglePlayerEndless();
break;
};
mustsetupgame = false;
DrawIMG(backgroundImage, screen, 0, 0);
DrawEverything(xsize,ysize,&theGame,&theGame2);
SDL_RenderPresent(screen);
}
if (!(highPriority)) {
SDL_Delay(1);
}
DrawIMG(backgroundImage, screen, 0, 0);
//updates the balls and explosions:
theBallManeger.update();
theExplosionManeger.update();
theTextManeger.update();
if (!bScreenLocked) {
SDL_Event event;
while ( SDL_PollEvent(&event) ) {
if ( event.type == SDL_QUIT ) {
Config::getInstance()->setShuttingDown(5);
done = 1;
}
if ( event.type == SDL_KEYDOWN ) {
if ( event.key.keysym.sym == SDLK_ESCAPE || ( event.key.keysym.sym == SDLK_RETURN && theGame.isGameOver() ) ) {
done=1;
DrawIMG(backgroundImage, screen, 0, 0);
}
if ((!editorMode)&&(!editorModeTest)&&(!theGame.GetAIenabled())) {
//player1:
if ( event.key.keysym.sym == keySettings[player1keys].up ) {
theGame.MoveCursor('N');
}
if ( event.key.keysym.sym == keySettings[player1keys].down ) {
theGame.MoveCursor('S');
}
if ( (event.key.keysym.sym == keySettings[player1keys].left) ) {
theGame.MoveCursor('W');
}
if ( (event.key.keysym.sym == keySettings[player1keys].right) ) {
theGame.MoveCursor('E');
}
if ( event.key.keysym.sym == keySettings[player1keys].push ) {
theGame.PushLine();
}
if ( event.key.keysym.sym == keySettings[player1keys].change ) {
theGame.SwitchAtCursor();
}
}
if (!editorMode && !theGame2.GetAIenabled()) {
//player2:
if ( event.key.keysym.sym == keySettings[player2keys].up ) {
theGame2.MoveCursor('N');
}
if ( event.key.keysym.sym == keySettings[player2keys].down ) {
theGame2.MoveCursor('S');
}
if ( (event.key.keysym.sym == keySettings[player2keys].left) ) {
theGame2.MoveCursor('W');
}
if ( (event.key.keysym.sym == keySettings[player2keys].right) ) {
theGame2.MoveCursor('E');
}
if ( event.key.keysym.sym == keySettings[player2keys].push ) {
theGame2.PushLine();
}
if ( event.key.keysym.sym == keySettings[player2keys].change ) {
theGame2.SwitchAtCursor();
}
}
//common:
if ((!singlePuzzle)&&(!editorMode)) {
if ( event.key.keysym.sym == SDLK_F2 ) {
/*#if NETWORK
if ((!showOptions)&&(!networkActive)){
#else
if ((!showOptions)){
#endif
StartSinglePlayerEndless();
}
*/
mustsetupgame = true;
}
if ( event.key.keysym.sym == SDLK_F10 ) {
//StartReplay("/home/poul/.gamesaves/blockattack/quicksave");
}
if ( event.key.keysym.sym == SDLK_F9 ) {
writeScreenShot();
}
if ( event.key.keysym.sym == SDLK_F5 ) {
}
if ( event.key.keysym.sym == SDLK_F11 ) {
} //F11
}
if ( event.key.keysym.sym == SDLK_F12 ) {
done=1;
}
}
} //while event PollEvent - read keys
/**********************************************************************
***************************** Joypad start ****************************
**********************************************************************/
//Gameplay
if (joyplay1||joyplay2) {
if (joypad1.working && !theGame.GetAIenabled()) {
if (joyplay1) {
joypad1.update();
if (joypad1.up) {
theGame.MoveCursor('N');
}
if (joypad1.down) {
theGame.MoveCursor('S');
}
if (joypad1.left) {
theGame.MoveCursor('W');
}
if (joypad1.right) {
theGame.MoveCursor('E');
}
if (joypad1.but1) {
theGame.SwitchAtCursor();
}
if (joypad1.but2) {
theGame.PushLine();
}
}
else {
joypad1.update();
if (joypad1.up) {
theGame2.MoveCursor('N');
}
if (joypad1.down) {
theGame2.MoveCursor('S');
}
if (joypad1.left) {
theGame2.MoveCursor('W');
}
if (joypad1.right) {
theGame2.MoveCursor('E');
}
if (joypad1.but1) {
theGame2.SwitchAtCursor();
}
if (joypad1.but2) {
theGame2.PushLine();
}
}
}
if (joypad2.working && !theGame2.GetAIenabled()) {
if (!joyplay2) {
joypad2.update();
if (joypad2.up) {
theGame.MoveCursor('N');
}
if (joypad2.down) {
theGame.MoveCursor('S');
}
if (joypad2.left) {
theGame.MoveCursor('W');
}
if (joypad2.right) {
theGame.MoveCursor('E');
}
if (joypad2.but1) {
theGame.SwitchAtCursor();
}
if (joypad2.but2) {
theGame.PushLine();
}
}
else {
joypad2.update();
if (joypad2.up) {
theGame2.MoveCursor('N');
}
if (joypad2.down) {
theGame2.MoveCursor('S');
}
if (joypad2.left) {
theGame2.MoveCursor('W');
}
if (joypad2.right) {
theGame2.MoveCursor('E');
}
if (joypad2.but1) {
theGame2.SwitchAtCursor();
}
if (joypad2.but2) {
theGame2.PushLine();
}
}
}
}
/**********************************************************************
***************************** Joypad end ******************************
**********************************************************************/
SDL_GetMouseState(&mousex,&mousey);
/********************************************************************
**************** Here comes mouse play ******************************
********************************************************************/
if ((mouseplay1)&&( ( (!editorMode)&&(!theGame.GetAIenabled()) ) ||(editorModeTest))) //player 1
if ((mousex > 50)&&(mousey>100)&&(mousex<50+300)&&(mousey<100+600)) {
int yLine, xLine;
yLine = ((100+600)-(mousey-100+theGame.GetPixels()))/50;
xLine = (mousex-50+25)/50;
yLine-=2;
xLine-=1;
if ((yLine>10)&&(theGame.GetTowerHeight()<12)) {
yLine=10;
}
if (((theGame.GetPixels()==50)||(theGame.GetPixels()==0)) && (yLine>11)) {
yLine=11;
}
if (yLine<0) {
yLine=0;
}
if (xLine<0) {
xLine=0;
}
if (xLine>4) {
xLine=4;
}
theGame.MoveCursorTo(xLine,yLine);
}
if ((mouseplay2)&&(!editorMode)&&(!theGame2.GetAIenabled())) //player 2
if ((mousex > xsize-500)&&(mousey>100)&&(mousex<xsize-500+300)&&(mousey<100+600)) {
int yLine, xLine;
yLine = ((100+600)-(mousey-100+theGame2.GetPixels()))/50;
xLine = (mousex-(xsize-500)+25)/50;
yLine-=2;
xLine-=1;
if ((yLine>10)&&(theGame2.GetTowerHeight()<12)) {
yLine=10;
}
if (((theGame2.GetPixels()==50)||(theGame2.GetPixels()==0)) && (yLine>11)) {
yLine=11;
}
if (yLine<0) {
yLine=0;
}
if (xLine<0) {
xLine=0;
}
if (xLine>4) {
xLine=4;
}
theGame2.MoveCursorTo(xLine,yLine);
}
/********************************************************************
**************** Here ends mouse play *******************************
********************************************************************/
// If the mouse button is released, make bMouseUp equal true
if (!SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) {
bMouseUp=true;
}
// If the mouse button 2 is released, make bMouseUp2 equal true
if ((SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(3))!=SDL_BUTTON(3)) {
bMouseUp2=true;
}
if ((!singlePuzzle)&&(!editorMode)) {
//read mouse events
if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
bMouseUp = false;
DrawIMG(backgroundImage, screen, 0, 0);
/********************************************************************
**************** Here comes mouse play ******************************
********************************************************************/
{
if (mouseplay1 && !theGame.GetAIenabled()) //player 1
if ((mousex > 50)&&(mousey>100)&&(mousex<50+300)&&(mousey<100+600)) {
theGame.SwitchAtCursor();
}
if (mouseplay2 && !theGame2.GetAIenabled()) //player 2
if ((mousex > xsize-500)&&(mousey>100)&&(mousex<xsize-500+300)&&(mousey<100+600)) {
theGame2.SwitchAtCursor();
}
}
/********************************************************************
**************** Here ends mouse play *******************************
********************************************************************/
if (stageButtonStatus != SBdontShow && (mousex > theGame.GetTopX()+cordNextButton.x)
&&(mousex < theGame.GetTopX()+cordNextButton.x+cordNextButton.xsize)
&&(mousey > theGame.GetTopY()+cordNextButton.y)&&(mousey < theGame.GetTopY()+cordNextButton.y+cordNextButton.ysize)) {
//Clicked the next button after a stage clear or puzzle
theGame.nextLevel(SDL_GetTicks());
}
if (stageButtonStatus != SBdontShow && (mousex > theGame.GetTopX()+cordRetryButton .x)
&&(mousex < theGame.GetTopX()+cordRetryButton.x+cordRetryButton.xsize)
&&(mousey > theGame.GetTopY()+cordRetryButton.y)&&(mousey < theGame.GetTopY()+cordRetryButton.y+cordRetryButton.ysize)) {
//Clicked the retry button
theGame.retryLevel(SDL_GetTicks());
}
//cout << "Mouse x: " << mousex << ", mouse y: " << mousey << endl;
}
//Mouse button 2:
if ((SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(3))==SDL_BUTTON(3) && bMouseUp2) {
bMouseUp2=false; //The button is pressed
/********************************************************************
**************** Here comes mouse play ******************************
********************************************************************/
if (mouseplay1 && !theGame.GetAIenabled()) {
//player 1
if ((mousex > 50)&&(mousey>100)&&(mousex<50+300)&&(mousey<100+600)) {
theGame.PushLine();
}
}
if (mouseplay2 && !theGame2.GetAIenabled()) {
//player 2
if ((mousex > xsize-500)&&(mousey>100)&&(mousex<xsize-500+300)&&(mousey<100+600)) {
theGame2.PushLine();
}
}
/********************************************************************
**************** Here ends mouse play *******************************
********************************************************************/
}
} //if !singlePuzzle
else {
}
} //if !bScreenBocked;
//Sees if music is stopped and if music is enabled
if ((!NoSound)&&(!Mix_PlayingMusic())&&(MusicEnabled)&&(!bNearDeath)) {
// then starts playing it.
Mix_VolumeMusic(MIX_MAX_VOLUME);
Mix_PlayMusic(bgMusic, -1); //music loop
}
if (bNearDeath!=bNearDeathPrev) {
if (bNearDeath) {
if (!NoSound &&(MusicEnabled)) {
Mix_VolumeMusic(MIX_MAX_VOLUME);
Mix_PlayMusic(highbeatMusic, 1);
}
}
else {
if (!NoSound &&(MusicEnabled)) {
Mix_VolumeMusic(MIX_MAX_VOLUME);
Mix_PlayMusic(bgMusic, -1);
}
}
}
bNearDeathPrev = bNearDeath;
//set bNearDeath to false theGame*.Update() will change to true as needed
bNearDeath = theGame.IsNearDeath() || theGame2.IsNearDeath();
//Updates the objects
theGame.Update(SDL_GetTicks());
theGame2.Update(SDL_GetTicks());
//see if anyone has won (two players only)
#if NETWORK
if (!networkPlay)
#endif
if (twoPlayers) {
if ((theGame.isGameOver()) && (theGame2.isGameOver())) {
if (theGame.GetScore()+theGame.GetHandicap()>theGame2.GetScore()+theGame2.GetHandicap()) {
theGame.setPlayerWon();
}
else if (theGame.GetScore()+theGame.GetHandicap()<theGame2.GetScore()+theGame2.GetHandicap()) {
theGame2.setPlayerWon();
}
else {
theGame.setDraw();
theGame2.setDraw();
}
//twoPlayers = false;
}
if ((theGame.isGameOver()) && (!theGame2.isGameOver())) {
theGame2.setPlayerWon();
//twoPlayers = false;
}
if ((!theGame.isGameOver()) && (theGame2.isGameOver())) {
theGame.setPlayerWon();
//twoPlayers = false;
}
}
if (theGame.isGameOver() && registerTTHighscorePlayer1) {
registerTTHighscorePlayer1 = false;
theTopScoresTimeTrial.addScore(theGame.name, theGame.GetScore());
}
if (theGame2.isGameOver() && registerTTHighscorePlayer2) {
registerTTHighscorePlayer2 = false;
theTopScoresTimeTrial.addScore(theGame2.name, theGame2.GetScore());
}
if (theGame.isGameOver() && registerEndlessHighscore) {
registerEndlessHighscore = false;
theTopScoresEndless.addScore(theGame.name, theGame.GetScore());
theGame.EndlessHighscoreEvent();
}
//Once evrything has been checked, update graphics
DrawEverything(xsize,ysize,&theGame,&theGame2);
SDL_GetMouseState(&mousex,&mousey);
//Remember mouse placement
oldMousex = mousex;
oldMousey = mousey;
//Draw the mouse:
mouse.Draw(screen, SDL_GetTicks(), mousex, mousey);
SDL_RenderPresent(screen);
} //game loop
return 0;
}