multiplayer_player_menu.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // SuperTux
  2. // Copyright (C) 2021 A. Semphris <semphris@protonmail.com>
  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/menu/multiplayer_player_menu.hpp"
  17. #include <fmt/format.h>
  18. #include <SDL.h>
  19. #include "control/game_controller_manager.hpp"
  20. #include "control/input_manager.hpp"
  21. #include "control/joystick_manager.hpp"
  22. #include "gui/dialog.hpp"
  23. #include "supertux/gameconfig.hpp"
  24. #include "supertux/game_session.hpp"
  25. #include "supertux/globals.hpp"
  26. #include "supertux/savegame.hpp"
  27. #include "supertux/sector.hpp"
  28. #include "object/player.hpp"
  29. #include "util/gettext.hpp"
  30. #include "util/log.hpp"
  31. MultiplayerPlayerMenu::MultiplayerPlayerMenu(int player_id)
  32. {
  33. add_label(fmt::format(_("Player {}"), player_id + 1));
  34. add_hl();
  35. add_toggle(-1, _("Play with the keyboard"), &InputManager::current()->m_uses_keyboard[player_id]);
  36. if (player_id != 0 && GameSession::current()
  37. && !GameSession::current()->get_savegame().is_title_screen())
  38. {
  39. bool player_is_in_sector = false;
  40. for (const auto* player : GameSession::current()->get_current_sector().get_players())
  41. {
  42. if (player->get_id() == player_id)
  43. {
  44. player_is_in_sector = true;
  45. break;
  46. }
  47. }
  48. if (player_is_in_sector)
  49. {
  50. add_entry(_("Remove Player"), [player_id] {
  51. // Re-check everything that concerns the sector, it might have changed
  52. // (e. g. when unplugging a controller with auto-management enabled)
  53. if (!GameSession::current() || GameSession::current()->get_savegame().is_title_screen())
  54. {
  55. log_warning << "Attempt to force player to despawn while not in session"
  56. << std::endl;
  57. return;
  58. }
  59. for (auto* player : GameSession::current()->get_current_sector().get_players())
  60. {
  61. if (player->get_id() == player_id)
  62. {
  63. player->remove_me();
  64. return;
  65. }
  66. }
  67. log_warning << "Could not find player with ID " << player_id
  68. << " (number " << (player_id + 1) << "in sector"
  69. << std::endl;
  70. });
  71. add_entry(_("Respawn Player"), [player_id] {
  72. // Re-check everything that concerns the sector, it might have changed
  73. // (e. g. when unplugging a controller with auto-management enabled)
  74. if (!GameSession::current() || GameSession::current()->get_savegame().is_title_screen())
  75. {
  76. log_warning << "Attempt to force player to respawn while not in session"
  77. << std::endl;
  78. return;
  79. }
  80. for (auto* player : GameSession::current()->get_current_sector().get_players())
  81. {
  82. if (player->get_id() == player_id)
  83. {
  84. player->multiplayer_prepare_spawn();
  85. return;
  86. }
  87. }
  88. log_warning << "Could not find player with ID " << player_id
  89. << " (number " << (player_id + 1) << "in sector"
  90. << std::endl;
  91. });
  92. }
  93. else
  94. {
  95. add_entry(_("Spawn Player"), [player_id] {
  96. // Re-check everything that concerns the sector, it might have changed
  97. // (e. g. when unplugging a controller with auto-management enabled)
  98. if (!GameSession::current() || GameSession::current()->get_savegame().is_title_screen())
  99. {
  100. log_warning << "Attempt to force player to spawn while not in session"
  101. << std::endl;
  102. return;
  103. }
  104. auto& sector = GameSession::current()->get_current_sector();
  105. auto& player_status = GameSession::current()->get_savegame().get_player_status();
  106. // TODO: This is probably needed because adding/removing users manually
  107. // or automatically by plugging in controllers might not always fix the
  108. // player_status object; check if that statement is correct
  109. if (player_status.m_num_players <= player_id)
  110. player_status.add_player();
  111. // ID = 0 is impossible, so no need to write `(id == 0) ? "" : ...`
  112. auto& player = sector.add<Player>(player_status, "Tux" + std::to_string(player_id + 1), player_id);
  113. player.multiplayer_prepare_spawn();
  114. });
  115. }
  116. }
  117. add_hl();
  118. add_label(_("Controllers"));
  119. if (InputManager::current()->m_use_game_controller)
  120. {
  121. for (auto& pair : InputManager::current()->game_controller_manager->get_controller_mapping())
  122. {
  123. auto controller = pair.first;
  124. std::string prefix = (pair.second == -1) ? "" : (pair.second == player_id) ? "-> " : ("[" + std::to_string(pair.second + 1) + "] ");
  125. add_entry(prefix + std::string(SDL_GameControllerName(pair.first)), [controller, player_id] {
  126. InputManager::current()->game_controller_manager->bind_controller(controller, player_id);
  127. auto err = InputManager::current()->game_controller_manager->rumble(controller);
  128. switch (err)
  129. {
  130. case 1:
  131. Dialog::show_message(_("This controller does not support rumbling;"
  132. "\nplease check the controllers manually."));
  133. break;
  134. case 2:
  135. Dialog::show_message(_("This SuperTux build does not support "
  136. "rumbling\ncontrollers; please check the "
  137. "controllers manually."));
  138. break;
  139. default:
  140. break;
  141. }
  142. MenuManager::instance().set_menu(std::make_unique<MultiplayerPlayerMenu>(player_id));
  143. });
  144. }
  145. }
  146. else
  147. {
  148. for (auto& pair : InputManager::current()->joystick_manager->get_joystick_mapping())
  149. {
  150. auto joystick = pair.first;
  151. std::string prefix = (pair.second == -1) ? "" : (pair.second == player_id) ? "-> " : ("[" + std::to_string(pair.second + 1) + "] ");
  152. add_entry(prefix + std::string(SDL_JoystickName(pair.first)), [joystick, player_id] {
  153. InputManager::current()->joystick_manager->bind_joystick(joystick, player_id);
  154. auto err = InputManager::current()->joystick_manager->rumble(joystick);
  155. switch (err)
  156. {
  157. case 1:
  158. Dialog::show_message(_("This joystick does not support rumbling;"
  159. "\nplease check the joysticks manually."));
  160. break;
  161. case 2:
  162. Dialog::show_message(_("This SuperTux build does not support "
  163. "rumbling\njoysticks; please check the "
  164. "joysticks manually."));
  165. break;
  166. default:
  167. break;
  168. }
  169. MenuManager::instance().set_menu(std::make_unique<MultiplayerPlayerMenu>(player_id));
  170. });
  171. }
  172. }
  173. add_hl();
  174. add_back(_("Back"));
  175. }
  176. /* EOF */