Changed level editor to a class.
[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 static LevelEditor* leveleditor;
73
74 void free_contrib_menu()
75 {
76   for(std::vector<LevelSubset*>::iterator i = contrib_subsets.begin();
77       i != contrib_subsets.end(); ++i)
78     delete *i;
79
80   contrib_subsets.clear();
81   contrib_menu->clear();
82 }
83
84 void generate_contrib_menu()
85 {
86   string_list_type level_subsets = dsubdirs("/levels", "info");
87
88   free_contrib_menu();
89
90   contrib_menu->additem(MN_LABEL,"Contrib Levels",0,0);
91   contrib_menu->additem(MN_HL,"",0,0);
92
93   for (int i = 0; i < level_subsets.num_items; ++i)
94     {
95       LevelSubset* subset = new LevelSubset();
96       subset->load(level_subsets.item[i]);
97       contrib_menu->additem(MN_GOTO, subset->title.c_str(), i,
98           contrib_subset_menu, i+1);
99       contrib_subsets.push_back(subset);
100     }
101
102   contrib_menu->additem(MN_HL,"",0,0);
103   contrib_menu->additem(MN_BACK,"Back",0,0);
104
105   string_list_free(&level_subsets);
106 }
107
108 void check_contrib_menu()
109 {
110   static int current_subset = -1;
111
112   int index = contrib_menu->check();
113   if (index != -1)
114     {
115       index -= 1;
116       if (index >= 0 && index <= int(contrib_subsets.size()))
117         {
118           if (current_subset != index)
119             {
120               current_subset = index;
121               // FIXME: This shouln't be busy looping
122               LevelSubset& subset = * (contrib_subsets[index]);
123           
124               current_contrib_subset = &subset;
125
126               contrib_subset_menu->clear();
127
128               contrib_subset_menu->additem(MN_LABEL, subset.title, 0,0);
129               contrib_subset_menu->additem(MN_HL,"",0,0);
130               
131               for (int i = 1; i <= subset.levels; ++i)
132                 {
133                   Level* level = new Level;
134                   level->load(subset.get_level_filename(i));
135                   contrib_subset_menu->additem(MN_ACTION, level->get_name(), 0, 0, i);
136                   delete level;
137                 }
138               
139               contrib_subset_menu->additem(MN_HL,"",0,0);      
140               contrib_subset_menu->additem(MN_BACK, "Back", 0, 0);
141
142               titlesession->get_current_sector()->activate();
143               titlesession->set_current();
144             }
145         }
146       else
147         {
148           // Back button
149         }
150     }
151 }
152
153 void check_contrib_subset_menu()
154 {
155   int index = contrib_subset_menu->check();
156   if (index != -1)
157     {
158       if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION)
159         {
160           std::cout << "Starting level: " << index << std::endl;
161           
162           GameSession session(
163               current_contrib_subset->get_level_filename(index), ST_GL_PLAY);
164           session.run();
165           player_status.reset();
166           Menu::set_current(main_menu);
167           titlesession->get_current_sector()->activate();
168           titlesession->set_current();
169         }
170     }  
171 }
172
173 void draw_demo(double frame_ratio)
174 {
175   Sector* world  = titlesession->get_current_sector();
176   Player* tux = world->player;
177
178   world->play_music(LEVEL_MUSIC);
179   
180   global_frame_counter++;
181   tux->key_event((SDLKey) keymap.right,DOWN);
182   
183   if(random_timer.check())
184     {
185       if(walking)
186         tux->key_event((SDLKey) keymap.jump,UP);
187       else
188         tux->key_event((SDLKey) keymap.jump,DOWN);
189     }
190   else
191     {
192       random_timer.start(rand() % 3000 + 3000);
193       walking = !walking;
194     }
195
196   // Wrap around at the end of the level back to the beginnig
197   if(world->solids->get_width() * 32 - 320 < tux->base.x)
198     {
199       tux->level_begin();
200     }
201
202   tux->can_jump = true;
203   float last_tux_x_pos = tux->base.x;
204   world->action(frame_ratio);
205   
206
207   // disabled for now, since with the new jump code we easily get deadlocks
208   // Jump if tux stays in the same position for one loop, ie. if he is
209   // stuck behind a wall
210   if (last_tux_x_pos == tux->base.x)
211     {
212       walking = false;
213     }
214
215   world->draw(*titlesession->context);
216 }
217
218 /* --- TITLE SCREEN --- */
219 void title(void)
220 {
221   random_timer.init(true);
222
223   walking = true;
224
225   st_pause_ticks_init();
226
227   titlesession = new GameSession(datadir + "/levels/misc/menu.stl", ST_GL_DEMO_GAME);
228
229   /* Load images: */
230   bkg_title = new Surface(datadir + "/images/background/arctis.jpg", IGNORE_ALPHA);
231   logo = new Surface(datadir + "/images/title/logo.png", USE_ALPHA);
232   img_choose_subset = new Surface(datadir + "/images/status/choose-level-subset.png", USE_ALPHA);
233
234   /* --- Main title loop: --- */
235   frame = 0;
236
237   update_time = st_get_ticks();
238   random_timer.start(rand() % 2000 + 2000);
239
240   Menu::set_current(main_menu);
241   DrawingContext& context = *titlesession->context;
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(frame_ratio);
269      
270       if (Menu::current() == main_menu)
271         context.draw_surface(logo, Vector(screen->w/2 - logo->w/2, 30),
272             LAYER_FOREGROUND1+1);
273
274       context.draw_text(white_small_text,
275           " SuperTux " VERSION "\n"
276           "Copyright (c) 2003 SuperTux Devel Team\n"
277           "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
278           "are welcome to redistribute it under certain conditions; see the file COPYING\n"
279           "for details.\n", Vector(0, screen->h - 70), LAYER_FOREGROUND1);
280
281       /* Don't draw menu, if quit is true */
282       Menu* menu = Menu::current();
283       if(menu)
284         {
285           menu->draw(context);
286           menu->action();
287         
288           if(menu == main_menu)
289             {
290               switch (main_menu->check())
291                 {
292                 case MNID_STARTGAME:
293                   // Start Game, ie. goto the slots menu
294                   update_load_save_game_menu(load_game_menu);
295                   break;
296                 case MNID_CONTRIB:
297                   // Contrib Menu
298                   puts("Entering contrib menu");
299                   generate_contrib_menu();
300                   break;
301                 case MNID_LEVELEDITOR:
302                   leveleditor = new LevelEditor();
303                   leveleditor->run();
304                   delete leveleditor;
305                   Menu::set_current(main_menu);
306                   break;
307                 case MNID_CREDITS:
308                   display_text_file("CREDITS", bkg_title, 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                 if(confirm_dialog(bkg_title, str))
329                   {
330                   sprintf(str,"%s/slot%d.stsg", st_save_dir, slot);
331                   printf("Removing: %s\n",str);
332                   remove(str);
333                   }
334
335                 update_load_save_game_menu(load_game_menu);
336                 Menu::set_current(main_menu);
337                 update_time = st_get_ticks();
338                 }
339               else if (process_load_game_menu())
340                 {
341                   // FIXME: shouldn't be needed if GameSession doesn't relay on global variables
342                   titlesession->get_current_sector()->activate();
343                   titlesession->set_current();
344                   //titletux.level_begin();
345                   update_time = st_get_ticks();
346                 }
347             }
348           else if(menu == contrib_menu)
349             {
350               check_contrib_menu();
351             }
352           else if (menu == contrib_subset_menu)
353             {
354               check_contrib_subset_menu();
355             }
356         }
357
358       mouse_cursor->draw(context);
359      
360       context.do_drawing();
361
362       /* Set the time of the last update and the time of the current update */
363       last_update_time = update_time;
364       update_time = st_get_ticks();
365
366       /* Pause: */
367       frame++;
368       SDL_Delay(25);
369     }
370   /* Free surfaces: */
371
372   free_contrib_menu();
373   delete titlesession;
374   delete bkg_title;
375   delete logo;
376   delete img_choose_subset;
377 }
378
379 // EOF //
380