game_session.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. // SuperTux
  2. // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. #include "supertux/game_session.hpp"
  17. #include <cfloat>
  18. #include "audio/sound_manager.hpp"
  19. #include "control/input_manager.hpp"
  20. #include "editor/editor.hpp"
  21. #include "gui/menu_manager.hpp"
  22. #include "math/vector.hpp"
  23. #include "object/camera.hpp"
  24. #include "object/endsequence_fireworks.hpp"
  25. #include "object/endsequence_walk.hpp"
  26. #include "object/level_time.hpp"
  27. #include "object/music_object.hpp"
  28. #include "object/player.hpp"
  29. #include "object/spawnpoint.hpp"
  30. #include "sdk/integration.hpp"
  31. #include "supertux/constants.hpp"
  32. #include "supertux/fadetoblack.hpp"
  33. #include "supertux/gameconfig.hpp"
  34. #include "supertux/level.hpp"
  35. #include "supertux/level_parser.hpp"
  36. #include "supertux/levelintro.hpp"
  37. #include "supertux/levelset_screen.hpp"
  38. #include "supertux/menu/menu_storage.hpp"
  39. #include "supertux/savegame.hpp"
  40. #include "supertux/screen_manager.hpp"
  41. #include "supertux/sector.hpp"
  42. #include "supertux/shrinkfade.hpp"
  43. #include "util/file_system.hpp"
  44. #include "video/compositor.hpp"
  45. #include "video/drawing_context.hpp"
  46. #include "video/surface.hpp"
  47. #include "worldmap/worldmap.hpp"
  48. static const float SAFE_TIME = 1.0f;
  49. static const int SHRINKFADE_LAYER = LAYER_LIGHTMAP - 1;
  50. static const float TELEPORT_FADE_TIME = 1.0f;
  51. GameSession::GameSession(const std::string& levelfile_, Savegame& savegame, Statistics* statistics,
  52. bool preserve_music) :
  53. reset_button(false),
  54. reset_checkpoint_button(false),
  55. m_prevent_death(false),
  56. m_level(),
  57. m_statistics_backdrop(Surface::from_file("images/engine/menu/score-backdrop.png")),
  58. m_scripts(),
  59. m_currentsector(nullptr),
  60. m_end_sequence(nullptr),
  61. m_game_pause(false),
  62. m_speed_before_pause(ScreenManager::current()->get_speed()),
  63. m_levelfile(levelfile_),
  64. m_spawnpoints(),
  65. m_activated_checkpoint(),
  66. m_newsector(),
  67. m_newspawnpoint(),
  68. m_spawn_fade_type(ScreenFade::FadeType::NONE),
  69. m_spawn_fade_timer(),
  70. m_spawn_with_invincibility(false),
  71. m_best_level_statistics(statistics),
  72. m_savegame(savegame),
  73. m_play_time(0),
  74. m_levelintro_shown(false),
  75. m_coins_at_start(),
  76. m_boni_at_start(),
  77. m_max_fire_bullets_at_start(),
  78. m_max_ice_bullets_at_start(),
  79. m_active(false),
  80. m_end_seq_started(false),
  81. m_pause_target_timer(false),
  82. m_current_cutscene_text(),
  83. m_endsequence_timer()
  84. {
  85. set_start_point(DEFAULT_SECTOR_NAME, DEFAULT_SPAWNPOINT_NAME);
  86. m_boni_at_start.resize(InputManager::current()->get_num_users(), NO_BONUS);
  87. m_max_fire_bullets_at_start.resize(InputManager::current()->get_num_users(), 0);
  88. m_max_ice_bullets_at_start.resize(InputManager::current()->get_num_users(), 0);
  89. if (restart_level(false, preserve_music) != 0)
  90. throw std::runtime_error ("Initializing the level failed.");
  91. }
  92. void
  93. GameSession::reset_level()
  94. {
  95. for (const auto& p : m_currentsector->get_players())
  96. {
  97. try
  98. {
  99. p->set_bonus(m_boni_at_start.at(p->get_id()));
  100. }
  101. catch(const std::out_of_range&)
  102. {
  103. }
  104. }
  105. PlayerStatus& currentStatus = m_savegame.get_player_status();
  106. currentStatus.coins = m_coins_at_start;
  107. currentStatus.bonus = m_boni_at_start;
  108. currentStatus.max_fire_bullets = m_max_fire_bullets_at_start;
  109. currentStatus.max_ice_bullets = m_max_ice_bullets_at_start;
  110. clear_respawn_points();
  111. m_activated_checkpoint = nullptr;
  112. m_pause_target_timer = false;
  113. m_spawn_with_invincibility = false;
  114. }
  115. int
  116. GameSession::restart_level(bool after_death, bool preserve_music)
  117. {
  118. const PlayerStatus& currentStatus = m_savegame.get_player_status();
  119. m_coins_at_start = currentStatus.coins;
  120. m_max_fire_bullets_at_start = currentStatus.max_fire_bullets;
  121. m_max_ice_bullets_at_start = currentStatus.max_ice_bullets;
  122. m_boni_at_start = currentStatus.bonus;
  123. // Needed for the title screen apparently.
  124. if (m_currentsector)
  125. {
  126. try
  127. {
  128. for (const auto& p : m_currentsector->get_players())
  129. {
  130. p->set_bonus(m_boni_at_start.at(p->get_id()), false, false);
  131. m_boni_at_start[p->get_id()] = currentStatus.bonus[p->get_id()];
  132. }
  133. }
  134. catch (const std::out_of_range&)
  135. {
  136. }
  137. }
  138. m_game_pause = false;
  139. m_end_sequence = nullptr;
  140. m_endsequence_timer.stop();
  141. m_spawn_with_invincibility = false;
  142. InputManager::current()->reset();
  143. m_currentsector = nullptr;
  144. const std::string base_dir = FileSystem::dirname(m_levelfile);
  145. if (base_dir == "./") {
  146. m_levelfile = FileSystem::basename(m_levelfile);
  147. }
  148. try {
  149. m_level = LevelParser::from_file(m_levelfile, false, false);
  150. /* Determine the spawnpoint to spawn/respawn Tux to. */
  151. const GameSession::SpawnPoint* spawnpoint = nullptr;
  152. if (m_activated_checkpoint && reset_checkpoint_button) // Checkpoint is activated and respawn from it is requested.
  153. {
  154. reset_checkpoint_button = false;
  155. // Attempt to find the last checkpoint's spawnpoint.
  156. for (int i = static_cast<int>(m_spawnpoints.size()) - 1; i >= 0; i--)
  157. {
  158. if (m_spawnpoints.at(i).is_checkpoint) // Checkpoint found.
  159. {
  160. spawnpoint = &m_spawnpoints.at(i);
  161. // Remove any spawnpoints after the checkpoint one.
  162. if (i < static_cast<int>(m_spawnpoints.size()) - 1)
  163. m_spawnpoints.erase(m_spawnpoints.begin() + i + 1, m_spawnpoints.end());
  164. break;
  165. }
  166. }
  167. if (!spawnpoint) // Spawnpoint has not been found.
  168. {
  169. throw std::runtime_error("Cannot find the position of the last activated checkpoint.");
  170. }
  171. }
  172. else if (after_death && m_spawnpoints.size() > 1) // Respawn from the last respawn position, because Tux is respawning.
  173. {
  174. spawnpoint = &get_last_spawnpoint();
  175. }
  176. else // Respawn from the start position.
  177. {
  178. spawnpoint = &m_spawnpoints.front();
  179. m_play_time = 0; // Reset play time.
  180. }
  181. /* Perform the respawn from the chosen spawnpoint. */
  182. // Load the spawn sector.
  183. m_currentsector = m_level->get_sector(spawnpoint->sector);
  184. if (!m_currentsector)
  185. {
  186. throw std::runtime_error("Couldn't find sector '" + spawnpoint->sector + "' to spawn/respawn Tux.");
  187. }
  188. // Activate on either the spawnpoint (if set), or the spawn position.
  189. if (spawnpoint->spawnpoint.empty())
  190. {
  191. m_currentsector->activate(spawnpoint->position);
  192. }
  193. else
  194. {
  195. m_currentsector->activate(spawnpoint->spawnpoint);
  196. }
  197. }
  198. catch (std::exception& e) {
  199. log_fatal << "Couldn't start level: " << e.what() << std::endl;
  200. ScreenManager::current()->pop_screen();
  201. return (-1);
  202. }
  203. if (m_levelintro_shown)
  204. {
  205. const Vector shrinkpos = get_fade_point();
  206. ScreenManager::current()->set_screen_fade(std::make_unique<ShrinkFade>(shrinkpos, TELEPORT_FADE_TIME, SHRINKFADE_LAYER, ShrinkFade::FADEIN));
  207. }
  208. if (!preserve_music)
  209. {
  210. auto& music_object = m_currentsector->get_singleton_by_type<MusicObject>();
  211. if (after_death == true) {
  212. music_object.resume_music();
  213. } else {
  214. SoundManager::current()->stop_music();
  215. music_object.play_music(LEVEL_MUSIC);
  216. }
  217. }
  218. auto level_times = m_currentsector->get_objects_by_type<LevelTime>();
  219. auto it = level_times.begin();
  220. while (it != level_times.end())
  221. {
  222. it->set_time(it->get_time() - m_play_time);
  223. it++;
  224. }
  225. return (0);
  226. }
  227. void
  228. GameSession::on_escape_press(bool force_quick_respawn)
  229. {
  230. auto players = m_currentsector->get_players();
  231. int alive = m_currentsector->get_object_count<Player>([](const Player& p) {
  232. return !p.is_dead() && !p.is_dying();
  233. });
  234. if ((!alive && (m_play_time > 2.0f || force_quick_respawn)) || m_end_sequence)
  235. {
  236. // Let the timers run out, we fast-forward them to force past a sequence.
  237. if (m_end_sequence)
  238. {
  239. if (m_end_sequence->is_running())
  240. {
  241. m_end_sequence->stop();
  242. }
  243. else
  244. {
  245. m_endsequence_timer.start(FLT_EPSILON);
  246. }
  247. }
  248. for (auto* player : players)
  249. player->m_dying_timer.start(FLT_EPSILON);
  250. return; // Don't let the player open the menu, when Tux is dying.
  251. }
  252. if (m_level->m_is_in_cutscene && !m_level->m_skip_cutscene)
  253. {
  254. m_level->m_skip_cutscene = true;
  255. return;
  256. }
  257. if (m_level->m_suppress_pause_menu && ScreenManager::current()->has_pending_fadeout())
  258. return;
  259. if (!m_level->m_suppress_pause_menu) {
  260. toggle_pause();
  261. } else {
  262. abort_level();
  263. }
  264. }
  265. Vector
  266. GameSession::get_fade_point() const
  267. {
  268. return get_fade_point(Vector(0.0f, 0.0f));
  269. }
  270. Vector
  271. GameSession::get_fade_point(const Vector& position) const
  272. {
  273. Vector fade_point(0.0f, 0.0f);
  274. if (position.x != 0.0f && position.y != 0.0f)
  275. {
  276. fade_point = position;
  277. }
  278. else
  279. {
  280. if (m_level->m_is_in_cutscene || m_currentsector->get_camera().get_mode() == Camera::Mode::MANUAL)
  281. {
  282. fade_point = m_currentsector->get_camera().get_center();
  283. }
  284. else
  285. {
  286. // Get "middle" of all alive players
  287. Vector average_position(0.0f, 0.0f);
  288. size_t alive_players = 0U;
  289. for (const auto* player : m_currentsector->get_players())
  290. {
  291. if (!player->is_dead() && !player->is_dying())
  292. {
  293. average_position += player->get_bbox().get_middle();
  294. alive_players++;
  295. }
  296. }
  297. if (alive_players > 0U)
  298. {
  299. fade_point = average_position / alive_players;
  300. }
  301. else
  302. {
  303. fade_point = m_currentsector->get_camera().get_center();
  304. }
  305. }
  306. }
  307. const Camera& camera = m_currentsector->get_camera();
  308. return (fade_point - camera.get_translation()) * camera.get_current_scale();
  309. }
  310. void
  311. GameSession::toggle_pause()
  312. {
  313. // Pause.
  314. if (!m_game_pause && !MenuManager::instance().is_active())
  315. {
  316. m_speed_before_pause = ScreenManager::current()->get_speed();
  317. ScreenManager::current()->set_speed(0);
  318. MenuManager::instance().set_menu(MenuStorage::GAME_MENU);
  319. SoundManager::current()->pause_sounds();
  320. m_currentsector->stop_looping_sounds();
  321. SoundManager::current()->pause_music();
  322. m_game_pause = true;
  323. }
  324. // Unpause is done in update() after the menu is processed.
  325. }
  326. void
  327. GameSession::abort_level()
  328. {
  329. MenuManager::instance().clear_menu_stack();
  330. ScreenManager::current()->pop_screen();
  331. for (const auto& p : m_currentsector->get_players())
  332. {
  333. try
  334. {
  335. p->set_bonus(m_boni_at_start.at(p->get_id()));
  336. }
  337. catch(const std::out_of_range&)
  338. {
  339. }
  340. }
  341. PlayerStatus& currentStatus = m_savegame.get_player_status();
  342. currentStatus.coins = m_coins_at_start;
  343. currentStatus.max_fire_bullets = m_max_fire_bullets_at_start;
  344. currentStatus.max_ice_bullets = m_max_ice_bullets_at_start;
  345. SoundManager::current()->stop_sounds();
  346. }
  347. bool
  348. GameSession::is_active() const
  349. {
  350. return !m_game_pause && m_active && !(m_end_sequence && m_end_sequence->is_running());
  351. }
  352. void
  353. GameSession::check_end_conditions()
  354. {
  355. bool all_dead = true;
  356. for (const auto* p : m_currentsector->get_players())
  357. if (!(all_dead &= p->is_dead()))
  358. break;
  359. bool all_dead_or_winning = true;
  360. for (const auto* p : m_currentsector->get_players())
  361. if (!(all_dead_or_winning &= (p->is_dead() || p->is_dying() || p->is_winning())))
  362. break;
  363. /* End of level? */
  364. if (m_endsequence_timer.check() || (all_dead_or_winning && m_end_sequence && m_endsequence_timer.get_period() > 0.f)) {
  365. m_endsequence_timer.stop();
  366. for (auto* p : m_currentsector->get_players())
  367. p->set_winning();
  368. start_sequence(nullptr, Sequence::SEQ_ENDSEQUENCE);
  369. } else if (m_end_sequence && m_end_sequence->is_done()) {
  370. finish(true);
  371. } else if (!m_end_sequence && all_dead) {
  372. restart_level(true);
  373. }
  374. }
  375. void
  376. GameSession::draw(Compositor& compositor)
  377. {
  378. auto& context = compositor.make_context();
  379. m_currentsector->draw(context);
  380. drawstatus(context);
  381. if (m_game_pause)
  382. draw_pause(context);
  383. }
  384. void
  385. GameSession::draw_pause(DrawingContext& context)
  386. {
  387. context.color().draw_filled_rect(
  388. Rectf(context.get_rect()),
  389. Color(0.0f, 0.0f, 0.0f, 0.25f),
  390. LAYER_FOREGROUND1);
  391. }
  392. void
  393. GameSession::setup()
  394. {
  395. if (m_currentsector == nullptr)
  396. return;
  397. if (m_currentsector != Sector::current()) {
  398. m_currentsector->activate(m_currentsector->get_players()[0]->get_pos());
  399. }
  400. m_currentsector->get_singleton_by_type<MusicObject>().play_music(LEVEL_MUSIC);
  401. int total_stats_to_be_collected = m_level->m_stats.m_total_coins + m_level->m_stats.m_total_badguys + m_level->m_stats.m_total_secrets;
  402. if ((!m_levelintro_shown) && (total_stats_to_be_collected > 0)) {
  403. m_levelintro_shown = true;
  404. m_active = false;
  405. ScreenManager::current()->push_screen(std::make_unique<LevelIntro>(*m_level, m_best_level_statistics, m_savegame.get_player_status()));
  406. ScreenManager::current()->set_screen_fade(std::make_unique<FadeToBlack>(FadeToBlack::FADEIN, TELEPORT_FADE_TIME));
  407. }
  408. else
  409. {
  410. const Vector shrinkpos = get_fade_point();
  411. ScreenManager::current()->set_screen_fade(std::make_unique<ShrinkFade>(shrinkpos, TELEPORT_FADE_TIME, SHRINKFADE_LAYER, ShrinkFade::FADEIN));
  412. }
  413. m_end_seq_started = false;
  414. }
  415. void
  416. GameSession::leave()
  417. {
  418. }
  419. void
  420. GameSession::update(float dt_sec, const Controller& controller)
  421. {
  422. // Set active flag.
  423. if (!m_active)
  424. {
  425. m_active = true;
  426. }
  427. // Handle controller.
  428. if (controller.pressed_any(Control::ESCAPE, Control::START))
  429. {
  430. on_escape_press(controller.hold(Control::LEFT)
  431. || controller.hold(Control::RIGHT));
  432. }
  433. if (controller.pressed(Control::CHEAT_MENU) &&
  434. (g_config->developer_mode || (Editor::current() && Editor::current()->is_testing_level()))
  435. )
  436. {
  437. if (!MenuManager::instance().is_active())
  438. {
  439. toggle_pause();
  440. MenuManager::instance().set_menu(MenuStorage::CHEAT_MENU);
  441. }
  442. }
  443. if (controller.pressed(Control::DEBUG_MENU) && g_config->developer_mode)
  444. {
  445. if (!MenuManager::instance().is_active())
  446. {
  447. toggle_pause();
  448. MenuManager::instance().set_menu(MenuStorage::DEBUG_MENU);
  449. }
  450. }
  451. // Animate the full-completion stats stuff - do this even when the game isn't paused (that's a
  452. // design choice, if you prefer it not to animate when paused, add `if (!m_game_pause)`).
  453. m_level->m_stats.update_timers(dt_sec);
  454. // Unpause the game if the menu has been closed.
  455. if (m_game_pause && !MenuManager::instance().is_active()) {
  456. ScreenManager::current()->set_speed(m_speed_before_pause);
  457. SoundManager::current()->resume_music();
  458. SoundManager::current()->resume_sounds();
  459. assert(m_currentsector != nullptr);
  460. m_currentsector->play_looping_sounds();
  461. m_game_pause = false;
  462. }
  463. check_end_conditions();
  464. // Respawning in new sector?
  465. if (!m_newsector.empty() && !m_newspawnpoint.empty() && (m_spawn_fade_timer.check() || m_spawn_fade_type == ScreenFade::FadeType::NONE)) {
  466. auto sector = m_level->get_sector(m_newsector);
  467. std::string current_music = m_currentsector->get_singleton_by_type<MusicObject>().get_music();
  468. if (sector == nullptr) {
  469. log_warning << "Sector '" << m_newsector << "' not found" << std::endl;
  470. sector = m_level->get_sector(m_spawnpoints.at(0).sector); // Assign start sector.
  471. }
  472. assert(m_currentsector != nullptr);
  473. m_currentsector->stop_looping_sounds();
  474. sector->activate(m_newspawnpoint);
  475. // Start the new sector's music only if it's different from the current one.
  476. if (current_music != sector->get_singleton_by_type<MusicObject>().get_music())
  477. sector->get_singleton_by_type<MusicObject>().play_music(LEVEL_MUSIC);
  478. m_currentsector = sector;
  479. m_currentsector->play_looping_sounds();
  480. switch (m_spawn_fade_type)
  481. {
  482. case ScreenFade::FadeType::FADE:
  483. {
  484. ScreenManager::current()->set_screen_fade(std::make_unique<FadeToBlack>(FadeToBlack::FADEIN, TELEPORT_FADE_TIME));
  485. break;
  486. }
  487. case ScreenFade::FadeType::CIRCLE:
  488. {
  489. const Vector spawn_point_position = sector->get_spawn_point_position(m_newspawnpoint);
  490. const Vector shrinkpos = get_fade_point(spawn_point_position);
  491. ScreenManager::current()->set_screen_fade(std::make_unique<ShrinkFade>(shrinkpos, TELEPORT_FADE_TIME, SHRINKFADE_LAYER, ShrinkFade::FADEIN));
  492. break;
  493. }
  494. default:
  495. break;
  496. }
  497. for (auto* p : m_currentsector->get_players())
  498. {
  499. // Give back control to the player
  500. p->activate();
  501. if (m_spawn_with_invincibility)
  502. {
  503. // Make all players temporarily safe after spawning
  504. p->make_temporarily_safe(SAFE_TIME);
  505. }
  506. }
  507. m_newsector = "";
  508. m_newspawnpoint = "";
  509. }
  510. // Update the world state and all objects in the world.
  511. if (!m_game_pause) {
  512. assert(m_currentsector != nullptr);
  513. // Update the world.
  514. if (!m_end_sequence || !m_end_sequence->is_running()) {
  515. if (!m_level->m_is_in_cutscene && !m_pause_target_timer)
  516. {
  517. m_play_time += dt_sec;
  518. m_level->m_stats.finish(m_play_time);
  519. }
  520. m_currentsector->update(dt_sec);
  521. } else {
  522. bool are_all_stopped = true;
  523. for (const auto& player : m_currentsector->get_players())
  524. {
  525. if (!(m_end_sequence->is_tux_stopped(player->get_id())
  526. || player->get_ending_direction() == 0))
  527. {
  528. are_all_stopped = false;
  529. break;
  530. }
  531. }
  532. if (!are_all_stopped) {
  533. m_currentsector->update(dt_sec);
  534. } else {
  535. m_end_sequence->update(dt_sec);
  536. }
  537. }
  538. }
  539. if (m_currentsector == nullptr)
  540. return;
  541. // Update sounds.
  542. SoundManager::current()->set_listener_position(m_currentsector->get_camera().get_center());
  543. /* Handle music: */
  544. if (m_end_sequence)
  545. return;
  546. bool invincible_timer_started = false;
  547. float max_invincible_timer_left = 0.f;
  548. for (const auto* p : m_currentsector->get_players())
  549. {
  550. invincible_timer_started |= (p->m_invincible_timer.started() && !p->is_winning());
  551. max_invincible_timer_left = std::max(max_invincible_timer_left, p->m_invincible_timer.get_timeleft());
  552. }
  553. auto& music_object = m_currentsector->get_singleton_by_type<MusicObject>();
  554. if (invincible_timer_started) {
  555. if (max_invincible_timer_left <= TUX_INVINCIBLE_TIME_WARNING) {
  556. if (music_object.get_music_type() != HERRING_WARNING_MUSIC)
  557. music_object.play_music(HERRING_WARNING_MUSIC);
  558. } else {
  559. if (music_object.get_music_type() != HERRING_MUSIC)
  560. music_object.play_music(HERRING_MUSIC);
  561. }
  562. } else if (music_object.get_music_type() != LEVEL_MUSIC) {
  563. music_object.play_music(LEVEL_MUSIC);
  564. }
  565. if (reset_button) {
  566. reset_button = false;
  567. reset_level();
  568. restart_level();
  569. } else if(reset_checkpoint_button) {
  570. for (auto* p : m_currentsector->get_players())
  571. p->kill(true);
  572. }
  573. }
  574. IntegrationStatus
  575. GameSession::get_status() const
  576. {
  577. IntegrationStatus status;
  578. status.m_details.push_back(Editor::current() ? "Testing" : "Playing");
  579. if (!Editor::current() || !g_config->hide_editor_levelnames)
  580. {
  581. const std::string label = get_current_level().is_worldmap() ? "In worldmap: " : "In level: ";
  582. status.m_details.push_back(label + get_current_level().get_name());
  583. }
  584. return status;
  585. }
  586. void
  587. GameSession::finish(bool win)
  588. {
  589. if (m_end_seq_started)
  590. return;
  591. m_end_seq_started = true;
  592. using namespace worldmap;
  593. if (win) {
  594. if (WorldMapSector::current())
  595. {
  596. WorldMapSector::current()->finished_level(m_level.get());
  597. }
  598. if (LevelsetScreen::current())
  599. {
  600. LevelsetScreen::current()->finished_level(win);
  601. }
  602. }
  603. ScreenManager::current()->pop_screen();
  604. }
  605. void
  606. GameSession::respawn(const std::string& sector, const std::string& spawnpoint)
  607. {
  608. m_newsector = sector;
  609. m_newspawnpoint = spawnpoint;
  610. m_spawn_with_invincibility = false;
  611. m_spawn_fade_type = ScreenFade::FadeType::NONE;
  612. }
  613. void
  614. GameSession::respawn_with_fade(const std::string& sector,
  615. const std::string& spawnpoint,
  616. const ScreenFade::FadeType fade_type,
  617. const Vector& fade_point,
  618. const bool make_invincible)
  619. {
  620. respawn(sector, spawnpoint);
  621. m_spawn_fade_type = fade_type;
  622. m_spawn_with_invincibility = make_invincible;
  623. bool transition_takes_time = false;
  624. switch (m_spawn_fade_type)
  625. {
  626. case ScreenFade::FadeType::FADE:
  627. {
  628. ScreenManager::current()->set_screen_fade(std::make_unique<FadeToBlack>(FadeToBlack::FADEOUT, TELEPORT_FADE_TIME));
  629. transition_takes_time = true;
  630. break;
  631. }
  632. case ScreenFade::FadeType::CIRCLE:
  633. {
  634. const Vector shrinkpos = get_fade_point(fade_point);
  635. ScreenManager::current()->set_screen_fade(std::make_unique<ShrinkFade>(shrinkpos, TELEPORT_FADE_TIME, SHRINKFADE_LAYER, ShrinkFade::FADEOUT));
  636. transition_takes_time = true;
  637. break;
  638. }
  639. default:
  640. break;
  641. }
  642. if (transition_takes_time)
  643. {
  644. m_spawn_fade_timer.start(TELEPORT_FADE_TIME);
  645. // Make all players safe during the fadeout transition
  646. for (Player* player : m_currentsector->get_players())
  647. {
  648. player->make_temporarily_safe(TELEPORT_FADE_TIME);
  649. }
  650. }
  651. }
  652. void
  653. GameSession::set_start_point(const std::string& sector,
  654. const std::string& spawnpoint)
  655. {
  656. if (!m_spawnpoints.empty()) m_spawnpoints.erase(m_spawnpoints.begin());
  657. m_spawnpoints.insert(m_spawnpoints.begin(), { sector, spawnpoint });
  658. }
  659. void
  660. GameSession::set_start_pos(const std::string& sector, const Vector& pos)
  661. {
  662. if (!m_spawnpoints.empty()) m_spawnpoints.erase(m_spawnpoints.begin());
  663. m_spawnpoints.insert(m_spawnpoints.begin(), { sector, pos });
  664. }
  665. void
  666. GameSession::set_respawn_point(const std::string& sector,
  667. const std::string& spawnpoint)
  668. {
  669. m_spawnpoints.push_back({ sector, spawnpoint });
  670. }
  671. void
  672. GameSession::set_respawn_pos(const std::string& sector, const Vector& pos)
  673. {
  674. m_spawnpoints.push_back({ sector, pos });
  675. }
  676. void
  677. GameSession::clear_respawn_points()
  678. {
  679. // Delete all respawn points (all, other than the start one).
  680. if (m_spawnpoints.size() > 1)
  681. m_spawnpoints.erase(m_spawnpoints.begin() + 1, m_spawnpoints.end());
  682. }
  683. const GameSession::SpawnPoint&
  684. GameSession::get_last_spawnpoint() const
  685. {
  686. return m_spawnpoints.back();
  687. }
  688. void
  689. GameSession::set_checkpoint_pos(const std::string& sector, const Vector& pos)
  690. {
  691. m_spawnpoints.push_back({ sector, pos, true });
  692. m_activated_checkpoint = &m_spawnpoints.back();
  693. }
  694. const GameSession::SpawnPoint*
  695. GameSession::get_active_checkpoint_spawnpoint() const
  696. {
  697. return m_activated_checkpoint;
  698. }
  699. std::string
  700. GameSession::get_working_directory() const
  701. {
  702. return FileSystem::dirname(m_levelfile);
  703. }
  704. bool
  705. GameSession::has_active_sequence() const
  706. {
  707. return m_end_sequence;
  708. }
  709. void
  710. GameSession::start_sequence(Player* caller, Sequence seq, const SequenceData* data)
  711. {
  712. // Handle special "stoptux" sequence.
  713. if (seq == SEQ_STOPTUX) {
  714. if (!m_end_sequence) {
  715. log_warning << "Final target reached without an active end sequence" << std::endl;
  716. start_sequence(caller, SEQ_ENDSEQUENCE);
  717. }
  718. if (m_end_sequence)
  719. {
  720. if (caller)
  721. {
  722. m_end_sequence->stop_tux(caller->get_id());
  723. }
  724. else
  725. {
  726. for (const auto* player : Sector::get().get_players())
  727. m_end_sequence->stop_tux(player->get_id());
  728. }
  729. }
  730. return;
  731. }
  732. if (caller)
  733. caller->set_winning();
  734. int remaining_players = get_current_sector().get_object_count<Player>([](const Player& p){
  735. return !p.is_dead() && !p.is_dying() && !p.is_winning();
  736. });
  737. // Abort if a sequence is already playing.
  738. if (m_end_sequence && m_end_sequence->is_running())
  739. return;
  740. // Set the sequence to prepare it.
  741. if (!m_end_sequence) {
  742. std::unique_ptr<EndSequence> end_sequence;
  743. if (seq == SEQ_ENDSEQUENCE) {
  744. end_sequence = std::make_unique<EndSequenceWalk>();
  745. } else if (seq == SEQ_FIREWORKS) {
  746. end_sequence = std::make_unique<EndSequenceFireworks>();
  747. } else {
  748. log_warning << "Unknown sequence '" << static_cast<int>(seq) << "'. Ignoring." << std::endl;
  749. return;
  750. }
  751. m_end_sequence = static_cast<EndSequence*>(&m_currentsector->add_object(std::move(end_sequence)));
  752. }
  753. if (caller)
  754. {
  755. caller->set_ending_direction((caller->get_physic().get_velocity_x() < 0) ? -1 : 1);
  756. caller->set_controller(m_end_sequence->get_controller(caller->get_id()));
  757. caller->set_speedlimit(230); // MAX_WALK_XM
  758. }
  759. // Don't play the prepared sequence if there are more players that are still playing.
  760. if (remaining_players > 0)
  761. {
  762. if (!m_endsequence_timer.started())
  763. m_endsequence_timer.start(10.f);
  764. return;
  765. }
  766. m_endsequence_timer.stop();
  767. if (const auto& worldmap_sector = worldmap::WorldMapSector::current())
  768. {
  769. if (data != nullptr)
  770. {
  771. if (!data->fade_tilemap.empty())
  772. {
  773. worldmap_sector->set_initial_fade_tilemap(data->fade_tilemap, data->fade_type);
  774. }
  775. if (!data->spawnpoint.empty())
  776. {
  777. worldmap_sector->get_worldmap().set_initial_spawnpoint(data->spawnpoint);
  778. }
  779. }
  780. }
  781. /* Slow down the game for end-sequence. */
  782. ScreenManager::current()->set_speed(0.5f);
  783. m_end_sequence->start();
  784. SoundManager::current()->play_music("music/misc/leveldone.ogg", false);
  785. for (auto* p : m_currentsector->get_players())
  786. {
  787. p->set_winning();
  788. p->set_controller(m_end_sequence->get_controller(p->get_id()));
  789. p->set_speedlimit(230); // MAX_WALK_XM.
  790. }
  791. // Stop all clocks.
  792. for (LevelTime& lt : m_currentsector->get_objects_by_type<LevelTime>())
  793. {
  794. lt.stop();
  795. }
  796. }
  797. void
  798. GameSession::set_target_timer_paused(bool paused)
  799. {
  800. m_pause_target_timer = paused;
  801. for (LevelTime& lt : m_currentsector->get_objects_by_type<LevelTime>())
  802. {
  803. if(paused)
  804. lt.stop();
  805. else
  806. lt.start();
  807. }
  808. }
  809. /* (Status): */
  810. void
  811. GameSession::drawstatus(DrawingContext& context)
  812. {
  813. // Draw level stats while end_sequence is running.
  814. if (m_end_sequence && m_end_sequence->is_running()) {
  815. m_level->m_stats.draw_endseq_panel(context, m_best_level_statistics, m_statistics_backdrop, m_level->m_target_time);
  816. }
  817. m_level->m_stats.draw_ingame_stats(context, m_game_pause);
  818. }
  819. /* EOF */