00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "Level.h"
00010
00011 #include "StateManager.h"
00012 #include "DescFinder.h"
00013 #include "PhaseLocker.h"
00014 #include "LevelInput.h"
00015 #include "LevelScript.h"
00016 #include "LevelLoading.h"
00017 #include "LevelCountDown.h"
00018 #include "CommandQueue.h"
00019 #include "MultiDrawer.h"
00020
00021 #include "Log.h"
00022 #include "Room.h"
00023 #include "StepCounter.h"
00024 #include "View.h"
00025 #include "OptionAgent.h"
00026 #include "VideoAgent.h"
00027 #include "ScriptException.h"
00028 #include "LogicException.h"
00029 #include "DemoMode.h"
00030 #include "SoundAgent.h"
00031 #include "SubTitleAgent.h"
00032 #include "StepDecor.h"
00033 #include "StatusDisplay.h"
00034 #include "Picture.h"
00035 #include "DialogStack.h"
00036
00037 #include <stdio.h>
00038 #include <assert.h>
00039
00040
00041
00042
00043
00044 Level::Level(const std::string &codename, const Path &datafile, int depth)
00045 : m_codename(codename), m_datafile(datafile)
00046 {
00047 m_desc = NULL;
00048 m_restartCounter = 1;
00049 m_depth = depth;
00050 m_newRound = false;
00051 m_locker = new PhaseLocker();
00052 m_levelScript = new LevelScript(this);
00053 m_loading = new LevelLoading(m_levelScript);
00054 m_countdown = new LevelCountDown(m_levelScript);
00055 m_show = new CommandQueue();
00056 m_background = new MultiDrawer();
00057 m_statusDisplay = new StatusDisplay();
00058 takeHandler(new LevelInput(this));
00059 registerDrawable(m_background);
00060 registerDrawable(SubTitleAgent::agent());
00061 registerDrawable(m_statusDisplay);
00062 }
00063
00064 Level::~Level()
00065 {
00066 own_cleanState();
00067 delete m_locker;
00068
00069
00070 delete m_show;
00071 delete m_countdown;
00072 delete m_loading;
00073 delete m_levelScript;
00074 delete m_background;
00075 delete m_statusDisplay;
00076 }
00077
00078 void
00079 Level::fillStatus(LevelStatus *status)
00080 {
00081 m_countdown->fillStatus(status);
00082 }
00083
00084
00085
00086
00087
00088 void
00089 Level::own_initState()
00090 {
00091 if (NULL == m_desc) {
00092 throw LogicException(ExInfo("level description is NULL")
00093 .addInfo("codename", m_codename));
00094 }
00095 m_countdown->reset();
00096 m_loading->reset();
00097
00098 m_locker->reset();
00099 m_locker->ensurePhases(1);
00100 SoundAgent::agent()->stopMusic();
00101
00102 m_levelScript->scriptDo("CODENAME = [[" + m_codename + "]]");
00103 m_levelScript->scriptInclude(m_datafile);
00104 }
00105
00106
00107
00108
00109 void
00110 Level::own_updateState()
00111 {
00112 m_newRound = false;
00113 if (m_locker->getLocked() == 0) {
00114 m_newRound = true;
00115 nextAction();
00116 }
00117 updateLevel();
00118 m_locker->decLock();
00119
00120 if (m_countdown->countDown(this)) {
00121 finishLevel();
00122 }
00123 }
00124
00125 void
00126 Level::own_pauseState()
00127 {
00128 m_levelScript->killPlan();
00129 }
00130
00131 void
00132 Level::own_resumeState()
00133 {
00134 if (m_levelScript->isRoom()) {
00135 initScreen();
00136 }
00137 }
00138
00139
00140
00141
00142 void
00143 Level::own_cleanState()
00144 {
00145 m_levelScript->cleanRoom();
00146 }
00147
00148
00149
00150
00151 void
00152 Level::own_noteBg()
00153 {
00154 if (m_loading->isLoading() && !m_loading->isPaused()) {
00155 m_loading->togglePause();
00156 }
00157 }
00158
00159 void
00160 Level::own_noteFg()
00161 {
00162 initScreen();
00163 if (m_loading->isLoading() && m_loading->isPaused()) {
00164 m_loading->togglePause();
00165 }
00166
00167 m_locker->ensurePhases(3);
00168 }
00169
00170
00171 bool
00172 Level::isLoading() const
00173 {
00174 return m_loading->isLoading();
00175 }
00176
00177 void
00178 Level::togglePause()
00179 {
00180 return m_loading->togglePause();
00181 }
00182
00183
00184
00185
00186 void
00187 Level::nextAction()
00188 {
00189 if (isLoading()) {
00190 nextLoadAction();
00191 }
00192 else {
00193 if (isShowing()) {
00194 nextShowAction();
00195 }
00196 else {
00197 nextPlayerAction();
00198 }
00199 }
00200 }
00201
00202
00203
00204
00205 void
00206 Level::updateLevel()
00207 {
00208 if (!isLoading()) {
00209 m_levelScript->updateScript();
00210 }
00211 }
00212
00213
00214
00215
00216
00217 void
00218 Level::finishLevel()
00219 {
00220 if (m_countdown->isFinishedEnough()) {
00221 m_countdown->saveSolution();
00222 GameState *nextState = m_countdown->createNextState();
00223 if (nextState) {
00224 changeState(nextState);
00225 }
00226 else {
00227 quitState();
00228 }
00229 }
00230 else if (m_countdown->isWrongEnough()) {
00231 action_restart();
00232 }
00233 }
00234
00235
00236
00237
00238
00239 void
00240 Level::nextPlayerAction()
00241 {
00242 if (m_levelScript->isRoom()) {
00243 m_levelScript->room()->nextRound(getInput());
00244 }
00245 }
00246
00247
00248
00249
00250
00251
00252
00253 void
00254 Level::saveGame(const std::string &models)
00255 {
00256 if (m_levelScript->isRoom()) {
00257 Path file = Path::dataWritePath("saves/" + m_codename + ".lua");
00258 FILE *saveFile = fopen(file.getNative().c_str(), "w");
00259 if (saveFile) {
00260 std::string moves =
00261 m_levelScript->room()->stepCounter()->getMoves();
00262 fputs("\nsaved_moves = '", saveFile);
00263 fputs(moves.c_str(), saveFile);
00264 fputs("'\n", saveFile);
00265
00266 fputs("\nsaved_models = ", saveFile);
00267 fputs(models.c_str(), saveFile);
00268 fclose(saveFile);
00269 displaySaveStatus();
00270 }
00271 else {
00272 LOG_WARNING(ExInfo("cannot save game")
00273 .addInfo("file", file.getNative()));
00274 }
00275 }
00276 }
00277
00278 void
00279 Level::displaySaveStatus()
00280 {
00281 static const int TIME = 3;
00282 LOG_INFO(ExInfo("game is saved")
00283 .addInfo("codename", m_codename));
00284 m_statusDisplay->displayStatus(
00285 new Picture(Path::dataReadPath("images/menu/status/saved.png"),
00286 V2(0, 0)), TIME);
00287 }
00288
00289
00290
00291
00292
00293 void
00294 Level::loadGame(const std::string &moves)
00295 {
00296 m_loading->loadGame(moves);
00297 }
00298
00299
00300
00301
00302
00303 void
00304 Level::loadReplay(const std::string &moves)
00305 {
00306 m_loading->loadReplay(moves);
00307 }
00308
00309
00310
00311
00312
00313 void
00314 Level::nextLoadAction()
00315 {
00316 m_loading->nextLoadAction();
00317 if (!isLoading()) {
00318 m_levelScript->scriptDo("script_loadState()");
00319 }
00320 }
00321
00322
00323
00324
00325 void
00326 Level::nextShowAction()
00327 {
00328 if (m_levelScript->isRoom()) {
00329 m_levelScript->room()->beginFall();
00330 m_show->executeFirst();
00331 m_levelScript->room()->finishRound();
00332 }
00333 }
00334
00335
00336
00337
00338
00339 bool
00340 Level::action_restart()
00341 {
00342 own_cleanState();
00343 m_restartCounter++;
00344
00345
00346 own_initState();
00347 return true;
00348 }
00349
00350
00351
00352
00353
00354
00355 bool
00356 Level::action_move(char symbol)
00357 {
00358 return m_levelScript->room()->makeMove(symbol);
00359 }
00360
00361
00362
00363
00364
00365 bool
00366 Level::action_save()
00367 {
00368 if (m_levelScript->room()->isSolvable()) {
00369 m_levelScript->scriptDo("script_save()");
00370 }
00371 else {
00372 LOG_INFO(ExInfo("bad level condition, level cannot be finished, "
00373 "no save is made"));
00374 }
00375 return true;
00376 }
00377
00378
00379
00380
00381
00382 bool
00383 Level::action_load()
00384 {
00385 Path file = Path::dataReadPath("saves/" + m_codename + ".lua");
00386 if (file.exists()) {
00387 m_restartCounter--;
00388 action_restart();
00389 m_levelScript->scriptInclude(file);
00390 m_levelScript->scriptDo("script_load()");
00391 }
00392 else {
00393 LOG_INFO(ExInfo("there is no file to load")
00394 .addInfo("file", file.getNative()));
00395 }
00396 return true;
00397 }
00398
00399
00400 void
00401 Level::switchFish()
00402 {
00403 if (m_levelScript->isRoom()) {
00404 m_levelScript->room()->switchFish();
00405 }
00406 }
00407
00408 void
00409 Level::controlEvent(const KeyStroke &stroke)
00410 {
00411 if (m_levelScript->isRoom()) {
00412 m_levelScript->room()->controlEvent(stroke);
00413 }
00414 }
00415
00416 void
00417 Level::controlMouse(const MouseStroke &button)
00418 {
00419 if (m_levelScript->isRoom()) {
00420 m_levelScript->room()->controlMouse(button);
00421 }
00422 }
00423
00424
00425
00426
00427
00428 void
00429 Level::createRoom(int w, int h, const Path &picture)
00430 {
00431 Room *room = new Room(w, h, picture, m_locker, m_levelScript);
00432 room->addDecor(new StepDecor(room->stepCounter()));
00433 m_levelScript->takeRoom(room);
00434 m_background->removeAll();
00435 m_background->acceptDrawer(room);
00436
00437 initScreen();
00438 }
00439
00440 void
00441 Level::initScreen()
00442 {
00443 if (m_levelScript->isRoom()) {
00444 std::string title = m_desc->findDesc(m_codename);
00445 title.append(": " + m_desc->findLevelName(m_codename));
00446
00447 OptionAgent *options = OptionAgent::agent();
00448 options->setParam("caption", title);
00449 options->setParam("screen_width",
00450 m_levelScript->room()->getW() * View::SCALE);
00451 options->setParam("screen_height",
00452 m_levelScript->room()->getH() * View::SCALE);
00453 VideoAgent::agent()->initVideoMode();
00454 }
00455 }
00456
00457 void
00458 Level::newDemo(const Path &demofile)
00459 {
00460 m_levelScript->interruptPlan();
00461 DemoMode *demo = new DemoMode(demofile);
00462 pushState(demo);
00463 }
00464
00465
00466 bool
00467 Level::isShowing() const
00468 {
00469 return !m_show->empty();
00470 }
00471
00472 void
00473 Level::interruptShow()
00474 {
00475 m_show->removeAll();
00476 }
00477
00478 void
00479 Level::planShow(Command *new_command)
00480 {
00481 m_show->planCommand(new_command);
00482 }
00483
00484 std::string
00485 Level::getLevelName() const
00486 {
00487 return m_desc->findLevelName(m_codename);
00488 }
00489
00490 int
00491 Level::getCountForSolved() const
00492 {
00493 int countdown = 10;
00494 if (isLoading()) {
00495 countdown = 0;
00496 }
00497 else if (m_levelScript->dialogs()->areRunning()) {
00498 countdown = 30;
00499 }
00500 return countdown;
00501 }
00502
00503 int
00504 Level::getCountForWrong() const
00505 {
00506
00507 return 70;
00508 }
00509