File: BlockGame.hpp

package info (click to toggle)
blockattack 2.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 9,992 kB
  • sloc: cpp: 26,060; pascal: 351; sh: 172; makefile: 15
file content (368 lines) | stat: -rw-r--r-- 11,915 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
/*
===========================================================================
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://www.blockattack.net
===========================================================================
*/

#ifndef BLOCKGAME_HPP
#define BLOCKGAME_HPP 1

#include "stats.h"
#include "common.h"
#include <deque>
#include "cereal/cereal.hpp"
#include "cereal/types/deque.hpp"
#include "cereal/types/string.hpp"

#define NUMBEROFCHAINS 100
#define BLOCKWAIT 100000
#define BLOCKHANG 1000

enum stageButton {SBdontShow, SBstageClear, SBpuzzleMode};

extern stageButton stageButtonStatus;

//This is the size of the blocks. They are always 50. The internal logic calculates it that way
const int bsize = 50;

/**
 * This struct defines the start conditions of the game
 */
struct BlockGameStartInfo {
	unsigned int ticks = 0;
	bool timeTrial = false;
	///True means a stage clear game will be started. level must be set too.
	bool stageClear = false;
	///True if puzzle mode. level must be set too.
	bool puzzleMode = false;
	///Single puzzle is used for the editor only.
	bool singlePuzzle = false;
	int level = 0;
	bool AI = false;
	/**
	 * True means that stats will be recorded.
	 * If AI is true then this will be overruled to false 
	 */
	bool recordStats = true;
	bool vsMode = false;
	/**
	 * Set to true if we are fighting an AI. level should be the AI level we are fighting
	 */
	bool vsAI = false;
	int startBlocks = -1;
	int handicap = 0;
	int gameSpeed = 0;
	template <class Archive>
	void serialize( Archive & ar )
	{
		ar( CEREAL_NVP(ticks), CEREAL_NVP(timeTrial), CEREAL_NVP(stageClear), CEREAL_NVP(puzzleMode), CEREAL_NVP(singlePuzzle), 
			CEREAL_NVP(level), CEREAL_NVP(AI), CEREAL_NVP(recordStats), CEREAL_NVP(vsMode), CEREAL_NVP(vsAI), 
			CEREAL_NVP(startBlocks), CEREAL_NVP(handicap), CEREAL_NVP(gameSpeed) );
	}
};

struct GarbageStruct {
	bool greyGarbage = false;
	int width = 0;
	int height = 0;
	void setGarbage(int w, int h, bool g = false) {
		greyGarbage = g;
		width = w;
		height = h;
	}
	template <class Archive>
	void serialize( Archive & ar )
	{
		ar( CEREAL_NVP(greyGarbage), CEREAL_NVP(width), CEREAL_NVP(height) );
	}
};

struct BlockGameAction {
	enum class Action {NONE, UPDATE, SET_DRAW, SET_WON, SET_GAME_OVER, MOVE, SWITCH, PUSH, PUSH_GARBAGE, MOUSE_DOWN, MOUSE_UP, MOUSE_MOVE};
	Action action = Action::NONE;
	unsigned int tick = 0;  //< Used for update
	char way = '\0';  //< The direction to move the cursor: 'N', 'E', 'S' or 'W'
	int x = 0;
	int y = 0;
	std::vector<GarbageStruct> garbage;
	template <class Archive>
	void serialize( Archive & ar )
	{
		ar( CEREAL_NVP(action), CEREAL_NVP(tick), CEREAL_NVP(way), CEREAL_NVP(x), CEREAL_NVP(y), CEREAL_NVP(garbage) );
	}
};

struct BlockGameInfoExtra {
	std::string name;
	int score = 0;
	int seconds = 0;
	template <class Archive>
	void serialize( Archive & ar )
	{
		ar( CEREAL_NVP(name), CEREAL_NVP(score), CEREAL_NVP(seconds) );
	}
};

struct BlockGameInfo {
	BlockGameStartInfo startInfo;
	std::deque<BlockGameAction> actions;
	BlockGameInfoExtra extra;
	template <class Archive>
	void serialize( Archive & ar )
	{
		ar( CEREAL_NVP(startInfo), CEREAL_NVP(actions), CEREAL_NVP(extra) );
	}
};

////////////////////////////////////////////////////////////////////////////////
//The BloackGame class represents a board, score, time etc. for a single player/
////////////////////////////////////////////////////////////////////////////////
class BlockGame
{
private:
	int prevTowerHeight = 0;
	bool bGarbageFallLeft = false;
	bool singlePuzzle = false;

	int nextGarbageNumber = 0;
	int pushedPixelAt = 0;
	int nrPushedPixel = 0;
	int nrFellDown = 0;
	unsigned int nrStops = 0;
	bool garbageToBeCleared[7][30] = {};
	unsigned int lastAImove = 0;

	int AI_LineOffset = 0; //how many lines have changed since command
	int hangTicks = 0;    //How many times have hang been decreased?
	//int the two following index 0 may NOT be used (what the fuck did I meen?)
	int chainSize[NUMBEROFCHAINS]{}; //Contains the chains
	bool chainUsed[NUMBEROFCHAINS]{};   //True if the chain is used

	unsigned int nextRandomNumber = 0;
	int Level = 0; //Only used in stageClear and puzzle (not implemented)

	BlockGameInfo replayInfo;
	
	int rand2();
	int firstUnusedChain();

//public:
protected:
	int lastCounter = 0;
	std::string strHolder;
	bool bDraw = false;
	unsigned int ticks = 0;
	unsigned int gameStartedAt = 0;
	unsigned int gameEndedAfter = 0;		//How long did the game last?
	int linesCleared = 0;
	int TowerHeight = 0;
	int board[7][30];
	int stop = 0;
	int speedLevel = 0;
	int pixels = 0;
	int MovesLeft = 0;
	bool timetrial = false;
	bool stageClear = false;
	bool vsMode = false;
	bool puzzleMode = false;
	int stageClearLimit = 0; //stores number of lines user must clear to win
	int combo = 0;
	int chain = 0;
	int cursorx = 2; //stores cursor position
	int cursory = 3; // -||-
	int mouse_cursorx = -1;  //Stores the mouse hold cursor. -1 if nothing is selected.
	int mouse_cursory = -1;
	double speed = 0.0;
	double baseSpeed = 0.0; //factor for speed. Lower value = faster gameplay
	int score = 0;
	bool bGameOver = false;
	bool hasWonTheGame = false;
	int AI_MoveSpeed = 0;   //How often will the computer move? milliseconds
	bool AI_Enabled = false;
	bool recordStats = true;
	bool vsAI = false;  //Set to true for single player vs

	int handicap = 0;
	
	std::vector<GarbageStruct> garbageSendQueue;

	int AIlineToClear = 0;

	short AIstatus = 0;   //Status flags:
	//0: nothing, 2: clear tower, 3: clear horisontal, 4: clear vertical
	//1: make more lines, 5: make 2 lines, 6: make 1 line

public:

	std::string name;

public:
	BlockGame();
	virtual ~BlockGame() = default;

	int getAIlevel()  const;
	
	virtual void AddText(int, int, unsigned int, int) const  {}
	virtual void AddBall(int, int, bool, int) const  {}
	virtual void AddExplosion(int, int) const  {}
	virtual void PlayerWonEvent() const  {}
	virtual void DrawEvent() const {}
	virtual void BlockPopEvent() const  {}
	virtual void LongChainDoneEvent() const  {}
	virtual void TimeTrialEndEvent() const  {}
	virtual void EndlessHighscoreEvent() const  {}
	
	void NewGame(const BlockGameStartInfo &s);
	void DoAction (const BlockGameAction& action);
	/**
	 * This function returns all the garbage.
	 * This is actual const in the way that it does not change the games state
	 * Technically it is not const because it empties the queue that are stored inside the object even if not part of the game state.
	 * @param poppedData
	 */
	void PopSendGarbage(std::vector<GarbageStruct>& poppedData);
	
	int GetScore() const;
	int GetHandicap() const;
	bool isGameOver() const;
	int GetGameStartedAt() const;
	int GetGameEndedAt() const;
	bool isTimeTrial() const;
	bool isStageClear() const;
	bool isVsMode() const;
	bool isPuzzleMode() const;
	int GetLinesCleared() const;
	int GetStageClearLimit() const;
	int GetChains() const;
	int GetPixels() const;
	int GetSpeedLevel() const;
	int GetTowerHeight() const;
	int GetCursorX() const;
	int GetCursorY() const;
	void GetMouseCursor(bool& pressed, int& x, int&y) const;
	bool GetIsWinner() const;
	bool isSinglePuzzle() const;
	int getLevel() const;
	bool GetAIenabled() const;
	bool IsNearDeath() const;
	const BlockGameInfo& GetBlockGameInfo() {
		return replayInfo;
	}
private:
	void NewGame(unsigned int ticks);
	//Test if LineNr is an empty line, returns false otherwise.
	bool LineEmpty(int lineNr) const;
	//Test if the entire board is empty (used for Puzzles)
	bool BoardEmpty() const;
	//Anything that the user can't move? In that case Game Over cannot occur
	bool hasStaticContent() const;
	void putStartBlocks();
	void putStartBlocks(int n);
	//decreases hang for all hanging blocks and wait for waiting blocks
	void ReduceStuff();
	void setGameSpeed(int globalSpeedLevel);
	void setHandicap(int globalHandicap);
	//Clears garbage, must take one the lower left corner!
	int GarbageClearer(int x, int y, int number, bool aLineToClear, int chain);
	//Marks garbage that must be cleared
	int GarbageMarker(int x, int y);
	int FirstGarbageMarker(int x, int y);
	//Clear Blocks if 3 or more is alligned (naive implemented)
	void ClearBlocks();
	//Moves all peaces a spot down if possible
	int FallBlock(int x, int y, int number);
	//Makes all Garbage fall one spot
	void GarbageFall();
	//Makes the blocks fall (it doesn't test time, this must be done before hand)
	void FallDown();
	//Pushes a single pixel, so it appears to scrool
	void PushPixels();
	//See how high the tower is, saved in integer TowerHeight
	void FindTowerHeight();
	//Generates a new line and moves the field one block up (restart puzzle mode)
	void PushLine();
	//prints "Game Over" and ends game
	void SetGameOver();
	//Moves the cursor, receaves N,S,E or W as a char an moves as desired
	void MoveCursor(char way);
	//switches the two blocks at the cursor position, unless game over
	void SwitchAtCursor();
	//Creates garbage using a given wide and height
	bool CreateGarbage(int wide, int height);
	//Creates garbage using a given wide and height
	bool CreateGreyGarbage();
	void MouseDown(int x, int y);  //Send then the mouse is pressed 
	void MouseMove(int x);  //Send then the mouse moves
	void MouseUp();  //Send then the mouse goes up
	void MoveCursorTo(int x, int y);
	void FinalizeBlockGameInfo();
///////////////////////////////////////////////////////////////////////////
/////////////////////////// AI starts here! ///////////////////////////////
///////////////////////////////////////////////////////////////////////////
	//First the helpet functions:
	int nrOfType(int line, int type);
	int AIcolorToClear = 0;
	//See if a combo can be made in this line
	int horiInLine(int line);
	bool horiClearPossible();
	//the Line Has Unmoveable Objects witch might stall the AI
	bool lineHasGarbage(int line);
	//Types 0..6 in line
	int nrOfRealTypes(int line);
	//See if there is a tower
	bool ThereIsATower();
	double firstInLine1(int line);
	//returns the first coordinate of the block of type
	double firstInLine(int line, int type);
	//There in the line shall we move
	int closestTo(int line, int place);
	//The AI will remove a tower
	void AI_ClearTower();
	//The AI will try to clear block horisontally
	void AI_ClearHori();
	//Test if vertical clear is possible
	bool veriClearPossible();
	//There in the line shall we move
	int closestTo(int line, int type, int place);
	//The AI will try to clear blocks vertically
	void AI_ClearVertical();
	bool firstLineCreated = 0;
	void AI_Move();
//////////////////////////////////////////////////////////////////
///////////////////////////// AI ends here! //////////////////////
//////////////////////////////////////////////////////////////////
	//Set the move speed of the AI based on the aiLevel parameter
	void setAIlevel(int aiLevel);
	void PushLineInternal();
	//Prints "winner" and ends game
	void setPlayerWon();
	//Prints "draw" and ends the game
	void setDraw();
	//Updates evrything, if not called nothing happends
	void Update();
	void UpdateInternal(unsigned int newtick);
};

//Play the next level
void nextLevel(BlockGame& g, unsigned int ticks);
//Replay the current level
void retryLevel(BlockGame& g, unsigned int ticks);

#endif