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 | |
12 | KBlocksGameLogic::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 | |
36 | KBlocksGameLogic::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 | |
53 | KBlocksGameLogic::~KBlocksGameLogic() |
54 | { |
55 | if (mpGameRecorder) |
56 | { |
57 | delete mpGameRecorder; |
58 | } |
59 | delete [] maGameList; |
60 | } |
61 | |
62 | int 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 | |
75 | KBlocksSingleGame* KBlocksGameLogic::getSingleGame(int index) |
76 | { |
77 | if ((index < 0) || (index >= mGameCount)) |
78 | { |
79 | return 0; |
80 | } |
81 | return maGameList[index]; |
82 | } |
83 | |
84 | bool 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 | |
149 | void KBlocksGameLogic::saveRecord(const char * fileName, bool binaryMode) |
150 | { |
151 | if (mpGameRecorder) |
152 | { |
153 | mpGameRecorder->save(fileName, binaryMode); |
154 | } |
155 | } |
156 | |
157 | int 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 | |
168 | int 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 | |
207 | void KBlocksGameLogic::setGameSeed(int seed) |
208 | { |
209 | mGameSeed = (seed % 256); |
210 | } |
211 | |
212 | void KBlocksGameLogic::setGamePunish(bool flag) |
213 | { |
214 | mPunishFlag = flag; |
215 | } |
216 | |
217 | void 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 | |
226 | void 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 | |
235 | void KBlocksGameLogic::setInitInterval(int interval) |
236 | { |
237 | mInitialInterval = interval; |
238 | } |
239 | |
240 | void KBlocksGameLogic::setLevelUpInterval(int interval) |
241 | { |
242 | mLevelUpInterval = interval; |
243 | } |
244 | |
245 | bool 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 | |
256 | bool KBlocksGameLogic::stopGame() |
257 | { |
258 | if (mGameCount == 0) |
259 | { |
260 | return false; |
261 | } |
262 | deleteSingleGames(); |
263 | |
264 | return true; |
265 | } |
266 | |
267 | void KBlocksGameLogic::pauseGame(bool pauseFlag) |
268 | { |
269 | for(int i = 0; i < mGameCount; i++) |
270 | { |
271 | maGameList[i]->pauseGame(pauseFlag); |
272 | } |
273 | } |
274 | |
275 | void KBlocksGameLogic::continueGame() |
276 | { |
277 | for(int i = 0; i < mGameCount; i++) |
278 | { |
279 | maGameList[i]->continueGame(); |
280 | } |
281 | } |
282 | |
283 | void 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 | |
334 | void 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 | |