3 # Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 # -----------------------------------------------------------------------------
21 # This patch allows two players to cooperatively jump and run through
24 # Note that this is more or less a friendly hack. Most objects and all levels
25 # of SuperTux were not designed to work with two players. Expect lots of bugs.
27 # Installing the patch should be pretty straightforward. Simply run the
28 # following command prior to running jam:
30 # patch -p0 < contrib/supertux-coop.diff
32 # This patch works for revision 4866. It may break for later revisions.
34 # -----------------------------------------------------------------------------
35 Index: src/control/joystickkeyboardcontroller.cpp
36 ===================================================================
37 --- src/control/joystickkeyboardcontroller.cpp (revision 4856)
38 +++ src/control/joystickkeyboardcontroller.cpp (working copy)
40 #include "game_session.hpp"
41 #include "console.hpp"
42 #include "gameconfig.hpp"
45 class JoystickKeyboardController::JoystickMenu : public Menu
49 ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
50 if(i == joy_button_map.end()) {
51 - log_debug << "Unmapped joybutton " << (int)event.jbutton.button << " pressed" << std::endl;
52 + //log_debug << "Unmapped joybutton " << (int)event.jbutton.button << " pressed" << std::endl;
57 // if console key was pressed: toggle console
58 if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE)) {
59 if (event.type != SDL_KEYDOWN) return;
60 - Console::instance->toggle();
61 + if (this == main_controller) Console::instance->toggle();
65 // if console is open: send key there
66 if (Console::instance->hasFocus()) {
67 - process_console_key_event(event);
68 + if (this == main_controller) process_console_key_event(event);
74 // default action: update controls
75 if(key_mapping == keymap.end()) {
76 - log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
77 + //log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
80 Control control = key_mapping->second;
81 Index: src/options_menu.cpp
82 ===================================================================
83 --- src/options_menu.cpp (revision 4856)
84 +++ src/options_menu.cpp (working copy)
87 add_submenu(_("Setup Keyboard"), main_controller->get_key_options_menu());
88 add_submenu(_("Setup Joystick"),main_controller->get_joystick_options_menu());
89 + add_submenu(std::string(_("Setup Keyboard"))+" (P2)", secondary_controller->get_key_options_menu());
90 + add_submenu(std::string(_("Setup Joystick"))+" (P2)", secondary_controller->get_joystick_options_menu());
95 ===================================================================
96 --- src/main.hpp (revision 4856)
97 +++ src/main.hpp (working copy)
100 class JoystickKeyboardController;
101 extern JoystickKeyboardController* main_controller;
102 +extern JoystickKeyboardController* secondary_controller;
105 Index: src/game_session.cpp
106 ===================================================================
107 --- src/game_session.cpp (revision 4856)
108 +++ src/game_session.cpp (working copy)
112 main_controller->reset();
113 + secondary_controller->reset();
119 // TODO make a screen out of this, another mainloop is ugly
120 main_controller->update();
121 + secondary_controller->update();
123 while (SDL_PollEvent(&event)) {
124 main_controller->process_event(event);
125 + secondary_controller->process_event(event);
126 if(event.type == SDL_QUIT)
129 Index: src/mainloop.cpp
130 ===================================================================
131 --- src/mainloop.cpp (revision 4856)
132 +++ src/mainloop.cpp (working copy)
134 MainLoop::process_events()
136 main_controller->update();
137 + secondary_controller->update();
139 while(SDL_PollEvent(&event)) {
140 main_controller->process_event(event);
141 + secondary_controller->process_event(event);
142 if(Menu::current() != NULL)
143 Menu::current()->event(event);
144 if(event.type == SDL_QUIT)
145 Index: src/object/player.cpp
146 ===================================================================
147 --- src/object/player.cpp (revision 4856)
148 +++ src/object/player.cpp (working copy)
152 controller = main_controller;
153 + if (name == "Penny") controller = secondary_controller;
154 smalltux_gameover = sprite_manager->create("images/creatures/tux_small/smalltux-gameover.sprite");
155 smalltux_star = sprite_manager->create("images/creatures/tux_small/smalltux-star.sprite");
156 bigtux_star = sprite_manager->create("images/creatures/tux_big/bigtux-star.sprite");
159 int layer = LAYER_OBJECTS + 1;
161 + // draw second player behind main player
162 + if (name == "Penny") layer -= 20;
164 /* Set Tux sprite action */
167 @@ -1049,6 +1053,12 @@
171 + // Multiple Players pass through one another
172 + Player* player = dynamic_cast<Player*> (&other);
177 if(hit.left || hit.right) {
178 try_grab(); //grab objects right now, in update it will be too late
180 @@ -1141,6 +1151,8 @@
181 dying_timer.start(3.0);
182 set_group(COLGROUP_DISABLED);
184 + if (name == "Penny") return;
186 DisplayEffect* effect = new DisplayEffect();
187 effect->fade_out(3.0);
188 Sector::current()->add_object(effect);
189 Index: src/gameconfig.cpp
190 ===================================================================
191 --- src/gameconfig.cpp (revision 4856)
192 +++ src/gameconfig.cpp (working copy)
194 if(config_control_lisp && main_controller) {
195 main_controller->read(*config_control_lisp);
197 + const lisp::Lisp* config_control_lisp2 = config_lisp->get_lisp("control-p2");
198 + if(config_control_lisp2 && secondary_controller) {
199 + secondary_controller->read(*config_control_lisp2);
205 main_controller->write(writer);
206 writer.end_list("control");
208 + if(secondary_controller) {
209 + writer.start_list("control-p2");
210 + secondary_controller->write(writer);
211 + writer.end_list("control-p2");
214 writer.end_list("supertux-config");
217 ===================================================================
218 --- src/main.cpp (revision 4856)
219 +++ src/main.cpp (working copy)
222 SDL_Surface* screen = 0;
223 JoystickKeyboardController* main_controller = 0;
224 +JoystickKeyboardController* secondary_controller = 0;
225 TinyGetText::DictionaryManager dictionary_manager;
230 timelog("controller");
231 main_controller = new JoystickKeyboardController();
232 + secondary_controller = new JoystickKeyboardController();
235 timelog("tinygettext");
239 delete main_controller;
240 + delete secondary_controller;
241 main_controller = NULL;
242 + secondary_controller = NULL;
243 delete Console::instance;
244 Console::instance = NULL;
245 Scripting::exit_squirrel();
246 Index: src/sector.cpp
247 ===================================================================
248 --- src/sector.cpp (revision 4856)
249 +++ src/sector.cpp (working copy)
251 bool Sector::show_collrects = false;
252 bool Sector::draw_solids_only = false;
255 + // two-player hack: second player's player_status
256 + PlayerStatus* second_player_status = 0;
259 Sector::Sector(Level* parent)
260 : level(parent), currentmusic(LEVEL_MUSIC),
261 ambient_light( 1.0f, 1.0f, 1.0f, 1.0f ), gravity(10.0), player(0), camera(0)
263 add_object(new Player(player_status, "Tux"));
265 + // two-player hack: second player has dummy player_status
266 + if (!second_player_status) second_player_status = new PlayerStatus();
267 + add_object(new Player(second_player_status, "Penny"));
269 add_object(new DisplayEffect("Effect"));
270 add_object(new TextObject("Text"));
276 + // two-player hack: move other players to main player's position
277 + for(GameObjects::iterator i = gameobjects.begin();
278 + i != gameobjects.end(); ++i) {
279 + Player* p = dynamic_cast<Player*>(*i);
281 + if (p == player) continue;
282 + p->move(player->get_pos());
286 camera->reset(player->get_pos());
287 update_game_objects();
291 player->check_bounds(camera);
293 + // two-player hack: keep other players in bound, too
294 + for(GameObjects::iterator i = gameobjects.begin();
295 + i != gameobjects.end(); ++i) {
296 + Player* p = dynamic_cast<Player*>(*i);
298 + if (p == player) continue;
299 + p->check_bounds(camera);
303 for(GameObjects::iterator i = gameobjects.begin();
304 i != gameobjects.end(); ++i) {
306 Player* player = dynamic_cast<Player*> (object);
308 if(this->player != 0) {
309 - log_warning << "Multiple players added. Ignoring" << std::endl;
310 + //log_warning << "Multiple players added. Ignoring" << std::endl;
313 this->player = player;