game_session.cpp 26 KB

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