Game end works this way now:
[crack-attack.git] / src / Game.cxx
blobbe77c387825c3cc621b32fecc099928f0b07463a
1 /*
2 * Game.cxx
3 * Daniel Nelson - 8/25/0
5 * Copyright (C) 2000 Daniel Nelson
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * Daniel Nelson - aluminumangel.org
22 * 174 W. 18th Ave.
23 * Columbus, OH 43210
25 * The core loop plus extras.
26 * Remove dying_count_2.
29 #include <GL/glut.h>
31 #include "glext.h"
33 #include <sys/time.h>
35 #include <cassert>
37 using namespace std;
39 #include "Game.h"
40 #include "BlockManager.h"
41 #include "CelebrationManager.h"
42 #include "Clock.h"
43 #include "Controller.h"
44 #include "ActionRecorder.h"
45 #include "Communicator.h"
46 #include "ComboManager.h"
47 #include "CountDownManager.h"
48 #include "Creep.h"
49 #include "GarbageGenerator.h"
50 #include "GarbageManager.h"
51 #include "Grid.h"
52 #include "LevelLights.h"
53 #include "LoseBar.h"
54 #include "MessageManager.h"
55 #include "MetaState.h"
56 #include "Random.h"
57 #include "Score.h"
58 #include "ScoreRecordManager.h"
59 #include "SignManager.h"
60 #include "Sine.h"
61 #include "SparkleManager.h"
62 #include "Spring.h"
63 #include "Swapper.h"
64 #include "WinRecord.h"
65 #include "X.h"
66 #include "ComputerPlayer.h"
67 #ifdef AUDIO_ENABLED
68 #include "Music.h"
69 #endif
71 int Game::time_step;
72 int Game::state;
73 int Game::awaking_count;
74 int Game::dying_count;
75 int Game::dying_count_2;
76 int Game::previous_time;
77 int Game::remaining_time;
78 bool Game::button_down_pause;
79 bool Game::step_play;
80 int Game::sync_wait;
81 double Game::lastframe = 0.0;
83 void Game::initialize ( )
85 Random::initialize();
86 WinRecord::initialize();
87 LevelLights::initialize();
88 Score::initialize();
89 Sine::initialize();
90 LoseBar::initialize();
91 ActionRecorder::initialize();
93 gameFinish();
96 void Game::gameStart ( )
98 state = GS_NORMAL;
100 awaking_count = 0;
101 dying_count = 0;
103 WinRecord::gameStart();
105 BlockManager::gameStart();
106 GarbageManager::gameStart();
107 ComboManager::gameStart();
108 GarbageGenerator::gameStart();
109 X::gameStart();
110 Grid::gameStart();
111 Controller::gameStart();
112 Creep::gameStart();
113 Swapper::gameStart();
114 Spring::gameStart();
115 LevelLights::gameStart();
116 CountDownManager::gameStart();
117 Clock::gameStart();
118 LoseBar::gameStart();
119 ComputerPlayer::gameStart();
121 button_down_pause = false;
123 step_play = true;
125 remaining_time = 0;
126 time_step = 1;
129 void Game::gameFinish ( )
131 remaining_time = 0;
132 time_step = 1;
135 void Game::cleanUp ( )
137 CountDownManager::cleanUp();
138 Score::cleanUp();
141 void Game::loss ( )
143 * Called when creep detects a game loss condition; opponent may have already
144 * lost, so me must wait for confirmation.
147 if (!(MetaState::mode & CM_SOLO)) {
148 if (!(state & (GS_MAY_HAVE_LOST | GS_WON))) {
149 state = GS_MAY_HAVE_LOST;
150 Communicator::setLossTimeStep();
152 } else
153 state |= GS_END_PLAY;
156 void Game::lossConfirmation ( )
158 * Called by Communicator when opponent confirms game loss. Now we must only
159 * wait for the level lights to end play.
162 state = GS_LOST | GS_END_PLAY;
165 void Game::aiPlayerLoss ( )
167 if (!(state & GS_WON) && !(state & GS_END_PLAY))
168 state = GS_WON | GS_END_PLAY;
171 void Game::won ( )
173 * Called by Communicator when opponent signals a game loss that predates
174 * ours or signals a reverse of our game loss. Now we must wait to confirm
175 * our opponent's loss and for the level lights to end play.
178 if (!(state & GS_WON))
179 state = GS_WON | GS_MUST_CONFIRM_LOSS;
182 void Game::concession ( )
184 * Called by the controller upon player concession.
187 if (CountDownManager::start_pause_alarm != 0) return;
189 loss();
190 MetaState::state |= MS_CONCESSION;
193 void Game::buttonPause ( )
194 // run time step during pause (for Communicator); then reset the clock to the
195 // value at the pause time
197 // unpause
198 if ((state & (GS_PAUSED | GS_SYNC_WAIT)) == GS_PAUSED) {
199 state = GS_NORMAL;
201 MessageManager::freeMessage();
202 if (CountDownManager::state != -1)
203 MessageManager::readyMessage(CountDownManager::state);
205 if (!(MetaState::mode & CM_SOLO)) {
206 Communicator::unpauseSyncCheck();
207 Communicator::signalUnpaused();
209 #ifdef AUDIO_ENABLED
210 Music::resume();
211 #endif
213 // pause
214 } else {
215 // to simplify things, you can't pause if you're about to lose
216 if (!(state & GS_NORMAL)) return;
218 state = GS_PAUSED;
220 if (CountDownManager::state != -1)
221 MessageManager::freeMessage();
222 MessageManager::readyMessage(MS_PAUSED);
224 if (!(MetaState::mode & CM_SOLO))
225 Communicator::signalPaused();
226 #ifdef AUDIO_ENABLED
227 Music::pause();
228 #endif
232 void Game::netSignalPause ( )
234 if (!(state & GS_NORMAL)) return;
236 state = GS_PAUSED;
238 if (CountDownManager::state != -1)
239 MessageManager::freeMessage();
240 MessageManager::readyMessage(MS_PAUSED);
243 void Game::netSignalUnpause ( )
245 if ((state & (GS_PAUSED | GS_SYNC_WAIT)) != GS_PAUSED) return;
247 state = GS_NORMAL;
249 MessageManager::freeMessage();
250 if (CountDownManager::state != -1)
251 MessageManager::readyMessage(CountDownManager::state);
254 void Game::syncPause ( int delay )
256 assert(delay > 0);
258 state = GS_PAUSED | GS_SYNC_WAIT;
259 sync_wait = delay;
261 if (CountDownManager::state != -1)
262 MessageManager::freeMessage();
263 MessageManager::readyMessage(MS_WAITING);
266 void Game::syncUnpause ( )
268 state = GS_NORMAL;
270 MessageManager::freeMessage();
271 if (CountDownManager::state != -1)
272 MessageManager::readyMessage(CountDownManager::state);
275 void Game::idleMeta ( )
277 #ifndef _WIN32
278 timeval now;
279 double nowd;
280 gettimeofday(&now,NULL);
281 #define FPSDIFF (1.0f/30.0f)
282 nowd = now.tv_sec;
283 nowd += (double)now.tv_usec / 1000000.0f;
285 if ( (nowd - lastframe) > FPSDIFF ) {
286 lastframe = nowd;
287 } else {
288 usleep(1000);
290 #endif
292 int modified_and_complete = false;
294 do {
296 int time = glutGet((GLenum) GLUT_ELAPSED_TIME);
297 remaining_time += time - previous_time;
298 previous_time = time;
300 // no time step yet
301 if (remaining_time < GC_TIME_STEP_PERIOD) break;
303 remaining_time -= GC_TIME_STEP_PERIOD;
304 time_step++;
306 if (remaining_time < GC_TIME_STEP_PERIOD)
307 modified_and_complete = true;
308 else
309 DOT(3);
311 // communicate state and other stuff
312 if (!(MetaState::state & MS_GAME_OVER_KEY_WAIT) &&
313 !(MetaState::mode & CM_SOLO))
314 Communicator::timeStepMeta();
316 // advance celebration
317 CelebrationManager::timeStep();
319 // advance the score record
320 ScoreRecordManager::timeStep();
322 // update message pulse
323 MessageManager::timeStep();
325 // update the pretty stuff too
326 SparkleManager::timeStep();
327 SignManager::timeStep();
328 if (!(MetaState::mode & CM_REALLY_LOW_GRAPHICS))
329 WinRecord::timeStep();
330 LevelLights::timeStep();
332 // advance the clock through its final tick fade
333 Clock::timeStepMeta();
335 // advance the score through its final increment fade
336 Score::timeStepMeta();
338 } while (false);
340 if (modified_and_complete) {
341 glFinish();
342 glutPostRedisplay();
346 void Game::idlePlay ( )
348 #ifndef _WIN32
349 timeval now;
350 double nowd;
351 gettimeofday(&now,NULL);
352 #define FPSDIFF (1.0f/30.0f)
353 nowd = now.tv_sec;
354 nowd += (double)now.tv_usec / 1000000.0f;
356 if ( (nowd - lastframe) > FPSDIFF ) {
357 lastframe = nowd;
358 } else {
359 usleep(1000);
361 #endif
363 int modified_and_complete = false;
365 do {
367 int time = glutGet((GLenum) GLUT_ELAPSED_TIME);
368 remaining_time += time - previous_time;
369 previous_time = time;
371 // no time step yet
372 if (remaining_time < GC_TIME_STEP_PERIOD) break;
374 remaining_time -= GC_TIME_STEP_PERIOD;
376 if (remaining_time < GC_TIME_STEP_PERIOD)
377 modified_and_complete = true;
378 else
379 DOT(2);
381 if (!(state & GS_PAUSED)) {
382 if (step_play) {
384 time_step++;
386 // check for and continue swaps and moves
387 Swapper::timeStep();
389 // update the level lights
390 LevelLights::timeStep();
392 // update message pulse
393 MessageManager::timeStep();
395 // move the win record stars
396 WinRecord::timeStep();
398 // update the starting count down
399 CountDownManager::timeStep();
400 if (CountDownManager::start_pause_alarm != 0) {
401 // some objects require a time step during start pause
403 if (!(MetaState::mode & CM_SOLO))
404 Communicator::timeStepPlay();
406 // reset the clock
407 Clock::timeStepMeta();
409 continue;
412 if (MetaState::mode & CM_AI)
413 ComputerPlayer::timeStep();
415 // loop over the grid, bottom to top; garbage will advance x and y
416 for (int y = 1; y < GC_PLAY_HEIGHT; y++)
417 for (int x = 0; x < GC_PLAY_WIDTH; x++) {
418 if (Grid::residentTypeAt(x, y) & GR_EMPTY) continue;
420 if (Grid::residentTypeAt(x, y) & GR_BLOCK)
421 Grid::blockAt(x, y).timeStep();
422 else
423 Grid::garbageAt(x, y).timeStep(x, y);
426 // perhaps creep upward
427 Creep::timeStep();
429 // process elimination check requests and update top_occupied_row
430 Grid::timeStep();
432 // handle new and finished combos
433 ComboManager::timeStep();
436 // communicate garbage and other stuff
437 if (!(MetaState::mode & CM_SOLO))
438 Communicator::timeStepPlay();
440 if (step_play) {
442 // drop queued garbage
443 GarbageGenerator::timeStep();
445 // move the sparkles and signs
446 SparkleManager::timeStep();
447 SignManager::timeStep();
449 // update the impact spring
450 if (!(MetaState::mode & CM_REALLY_LOW_GRAPHICS))
451 Spring::timeStep();
453 // update the clock
454 Clock::timeStepPlay();
456 // update the score
457 Score::timeStepPlay();
459 // update the losebar
460 LoseBar::timeStep();
462 // advance extreme effects
463 if (MetaState::mode & CM_X)
464 X::timeStep();
467 } else {
469 // if this is a sync pause, count down the waiting period
470 if (state & GS_SYNC_WAIT && !--sync_wait)
471 syncUnpause();
473 // communicate when paused
474 if (!(MetaState::mode & CM_SOLO))
475 Communicator::timeStepPlay();
477 // update message pulse
478 MessageManager::timeStep();
481 if (state & (GS_MAY_HAVE_LOST | GS_MUST_CONFIRM_LOSS))
482 step_play = false;
484 if (state & GS_END_PLAY) {
485 // step_play = false;
486 if (state & GS_PAUSED)
487 MessageManager::freeMessage();
489 if ((MetaState::mode & CM_SOLO) && !(MetaState::mode & CM_AI))
490 state = Score::gameFinish();
492 if (MetaState::mode & CM_AI)
493 state = ComputerPlayer::gameFinish();
495 ActionRecorder::gameFinish();
497 if (state & GS_LOST)
498 MetaState::gameLoss();
499 else
500 MetaState::gameWon();
502 break;
505 } while (false);
507 if (!button_down_pause) {
508 if (Controller::pauseCommand()) {
509 button_down_pause = true;
510 buttonPause();
512 } else
513 if (!Controller::pauseCommand())
514 button_down_pause = false;
516 if (modified_and_complete) {
517 glFinish();
518 glutPostRedisplay();