00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "global.hpp"
00025
00026 #include "config.hpp"
00027 #include "construct_dialog.hpp"
00028 #include "cursor.hpp"
00029 #include "game_display.hpp"
00030 #include "events.hpp"
00031 #include "filesystem.hpp"
00032 #include "game_config.hpp"
00033 #include "hotkeys.hpp"
00034 #include "key.hpp"
00035 #include "gettext.hpp"
00036 #include "log.hpp"
00037 #include "marked-up_text.hpp"
00038 #include "preferences_display.hpp"
00039 #include "sdl_utils.hpp"
00040 #include "show_dialog.hpp"
00041 #include "titlescreen.hpp"
00042 #include "util.hpp"
00043 #include "video.hpp"
00044 #include "serialization/parser.hpp"
00045 #include "serialization/preprocessor.hpp"
00046 #include <algorithm>
00047 #include <vector>
00048
00049 #include "SDL_ttf.h"
00050
00051
00052 #define LOG_DP LOG_STREAM(info, display)
00053
00054 #define ERR_DP LOG_STREAM(err, display)
00055 #define LOG_CONFIG LOG_STREAM(info, config)
00056 #define ERR_CONFIG LOG_STREAM(err, config)
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 static bool fade_logo(game_display& screen, int xpos, int ypos)
00073 {
00074 const surface logo(image::get_image(game_config::game_logo));
00075 if(logo == NULL) {
00076 ERR_DP << "Could not find game logo\n";
00077 return true;
00078 }
00079
00080 surface const fb = screen.video().getSurface();
00081
00082 if(fb == NULL || xpos < 0 || ypos < 0 || xpos + logo->w > fb->w || ypos + logo->h > fb->h) {
00083 return true;
00084 }
00085
00086
00087 static bool faded_in = false;
00088
00089
00090 CKey key;
00091 bool last_button = key[SDLK_ESCAPE] || key[SDLK_SPACE];
00092
00093 LOG_DP << "fading logo in....\n";
00094 LOG_DP << "logo size: " << logo->w << "," << logo->h << "\n";
00095
00096 for(int x = 0; x != logo->w; ++x) {
00097 SDL_Rect srcrect = {x,0,1,logo->h};
00098 SDL_Rect dstrect = {xpos+x,ypos,1,logo->h};
00099 SDL_BlitSurface(logo,&srcrect,fb,&dstrect);
00100
00101 update_rect(dstrect);
00102
00103 if(!faded_in && (x%5) == 0) {
00104
00105 const bool new_button = key[SDLK_ESCAPE] || key[SDLK_SPACE] ||
00106 key[SDLK_RETURN] || key[SDLK_KP_ENTER] ;
00107 if(new_button && !last_button) {
00108 faded_in = true;
00109 }
00110
00111 last_button = new_button;
00112
00113 screen.update_display();
00114 screen.delay(10);
00115
00116 events::pump();
00117 if(screen.video().modeChanged()) {
00118 faded_in = true;
00119 return false;
00120 }
00121 }
00122
00123 }
00124
00125 LOG_DP << "logo faded in\n";
00126
00127 faded_in = true;
00128 return true;
00129 }
00130
00131
00132
00133 static void read_tips_of_day(config& tips_of_day)
00134 {
00135 tips_of_day.clear();
00136 LOG_CONFIG << "Loading tips of day\n";
00137 try {
00138 scoped_istream stream = preprocess_file("data/hardwired/tips.cfg");
00139 read(tips_of_day, *stream);
00140 } catch(config::error&) {
00141 ERR_CONFIG << "Could not read data/hardwired/tips.cfg\n";
00142 }
00143
00144
00145 config::child_itors tips = tips_of_day.child_range("tip");
00146 if (tips.first != tips.second) {
00147 std::random_shuffle(tips.first, tips.second);
00148 }
00149 }
00150
00151
00152 static void next_tip_of_day(config& tips_of_day, bool reverse = false)
00153 {
00154
00155
00156 config::child_itors tips = tips_of_day.child_range("tip");
00157 if (tips.first != tips.second) {
00158 config::child_iterator direction = reverse ? tips.first+1 : tips.second-1;
00159 std::rotate(tips.first, direction, tips.second);
00160 }
00161 }
00162
00163
00164 static const config* get_tip_of_day(config& tips_of_day)
00165 {
00166 if (tips_of_day.empty()) {
00167 read_tips_of_day(tips_of_day);
00168 }
00169
00170 const config::child_list& tips = tips_of_day.get_children("tip");
00171
00172
00173 for (size_t t=0; t < tips.size(); t++, next_tip_of_day(tips_of_day)) {
00174 const config* tip = tips.front();
00175 if (tip == NULL) continue;
00176
00177 const std::vector<std::string> needed_units = utils::split((*tip)["encountered_units"],',');
00178 if (needed_units.empty()) {
00179 return tip;
00180 }
00181 const std::set<std::string>& seen_units = preferences::encountered_units();
00182
00183
00184
00185 for (std::vector<std::string>::const_iterator i = needed_units.begin();
00186 i != needed_units.end(); i++) {
00187 int needed_units_nb = lexical_cast_default<int>(*i,-1);
00188 if (needed_units_nb !=-1) {
00189 if (needed_units_nb <= static_cast<int>(seen_units.size())) {
00190 return tip;
00191 }
00192 } else if (seen_units.find(*i) != seen_units.end()) {
00193 return tip;
00194 }
00195 }
00196 }
00197
00198 return NULL;
00199 }
00200
00201
00202
00203
00204
00205 static void draw_tip_of_day(game_display& screen,
00206 config& tips_of_day,
00207 const gui::dialog_frame::style& style,
00208 gui::button* const previous_tip_button,
00209 gui::button* const next_tip_button,
00210 gui::button* const help_tip_button,
00211 const SDL_Rect* const main_dialog_area,
00212 surface_restorer& tip_of_day_restorer)
00213 {
00214 if(preferences::show_tip_of_day() == false) {
00215 return;
00216 }
00217
00218
00219 tip_of_day_restorer.restore();
00220
00221
00222 const config* tip = get_tip_of_day(tips_of_day);
00223 if(tip != NULL) {
00224 int tip_width = game_config::title_tip_width * screen.w() / 1024;
00225
00226 try {
00227 const std::string& text =
00228 font::word_wrap_text((*tip)["text"], font::SIZE_NORMAL, tip_width);
00229 const std::string& source =
00230 font::word_wrap_text((*tip)["source"], font::SIZE_NORMAL, tip_width);
00231
00232 const int pad = game_config::title_tip_padding;
00233
00234 SDL_Rect area = font::text_area(text,font::SIZE_NORMAL);
00235 area.w = tip_width;
00236 SDL_Rect source_area = font::text_area(source, font::SIZE_NORMAL, TTF_STYLE_ITALIC);
00237 area.w = maximum<size_t>(area.w, source_area.w) + 2*pad;
00238 area.h += source_area.h + next_tip_button->location().h + 3*pad;
00239
00240 area.x = main_dialog_area->x - (game_config::title_tip_x * screen.w() / 1024) - area.w;
00241 area.y = main_dialog_area->y + main_dialog_area->h - area.h;
00242
00243
00244
00245
00246
00247
00248
00249 int button_x = area.x + area.w - next_tip_button->location().w - pad;
00250 int button_y = area.y + area.h - pad - next_tip_button->location().h;
00251 next_tip_button->set_location(button_x, button_y);
00252 next_tip_button->set_dirty();
00253
00254 button_x -= previous_tip_button->location().w + pad;
00255 previous_tip_button->set_location(button_x, button_y);
00256 previous_tip_button->set_dirty();
00257
00258 button_x = area.x + pad;
00259 help_tip_button->set_location(button_x, button_y);
00260 help_tip_button->set_dirty();
00261
00262 gui::dialog_frame f(screen.video(), "", style, false);
00263 tip_of_day_restorer = surface_restorer(&screen.video(), f.layout(area).exterior);
00264 f.draw_background();
00265 f.draw_border();
00266
00267 font::draw_text(&screen.video(), area, font::SIZE_NORMAL, font::NORMAL_COLOUR,
00268 text, area.x + pad, area.y + pad);
00269
00270 font::draw_text(&screen.video(), area, font::SIZE_NORMAL, font::NORMAL_COLOUR,
00271 source, area.x + area.w - source_area.w - pad,
00272 next_tip_button->location().y - source_area.h - pad,
00273 false, TTF_STYLE_ITALIC);
00274 } catch (utils::invalid_utf8_exception&) {
00275 LOG_STREAM(err, engine) << "Invalid utf-8 found, tips of day aren't drawn.\n";
00276 return;
00277 }
00278
00279 LOG_DP << "drew tip of day\n";
00280 }
00281 }
00282
00283
00284
00285
00286
00287 static void draw_background(game_display& screen)
00288 {
00289 bool fade_failed = false;
00290 do {
00291 int logo_x = game_config::title_logo_x * screen.w() / 1024,
00292 logo_y = game_config::title_logo_y * screen.h() / 768;
00293
00294
00295 std::vector<std::string> game_title_list =
00296 utils::split(game_config::game_title, ',', utils::STRIP_SPACES | utils::REMOVE_EMPTY);
00297
00298 if(game_title_list.empty()) {
00299 ERR_CONFIG << "No title image defined\n";
00300 } else {
00301 surface const title_surface(scale_surface(
00302 image::get_image(game_title_list[rand()%game_title_list.size()]),
00303 screen.w(), screen.h()));
00304
00305
00306 if (title_surface.null()) {
00307 ERR_DP << "Could not find title image\n";
00308 } else {
00309 screen.video().blit_surface(0, 0, title_surface);
00310 update_rect(screen_area());
00311 LOG_DP << "displayed title image\n";
00312 }
00313 }
00314
00315 fade_failed = !fade_logo(screen, logo_x, logo_y);
00316 } while (fade_failed);
00317 LOG_DP << "faded logo\n";
00318
00319
00320 const std::string& version_str = _("Version") +
00321 std::string(" ") + game_config::revision;
00322
00323 const SDL_Rect version_area = font::draw_text(NULL, screen_area(),
00324 font::SIZE_TINY, font::NORMAL_COLOUR,
00325 version_str,0,0);
00326 const size_t versiony = screen.h() - version_area.h;
00327
00328 if(versiony < size_t(screen.h())) {
00329 draw_solid_tinted_rectangle(0, versiony - 2, version_area.w + 3, version_area.h + 2,0,0,0,0.75,screen.video().getSurface());
00330 font::draw_text(&screen.video(),screen.screen_area(),
00331 font::SIZE_TINY, font::NORMAL_COLOUR,
00332 version_str,0,versiony);
00333 }
00334
00335 LOG_DP << "drew version number\n";
00336 }
00337
00338
00339 namespace gui {
00340
00341 TITLE_RESULT show_title(game_display& screen, config& tips_of_day, bool redraw_background)
00342 {
00343 cursor::set(cursor::NORMAL);
00344
00345 const preferences::display_manager disp_manager(&screen);
00346 const hotkey::basic_handler key_handler(&screen);
00347
00348 const font::floating_label_context label_manager;
00349
00350 screen.video().modeChanged();
00351
00352 if (redraw_background)
00353 draw_background(screen);
00354
00355
00356
00357 static const char* button_labels[] = {
00358 N_("TitleScreen button^Tutorial"),
00359 N_("TitleScreen button^Campaign"),
00360 N_("TitleScreen button^Multiplayer"),
00361 N_("TitleScreen button^Load"),
00362 N_("TitleScreen button^Add-ons"),
00363 #ifdef MAP_EDITOR
00364 N_("TitleScreen button^Editor"),
00365 #endif
00366 N_("TitleScreen button^Language"),
00367 N_("TitleScreen button^Preferences"),
00368 N_("TitleScreen button^Credits"),
00369 N_("TitleScreen button^Quit"),
00370
00371
00372 N_("TitleScreen button^Previous"),
00373 N_("TitleScreen button^Next"),
00374 N_("TitleScreen button^Help"),
00375
00376 N_("TitleScreen button^Help Wesnoth") };
00377
00378 static const char* help_button_labels[] = { N_("Start a tutorial to familiarize yourself with the game"),
00379 N_("Start a new single player campaign"),
00380 N_("Play multiplayer (hotseat, LAN, or Internet), or a single scenario against the AI"),
00381 N_("Load a saved game"),
00382 N_("Download usermade campaigns, eras, or map packs"),
00383 #ifdef MAP_EDITOR
00384 N_("Start the map editor"),
00385 #endif
00386 N_("Change the language"),
00387 N_("Configure the game's settings"),
00388 N_("View the credits"),
00389 N_("Quit the game"),
00390 N_("Show next tip of the day"),
00391 N_("Show Battle for Wesnoth help"),
00392 N_("Upload statistics") };
00393
00394 static const size_t nbuttons = sizeof(button_labels)/sizeof(*button_labels);
00395 const int menu_xbase = (game_config::title_buttons_x*screen.w())/1024;
00396 const int menu_xincr = 0;
00397
00398 #ifdef USE_TINY_GUI
00399 const int menu_ybase = (game_config::title_buttons_y*screen.h())/768 - 15;
00400 const int menu_yincr = 15;
00401 #else
00402 const int menu_ybase = (game_config::title_buttons_y*screen.h())/768;
00403 const int menu_yincr = 35;
00404 #endif
00405
00406 const int padding = game_config::title_buttons_padding;
00407
00408 std::vector<button> buttons;
00409 size_t b, max_width = 0;
00410 size_t n_menubuttons = 0;
00411 for(b = 0; b != nbuttons; ++b) {
00412 buttons.push_back(button(screen.video(),sgettext(button_labels[b])));
00413 buttons.back().set_help_string(sgettext(help_button_labels[b]));
00414 max_width = maximum<size_t>(max_width,buttons.back().width());
00415
00416 n_menubuttons = b;
00417 if(b == QUIT_GAME) break;
00418 }
00419
00420 SDL_Rect main_dialog_area = {menu_xbase-padding, menu_ybase-padding, max_width+padding*2,
00421 menu_yincr*(n_menubuttons)+buttons.back().height()+padding*2};
00422
00423 gui::dialog_frame main_frame(screen.video(), "", gui::dialog_frame::titlescreen_style, false);
00424 main_frame.layout(main_dialog_area);
00425
00426
00427
00428 if (redraw_background) {
00429 main_frame.draw_background();
00430 main_frame.draw_border();
00431 }
00432
00433 for(b = 0; b != nbuttons; ++b) {
00434 buttons[b].set_width(max_width);
00435 buttons[b].set_location(menu_xbase + b*menu_xincr, menu_ybase + b*menu_yincr);
00436 if(b == QUIT_GAME) break;
00437 }
00438
00439 b = TIP_PREVIOUS;
00440 gui::button previous_tip_button(screen.video(),sgettext(button_labels[b]),button::TYPE_PRESS,"lite_small");
00441 previous_tip_button.set_help_string( sgettext(button_labels[b] ));
00442
00443 b = TIP_NEXT;
00444 gui::button next_tip_button(screen.video(),sgettext(button_labels[b]),button::TYPE_PRESS,"lite_small");
00445 next_tip_button.set_help_string( sgettext(button_labels[b] ));
00446
00447 b = SHOW_HELP;
00448 gui::button help_tip_button(screen.video(),sgettext(button_labels[b]),button::TYPE_PRESS,"lite_small");
00449 help_tip_button.set_help_string( sgettext(button_labels[b] ));
00450
00451
00452 gui::button beg_button(screen.video(),("Help Wesnoth"),button::TYPE_IMAGE,"menu-button",button::MINIMUM_SPACE);
00453 beg_button.set_help_string(_("Help Wesnoth by sending us information"));
00454
00455 next_tip_of_day(tips_of_day);
00456
00457 surface_restorer tip_of_day_restorer;
00458
00459 draw_tip_of_day(screen, tips_of_day, gui::dialog_frame::titlescreen_style,
00460 &previous_tip_button, &next_tip_button, &help_tip_button, &main_dialog_area, tip_of_day_restorer);
00461
00462 const int pad = game_config::title_tip_padding;
00463 beg_button.set_location(screen.w() - pad - beg_button.location().w,
00464 screen.h() - pad - beg_button.location().h);
00465 events::raise_draw_event();
00466
00467 LOG_DP << "drew buttons dialog\n";
00468
00469 CKey key;
00470
00471 bool last_escape = key[SDLK_ESCAPE] != 0;
00472
00473 update_whole_screen();
00474
00475 LOG_DP << "entering interactive loop...\n";
00476
00477 for(;;) {
00478 for(size_t b = 0; b != buttons.size(); ++b) {
00479 if(buttons[b].pressed()) {
00480 return TITLE_RESULT(b);
00481 }
00482 }
00483
00484 if(previous_tip_button.pressed()) {
00485 next_tip_of_day(tips_of_day, true);
00486 draw_tip_of_day(screen, tips_of_day, gui::dialog_frame::titlescreen_style,
00487 &previous_tip_button, &next_tip_button, &help_tip_button, &main_dialog_area, tip_of_day_restorer);
00488 }
00489 if(next_tip_button.pressed()) {
00490 next_tip_of_day(tips_of_day, false);
00491 draw_tip_of_day(screen, tips_of_day, gui::dialog_frame::titlescreen_style,
00492 &previous_tip_button, &next_tip_button, &help_tip_button, &main_dialog_area, tip_of_day_restorer);
00493 }
00494
00495 if(help_tip_button.pressed()) {
00496 return SHOW_HELP;
00497 }
00498 if(beg_button.pressed()) {
00499 return BEG_FOR_UPLOAD;
00500 }
00501
00502 events::raise_process_event();
00503 events::raise_draw_event();
00504
00505 screen.flip();
00506
00507 if(!last_escape && key[SDLK_ESCAPE])
00508 return QUIT_GAME;
00509
00510 last_escape = key[SDLK_ESCAPE] != 0;
00511
00512 events::pump();
00513
00514
00515
00516 if(screen.video().modeChanged()) {
00517 return REDRAW_BACKGROUND;
00518 }
00519
00520 screen.delay(20);
00521 }
00522
00523 return QUIT_GAME;
00524 }
00525
00526 }
00527
00528