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