00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "Room.h"
00010
00011 #include "WavyPicture.h"
00012 #include "Field.h"
00013 #include "FinderAlg.h"
00014 #include "ResSoundPack.h"
00015 #include "Controls.h"
00016 #include "PhaseLocker.h"
00017 #include "Planner.h"
00018 #include "View.h"
00019
00020 #include "Log.h"
00021 #include "Rules.h"
00022 #include "LogicException.h"
00023 #include "LoadException.h"
00024 #include "Unit.h"
00025 #include "TimerAgent.h"
00026 #include "SubTitleAgent.h"
00027 #include "DialogStack.h"
00028 #include "SoundAgent.h"
00029 #include "OptionAgent.h"
00030 #include "ModelList.h"
00031 #include "Landslip.h"
00032 #include "MouseStroke.h"
00033 #include "MouseControl.h"
00034
00035 #include <assert.h>
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 Room::Room(int w, int h, const Path &picture,
00047 PhaseLocker *locker, Planner *levelScript)
00048 {
00049 m_locker = locker;
00050 m_levelScript = levelScript;
00051 m_fastFalling = false;
00052 m_bg = new WavyPicture(picture, V2(0, 0));
00053 m_field = new Field(w, h);
00054 m_finder = new FinderAlg(w, h);
00055 m_controls = new Controls(m_locker);
00056 m_view = new View(ModelList(&m_models));
00057 m_lastAction = Cube::ACTION_NO;
00058 m_soundPack = new ResSoundPack();
00059 m_startTime = TimerAgent::agent()->getCycles();
00060 }
00061
00062
00063
00064
00065 Room::~Room()
00066 {
00067 m_soundPack->removeAll();
00068 delete m_soundPack;
00069 m_levelScript->killPlan();
00070 m_levelScript->dialogs()->removeAll();
00071 SubTitleAgent::agent()->removeAll();
00072 delete m_controls;
00073 delete m_view;
00074
00075
00076 Cube::t_models::iterator end = m_models.end();
00077 for (Cube::t_models::iterator i = m_models.begin(); i != end; ++i) {
00078 delete (*i);
00079 }
00080
00081 delete m_finder;
00082 delete m_field;
00083 delete m_bg;
00084 }
00085
00086
00087
00088
00089 void
00090 Room::setWaves(float amplitude, float periode, float speed)
00091 {
00092 m_bg->setWamp(amplitude);
00093 m_bg->setWperiode(periode);
00094 m_bg->setWspeed(speed);
00095 }
00096
00097 void
00098 Room::addDecor(Decor *new_decor)
00099 {
00100 m_view->addDecor(new_decor);
00101 }
00102
00103
00104
00105
00106
00107
00108
00109 int
00110 Room::addModel(Cube *new_model, Unit *new_unit)
00111 {
00112 new_model->rules()->takeField(m_field);
00113 m_models.push_back(new_model);
00114
00115 if (new_unit) {
00116 new_unit->takeModel(new_model);
00117 m_controls->addUnit(new_unit);
00118 }
00119
00120 int model_index = m_models.size() - 1;
00121 new_model->setIndex(model_index);
00122 return model_index;
00123 }
00124
00125
00126
00127
00128
00129 Cube *
00130 Room::getModel(int model_index)
00131 {
00132 Cube *result = NULL;
00133 if (0 <= model_index && model_index < (int)m_models.size()) {
00134 result = m_models[model_index];
00135 }
00136 else {
00137 throw LogicException(ExInfo("bad model index")
00138 .addInfo("model_index", model_index));
00139 }
00140
00141 return result;
00142 }
00143
00144
00145
00146
00147 Cube *
00148 Room::askField(const V2 &loc)
00149 {
00150 return m_field->getModel(loc);
00151 }
00152
00153
00154
00155
00156
00157 void
00158 Room::nextRound(const InputProvider *input)
00159 {
00160 if (m_fastFalling) {
00161 while (beginFall()) {
00162 finishRound();
00163 }
00164 }
00165 else {
00166 beginFall();
00167 }
00168
00169 if (isFresh()) {
00170 if (m_controls->driving(input)) {
00171 m_lastAction = Cube::ACTION_MOVE;
00172 }
00173 else {
00174 MouseControl rat(m_controls, m_view, m_finder);
00175 if (rat.mouseDrive(input)) {
00176 m_lastAction = Cube::ACTION_MOVE;
00177 }
00178 }
00179 }
00180 finishRound();
00181 }
00182
00183
00184
00185
00186
00187 void
00188 Room::playImpact(Cube::eWeight impact)
00189 {
00190 switch (impact) {
00191 case Cube::NONE:
00192 break;
00193 case Cube::LIGHT:
00194 playSound("impact_light", 50);
00195 break;
00196 case Cube::HEAVY:
00197 playSound("impact_heavy", 50);
00198 break;
00199 default:
00200 assert(!"unknown impact weight");
00201 }
00202 }
00203
00204
00205
00206
00207
00208 void
00209 Room::playDead(Cube *model)
00210 {
00211 m_levelScript->dialogs()->killSound(model->getIndex());
00212 switch (model->getPower()) {
00213 case Cube::LIGHT:
00214 playSound("dead_small");
00215 break;
00216 case Cube::HEAVY:
00217 playSound("dead_big");
00218 break;
00219 default:
00220 LOG_WARNING(ExInfo("curious power of dead fish")
00221 .addInfo("power", model->getPower()));
00222 break;
00223 }
00224 }
00225
00226
00227
00228
00229
00230 void
00231 Room::prepareRound()
00232 {
00233 bool interrupt = false;
00234
00235
00236 Cube::t_models::iterator end = m_models.end();
00237 for (Cube::t_models::iterator i = m_models.begin(); i != end; ++i) {
00238 (*i)->rules()->occupyNewPos();
00239 }
00240 for (Cube::t_models::iterator j = m_models.begin(); j != end; ++j) {
00241 bool die = (*j)->rules()->checkDead(m_lastAction);
00242 interrupt |= die;
00243 if (die) {
00244 playDead(*j);
00245 }
00246 }
00247 for (Cube::t_models::iterator l = m_models.begin(); l != end; ++l) {
00248 (*l)->rules()->changeState();
00249 }
00250
00251 if (interrupt) {
00252 m_levelScript->interruptPlan();
00253 }
00254 }
00255
00256
00257
00258
00259
00260
00261 bool
00262 Room::fallout(bool interactive)
00263 {
00264 bool wentOut = false;
00265 Cube::t_models::iterator end = m_models.end();
00266 for (Cube::t_models::iterator i = m_models.begin(); i != end; ++i) {
00267 if (!(*i)->isLost()) {
00268 int outDepth = (*i)->rules()->actionOut();
00269 if (outDepth > 0) {
00270 wentOut = true;
00271 if (interactive) {
00272 m_locker->ensurePhases(3);
00273 }
00274 }
00275 else if (outDepth == -1) {
00276 m_levelScript->interruptPlan();
00277 }
00278 }
00279 }
00280
00281 return wentOut;
00282 }
00283
00284
00285
00286
00287
00288 bool
00289 Room::falldown(bool interactive)
00290 {
00291 ModelList models(&m_models);
00292 Landslip slip(models);
00293
00294 bool falling = slip.computeFall();
00295 if (interactive) {
00296 playImpact(slip.getImpact());
00297 }
00298 return falling;
00299 }
00300
00301
00302
00303
00304
00305 void
00306 Room::finishRound(bool interactive)
00307 {
00308 if (interactive) {
00309 m_controls->lockPhases();
00310 }
00311 m_view->noteNewRound(m_locker->getLocked());
00312
00313 Cube::t_models::iterator end = m_models.end();
00314 for (Cube::t_models::iterator i = m_models.begin(); i != end; ++i) {
00315 (*i)->rules()->finishRound();
00316 }
00317 }
00318
00319
00320 void
00321 Room::switchFish()
00322 {
00323 m_controls->switchActive();
00324 }
00325
00326 void
00327 Room::controlEvent(const KeyStroke &stroke)
00328 {
00329 m_controls->controlEvent(stroke);
00330 }
00331
00332 void
00333 Room::controlMouse(const MouseStroke &button)
00334 {
00335 if (button.isLeft()) {
00336 V2 fieldPos = m_view->getFieldPos(button.getLoc());
00337 Cube *model = askField(fieldPos);
00338 m_controls->activateSelected(model);
00339 }
00340 }
00341
00342
00343 const StepCounter *
00344 Room::stepCounter() const
00345 {
00346 return m_controls;
00347 }
00348
00349 void
00350 Room::checkActive()
00351 {
00352 return m_controls->checkActive();
00353 }
00354
00355 void
00356 Room::unBusyUnits()
00357 {
00358 Cube::t_models::iterator end = m_models.end();
00359 for (Cube::t_models::iterator i = m_models.begin(); i != end; ++i) {
00360 (*i)->setBusy(false);
00361 }
00362 }
00363
00364
00365
00366
00367
00368
00369 void
00370 Room::loadMove(char move)
00371 {
00372 static const bool NO_INTERACTIVE = false;
00373 bool falling = true;
00374 while (falling) {
00375 falling = beginFall(NO_INTERACTIVE);
00376 makeMove(move);
00377
00378 finishRound(NO_INTERACTIVE);
00379 }
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391 bool
00392 Room::beginFall(bool interactive)
00393 {
00394 prepareRound();
00395 m_lastAction = Cube::ACTION_NO;
00396
00397 if (fallout(interactive)) {
00398 m_lastAction = Cube::ACTION_MOVE;
00399 }
00400 else {
00401 if (falldown(interactive)) {
00402 m_lastAction = Cube::ACTION_FALL;
00403 }
00404 }
00405 return m_lastAction != Cube::ACTION_NO;
00406 }
00407
00408
00409
00410
00411
00412
00413 bool
00414 Room::makeMove(char move)
00415 {
00416 bool result = false;
00417 if (isFresh()) {
00418 if (!m_controls->makeMove(move)) {
00419 throw LoadException(ExInfo("load error - bad move")
00420 .addInfo("move", std::string(1, move)));
00421 }
00422 m_lastAction = Cube::ACTION_MOVE;
00423 result = true;
00424 }
00425 return result;
00426 }
00427
00428
00429
00430
00431 bool
00432 Room::cannotMove() const
00433 {
00434 return m_controls->cannotMove();
00435 }
00436
00437
00438
00439
00440 bool
00441 Room::isSolvable() const
00442 {
00443 Cube::t_models::const_iterator end = m_models.end();
00444 for (Cube::t_models::const_iterator i = m_models.begin(); i != end; ++i) {
00445 if ((*i)->isWrong()) {
00446 return false;
00447 }
00448 }
00449 return true;
00450 }
00451
00452
00453
00454
00455
00456
00457 bool
00458 Room::isSolved() const
00459 {
00460 if (!isFresh()) {
00461 return false;
00462 }
00463 Cube::t_models::const_iterator end = m_models.end();
00464 for (Cube::t_models::const_iterator i = m_models.begin(); i != end; ++i) {
00465 if (!(*i)->isSatisfy()) {
00466 return false;
00467 }
00468 }
00469 return true;
00470 }
00471
00472
00473 int
00474 Room::getW() const
00475 {
00476 return m_field->getW();
00477 }
00478
00479 int
00480 Room::getH() const
00481 {
00482 return m_field->getH();
00483 }
00484
00485 int
00486 Room::getCycles() const
00487 {
00488 return TimerAgent::agent()->getCycles() - m_startTime;
00489 }
00490
00491 void
00492 Room::addSound(const std::string &name, const Path &file)
00493 {
00494 m_soundPack->addSound(name, file);
00495 }
00496
00497 void
00498 Room::playSound(const std::string &name, int volume)
00499 {
00500 if (OptionAgent::agent()->getAsBool("sound", true)) {
00501 SoundAgent::agent()->playSound(
00502 m_soundPack->getRandomRes(name), volume);
00503 }
00504 }
00505
00506
00507
00508
00509
00510 void
00511 Room::setScreenShift(const V2 &shift)
00512 {
00513 m_view->setScreenShift(shift);
00514 }
00515
00516 void
00517 Room::changeBg(const Path &picture)
00518 {
00519 m_bg->changePicture(picture);
00520 }
00521
00522 void
00523 Room::drawOn(SDL_Surface *screen)
00524 {
00525 m_bg->drawOn(screen);
00526 m_view->drawOn(screen);
00527 }
00528