#303: Typo fixes from mathnerd314
[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 5235. It may break for later revisions.
33 #
34 # -----------------------------------------------------------------------------
35 Index: src/control/joystickkeyboardcontroller.cpp
36 ===================================================================
37 --- src/control/joystickkeyboardcontroller.cpp  (revision 5235)
38 +++ src/control/joystickkeyboardcontroller.cpp  (working copy)
39 @@ -30,6 +30,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 @@ -475,11 +476,11 @@
48    KeyMap::iterator key_mapping = keymap.find(event.key.keysym.sym);
49  
50    // if console key was pressed: toggle console
51 -  if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE)) {
52 +  if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE) && (this == main_controller)) {
53      if (event.type == SDL_KEYDOWN) 
54        Console::instance->toggle();
55    } else {
56 -    if (Console::instance->hasFocus()) {
57 +    if (Console::instance->hasFocus() && (this == main_controller)) {
58        // if console is open: send key there
59        process_console_key_event(event);
60      } else if (Menu::current()) {
61 @@ -487,7 +488,7 @@
62        process_menu_key_event(event);
63      } else if(key_mapping == keymap.end()) {
64        // default action: update controls
65 -      log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
66 +      //log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
67      } else {
68        Control control = key_mapping->second;
69        controls[control] = (event.type == SDL_KEYDOWN);
70 Index: src/options_menu.cpp
71 ===================================================================
72 --- src/options_menu.cpp        (revision 5235)
73 +++ src/options_menu.cpp        (working copy)
74 @@ -118,6 +118,8 @@
75    }
76    add_submenu(_("Setup Keyboard"), main_controller->get_key_options_menu());
77    add_submenu(_("Setup Joystick"),main_controller->get_joystick_options_menu());
78 +  add_submenu(std::string(_("Setup Keyboard"))+" (P2)", secondary_controller->get_key_options_menu());
79 +  add_submenu(std::string(_("Setup Joystick"))+" (P2)", secondary_controller->get_joystick_options_menu());
80    add_hl();
81    add_back(_("Back"));
82  }
83 Index: src/main.hpp
84 ===================================================================
85 --- src/main.hpp        (revision 5235)
86 +++ src/main.hpp        (working copy)
87 @@ -31,5 +31,6 @@
88  // global variables
89  class JoystickKeyboardController;
90  extern JoystickKeyboardController* main_controller;
91 +extern JoystickKeyboardController* secondary_controller;
92  
93  #endif
94 Index: src/game_session.cpp
95 ===================================================================
96 --- src/game_session.cpp        (revision 5235)
97 +++ src/game_session.cpp        (working copy)
98 @@ -120,6 +120,7 @@
99    end_sequence = 0;
100  
101    main_controller->reset();
102 +  secondary_controller->reset();
103  
104    currentsector = 0;
105  
106 @@ -463,6 +464,22 @@
107    process_events();
108    process_menu();
109  
110 +  // two-player hack: resurrect Penny when she dies
111 +  Player* tux = currentsector->player;
112 +  for(std::vector<GameObject*>::iterator i = currentsector->gameobjects.begin(); i != currentsector->gameobjects.end(); ++i) {
113 +    Player* p = dynamic_cast<Player*>(*i);
114 +    if (!p) continue;
115 +    if (p == tux) continue;
116 +    if (p->is_dead()) {
117 +      p->remove_me();
118 +      static PlayerStatus* ps = new PlayerStatus();
119 +      p = new Player(ps, "Penny");
120 +      currentsector->add_object(p);
121 +      p->move(tux->get_pos());
122 +      p->safe_timer.start(TUX_SAFE_TIME);
123 +    }
124 +  }
125 +
126    check_end_conditions();
127  
128    // respawning in new sector?
129 @@ -558,9 +575,11 @@
130  
131      // TODO make a screen out of this, another mainloop is ugly
132      main_controller->update();
133 +    secondary_controller->update();
134      SDL_Event event;
135      while (SDL_PollEvent(&event)) {
136        main_controller->process_event(event);
137 +      secondary_controller->process_event(event);
138        if(event.type == SDL_QUIT)
139          main_loop->quit();
140      }
141 Index: src/mainloop.cpp
142 ===================================================================
143 --- src/mainloop.cpp    (revision 5235)
144 +++ src/mainloop.cpp    (working copy)
145 @@ -177,9 +177,11 @@
146  MainLoop::process_events()
147  {
148    main_controller->update();
149 +  secondary_controller->update();
150    SDL_Event event;
151    while(SDL_PollEvent(&event)) {
152      main_controller->process_event(event);
153 +    secondary_controller->process_event(event);
154      if(Menu::current() != NULL)
155        Menu::current()->event(event);
156      if(event.type == SDL_QUIT)
157 Index: src/object/player.cpp
158 ===================================================================
159 --- src/object/player.cpp       (revision 5235)
160 +++ src/object/player.cpp       (working copy)
161 @@ -134,6 +134,7 @@
162  {
163    this->name = name;
164    controller = main_controller;
165 +  if (name == "Penny") controller = secondary_controller;
166    scripting_controller = new CodeController();
167    smalltux_gameover = sprite_manager->create("images/creatures/tux_small/smalltux-gameover.sprite");
168    smalltux_star = sprite_manager->create("images/creatures/tux_small/smalltux-star.sprite");
169 @@ -938,6 +939,20 @@
170  
171    int layer = LAYER_OBJECTS + 1;
172  
173 +  // two-player hack: draw Penny in a different color
174 +  if (name == "Penny") {
175 +    layer -= 20;
176 +    if(tux_body->head) tux_body->head->set_color(Color(1.0f, 1.0f, 0.5f, 1.0f));
177 +    if(tux_body->body) tux_body->body->set_color(Color(1.0f, 1.0f, 0.5f, 1.0f));
178 +    if(tux_body->arms) tux_body->arms->set_color(Color(1.0f, 1.0f, 0.5f, 1.0f));
179 +    if(tux_body->feet) tux_body->feet->set_color(Color(1.0f, 1.0f, 0.5f, 1.0f));
180 +  } else {
181 +    if(tux_body->head) tux_body->head->set_color(Color(1.0f, 1.0f, 1.0f, 1.0f));
182 +    if(tux_body->body) tux_body->body->set_color(Color(1.0f, 1.0f, 1.0f, 1.0f));
183 +    if(tux_body->arms) tux_body->arms->set_color(Color(1.0f, 1.0f, 1.0f, 1.0f));
184 +    if(tux_body->feet) tux_body->feet->set_color(Color(1.0f, 1.0f, 1.0f, 1.0f));
185 +  }
186 +
187    /* Set Tux sprite action */
188    if (climbing)
189      {
190 @@ -1114,6 +1129,12 @@
191      return FORCE_MOVE;
192    }
193  
194 +  // Multiple Players pass through one another
195 +  Player* player = dynamic_cast<Player*> (&other);
196 +  if(player) {
197 +    return FORCE_MOVE;
198 +  }
199 +
200    if(hit.left || hit.right) {
201      try_grab(); //grab objects right now, in update it will be too late
202    }
203 @@ -1206,6 +1227,8 @@
204      dying_timer.start(3.0);
205      set_group(COLGROUP_DISABLED);
206  
207 +    if (name == "Penny") return;
208 +
209      DisplayEffect* effect = new DisplayEffect();
210      effect->fade_out(3.0);
211      Sector::current()->add_object(effect);
212 Index: src/gameconfig.cpp
213 ===================================================================
214 --- src/gameconfig.cpp  (revision 5235)
215 +++ src/gameconfig.cpp  (working copy)
216 @@ -93,6 +93,10 @@
217    if(config_control_lisp && main_controller) {
218      main_controller->read(*config_control_lisp);
219    }
220 +  const lisp::Lisp* config_control_lisp2 = config_lisp->get_lisp("control-p2");
221 +  if(config_control_lisp2 && secondary_controller) {
222 +    secondary_controller->read(*config_control_lisp2);
223 +  }
224  }
225  
226  void
227 @@ -125,6 +129,11 @@
228      main_controller->write(writer);
229      writer.end_list("control");
230    }
231 +  if(secondary_controller) {
232 +    writer.start_list("control-p2");
233 +    secondary_controller->write(writer);
234 +    writer.end_list("control-p2");
235 +  }
236  
237    writer.end_list("supertux-config");
238  }
239 Index: src/main.cpp
240 ===================================================================
241 --- src/main.cpp        (revision 5235)
242 +++ src/main.cpp        (working copy)
243 @@ -64,6 +64,7 @@
244  namespace { DrawingContext *context_pointer; }
245  SDL_Surface *screen;
246  JoystickKeyboardController* main_controller = 0;
247 +JoystickKeyboardController* secondary_controller = 0;
248  TinyGetText::DictionaryManager dictionary_manager;
249  
250  int SCREEN_WIDTH;
251 @@ -539,6 +540,7 @@
252  
253      timelog("controller");
254      main_controller = new JoystickKeyboardController();
255 +    secondary_controller = new JoystickKeyboardController();
256      timelog("config");
257      init_config();
258      timelog("tinygettext");
259 @@ -615,7 +617,9 @@
260    delete config;
261    config = NULL;
262    delete main_controller;
263 +  delete secondary_controller;
264    main_controller = NULL;
265 +  secondary_controller = NULL;
266    delete Console::instance;
267    Console::instance = NULL;
268    Scripting::exit_squirrel();
269 Index: src/sector.cpp
270 ===================================================================
271 --- src/sector.cpp      (revision 5235)
272 +++ src/sector.cpp      (working copy)
273 @@ -74,11 +74,21 @@
274  bool Sector::show_collrects = false;
275  bool Sector::draw_solids_only = false;
276  
277 +namespace {
278 +  // two-player hack: second player's player_status 
279 +  PlayerStatus* second_player_status = 0;
280 +}
281 +
282  Sector::Sector(Level* parent)
283    : level(parent), currentmusic(LEVEL_MUSIC),
284    ambient_light( 1.0f, 1.0f, 1.0f, 1.0f ), gravity(10.0), player(0), camera(0)
285  {
286    add_object(new Player(player_status, "Tux"));
287 +
288 +  // two-player hack: second player has dummy player_status
289 +  if (!second_player_status) second_player_status = new PlayerStatus();
290 +  add_object(new Player(second_player_status, "Penny"));
291 +
292    add_object(new DisplayEffect("Effect"));
293    add_object(new TextObject("Text"));
294  
295 @@ -603,6 +613,16 @@
296      player->move(npos);
297    }
298  
299 +  // two-player hack: move other players to main player's position
300 +  for(GameObjects::iterator i = gameobjects.begin();
301 +      i != gameobjects.end(); ++i) {
302 +    Player* p = dynamic_cast<Player*>(*i);
303 +    if (!p) continue;
304 +    if (p == player) continue;
305 +    p->move(player->get_pos());
306 +  }
307 +
308 +
309    camera->reset(player->get_pos());
310    update_game_objects();
311  
312 @@ -651,6 +671,15 @@
313  {
314    player->check_bounds(camera);
315  
316 +  // two-player hack: keep other players in bound, too
317 +  for(GameObjects::iterator i = gameobjects.begin();
318 +      i != gameobjects.end(); ++i) {
319 +    Player* p = dynamic_cast<Player*>(*i);
320 +    if (!p) continue;
321 +    if (p == player) continue;
322 +    p->check_bounds(camera);
323 +  }
324 +
325    /* update objects */
326    for(GameObjects::iterator i = gameobjects.begin();
327            i != gameobjects.end(); ++i) {
328 @@ -745,7 +774,7 @@
329    Player* player = dynamic_cast<Player*> (object);
330    if(player != NULL) {
331      if(this->player != 0) {
332 -      log_warning << "Multiple players added. Ignoring" << std::endl;
333 +      //log_warning << "Multiple players added. Ignoring" << std::endl;
334        return false;
335      }
336      this->player = player;