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