levelintro.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // SuperTux -- LevelIntro screen
  2. // Copyright (C) 2008 Christoph Sommer <christoph.sommer@2008.expires.deltadevelopment.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/levelintro.hpp"
  17. #include "control/input_manager.hpp"
  18. #include "math/random.hpp"
  19. #include "object/player.hpp"
  20. #include "sprite/sprite.hpp"
  21. #include "sprite/sprite_manager.hpp"
  22. #include "supertux/fadetoblack.hpp"
  23. #include "supertux/gameconfig.hpp"
  24. #include "supertux/level.hpp"
  25. #include "supertux/player_status.hpp"
  26. #include "supertux/resources.hpp"
  27. #include "supertux/screen_manager.hpp"
  28. #include "supertux/sector.hpp"
  29. #include "util/gettext.hpp"
  30. #include "util/log.hpp"
  31. #include "video/compositor.hpp"
  32. #include <fmt/format.h>
  33. // TODO: Display all players on the intro scene
  34. LevelIntro::LevelIntro(const Level& level, const Statistics* best_level_statistics, const PlayerStatus& player_status) :
  35. m_level(level),
  36. m_best_level_statistics(best_level_statistics),
  37. m_player_sprite(),
  38. m_santa_sprite(),
  39. m_player_sprite_py(),
  40. m_player_sprite_vy(),
  41. m_player_sprite_jump_timer(),
  42. m_player_status(player_status)
  43. {
  44. for (int i = 0; i < InputManager::current()->get_num_users(); i++)
  45. {
  46. push_player();
  47. }
  48. }
  49. LevelIntro::~LevelIntro()
  50. {
  51. }
  52. void
  53. LevelIntro::setup()
  54. {
  55. }
  56. void
  57. LevelIntro::update(float dt_sec, const Controller& controller)
  58. {
  59. // Check if it's time to exit the screen
  60. if (controller.pressed_any(Control::JUMP, Control::ACTION, Control::MENU_SELECT,
  61. Control::START, Control::ESCAPE)) {
  62. ScreenManager::current()->pop_screen(std::make_unique<FadeToBlack>(FadeToBlack::FADEOUT, 0.1f));
  63. }
  64. // Check if players connected/disconnected
  65. while(m_player_sprite.size() < static_cast<size_t>(InputManager::current()->get_num_users()))
  66. push_player();
  67. while(m_player_sprite.size() > static_cast<size_t>(InputManager::current()->get_num_users()))
  68. pop_player();
  69. for (int i = 0; i < InputManager::current()->get_num_users(); i++)
  70. {
  71. if (!InputManager::current()->has_corresponsing_controller(i)
  72. && !InputManager::current()->m_uses_keyboard[i] && i != 0)
  73. continue;
  74. auto bonus_prefix = m_player_status.get_bonus_prefix(i);
  75. if (m_player_status.bonus[i] == FIRE_BONUS && g_config->christmas_mode)
  76. {
  77. bonus_prefix = "big";
  78. }
  79. m_player_sprite_py[i] += m_player_sprite_vy[i] * dt_sec;
  80. m_player_sprite_vy[i] += 100 * dt_sec * Sector::get().get_gravity();
  81. if (m_player_sprite_py[i] >= 0) {
  82. m_player_sprite_py[i] = 0;
  83. m_player_sprite_vy[i] = 0;
  84. m_player_sprite[i]->set_action(bonus_prefix + "-walk-right");
  85. } else {
  86. m_player_sprite[i]->set_action(bonus_prefix + "-jump-right");
  87. }
  88. if (m_player_sprite_jump_timer[i]->check()) {
  89. m_player_sprite_vy[i] = -300;
  90. m_player_sprite_jump_timer[i]->start(graphicsRandom.randf(2,3));
  91. }
  92. }
  93. }
  94. void LevelIntro::draw_stats_line(DrawingContext& context, int& py, const std::string& name, const std::string& stat, bool isPerfect)
  95. {
  96. std::stringstream ss;
  97. ss << name << ": " << stat;
  98. Color tcolor = isPerfect ? s_stat_perfect_color : s_stat_color;
  99. context.color().draw_center_text(Resources::normal_font, ss.str(), Vector(0, static_cast<float>(py)),
  100. LAYER_FOREGROUND1, tcolor);
  101. py += static_cast<int>(Resources::normal_font->get_height());
  102. }
  103. void
  104. LevelIntro::draw(Compositor& compositor)
  105. {
  106. auto& context = compositor.make_context();
  107. const Statistics& stats = m_level.m_stats;
  108. int py = static_cast<int>(context.get_height() / 2.0f - Resources::normal_font->get_height() / 2.0f);
  109. context.set_ambient_color(Color(1.0f, 1.0f, 1.0f, 1.0f));
  110. context.color().draw_filled_rect(context.get_rect(), Color(0.0f, 0.0f, 0.0f, 1.0f), 0);
  111. {
  112. context.color().draw_center_text(Resources::normal_font, m_level.get_name(), Vector(0, static_cast<float>(py)), LAYER_FOREGROUND1, s_header_color);
  113. py += static_cast<int>(Resources::normal_font->get_height());
  114. }
  115. std::string author = m_level.get_author();
  116. if ((!author.empty()) && (author != "SuperTux Team")) {
  117. std::string author_text = fmt::format(fmt::runtime(_("contributed by {}")), author);
  118. context.color().draw_center_text(Resources::small_font, author_text, Vector(0, static_cast<float>(py)), LAYER_FOREGROUND1, s_author_color);
  119. py += static_cast<int>(Resources::small_font->get_height());
  120. }
  121. py += 96;
  122. for (int i = 0; i < static_cast<int>(m_player_sprite.size()); i++)
  123. {
  124. if (!InputManager::current()->has_corresponsing_controller(i)
  125. && !InputManager::current()->m_uses_keyboard[i] && i != 0)
  126. context.transform().alpha = 0.25f;
  127. float offset = (static_cast<float>(i) - static_cast<float>(m_player_sprite.size()) / 2.f + 0.5f) * 64.f;
  128. m_player_sprite[i]->draw(context.color(), Vector((context.get_width() - m_player_sprite[i]->get_current_hitbox_width()) / 2 - offset,
  129. static_cast<float>(py) + m_player_sprite_py[i] - m_player_sprite[i]->get_current_hitbox_height()), LAYER_FOREGROUND1);
  130. Color power_color = (m_player_status.bonus[i] == FIRE_BONUS ? Color(1.f, 0.7f, 0.5f) :
  131. m_player_status.bonus[i] == ICE_BONUS ? Color(0.7f, 1.f, 1.f) :
  132. m_player_status.bonus[i] == AIR_BONUS ? Color(0.7f, 1.f, 0.5f) :
  133. m_player_status.bonus[i] == EARTH_BONUS ? Color(1.f, 0.9f, 0.6f) :
  134. Color(1.f, 1.f, 1.f));
  135. m_player_sprite[i]->set_color(power_color);
  136. /*if (m_player_status.bonus[i] > GROWUP_BONUS) {
  137. m_santa_sprite[i]->draw(context.color(), Vector((context.get_width() - m_player_sprite[i]->get_current_hitbox_width()) / 2 - offset,
  138. static_cast<float>(py) + m_player_sprite_py[i] - m_player_sprite[i]->get_current_hitbox_height()), LAYER_FOREGROUND1);
  139. }*/
  140. context.transform().alpha = 1.f;
  141. }
  142. py += 32;
  143. if (m_best_level_statistics)
  144. {
  145. context.color().draw_center_text(Resources::normal_font,
  146. std::string("- ") + _("Best Level Statistics") + std::string(" -"),
  147. Vector(0, static_cast<float>(py)),
  148. LAYER_FOREGROUND1, s_stat_hdr_color);
  149. py += static_cast<int>(Resources::normal_font->get_height());
  150. draw_stats_line(context, py, _("Coins"),
  151. Statistics::coins_to_string(m_best_level_statistics->get_coins(), stats.m_total_coins),
  152. m_best_level_statistics->get_coins() >= stats.m_total_coins);
  153. draw_stats_line(context, py, _("Badguys killed"),
  154. Statistics::frags_to_string(m_best_level_statistics->get_badguys(), stats.m_total_badguys),
  155. m_best_level_statistics->get_badguys() >= stats.m_total_badguys);
  156. draw_stats_line(context, py, _("Secrets"),
  157. Statistics::secrets_to_string(m_best_level_statistics->get_secrets(), stats.m_total_secrets),
  158. m_best_level_statistics->get_secrets() >= stats.m_total_secrets);
  159. bool targetTimeBeaten = m_level.m_target_time == 0.0f || (m_best_level_statistics->get_time() != 0.0f && m_best_level_statistics->get_time() < m_level.m_target_time);
  160. draw_stats_line(context, py, _("Best time"),
  161. Statistics::time_to_string(m_best_level_statistics->get_time()), targetTimeBeaten);
  162. if (m_level.m_target_time != 0.0f) {
  163. draw_stats_line(context, py, _("Level target time"),
  164. Statistics::time_to_string(m_level.m_target_time), targetTimeBeaten);
  165. }
  166. }
  167. py += 32;
  168. if (!m_level.m_note.empty()) {
  169. context.color().draw_center_text(Resources::normal_font, m_level.m_note, Vector(0, py), LAYER_FOREGROUND1);
  170. }
  171. }
  172. IntegrationStatus
  173. LevelIntro::get_status() const
  174. {
  175. IntegrationStatus status;
  176. status.m_details.push_back("Watching a cutscene");
  177. status.m_details.push_back("In level: " + m_level.get_name());
  178. return status;
  179. }
  180. void
  181. LevelIntro::push_player()
  182. {
  183. int i = static_cast<int>(m_player_sprite.size());
  184. if (i > InputManager::current()->get_num_users())
  185. {
  186. log_warning << "Attempt to push more players in intro scene than connected" << std::endl;
  187. return;
  188. }
  189. m_player_sprite.push_back(SpriteManager::current()->create("images/creatures/tux/tux.sprite"));
  190. m_santa_sprite.push_back(SpriteManager::current()->create("images/creatures/tux/santahat.sprite"));
  191. m_player_sprite_py.push_back(0);
  192. m_player_sprite_vy.push_back(0);
  193. m_player_sprite_jump_timer.push_back(std::make_unique<Timer>());
  194. //Show appropriate tux animation for player status.
  195. if (m_player_status.bonus[i] == FIRE_BONUS && g_config->christmas_mode)
  196. {
  197. m_player_sprite[i]->set_action("big-walk-right");
  198. m_santa_sprite[i]->set_action("santa-walk-right");
  199. }
  200. else
  201. {
  202. m_player_sprite[i]->set_action(m_player_status.get_bonus_prefix(i) + "-walk-right");
  203. }
  204. m_player_sprite_jump_timer[i]->start(graphicsRandom.randf(5,10));
  205. /* Set Tux powerup sprite action */
  206. m_santa_sprite[i]->set_action(m_player_sprite[i]->get_action());
  207. }
  208. void
  209. LevelIntro::pop_player()
  210. {
  211. if (m_player_sprite.size() <= 1)
  212. {
  213. log_warning << "Attempt to pop last player in intro scene" << std::endl;
  214. return;
  215. }
  216. m_player_sprite.pop_back();
  217. m_santa_sprite.pop_back();
  218. m_player_sprite_py.pop_back();
  219. m_player_sprite_vy.pop_back();
  220. m_player_sprite_jump_timer.pop_back();
  221. }
  222. /* EOF */