Pushed copyright message down.
[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* bkg_credits;
56 static Surface* logo;
57 static Surface* img_choose_subset;
58
59 static bool walking;
60 static Timer random_timer;
61
62 static int frame;
63 static unsigned int last_update_time;
64 static unsigned int update_time;
65
66 std::vector<LevelSubset*> contrib_subsets;
67 std::string current_contrib_subset;
68
69 void free_contrib_menu()
70 {
71   for(std::vector<LevelSubset*>::iterator i = contrib_subsets.begin();
72       i != contrib_subsets.end(); ++i)
73     delete *i;
74
75   contrib_subsets.clear();
76   contrib_menu->clear();
77 }
78
79 void generate_contrib_menu()
80 {
81   string_list_type level_subsets = dsubdirs("/levels", "info");
82
83   free_contrib_menu();
84
85   contrib_menu->additem(MN_LABEL,"Contrib Levels",0,0);
86   contrib_menu->additem(MN_HL,"",0,0);
87
88   for (int i = 0; i < level_subsets.num_items; ++i)
89     {
90       LevelSubset* subset = new LevelSubset();
91       subset->load(level_subsets.item[i]);
92       contrib_menu->additem(MN_GOTO, subset->title.c_str(), i,
93           contrib_subset_menu, i+1);
94       contrib_subsets.push_back(subset);
95     }
96
97   contrib_menu->additem(MN_HL,"",0,0);
98   contrib_menu->additem(MN_BACK,"Back",0,0);
99
100   string_list_free(&level_subsets);
101 }
102
103 void check_contrib_menu()
104 {
105   static int current_subset = -1;
106
107   int index = contrib_menu->check();
108   if (index != -1)
109     {
110       index -= 1;
111       if (index >= 0 && index <= int(contrib_subsets.size()))
112         {
113           if (current_subset != index)
114             {
115               current_subset = index;
116               // FIXME: This shouln't be busy looping
117               LevelSubset& subset = * (contrib_subsets[index]);
118           
119               current_contrib_subset = subset.name;
120
121               std::cout << "Updating the contrib subset menu..." << subset.levels << std::endl;
122       
123               contrib_subset_menu->clear();
124
125               contrib_subset_menu->additem(MN_LABEL, subset.title, 0,0);
126               contrib_subset_menu->additem(MN_HL,"",0,0);
127               for (int i = 1; i <= subset.levels; ++i)
128                 {
129                   Level level;
130                   level.load(subset.name, i);
131                   contrib_subset_menu->additem(MN_ACTION, level.name, 0, 0, i);
132                 }
133               contrib_subset_menu->additem(MN_HL,"",0,0);      
134               contrib_subset_menu->additem(MN_BACK, "Back", 0, 0);
135             }
136         }
137       else
138         {
139           // Back button
140         }
141     }
142 }
143
144 void check_contrib_subset_menu()
145 {
146   int index = contrib_subset_menu->check();
147   if (index != -1)
148     {
149       if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION)
150         {
151           std::cout << "Starting level: " << index << std::endl;
152           GameSession session(current_contrib_subset, index, ST_GL_PLAY);
153           session.run();
154           player_status.reset();
155           Menu::set_current(main_menu);
156         }
157     }  
158 }
159
160 void draw_background()
161 {
162   /* Draw the title background: */
163
164   bkg_title->draw_bg();
165 }
166
167 void draw_demo(GameSession* session, double frame_ratio)
168 {
169   World* world  = session->get_world();
170   World::set_current(world);
171   Level* plevel = session->get_level();
172   Player* tux = world->get_tux();
173
174   world->play_music(LEVEL_MUSIC);
175   
176   global_frame_counter++;
177   tux->key_event((SDLKey) keymap.right,DOWN);
178   
179   if(random_timer.check())
180     {
181       if(walking)
182         tux->key_event((SDLKey) keymap.jump,UP);
183       else
184         tux->key_event((SDLKey) keymap.jump,DOWN);
185     }
186   else
187     {
188       random_timer.start(rand() % 3000 + 3000);
189       walking = !walking;
190     }
191
192   // Wrap around at the end of the level back to the beginnig
193   if(plevel->width * 32 - 320 < tux->base.x)
194     {
195       tux->level_begin();
196       scroll_x = 0;
197     }
198
199   tux->can_jump = true;
200   float last_tux_x_pos = tux->base.x;
201   world->action(frame_ratio);
202   
203
204   // disabled for now, since with the new jump code we easily get deadlocks
205   // Jump if tux stays in the same position for one loop, ie. if he is
206   // stuck behind a wall
207   if (last_tux_x_pos == tux->base.x)
208     {
209       walking = false;
210     }
211
212   world->draw();
213 }
214
215 /* --- TITLE SCREEN --- */
216 void title(void)
217 {
218   random_timer.init(true);
219
220   walking = true;
221
222   st_pause_ticks_init();
223
224   GameSession session(datadir + "/levels/misc/menu.stl", 0, ST_GL_DEMO_GAME);
225
226   clearscreen(0, 0, 0);
227   updatescreen();
228
229   /* Load images: */
230   bkg_title = new Surface(datadir + "/images/title/background.jpg", IGNORE_ALPHA);
231   bkg_credits = new Surface(datadir + "/images/background/oiltux.jpg", IGNORE_ALPHA);
232   logo = new Surface(datadir + "/images/title/logo.png", USE_ALPHA);
233   img_choose_subset = new Surface(datadir + "/images/status/choose-level-subset.png", USE_ALPHA);
234
235   /* --- Main title loop: --- */
236   frame = 0;
237
238   /* Draw the title background: */
239   bkg_title->draw_bg();
240
241   update_time = st_get_ticks();
242   random_timer.start(rand() % 2000 + 2000);
243
244   Menu::set_current(main_menu);
245   while (Menu::current())
246     {
247       // if we spent to much time on a menu entry
248       if( (update_time - last_update_time) > 1000)
249         update_time = last_update_time = st_get_ticks();
250
251       // Calculate the movement-factor
252       double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
253       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
254         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
255       /* Lower the frame_ratio that Tux doesn't jump to hectically throught the demo. */
256       frame_ratio /= 2;
257
258       SDL_Event event;
259       while (SDL_PollEvent(&event))
260         {
261           if (Menu::current())
262             {
263               Menu::current()->event(event);
264             }
265          // FIXME: QUIT signal should be handled more generic, not locally
266           if (event.type == SDL_QUIT)
267             Menu::set_current(0);
268         }
269
270       /* Draw the background: */
271       draw_demo(&session, frame_ratio);
272       
273       if (Menu::current() == main_menu)
274         logo->draw(screen->w/2 - logo->w/2, 30);
275
276       white_small_text->draw(" SuperTux " VERSION "\n"
277                              "Copyright (c) 2003 SuperTux Devel Team\n"
278                              "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
279                              "are welcome to redistribute it under certain conditions; see the file COPYING\n"
280                              "for details.\n",
281                              0, screen->h - 70, 0);
282
283       /* Don't draw menu, if quit is true */
284       Menu* menu = Menu::current();
285       if(menu)
286         {
287           menu->draw();
288           menu->action();
289         
290           if(menu == main_menu)
291             {
292               switch (main_menu->check())
293                 {
294                 case MNID_STARTGAME:
295                   // Start Game, ie. goto the slots menu
296                   update_load_save_game_menu(load_game_menu);
297                   break;
298                 case MNID_CONTRIB:
299                   // Contrib Menu
300                   puts("Entering contrib menu");
301                   generate_contrib_menu();
302                   break;
303                 case MNID_LEVELEDITOR:
304                   leveleditor();
305                   Menu::set_current(main_menu);
306                   break;
307                 case MNID_CREDITS:
308                   display_text_file("CREDITS", bkg_credits, SCROLL_SPEED_CREDITS);
309                   Menu::set_current(main_menu);
310                   break;
311                 case MNID_QUITMAINMENU:
312                   Menu::set_current(0);
313                   break;
314                 }
315             }
316           else if(menu == options_menu)
317             {
318               process_options_menu();
319             }
320           else if(menu == load_game_menu)
321             {
322               if(event.key.keysym.sym == SDLK_DELETE)
323                 {
324                 int slot = menu->get_active_item_id();
325                 char str[1024];
326                 sprintf(str,"Are you sure you want to delete slot %d?", slot);
327                 
328                 draw_background();
329
330                 if(confirm_dialog(str))
331                   {
332                   sprintf(str,"%s/slot%d.stsg", st_save_dir, slot);
333                   printf("Removing: %s\n",str);
334                   remove(str);
335                   }
336
337                 update_load_save_game_menu(load_game_menu);
338                 Menu::set_current(main_menu);
339                 update_time = st_get_ticks();
340                 }
341               else if (process_load_game_menu())
342                 {
343                   // FIXME: shouldn't be needed if GameSession doesn't relay on global variables
344                   // reset tux
345                   scroll_x = 0;
346                   //titletux.level_begin();
347                   update_time = st_get_ticks();
348                 }
349             }
350           else if(menu == contrib_menu)
351             {
352               check_contrib_menu();
353             }
354           else if (menu == contrib_subset_menu)
355             {
356               check_contrib_subset_menu();
357             }
358         }
359
360       mouse_cursor->draw();
361       
362       flipscreen();
363
364       /* Set the time of the last update and the time of the current update */
365       last_update_time = update_time;
366       update_time = st_get_ticks();
367
368       /* Pause: */
369       frame++;
370       SDL_Delay(25);
371     }
372   /* Free surfaces: */
373
374   free_contrib_menu();
375   delete bkg_title;
376   delete bkg_credits;
377   delete logo;
378   delete img_choose_subset;
379 }
380
381 // EOF //
382