Skip to content

Commit 2f7c15b

Browse files
authored
Merge pull request #2043 from Semphriss/multiplayer
Multiplayer
2 parents b03a5c6 + c07860e commit 2f7c15b

File tree

89 files changed

+2974
-804
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+2974
-804
lines changed
1.33 KB
Loading

data/levels/community2016/Under_The_Water (davide).stl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2691,7 +2691,7 @@
26912691
(height 288)
26922692
(script "Level.spawn(\"forest\",\"main\");")
26932693
(button #f)
2694-
(x 9024)
2694+
(x 9056)
26952695
(y 672)
26962696
)
26972697
(secretarea
@@ -4275,7 +4275,7 @@
42754275
)
42764276
(spawnpoint
42774277
(name "main")
4278-
(x 32)
4278+
(x 96)
42794279
(y 800)
42804280
)
42814281
(tilemap

src/badguy/haywire.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ Haywire::collision_squished(GameObject& object)
103103
void
104104
Haywire::active_update(float dt_sec)
105105
{
106+
auto* player = get_nearest_player();
107+
106108
if (is_exploding) {
107109
ticking->set_position(get_pos());
108110
grunting->set_position(get_pos());
@@ -126,7 +128,7 @@ Haywire::active_update(float dt_sec)
126128

127129
if (is_exploding)
128130
{
129-
if (on_ground() && std::abs(m_physic.get_velocity_x()) > 40.f && !Sector::get().get_player().is_dying())
131+
if (on_ground() && std::abs(m_physic.get_velocity_x()) > 40.f && player)
130132
{
131133
//jump over 1-tall roadblocks
132134
Rectf jump_box = get_bbox();
@@ -153,7 +155,7 @@ Haywire::active_update(float dt_sec)
153155
gap_box.set_bottom(m_col.m_bbox.get_bottom() + 28.f);
154156

155157
if (Sector::get().is_free_of_statics(gap_box)
156-
&& (get_nearest_player()->get_bbox().get_bottom() <= m_col.m_bbox.get_bottom()))
158+
&& (player->get_bbox().get_bottom() <= m_col.m_bbox.get_bottom()))
157159
{
158160
m_physic.set_velocity_y(-325.f);
159161
}
@@ -173,17 +175,16 @@ Haywire::active_update(float dt_sec)
173175
walk_right_action = "active-right";
174176
}
175177

176-
auto p = get_nearest_player ();
177178
float target_velocity = 0.f;
178179

179180
if (stomped_timer.get_timeleft() >= 0.05f)
180181
{
181182
target_velocity = 0.f;
182183
}
183-
else if (p && time_stunned == 0.0f)
184+
else if (player && time_stunned == 0.0f)
184185
{
185186
/* Player is on the right or left*/
186-
target_velocity = (p->get_pos().x > get_pos().x) ? walk_speed : (-1.f) * walk_speed;
187+
target_velocity = (player->get_pos().x > get_pos().x) ? walk_speed : (-1.f) * walk_speed;
187188
}
188189

189190
WalkingBadguy::active_update(dt_sec, target_velocity, 3.f);

src/badguy/icecrusher.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ IceCrusher::after_editor_set() {
518518
bool
519519
IceCrusher::found_victim_down() const
520520
{
521-
if (auto* player = Sector::get().get_nearest_player(m_col.m_bbox))
521+
for (auto* player : Sector::get().get_players())
522522
{
523523
const Rectf& player_bbox = player->get_bbox();
524524
Rectf crush_area_down = Rectf(m_col.m_bbox.get_left()+1, m_col.m_bbox.get_bottom(),
@@ -537,7 +537,7 @@ IceCrusher::found_victim_down() const
537537
bool
538538
IceCrusher::found_victim_up() const
539539
{
540-
if (auto* player = Sector::get().get_nearest_player(m_col.m_bbox))
540+
for (auto* player : Sector::get().get_players())
541541
{
542542
const Rectf& player_bbox = player->get_bbox();
543543
Rectf crush_area_up = Rectf(m_col.m_bbox.get_left()+1, m_col.m_bbox.get_top(),
@@ -556,7 +556,7 @@ IceCrusher::found_victim_up() const
556556
bool
557557
IceCrusher::found_victim_right() const
558558
{
559-
if (auto* player = Sector::get().get_nearest_player(m_col.m_bbox))
559+
for (auto* player : Sector::get().get_players())
560560
{
561561
const Rectf& player_bbox = player->get_bbox();
562562
Rectf crush_area_right = get_bbox();
@@ -575,7 +575,7 @@ IceCrusher::found_victim_right() const
575575
bool
576576
IceCrusher::found_victim_left() const
577577
{
578-
if (auto* player = Sector::get().get_nearest_player(m_col.m_bbox))
578+
for (auto* player : Sector::get().get_players())
579579
{
580580
const Rectf& player_bbox = player->get_bbox();
581581
Rectf crush_area_left = get_bbox();
@@ -596,7 +596,7 @@ IceCrusher::eye_position(bool right) const
596596
{
597597
if (state == IDLE || state == CRUSHING_RIGHT || state == CRUSHING_LEFT)
598598
{
599-
if (auto* player = Sector::get().get_nearest_player (m_col.m_bbox))
599+
if (auto* player = Sector::get().get_nearest_player(m_col.m_bbox))
600600
{
601601
// Icecrusher focuses on approximate position of player's head
602602
const float player_focus_x = (player->get_bbox().get_right() + player->get_bbox().get_left()) * 0.5f;

src/badguy/yeti.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ Yeti::draw_hit_points(DrawingContext& context)
131131
{
132132
context.push_transform();
133133
context.set_translation(Vector(0, 0));
134+
context.transform().scale = 1.f;
134135

135136
for (int i = 0; i < hit_points; ++i)
136137
{

src/control/game_controller_manager.cpp

Lines changed: 159 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
#include <algorithm>
2020

2121
#include "control/input_manager.hpp"
22+
#include "object/player.hpp"
23+
#include "supertux/gameconfig.hpp"
24+
#include "supertux/globals.hpp"
25+
#include "supertux/game_session.hpp"
26+
#include "supertux/savegame.hpp"
27+
#include "supertux/sector.hpp"
2228
#include "util/log.hpp"
2329

2430
GameControllerManager::GameControllerManager(InputManager* parent) :
@@ -34,15 +40,26 @@ GameControllerManager::~GameControllerManager()
3440
{
3541
for (const auto& con : m_game_controllers)
3642
{
37-
SDL_GameControllerClose(con);
43+
SDL_GameControllerClose(con.first);
3844
}
3945
}
4046

4147
void
4248
GameControllerManager::process_button_event(const SDL_ControllerButtonEvent& ev)
4349
{
50+
int player_id;
51+
52+
{
53+
auto it = m_game_controllers.find(SDL_GameControllerFromInstanceID(ev.which));
54+
55+
if (it == m_game_controllers.end() || it->second < 0)
56+
return;
57+
58+
player_id = it->second;
59+
}
60+
4461
//log_info << "button event: " << static_cast<int>(ev.button) << " " << static_cast<int>(ev.state) << std::endl;
45-
Controller& controller = m_parent->get_controller();
62+
Controller& controller = m_parent->get_controller(player_id);
4663
auto set_control = [this, &controller](Control control, Uint8 value)
4764
{
4865
m_button_state[static_cast<int>(control)] = (value != 0);
@@ -116,11 +133,22 @@ GameControllerManager::process_button_event(const SDL_ControllerButtonEvent& ev)
116133
void
117134
GameControllerManager::process_axis_event(const SDL_ControllerAxisEvent& ev)
118135
{
136+
int player_id;
137+
138+
{
139+
auto it = m_game_controllers.find(SDL_GameControllerFromInstanceID(ev.which));
140+
141+
if (it == m_game_controllers.end() || it->second < 0)
142+
return;
143+
144+
player_id = it->second;
145+
}
146+
119147
// FIXME: buttons and axis are fighting for control ownership, need
120148
// to OR the values together
121149

122150
//log_info << "axis event: " << static_cast<int>(ev.axis) << " " << ev.value << std::endl;
123-
Controller& controller = m_parent->get_controller();
151+
Controller& controller = m_parent->get_controller(player_id);
124152
auto set_control = [this, &controller](Control control, bool value)
125153
{
126154
m_stick_state[static_cast<int>(control)] = value;
@@ -192,27 +220,146 @@ GameControllerManager::on_controller_added(int joystick_index)
192220
}
193221
else
194222
{
195-
m_game_controllers.push_back(game_controller);
223+
m_game_controllers[game_controller] = -1;
224+
225+
if (m_parent->m_use_game_controller && g_config->multiplayer_auto_manage_players)
226+
{
227+
int id = m_parent->get_num_users();
228+
for (int i = 0; i < m_parent->get_num_users(); i++)
229+
{
230+
if (!m_parent->has_corresponsing_controller(i) && !m_parent->m_uses_keyboard[i])
231+
{
232+
id = i;
233+
break;
234+
}
235+
}
236+
237+
if (id == m_parent->get_num_users())
238+
m_parent->push_user();
239+
240+
m_game_controllers[game_controller] = id;
241+
242+
if (GameSession::current() && !GameSession::current()->get_savegame().is_title_screen() && id != 0)
243+
{
244+
auto& sector = GameSession::current()->get_current_sector();
245+
auto& player_status = GameSession::current()->get_savegame().get_player_status();
246+
247+
if (player_status.m_num_players <= id)
248+
player_status.add_player();
249+
250+
// ID = 0 is impossible, so no need to write `(id == 0) ? "" : ...`
251+
auto& player = sector.add<Player>(player_status, "Tux" + std::to_string(id + 1), id);
252+
253+
player.multiplayer_prepare_spawn();
254+
}
255+
}
196256
}
197257
}
198258
}
199259

200260
void
201261
GameControllerManager::on_controller_removed(int instance_id)
202262
{
203-
for (auto& controller : m_game_controllers)
263+
std::vector<SDL_GameController*> erase_us;
264+
265+
auto it = std::find_if(m_game_controllers.begin(), m_game_controllers.end(), [instance_id] (decltype(m_game_controllers)::const_reference pair) {
266+
return SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(pair.first)) == instance_id;
267+
});
268+
269+
if (it != m_game_controllers.end())
204270
{
205-
auto joy = SDL_GameControllerGetJoystick(controller);
206-
SDL_JoystickID id = SDL_JoystickInstanceID(joy);
207-
if (id == instance_id)
271+
SDL_GameControllerClose(it->first);
272+
273+
auto deleted_player_id = it->second;
274+
275+
m_game_controllers.erase(it);
276+
277+
if (m_parent->m_use_game_controller && g_config->multiplayer_auto_manage_players
278+
&& deleted_player_id != 0 && !m_parent->m_uses_keyboard[deleted_player_id])
208279
{
209-
SDL_GameControllerClose(controller);
210-
controller = nullptr;
280+
// Sectors in worldmaps have no Player's of that class
281+
if (Sector::current() && Sector::current()->get_object_count<Player>() > 0)
282+
{
283+
auto players = Sector::current()->get_objects_by_type<Player>();
284+
auto it_players = players.begin();
285+
286+
while (it_players != players.end())
287+
{
288+
if (it_players->get_id() == deleted_player_id)
289+
it_players->remove_me();
290+
291+
it_players++;
292+
}
293+
}
211294
}
212295
}
296+
else
297+
{
298+
log_debug << "Controller was unplugged but was not initially detected: "
299+
<< SDL_JoystickName(SDL_JoystickFromInstanceID(instance_id))
300+
<< std::endl;
301+
}
302+
}
303+
304+
void
305+
GameControllerManager::on_player_removed(int player_id)
306+
{
307+
auto it2 = std::find_if(m_game_controllers.begin(), m_game_controllers.end(), [player_id](decltype(m_game_controllers)::const_reference pair) {
308+
return pair.second == player_id;
309+
});
310+
if (it2 != m_game_controllers.end())
311+
{
312+
it2->second = -1;
313+
// Try again, in case multiple controllers were bount to a player
314+
// Recursive call shouldn't go too deep except in hardcore scenarios
315+
on_player_removed(player_id);
316+
}
317+
}
318+
319+
bool
320+
GameControllerManager::has_corresponding_game_controller(int player_id) const
321+
{
322+
return std::find_if(m_game_controllers.begin(), m_game_controllers.end(), [player_id](decltype(m_game_controllers)::const_reference pair) {
323+
return pair.second == player_id;
324+
}) != m_game_controllers.end();
325+
}
326+
327+
int
328+
GameControllerManager::rumble(SDL_GameController* controller) const
329+
{
330+
#if SDL_VERSION_ATLEAST(2, 0, 9)
331+
if (g_config->multiplayer_buzz_controllers)
332+
{
333+
#if SDL_VERSION_ATLEAST(2, 0, 18)
334+
if (SDL_GameControllerHasRumble(controller))
335+
{
336+
#endif
337+
// TODO: Rumble intensity setting (like volume)
338+
SDL_GameControllerRumble(controller, 0xFFFF, 0xFFFF, 300);
339+
#if SDL_VERSION_ATLEAST(2, 0, 18)
340+
}
341+
else
342+
{
343+
return 1;
344+
}
345+
#endif
346+
}
347+
348+
return 0;
349+
#else
350+
return 2;
351+
#endif
352+
}
353+
354+
void
355+
GameControllerManager::bind_controller(SDL_GameController* controller, int player_id)
356+
{
357+
m_game_controllers[controller] = player_id;
213358

214-
m_game_controllers.erase(std::remove(m_game_controllers.begin(), m_game_controllers.end(), nullptr),
215-
m_game_controllers.end());
359+
if (!g_config->multiplayer_multibind)
360+
for (auto& pair2 : m_game_controllers)
361+
if (pair2.second == player_id && pair2.first != controller)
362+
pair2.second = -1;
216363
}
217364

218365
/* EOF */

src/control/game_controller_manager.hpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
#ifndef HEADER_SUPERTUX_CONTROL_GAME_CONTROLLER_MANAGER_HPP
1818
#define HEADER_SUPERTUX_CONTROL_GAME_CONTROLLER_MANAGER_HPP
1919

20-
#include <vector>
2120
#include <array>
21+
#include <vector>
22+
#include <unordered_map>
2223

2324
#include "control/controller.hpp"
2425

@@ -28,6 +29,11 @@ struct SDL_ControllerButtonEvent;
2829
struct _SDL_GameController;
2930
typedef struct _SDL_GameController SDL_GameController;
3031

32+
/**
33+
* Manages GameControllers.
34+
*
35+
* WARNING: Any edit done to this class should also be done to JoystickManager!
36+
*/
3137
class GameControllerManager final
3238
{
3339
public:
@@ -40,10 +46,20 @@ class GameControllerManager final
4046
void on_controller_added(int joystick_index);
4147
void on_controller_removed(int instance_id);
4248

49+
void on_player_removed(int player_id);
50+
bool has_corresponding_game_controller(int player_id) const;
51+
52+
/** @returns 0 if success, 1 if controller doesn't support rumbling, 2 if game doesn't support rumbling */
53+
int rumble(SDL_GameController* controller) const;
54+
55+
void bind_controller(SDL_GameController* controller, int player_id);
56+
57+
std::unordered_map<SDL_GameController*, int>& get_controller_mapping() { return m_game_controllers; }
58+
4359
private:
4460
InputManager* m_parent;
4561
int m_deadzone;
46-
std::vector<SDL_GameController*> m_game_controllers;
62+
std::unordered_map<SDL_GameController*, int> m_game_controllers;
4763
std::array<bool, static_cast<int>(Control::CONTROLCOUNT)> m_stick_state;
4864
std::array<bool, static_cast<int>(Control::CONTROLCOUNT)> m_button_state;
4965

0 commit comments

Comments
 (0)