eliminated global scroll_x and scroll_y variables
[supertux.git] / src / title.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
5 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 // 
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 //  02111-1307, USA.
21
22 #include <iostream>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <SDL.h>
29 #include <SDL_image.h>
30
31 #ifndef WIN32
32 #include <sys/types.h>
33 #include <ctype.h>
34 #endif
35
36 #include "defines.h"
37 #include "globals.h"
38 #include "title.h"
39 #include "screen.h"
40 #include "high_scores.h"
41 #include "menu.h"
42 #include "texture.h"
43 #include "timer.h"
44 #include "setup.h"
45 #include "level.h"
46 #include "gameloop.h"
47 #include "leveleditor.h"
48 #include "scene.h"
49 #include "player.h"
50 #include "math.h"
51 #include "tile.h"
52 #include "resources.h"
53
54 static Surface* bkg_title;
55 static Surface* logo;
56 static Surface* img_choose_subset;
57
58 static bool walking;
59 static Timer random_timer;
60
61 static int frame;
62 static unsigned int last_update_time;
63 static unsigned int update_time;
64
65 std::vector<LevelSubset*> contrib_subsets;
66 std::string current_contrib_subset;
67
68 void free_contrib_menu()
69 {
70   for(std::vector<LevelSubset*>::iterator i = contrib_subsets.begin();
71       i != contrib_subsets.end(); ++i)
72     delete *i;
73
74   contrib_subsets.clear();
75   contrib_menu->clear();
76 }
77
78 void generate_contrib_menu()
79 {
80   string_list_type level_subsets = dsubdirs("/levels", "info");
81
82   free_contrib_menu();
83
84   contrib_menu->additem(MN_LABEL,"Contrib Levels",0,0);
85   contrib_menu->additem(MN_HL,"",0,0);
86
87   for (int i = 0; i < level_subsets.num_items; ++i)
88     {
89       LevelSubset* subset = new LevelSubset();
90       subset->load(level_subsets.item[i]);
91       contrib_menu->additem(MN_GOTO, subset->title.c_str(), i,
92           contrib_subset_menu, i+1);
93       contrib_subsets.push_back(subset);
94     }
95
96   contrib_menu->additem(MN_HL,"",0,0);
97   contrib_menu->additem(MN_BACK,"Back",0,0);
98
99   string_list_free(&level_subsets);
100 }
101
102 void check_contrib_menu()
103 {
104   static int current_subset = -1;
105
106   int index = contrib_menu->check();
107   if (index != -1)
108     {
109       index -= 1;
110       if (index >= 0 && index <= int(contrib_subsets.size()))
111         {
112           if (current_subset != index)
113             {
114               current_subset = index;
115               // FIXME: This shouln't be busy looping
116               LevelSubset& subset = * (contrib_subsets[index]);
117           
118               current_contrib_subset = subset.name;
119
120               std::cout << "Updating the contrib subset menu..." << subset.levels << std::endl;
121       
122               contrib_subset_menu->clear();
123
124               contrib_subset_menu->additem(MN_LABEL, subset.title, 0,0);
125               contrib_subset_menu->additem(MN_HL,"",0,0);
126               for (int i = 1; i <= subset.levels; ++i)
127                 {
128                   Level level;
129                   level.load(subset.name, i, 0);
130                   contrib_subset_menu->additem(MN_ACTION, level.name, 0, 0, i);
131                 }
132               contrib_subset_menu->additem(MN_HL,"",0,0);      
133               contrib_subset_menu->additem(MN_BACK, "Back", 0, 0);
134             }
135         }
136       else
137         {
138           // Back button
139         }
140     }
141 }
142
143 void check_contrib_subset_menu()
144 {
145   int index = contrib_subset_menu->check();
146   if (index != -1)
147     {
148       if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION)
149         {
150           std::cout << "Starting level: " << index << std::endl;
151           GameSession session(current_contrib_subset, index, ST_GL_PLAY);
152           session.run();
153           player_status.reset();
154           Menu::set_current(main_menu);
155         }
156     }  
157 }
158
159 void draw_background()
160 {
161   /* Draw the title background: */
162
163   bkg_title->draw_bg();
164 }
165
166 void draw_demo(GameSession* session, double frame_ratio)
167 {
168   World* world  = session->get_world();
169   World::set_current(world);
170   Level* plevel = session->get_level();
171   Player* tux = world->get_tux();
172
173   world->play_music(LEVEL_MUSIC);
174   
175   global_frame_counter++;
176   tux->key_event((SDLKey) keymap.right,DOWN);
177   
178   if(random_timer.check())
179     {
180       if(walking)
181         tux->key_event((SDLKey) keymap.jump,UP);
182       else
183         tux->key_event((SDLKey) keymap.jump,DOWN);
184     }
185   else
186     {
187       random_timer.start(rand() % 3000 + 3000);
188       walking = !walking;
189     }
190
191   // Wrap around at the end of the level back to the beginnig
192   if(plevel->width * 32 - 320 < tux->base.x)
193     {
194       tux->level_begin();
195     }
196
197   tux->can_jump = true;
198   float last_tux_x_pos = tux->base.x;
199   world->action(frame_ratio);
200   
201
202   // disabled for now, since with the new jump code we easily get deadlocks
203   // Jump if tux stays in the same position for one loop, ie. if he is
204   // stuck behind a wall
205   if (last_tux_x_pos == tux->base.x)
206     {
207       walking = false;
208     }
209
210   world->draw();
211 }
212
213 /* --- TITLE SCREEN --- */
214 void title(void)
215 {
216   random_timer.init(true);
217
218   walking = true;
219
220   st_pause_ticks_init();
221
222   GameSession session(datadir + "/levels/misc/menu.stl", 0, ST_GL_DEMO_GAME);
223
224   clearscreen(0, 0, 0);
225   updatescreen();
226
227   /* Load images: */
228   bkg_title = new Surface(datadir + "/images/background/arctis.jpg", IGNORE_ALPHA);
229   logo = new Surface(datadir + "/images/title/logo.png", USE_ALPHA);
230   img_choose_subset = new Surface(datadir + "/images/status/choose-level-subset.png", USE_ALPHA);
231
232   /* --- Main title loop: --- */
233   frame = 0;
234
235   /* Draw the title background: */
236   bkg_title->draw_bg();
237
238   update_time = st_get_ticks();
239   random_timer.start(rand() % 2000 + 2000);
240
241   Menu::set_current(main_menu);
242   while (Menu::current())
243     {
244       // if we spent to much time on a menu entry
245       if( (update_time - last_update_time) > 1000)
246         update_time = last_update_time = st_get_ticks();
247
248       // Calculate the movement-factor
249       double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
250       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
251         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
252       /* Lower the frame_ratio that Tux doesn't jump to hectically throught the demo. */
253       frame_ratio /= 2;
254
255       SDL_Event event;
256       while (SDL_PollEvent(&event))
257         {
258           if (Menu::current())
259             {
260               Menu::current()->event(event);
261             }
262          // FIXME: QUIT signal should be handled more generic, not locally
263           if (event.type == SDL_QUIT)
264             Menu::set_current(0);
265         }
266
267       /* Draw the background: */
268       draw_demo(&session, frame_ratio);
269       
270       if (Menu::current() == main_menu)
271         logo->draw(screen->w/2 - logo->w/2, 30);
272
273       white_small_text->draw(" SuperTux " VERSION "\n"
274                              "Copyright (c) 2003 SuperTux Devel Team\n"
275                              "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
276                              "are welcome to redistribute it under certain conditions; see the file COPYING\n"
277                              "for details.\n",
278                              0, screen->h - 70, 0);
279
280       /* Don't draw menu, if quit is true */
281       Menu* menu = Menu::current();
282       if(menu)
283         {
284           menu->draw();
285           menu->action();
286         
287           if(menu == main_menu)
288             {
289               switch (main_menu->check())
290                 {
291                 case MNID_STARTGAME:
292                   // Start Game, ie. goto the slots menu
293                   update_load_save_game_menu(load_game_menu);
294                   break;
295                 case MNID_CONTRIB:
296                   // Contrib Menu
297                   puts("Entering contrib menu");
298                   generate_contrib_menu();
299                   break;
300                 case MNID_LEVELEDITOR:
301                   leveleditor();
302                   Menu::set_current(main_menu);
303                   break;
304                 case MNID_CREDITS:
305                   display_text_file("CREDITS", bkg_title, SCROLL_SPEED_CREDITS);
306                   Menu::set_current(main_menu);
307                   break;
308                 case MNID_QUITMAINMENU:
309                   Menu::set_current(0);
310                   break;
311                 }
312             }
313           else if(menu == options_menu)
314             {
315               process_options_menu();
316             }
317           else if(menu == load_game_menu)
318             {
319               if(event.key.keysym.sym == SDLK_DELETE)
320                 {
321                 int slot = menu->get_active_item_id();
322                 char str[1024];
323                 sprintf(str,"Are you sure you want to delete slot %d?", slot);
324                 
325                 draw_background();
326
327                 if(confirm_dialog(str))
328                   {
329                   sprintf(str,"%s/slot%d.stsg", st_save_dir, slot);
330                   printf("Removing: %s\n",str);
331                   remove(str);
332                   }
333
334                 update_load_save_game_menu(load_game_menu);
335                 Menu::set_current(main_menu);
336                 update_time = st_get_ticks();
337                 }
338               else if (process_load_game_menu())
339                 {
340                   // FIXME: shouldn't be needed if GameSession doesn't relay on global variables
341                   //titletux.level_begin();
342                   update_time = st_get_ticks();
343                 }
344             }
345           else if(menu == contrib_menu)
346             {
347               check_contrib_menu();
348             }
349           else if (menu == contrib_subset_menu)
350             {
351               check_contrib_subset_menu();
352             }
353         }
354
355       mouse_cursor->draw();
356       
357       flipscreen();
358
359       /* Set the time of the last update and the time of the current update */
360       last_update_time = update_time;
361       update_time = st_get_ticks();
362
363       /* Pause: */
364       frame++;
365       SDL_Delay(25);
366     }
367   /* Free surfaces: */
368
369   free_contrib_menu();
370   delete bkg_title;
371   delete logo;
372   delete img_choose_subset;
373 }
374
375 // EOF //
376