1/***************************************************************************
2* KBlocks, a falling blocks game for KDE *
3* Copyright (C) 2010 Zhongjie Cai <squall.leonhart.cai@gmail.com> *
4* *
5* This program is free software; you can redistribute it and/or modify *
6* it under the terms of the GNU General Public License as published by *
7* the Free Software Foundation; either version 2 of the License, or *
8* (at your option) any later version. *
9***************************************************************************/
10#include "KBlocksGameLogic.h"
11
12KBlocksGameLogic::KBlocksGameLogic(int capacity, bool record)
13{
14 mGameCount = 0;
15 mGameMax = capacity;
16
17 mGameSeed = 0;
18 mPunishFlag = true;
19
20 mStandbyMode = false;
21 mGameInterval = 0;
22
23 maGameList = new KBlocksSingleGame*[capacity];
24
25 if (record)
26 {
27 mpGameRecorder = new KBlocksGameRecorder();
28 }
29 else
30 {
31 mpGameRecorder = 0;
32 }
33 mpGameReplayer = 0;
34}
35
36KBlocksGameLogic::KBlocksGameLogic(KBlocksGameReplayer * p)
37{
38 mGameCount = 0;
39 mGameMax = p->getGameCount();
40
41 mGameSeed = 0;
42 mPunishFlag = true;
43
44 mStandbyMode = false;
45 mGameInterval = 0;
46
47 maGameList = new KBlocksSingleGame*[mGameMax];
48
49 mpGameRecorder = 0;
50 mpGameReplayer = p;
51}
52
53KBlocksGameLogic::~KBlocksGameLogic()
54{
55 if (mpGameRecorder)
56 {
57 delete mpGameRecorder;
58 }
59 delete [] maGameList;
60}
61
62int KBlocksGameLogic::getActiveGameCount()
63{
64 int result = 0;
65 for(int i = 0; i < mGameCount; i++)
66 {
67 if (maGameList[i]->isGameRunning())
68 {
69 result++;
70 }
71 }
72 return result;
73}
74
75KBlocksSingleGame* KBlocksGameLogic::getSingleGame(int index)
76{
77 if ((index < 0) || (index >= mGameCount))
78 {
79 return 0;
80 }
81 return maGameList[index];
82}
83
84bool KBlocksGameLogic::playRecordOneStep(int * changedPiece)
85{
86 int tmpCount;
87 vector<KBlocksReplayData> tmpData;
88 *changedPiece = 0;
89 if (mpGameReplayer->getNextRecords(&tmpData))
90 {
91 for(size_t i = 0; i < tmpData.size(); i++)
92 {
93 switch(tmpData[i].type)
94 {
95 case RecordDataType_MovePieceLeft:
96 maGameList[tmpData[i].index]->setCurrentPiece(-1, 0, 0);
97// printf("[%d] - Move Left\n", tmpData[i].index);
98 break;
99 case RecordDataType_MovePieceRight:
100 maGameList[tmpData[i].index]->setCurrentPiece(1, 0, 0);
101// printf("[%d] - Move Right\n", tmpData[i].index);
102 break;
103 case RecordDataType_MovePieceUp:
104 maGameList[tmpData[i].index]->setCurrentPiece(0, -1, 0);
105// printf("[%d] - Move Up\n", tmpData[i].index);
106 break;
107 case RecordDataType_MovePieceDown:
108 maGameList[tmpData[i].index]->setCurrentPiece(0, 1, 0);
109// printf("[%d] - Move Down\n", tmpData[i].index);
110 break;
111 case RecordDataType_RotatePieceCW:
112 maGameList[tmpData[i].index]->setCurrentPiece(0, 0, -1);
113// printf("[%d] - Rotate Left\n", tmpData[i].index);
114 break;
115 case RecordDataType_RotatePieceCCW:
116 maGameList[tmpData[i].index]->setCurrentPiece(0, 0, 1);
117// printf("[%d] - Rotate Right\n", tmpData[i].index);
118 break;
119 case RecordDataType_GameOneStep:
120 maGameList[tmpData[i].index]->forceUpdateGame();
121 *changedPiece |= (1 << tmpData[i].index);
122// printf("[%d] - Game Stepped\n", tmpData[i].index);
123 break;
124 case RecordDataType_PunishLineCount:
125 tmpCount = tmpData[i].value;
126 ++i;
127 if (tmpData[i].type == RecordDataType_PunishLineSeed)
128 {
129 maGameList[tmpData[i].index]->punishGame(tmpCount, tmpData[i].value);
130// printf("[%d] - Punish %d(%d)\n", tmpData[i].index, tmpCount, tmpData[i].value);
131 }
132 break;
133 case RecordDataType_Skipped:
134// printf("[%d] - A skipper step\n", tmpData[i].index);
135 break;
136 default:
137// printf("[%d] - Error default\n", tmpData[i].index);
138 break;
139 }
140 }
141 return true;
142 }
143 else
144 {
145 return false;
146 }
147}
148
149void KBlocksGameLogic::saveRecord(const char * fileName, bool binaryMode)
150{
151 if (mpGameRecorder)
152 {
153 mpGameRecorder->save(fileName, binaryMode);
154 }
155}
156
157int KBlocksGameLogic::levelUpGame(int level)
158{
159 mGameInterval -= (mLevelUpInterval * level);
160 if (mGameInterval < (mLevelUpInterval * 2))
161 {
162 mGameInterval = mLevelUpInterval;
163 }
164 setGameInterval(mGameInterval);
165 return mGameInterval;
166}
167
168int KBlocksGameLogic::updateGame(int * lineList)
169{
170 for(int i = 0; i < mGameCount; i++)
171 {
172 int tmpTotal = 0;
173 int tmpValue = 0;
174 int tmpPunishCount = 0;
175
176 while(maGameList[i]->pickGameResult(&tmpValue))
177 {
178 if (tmpValue < 0)
179 {
180 tmpTotal = -1;
181 tmpPunishCount = 0;
182 break;
183 }
184 tmpTotal += tmpValue;
185 tmpPunishCount += (tmpValue - 1);
186 }
187
188 lineList[i] = tmpTotal;
189
190 if ((mPunishFlag) && (tmpPunishCount > 0))
191 {
192 int punishSeed = rand() % 256;
193 for(int j = 0; j < i; j++)
194 {
195 maGameList[j]->punishGame(tmpPunishCount, punishSeed);
196 }
197 for(int j = i + 1; j < mGameCount; j++)
198 {
199 maGameList[j]->punishGame(tmpPunishCount, punishSeed);
200 }
201 }
202 }
203
204 return getActiveGameCount();
205}
206
207void KBlocksGameLogic::setGameSeed(int seed)
208{
209 mGameSeed = (seed % 256);
210}
211
212void KBlocksGameLogic::setGamePunish(bool flag)
213{
214 mPunishFlag = flag;
215}
216
217void KBlocksGameLogic::setGameStandbyMode(bool flag)
218{
219 mStandbyMode = flag;
220 for(int i = 0; i < mGameCount; i++)
221 {
222 maGameList[i]->setGameStandbyMode(mStandbyMode);
223 }
224}
225
226void KBlocksGameLogic::setGameInterval(int interval)
227{
228 mGameInterval = interval;
229 for(int i = 0; i < mGameCount; i++)
230 {
231 maGameList[i]->setGameInterval(mGameInterval);
232 }
233}
234
235void KBlocksGameLogic::setInitInterval(int interval)
236{
237 mInitialInterval = interval;
238}
239
240void KBlocksGameLogic::setLevelUpInterval(int interval)
241{
242 mLevelUpInterval = interval;
243}
244
245bool KBlocksGameLogic::startGame(int gameCount)
246{
247 if (mGameCount != 0)
248 {
249 return false;
250 }
251 mGameInterval = mInitialInterval;
252 createSingleGames(gameCount);
253 return true;
254}
255
256bool KBlocksGameLogic::stopGame()
257{
258 if (mGameCount == 0)
259 {
260 return false;
261 }
262 deleteSingleGames();
263
264 return true;
265}
266
267void KBlocksGameLogic::pauseGame(bool pauseFlag)
268{
269 for(int i = 0; i < mGameCount; i++)
270 {
271 maGameList[i]->pauseGame(pauseFlag);
272 }
273}
274
275void KBlocksGameLogic::continueGame()
276{
277 for(int i = 0; i < mGameCount; i++)
278 {
279 maGameList[i]->continueGame();
280 }
281}
282
283void KBlocksGameLogic::createSingleGames(int gameCount)
284{
285 if (gameCount > mGameMax)
286 {
287 gameCount = mGameMax;
288 }
289 mGameCount = gameCount;
290
291 if (mpGameRecorder)
292 {
293 mpGameRecorder->append(0, RecordDataType_GameCount, mGameCount);
294 if (mGameSeed < 0)
295 {
296 mpGameRecorder->append(0, RecordDataType_GameSeed, -mGameSeed);
297 }
298 else
299 {
300 mpGameRecorder->append(1, RecordDataType_GameSeed, mGameSeed);
301 }
302 }
303
304 int *seedList = new int[mGameCount];
305 if (mGameSeed < 0)
306 {
307 mGameSeed = -mGameSeed;
308 srand(mGameSeed);
309 for(int i = 0; i < mGameCount; i++)
310 {
311 seedList[i] = rand() % 256;
312 }
313 }
314 else
315 {
316 for(int i = 0; i < mGameCount; i++)
317 {
318 seedList[i] = mGameSeed;
319 }
320 }
321
322 for(int i = 0; i < mGameCount; i++)
323 {
324 maGameList[i] = new KBlocksSingleGame(i);
325 maGameList[i]->setGameStandbyMode(mStandbyMode);
326 maGameList[i]->setGameInterval(mGameInterval);
327 maGameList[i]->setGameRecorder(mpGameRecorder);
328 maGameList[i]->startGame(seedList[i]);
329 }
330
331 delete[] seedList;
332}
333
334void KBlocksGameLogic::deleteSingleGames()
335{
336 for(int i = 0; i < mGameCount; i++)
337 {
338 maGameList[i]->stopGame();
339 delete maGameList[i];
340 maGameList[i] = 0;
341 }
342 mGameCount = 0;
343}
344