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