Update for -nogl patch.
[supertux.git] / contrib / supertux-coop.diff
1 #
2 #  SuperTux -coop patch
3 #  Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
4 #
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.
9 #
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.
14 #
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.
18 #
19 # -----------------------------------------------------------------------------
20 #
21 #  This patch allows two players to cooperatively jump and run through 
22 #  SuperTux' levels.
23 #
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.
26 #
27 #  Installing the patch should be pretty straightforward. Simply run the
28 #  following command prior to running jam:
29 #
30 #  patch -p0 < contrib/supertux-coop.diff
31 #
32 #  This patch works for revision 4870. It may break for later revisions.
33 #
34 # -----------------------------------------------------------------------------
35 Index: src/control/joystickkeyboardcontroller.cpp
36 ===================================================================
37 --- src/control/joystickkeyboardcontroller.cpp  (revision 4870)
38 +++ src/control/joystickkeyboardcontroller.cpp  (working copy)
39 @@ -29,6 +29,7 @@
40  #include "game_session.hpp"
41  #include "console.hpp"
42  #include "gameconfig.hpp"
43 +#include "main.hpp"
44  
45  class JoystickKeyboardController::JoystickMenu : public Menu
46  {
47 @@ -339,7 +340,7 @@
48  
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;
53          return;
54        }
55  
56 @@ -360,13 +361,13 @@
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();
62      return;
63    }
64  
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);
69      return;
70    }
71  
72 @@ -378,7 +379,7 @@
73  
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;
78      return;
79    }
80    Control control = key_mapping->second;
81 Index: src/options_menu.cpp
82 ===================================================================
83 --- src/options_menu.cpp        (revision 4870)
84 +++ src/options_menu.cpp        (working copy)
85 @@ -58,6 +58,8 @@
86    }
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());
91    add_hl();
92    add_back(_("Back"));
93  }
94 Index: src/main.hpp
95 ===================================================================
96 --- src/main.hpp        (revision 4870)
97 +++ src/main.hpp        (working copy)
98 @@ -31,5 +31,6 @@
99  // global variables
100  class JoystickKeyboardController;
101  extern JoystickKeyboardController* main_controller;
102 +extern JoystickKeyboardController* secondary_controller;
103  
104  #endif
105 Index: src/game_session.cpp
106 ===================================================================
107 --- src/game_session.cpp        (revision 4870)
108 +++ src/game_session.cpp        (working copy)
109 @@ -118,6 +118,7 @@
110    end_sequence = 0;
111  
112    main_controller->reset();
113 +  secondary_controller->reset();
114  
115    currentsector = 0;
116  
117 @@ -448,6 +449,22 @@
118    process_events();
119    process_menu();
120  
121 +  // two-player hack: resurrect Penny when she dies
122 +  Player* tux = currentsector->player;
123 +  for(std::vector<GameObject*>::iterator i = currentsector->gameobjects.begin(); i != currentsector->gameobjects.end(); ++i) {
124 +    Player* p = dynamic_cast<Player*>(*i);
125 +    if (!p) continue;
126 +    if (p == tux) continue;
127 +    if (p->is_dead()) {
128 +      p->remove_me();
129 +      static PlayerStatus* ps = new PlayerStatus();
130 +      p = new Player(ps, "Penny");
131 +      currentsector->add_object(p);
132 +      p->move(tux->get_pos());
133 +      p->safe_timer.start(TUX_SAFE_TIME);
134 +    }
135 +  }
136 +
137    check_end_conditions();
138  
139    // respawning in new sector?
140 @@ -543,9 +560,11 @@
141  
142      // TODO make a screen out of this, another mainloop is ugly
143      main_controller->update();
144 +    secondary_controller->update();
145      SDL_Event event;
146      while (SDL_PollEvent(&event)) {
147        main_controller->process_event(event);
148 +      secondary_controller->process_event(event);
149        if(event.type == SDL_QUIT)
150          main_loop->quit();
151      }
152 Index: src/mainloop.cpp
153 ===================================================================
154 --- src/mainloop.cpp    (revision 4870)
155 +++ src/mainloop.cpp    (working copy)
156 @@ -166,9 +166,11 @@
157  MainLoop::process_events()
158  {
159    main_controller->update();
160 +  secondary_controller->update();
161    SDL_Event event;
162    while(SDL_PollEvent(&event)) {
163      main_controller->process_event(event);
164 +    secondary_controller->process_event(event);
165      if(Menu::current() != NULL)
166        Menu::current()->event(event);
167      if(event.type == SDL_QUIT)
168 Index: src/object/player.cpp
169 ===================================================================
170 --- src/object/player.cpp       (revision 4870)
171 +++ src/object/player.cpp       (working copy)
172 @@ -116,6 +116,7 @@
173  {
174    this->name = name;
175    controller = main_controller;
176 +  if (name == "Penny") controller = secondary_controller;
177    smalltux_gameover = sprite_manager->create("images/creatures/tux_small/smalltux-gameover.sprite");
178    smalltux_star = sprite_manager->create("images/creatures/tux_small/smalltux-star.sprite");
179    bigtux_star = sprite_manager->create("images/creatures/tux_big/bigtux-star.sprite");
180 @@ -875,6 +876,20 @@
181  
182    int layer = LAYER_OBJECTS + 1;
183  
184 +  // two-player hack: draw Penny in a different color
185 +  if (name == "Penny") {
186 +    layer -= 20;
187 +    if(tux_body->head) tux_body->head->set_color(Color(1.0f, 1.0f, 0.5f, 1.0f));
188 +    if(tux_body->body) tux_body->body->set_color(Color(1.0f, 1.0f, 0.5f, 1.0f));
189 +    if(tux_body->arms) tux_body->arms->set_color(Color(1.0f, 1.0f, 0.5f, 1.0f));
190 +    if(tux_body->feet) tux_body->feet->set_color(Color(1.0f, 1.0f, 0.5f, 1.0f));
191 +  } else {
192 +    if(tux_body->head) tux_body->head->set_color(Color(1.0f, 1.0f, 1.0f, 1.0f));
193 +    if(tux_body->body) tux_body->body->set_color(Color(1.0f, 1.0f, 1.0f, 1.0f));
194 +    if(tux_body->arms) tux_body->arms->set_color(Color(1.0f, 1.0f, 1.0f, 1.0f));
195 +    if(tux_body->feet) tux_body->feet->set_color(Color(1.0f, 1.0f, 1.0f, 1.0f));
196 +  }
197 +
198    /* Set Tux sprite action */
199    if (climbing)
200      {
201 @@ -1049,6 +1064,12 @@
202      return FORCE_MOVE;
203    }
204  
205 +  // Multiple Players pass through one another
206 +  Player* player = dynamic_cast<Player*> (&other);
207 +  if(player) {
208 +    return FORCE_MOVE;
209 +  }
210 +
211    if(hit.left || hit.right) {
212      try_grab(); //grab objects right now, in update it will be too late
213    }
214 @@ -1141,6 +1162,8 @@
215      dying_timer.start(3.0);
216      set_group(COLGROUP_DISABLED);
217  
218 +    if (name == "Penny") return;
219 +
220      DisplayEffect* effect = new DisplayEffect();
221      effect->fade_out(3.0);
222      Sector::current()->add_object(effect);
223 Index: src/gameconfig.cpp
224 ===================================================================
225 --- src/gameconfig.cpp  (revision 4870)
226 +++ src/gameconfig.cpp  (working copy)
227 @@ -86,6 +86,10 @@
228    if(config_control_lisp && main_controller) {
229      main_controller->read(*config_control_lisp);
230    }
231 +  const lisp::Lisp* config_control_lisp2 = config_lisp->get_lisp("control-p2");
232 +  if(config_control_lisp2 && secondary_controller) {
233 +    secondary_controller->read(*config_control_lisp2);
234 +  }
235  }
236  
237  void
238 @@ -116,6 +120,11 @@
239      main_controller->write(writer);
240      writer.end_list("control");
241    }
242 +  if(secondary_controller) {
243 +    writer.start_list("control-p2");
244 +    secondary_controller->write(writer);
245 +    writer.end_list("control-p2");
246 +  }
247  
248    writer.end_list("supertux-config");
249  }
250 Index: src/main.cpp
251 ===================================================================
252 --- src/main.cpp        (revision 4870)
253 +++ src/main.cpp        (working copy)
254 @@ -58,6 +58,7 @@
255  
256  SDL_Surface* screen = 0;
257  JoystickKeyboardController* main_controller = 0;
258 +JoystickKeyboardController* secondary_controller = 0;
259  TinyGetText::DictionaryManager dictionary_manager;
260  
261  int SCREEN_WIDTH;
262 @@ -514,6 +515,7 @@
263  
264      timelog("controller");
265      main_controller = new JoystickKeyboardController();
266 +    secondary_controller = new JoystickKeyboardController();
267      timelog("config");
268      init_config();
269      timelog("tinygettext");
270 @@ -587,7 +589,9 @@
271    delete config;
272    config = NULL;
273    delete main_controller;
274 +  delete secondary_controller;
275    main_controller = NULL;
276 +  secondary_controller = NULL;
277    delete Console::instance;
278    Console::instance = NULL;
279    Scripting::exit_squirrel();
280 Index: src/sector.cpp
281 ===================================================================
282 --- src/sector.cpp      (revision 4870)
283 +++ src/sector.cpp      (working copy)
284 @@ -74,11 +74,21 @@
285  bool Sector::show_collrects = false;
286  bool Sector::draw_solids_only = false;
287  
288 +namespace {
289 +  // two-player hack: second player's player_status 
290 +  PlayerStatus* second_player_status = 0;
291 +}
292 +
293  Sector::Sector(Level* parent)
294    : level(parent), currentmusic(LEVEL_MUSIC),
295    ambient_light( 1.0f, 1.0f, 1.0f, 1.0f ), gravity(10.0), player(0), camera(0)
296  {
297    add_object(new Player(player_status, "Tux"));
298 +
299 +  // two-player hack: second player has dummy player_status
300 +  if (!second_player_status) second_player_status = new PlayerStatus();
301 +  add_object(new Player(second_player_status, "Penny"));
302 +
303    add_object(new DisplayEffect("Effect"));
304    add_object(new TextObject("Text"));
305  
306 @@ -591,6 +601,16 @@
307      player->move(npos);
308    }
309  
310 +  // two-player hack: move other players to main player's position
311 +  for(GameObjects::iterator i = gameobjects.begin();
312 +      i != gameobjects.end(); ++i) {
313 +    Player* p = dynamic_cast<Player*>(*i);
314 +    if (!p) continue;
315 +    if (p == player) continue;
316 +    p->move(player->get_pos());
317 +  }
318 +
319 +
320    camera->reset(player->get_pos());
321    update_game_objects();
322  
323 @@ -639,6 +659,15 @@
324  {
325    player->check_bounds(camera);
326  
327 +  // two-player hack: keep other players in bound, too
328 +  for(GameObjects::iterator i = gameobjects.begin();
329 +      i != gameobjects.end(); ++i) {
330 +    Player* p = dynamic_cast<Player*>(*i);
331 +    if (!p) continue;
332 +    if (p == player) continue;
333 +    p->check_bounds(camera);
334 +  }
335 +
336    /* update objects */
337    for(GameObjects::iterator i = gameobjects.begin();
338            i != gameobjects.end(); ++i) {
339 @@ -721,7 +750,7 @@
340    Player* player = dynamic_cast<Player*> (object);
341    if(player != NULL) {
342      if(this->player != 0) {
343 -      log_warning << "Multiple players added. Ignoring" << std::endl;
344 +      //log_warning << "Multiple players added. Ignoring" << std::endl;
345        return false;
346      }
347      this->player = player;