/* =========================================================================== 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 #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 #include #include //Used for srand() #include //Still used by itoa2 #include #include "SDL.h" //The SDL libary, used for most things #include //Used for sound & music #include //To load PNG images! #include //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 #include "MenuSystem.h" #include "puzzlehandler.hpp" #include #include //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; i800 || 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 (!(frameNumbertime; } 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; i5) { 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 (LevelgameStartedAt+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) && (mousexscoreY) && (mouseybackX) && (mousexbackY) && (mouseynextX) && (mousexnextY) && (mousey=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; isetShuttingDown(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) && (mousexy+420) && (mouseyx+20) && (mousexy+420) && (mouseyx+10) && (mousexy+10+i*36) && (mouseyDoPaintJob(); 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(&tempBool),sizeof(bool)); stageCleared[i]=tempBool; } if (!stageFile.eof()) { for (int i=0; i(&tempUInt32),sizeof(Uint32)); } stageScores[i]=tempUInt32; totalScore+=tempUInt32; } for (int i=0; i(&tempUInt32),sizeof(Uint32)); } stageTimes[i]=tempUInt32; totalTime += tempUInt32; } } else { for (int i=0; i= 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) && ( (j0) { 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 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" SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); //Open video int createWindowParams = 0; //SDL_WINDOW_RESIZABLE; 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"); //SDL_RenderSetLogicalSize(renderer, xsize, ysize); 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()); } SDL_RenderClear(screen); 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); } SDL_RenderClear(screen); 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)&&(mousex10)&&(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 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)&&(mousextheGame2.GetScore()+theGame2.GetHandicap()) { theGame.setPlayerWon(); } else if (theGame.GetScore()+theGame.GetHandicap()