Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

Level.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004 Ivo Danihelka (ivo@danihelka.net)
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
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  * Create new level.
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     //NOTE: m_show must be removed before levelScript
00069     // because uses the same script
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  * Start gameplay.
00086  * fillDesc() and fillStatus() must be called before.
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     //NOTE: let level first to draw and then play
00098     m_locker->reset();
00099     m_locker->ensurePhases(1);
00100     SoundAgent::agent()->stopMusic();
00101     //TODO: escape "codename"
00102     m_levelScript->scriptDo("CODENAME = [[" + m_codename + "]]");
00103     m_levelScript->scriptInclude(m_datafile);
00104 }
00105 //-----------------------------------------------------------------
00106 /**
00107  * Update level.
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  * Clean room after visit.
00141  */
00142     void
00143 Level::own_cleanState()
00144 {
00145     m_levelScript->cleanRoom();
00146 }
00147 //-----------------------------------------------------------------
00148 /**
00149  * Loading is paused on background.
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     //NOTE: ensure that unwanted mouse press will not move a fish
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  * Process next action.
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  * Update level (plan dialogs, do anim, ...).
00204  */
00205     void
00206 Level::updateLevel()
00207 {
00208     if (!isLoading()) {
00209         m_levelScript->updateScript();
00210     }
00211 }
00212 //-----------------------------------------------------------------
00213 /**
00214  * Finish complete level.
00215  * Save solution.
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  * Update room.
00237  * Let objects to move.
00238  */
00239     void
00240 Level::nextPlayerAction()
00241 {
00242     if (m_levelScript->isRoom()) {
00243          m_levelScript->room()->nextRound(getInput());
00244     }
00245 }
00246 
00247 //-----------------------------------------------------------------
00248 /**
00249  * Write save to the file.
00250  * Save moves and models state.
00251  * @param models saved models
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  * Start loading mode.
00291  * @param moves saved moves to load
00292  */
00293     void
00294 Level::loadGame(const std::string &moves)
00295 {
00296     m_loading->loadGame(moves);
00297 }
00298 //-----------------------------------------------------------------
00299 /**
00300  * Start replay mode.
00301  * @param moves saved moves to load
00302  */
00303     void
00304 Level::loadReplay(const std::string &moves)
00305 {
00306     m_loading->loadReplay(moves);
00307 }
00308 
00309 //-----------------------------------------------------------------
00310 /**
00311  * Load next move.
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  * Let show execute.
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  * (re)start room.
00337  * @return true
00338  */
00339     bool
00340 Level::action_restart()
00341 {
00342     own_cleanState();
00343     m_restartCounter++;
00344     //TODO: is ok to run the script on second time?
00345     //NOTE: planned show remains after restart
00346     own_initState();
00347     return true;
00348 }
00349 //-----------------------------------------------------------------
00350 /**
00351  * Move a fish.
00352  * @param symbol move symbol, e.g. 'U', 'D', 'L', 'R'
00353  * @return true when move is done
00354  */
00355     bool
00356 Level::action_move(char symbol)
00357 {
00358     return m_levelScript->room()->makeMove(symbol);
00359 }
00360 //-----------------------------------------------------------------
00361 /**
00362  * Save position.
00363  * @return true
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  * Load position.
00380  * @return true
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  * Create new room
00426  * and change screen resolution.
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     //NOTE: don't forget to change briefcase_help_demo too
00507     return 70;
00508 }
00509 

Generated on Wed Jun 1 09:54:31 2005 for Fish Fillets - Next Generation by  doxygen 1.4.2