1 /* 2 =========================================================================== 3 blockattack - Block Attack - Rise of the Blocks 4 Copyright (C) 2005-2012 Poul Sander 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see http://www.gnu.org/licenses/ 18 19 Source information and contacts persons can be found at 20 http://www.blockattack.net 21 =========================================================================== 22 */ 23 24 #ifndef BLOCKGAME_HPP 25 #define BLOCKGAME_HPP 1 26 27 #include "stats.h" 28 #include "common.h" 29 #include <deque> 30 #include "cereal/cereal.hpp" 31 #include "cereal/types/deque.hpp" 32 #include "cereal/types/string.hpp" 33 34 #define NUMBEROFCHAINS 100 35 #define BLOCKWAIT 100000 36 #define BLOCKHANG 1000 37 38 enum stageButton {SBdontShow, SBstageClear, SBpuzzleMode}; 39 40 extern stageButton stageButtonStatus; 41 42 //This is the size of the blocks. They are always 50. The internal logic calculates it that way 43 const int bsize = 50; 44 45 /** 46 * This struct defines the start conditions of the game 47 */ 48 struct BlockGameStartInfo { 49 unsigned int ticks = 0; 50 bool timeTrial = false; 51 ///True means a stage clear game will be started. level must be set too. 52 bool stageClear = false; 53 ///True if puzzle mode. level must be set too. 54 bool puzzleMode = false; 55 ///Single puzzle is used for the editor only. 56 bool singlePuzzle = false; 57 int level = 0; 58 bool AI = false; 59 /** 60 * True means that stats will be recorded. 61 * If AI is true then this will be overruled to false 62 */ 63 bool recordStats = true; 64 bool vsMode = false; 65 /** 66 * Set to true if we are fighting an AI. level should be the AI level we are fighting 67 */ 68 bool vsAI = false; 69 int startBlocks = -1; 70 int handicap = 0; 71 int gameSpeed = 0; 72 template <class Archive> serializeBlockGameStartInfo73 void serialize( Archive & ar ) 74 { 75 ar( CEREAL_NVP(ticks), CEREAL_NVP(timeTrial), CEREAL_NVP(stageClear), CEREAL_NVP(puzzleMode), CEREAL_NVP(singlePuzzle), 76 CEREAL_NVP(level), CEREAL_NVP(AI), CEREAL_NVP(recordStats), CEREAL_NVP(vsMode), CEREAL_NVP(vsAI), 77 CEREAL_NVP(startBlocks), CEREAL_NVP(handicap), CEREAL_NVP(gameSpeed) ); 78 } 79 }; 80 81 struct GarbageStruct { 82 bool greyGarbage = false; 83 int width = 0; 84 int height = 0; setGarbageGarbageStruct85 void setGarbage(int w, int h, bool g = false) { 86 greyGarbage = g; 87 width = w; 88 height = h; 89 } 90 template <class Archive> serializeGarbageStruct91 void serialize( Archive & ar ) 92 { 93 ar( CEREAL_NVP(greyGarbage), CEREAL_NVP(width), CEREAL_NVP(height) ); 94 } 95 }; 96 97 struct BlockGameAction { 98 enum class Action {NONE, UPDATE, SET_DRAW, SET_WON, SET_GAME_OVER, MOVE, SWITCH, PUSH, PUSH_GARBAGE, MOUSE_DOWN, MOUSE_UP, MOUSE_MOVE}; 99 Action action = Action::NONE; 100 unsigned int tick = 0; //< Used for update 101 char way = '\0'; //< The direction to move the cursor: 'N', 'E', 'S' or 'W' 102 int x = 0; 103 int y = 0; 104 std::vector<GarbageStruct> garbage; 105 template <class Archive> serializeBlockGameAction106 void serialize( Archive & ar ) 107 { 108 ar( CEREAL_NVP(action), CEREAL_NVP(tick), CEREAL_NVP(way), CEREAL_NVP(x), CEREAL_NVP(y), CEREAL_NVP(garbage) ); 109 } 110 }; 111 112 struct BlockGameInfoExtra { 113 std::string name; 114 int score = 0; 115 int seconds = 0; 116 template <class Archive> serializeBlockGameInfoExtra117 void serialize( Archive & ar ) 118 { 119 ar( CEREAL_NVP(name), CEREAL_NVP(score), CEREAL_NVP(seconds) ); 120 } 121 }; 122 123 struct BlockGameInfo { 124 BlockGameStartInfo startInfo; 125 std::deque<BlockGameAction> actions; 126 BlockGameInfoExtra extra; 127 template <class Archive> serializeBlockGameInfo128 void serialize( Archive & ar ) 129 { 130 ar( CEREAL_NVP(startInfo), CEREAL_NVP(actions), CEREAL_NVP(extra) ); 131 } 132 }; 133 134 //////////////////////////////////////////////////////////////////////////////// 135 //The BloackGame class represents a board, score, time etc. for a single player/ 136 //////////////////////////////////////////////////////////////////////////////// 137 class BlockGame 138 { 139 private: 140 int prevTowerHeight = 0; 141 bool bGarbageFallLeft = false; 142 bool singlePuzzle = false; 143 144 int nextGarbageNumber = 0; 145 int pushedPixelAt = 0; 146 int nrPushedPixel = 0; 147 int nrFellDown = 0; 148 unsigned int nrStops = 0; 149 bool garbageToBeCleared[7][30] = {}; 150 unsigned int lastAImove = 0; 151 152 int AI_LineOffset = 0; //how many lines have changed since command 153 int hangTicks = 0; //How many times have hang been decreased? 154 //int the two following index 0 may NOT be used (what the fuck did I meen?) 155 int chainSize[NUMBEROFCHAINS]{}; //Contains the chains 156 bool chainUsed[NUMBEROFCHAINS]{}; //True if the chain is used 157 158 unsigned int nextRandomNumber = 0; 159 int Level = 0; //Only used in stageClear and puzzle (not implemented) 160 161 BlockGameInfo replayInfo; 162 163 int rand2(); 164 int firstUnusedChain(); 165 166 protected: 167 int lastCounter = 0; 168 std::string strHolder; 169 bool bDraw = false; 170 unsigned int ticks = 0; 171 unsigned int gameStartedAt = 0; 172 unsigned int gameEndedAfter = 0; //How long did the game last? 173 int linesCleared = 0; 174 int TowerHeight = 0; 175 int board[7][30]; 176 int stop = 0; 177 int speedLevel = 0; 178 int pixels = 0; 179 int MovesLeft = 0; 180 bool timetrial = false; 181 bool stageClear = false; 182 bool vsMode = false; 183 bool puzzleMode = false; 184 int stageClearLimit = 0; //stores number of lines user must clear to win 185 int combo = 0; 186 int chain = 0; 187 int cursorx = 2; //stores cursor position 188 int cursory = 3; // -||- 189 int mouse_cursorx = -1; //Stores the mouse hold cursor. -1 if nothing is selected. 190 int mouse_cursory = -1; 191 double speed = 0.0; 192 double baseSpeed = 0.0; //factor for speed. Lower value = faster gameplay 193 int score = 0; 194 bool bGameOver = false; 195 bool hasWonTheGame = false; 196 int AI_MoveSpeed = 0; //How often will the computer move? milliseconds 197 bool AI_Enabled = false; 198 bool recordStats = true; 199 bool vsAI = false; //Set to true for single player vs 200 201 int handicap = 0; 202 203 std::vector<GarbageStruct> garbageSendQueue; 204 205 int AIlineToClear = 0; 206 207 short AIstatus = 0; //Status flags: 208 //0: nothing, 2: clear tower, 3: clear horisontal, 4: clear vertical 209 //1: make more lines, 5: make 2 lines, 6: make 1 line 210 211 public: 212 213 std::string name; 214 215 public: 216 BlockGame(); 217 virtual ~BlockGame() = default; 218 219 int getAIlevel() const; 220 AddText(int,int,unsigned int,int) const221 virtual void AddText(int, int, unsigned int, int) const {} AddBall(int,int,bool,int) const222 virtual void AddBall(int, int, bool, int) const {} AddExplosion(int,int) const223 virtual void AddExplosion(int, int) const {} PlayerWonEvent() const224 virtual void PlayerWonEvent() const {} DrawEvent() const225 virtual void DrawEvent() const {} BlockPopEvent() const226 virtual void BlockPopEvent() const {} LongChainDoneEvent() const227 virtual void LongChainDoneEvent() const {} TimeTrialEndEvent() const228 virtual void TimeTrialEndEvent() const {} EndlessHighscoreEvent() const229 virtual void EndlessHighscoreEvent() const {} 230 231 void NewGame(const BlockGameStartInfo &s); 232 void DoAction (const BlockGameAction& action); 233 /** 234 * This function returns all the garbage. 235 * This is actual const in the way that it does not change the games state 236 * Technically it is not const because it empties the queue that are stored inside the object even if not part of the game state. 237 * @param poppedData 238 */ 239 void PopSendGarbage(std::vector<GarbageStruct>& poppedData); 240 241 int GetScore() const; 242 int GetHandicap() const; 243 bool isGameOver() const; 244 int GetGameStartedAt() const; 245 int GetGameEndedAt() const; 246 bool isTimeTrial() const; 247 bool isStageClear() const; 248 bool isVsMode() const; 249 bool isPuzzleMode() const; 250 int GetLinesCleared() const; 251 int GetStageClearLimit() const; 252 int GetChains() const; 253 int GetPixels() const; 254 int GetSpeedLevel() const; 255 int GetTowerHeight() const; 256 int GetCursorX() const; 257 int GetCursorY() const; 258 void GetMouseCursor(bool& pressed, int& x, int&y) const; 259 bool GetIsWinner() const; 260 bool isSinglePuzzle() const; 261 int getLevel() const; 262 bool GetAIenabled() const; 263 bool IsNearDeath() const; GetBaseSpeed() const264 double GetBaseSpeed() const { return baseSpeed; } GetBlockGameInfo()265 const BlockGameInfo& GetBlockGameInfo() { 266 return replayInfo; 267 } 268 private: 269 void NewGameInternal(unsigned int ticks); 270 //Test if LineNr is an empty line, returns false otherwise. 271 bool LineEmpty(int lineNr) const; 272 //Test if the entire board is empty (used for Puzzles) 273 bool BoardEmpty() const; 274 //Anything that the user can't move? In that case Game Over cannot occur 275 bool hasStaticContent() const; 276 void putStartBlocks(); 277 void putStartBlocks(int n); 278 //decreases hang for all hanging blocks and wait for waiting blocks 279 void ReduceStuff(); 280 void setGameSpeed(int globalSpeedLevel); 281 void setHandicap(int globalHandicap); 282 //Clears garbage, must take one the lower left corner! 283 int GarbageClearer(int x, int y, int number, bool aLineToClear, int chain); 284 //Marks garbage that must be cleared 285 int GarbageMarker(int x, int y); 286 int FirstGarbageMarker(int x, int y); 287 //Clear Blocks if 3 or more is alligned (naive implemented) 288 void ClearBlocks(); 289 //Moves all peaces a spot down if possible 290 int FallBlock(int x, int y, int number); 291 //Makes all Garbage fall one spot 292 void GarbageFall(); 293 //Makes the blocks fall (it doesn't test time, this must be done before hand) 294 void FallDown(); 295 //Pushes a single pixel, so it appears to scrool 296 void PushPixels(); 297 //See how high the tower is, saved in integer TowerHeight 298 void FindTowerHeight(); 299 //Generates a new line and moves the field one block up (restart puzzle mode) 300 void PushLine(); 301 //prints "Game Over" and ends game 302 void SetGameOver(); 303 //Moves the cursor, receaves N,S,E or W as a char an moves as desired 304 void MoveCursor(char way); 305 //switches the two blocks at the cursor position, unless game over 306 void SwitchAtCursor(); 307 //Creates garbage using a given wide and height 308 bool CreateGarbage(int wide, int height); 309 //Creates garbage using a given wide and height 310 bool CreateGreyGarbage(); 311 void MouseDown(int x, int y); //Send then the mouse is pressed 312 void MouseMove(int x); //Send then the mouse moves 313 void MouseUp(); //Send then the mouse goes up 314 void MoveCursorTo(int x, int y); 315 void FinalizeBlockGameInfo(); 316 /////////////////////////////////////////////////////////////////////////// 317 /////////////////////////// AI starts here! /////////////////////////////// 318 /////////////////////////////////////////////////////////////////////////// 319 //First the helpet functions: 320 int nrOfType(int line, int type); 321 int AIcolorToClear = 0; 322 //See if a combo can be made in this line 323 int horiInLine(int line); 324 bool horiClearPossible(); 325 //the Line Has Unmoveable Objects witch might stall the AI 326 bool lineHasGarbage(int line); 327 //Types 0..6 in line 328 int nrOfRealTypes(int line); 329 //See if there is a tower 330 bool ThereIsATower(); 331 double firstInLine1(int line); 332 //returns the first coordinate of the block of type 333 double firstInLine(int line, int type); 334 //There in the line shall we move 335 int closestTo(int line, int place); 336 //The AI will remove a tower 337 void AI_ClearTower(); 338 //The AI will try to clear block horisontally 339 void AI_ClearHori(); 340 //Test if vertical clear is possible 341 bool veriClearPossible(); 342 //There in the line shall we move 343 int closestTo(int line, int type, int place); 344 //The AI will try to clear blocks vertically 345 void AI_ClearVertical(); 346 bool firstLineCreated = 0; 347 void AI_Move(); 348 ////////////////////////////////////////////////////////////////// 349 ///////////////////////////// AI ends here! ////////////////////// 350 ////////////////////////////////////////////////////////////////// 351 //Set the move speed of the AI based on the aiLevel parameter 352 void setAIlevel(int aiLevel); 353 void PushLineInternal(); 354 //Prints "winner" and ends game 355 void setPlayerWon(); 356 //Prints "draw" and ends the game 357 void setDraw(); 358 //Updates evrything, if not called nothing happends 359 void Update(); 360 void UpdateInternal(unsigned int newtick); 361 }; 362 363 //Play the next level 364 void nextLevel(BlockGame& g, unsigned int ticks); 365 //Replay the current level 366 void retryLevel(BlockGame& g, unsigned int ticks); 367 368 #endif 369