00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "global.hpp"
00019
00020 #include "display.hpp"
00021 #include "events.hpp"
00022 #include "game_config.hpp"
00023 #include "gettext.hpp"
00024 #include "image.hpp"
00025 #include "intro.hpp"
00026 #include "font.hpp"
00027 #include "key.hpp"
00028 #include "log.hpp"
00029 #include "marked-up_text.hpp"
00030 #include "sdl_utils.hpp"
00031 #include "sound.hpp"
00032 #include "util.hpp"
00033 #include "video.hpp"
00034 #include "widgets/button.hpp"
00035 #include "game_events.hpp"
00036 #include "language.hpp"
00037
00038 #include <cstdlib>
00039 #include <sstream>
00040 #include <vector>
00041
00042 #define LOG_NG LOG_STREAM(info, engine)
00043
00044 static bool show_intro_part(display &disp, const config& part,
00045 const std::string& scenario);
00046
00047
00048 void show_intro(display &disp, const config& data, const config& level)
00049 {
00050 LOG_NG << "showing intro sequence...\n";
00051
00052
00053 const resize_lock stop_resizing;
00054 const events::event_context context;
00055
00056 bool showing = true;
00057
00058 const std::string& scenario = level["name"];
00059
00060 for(config::all_children_iterator i = data.ordered_begin();
00061 i != data.ordered_end() && showing; i++) {
00062 std::pair<const std::string*, const config*> item = *i;
00063
00064 if(*item.first == "part") {
00065 showing = show_intro_part(disp, (*item.second), scenario);
00066 } else if(*item.first == "if") {
00067 const std::string type = game_events::conditional_passed(
00068 NULL, item.second) ? "then":"else";
00069 const config* const thens = (*item.second).child(type);
00070 if(thens == NULL) {
00071 LOG_NG << "no intro story this way...\n";
00072 return;
00073 }
00074 const config& selection = *thens;
00075 show_intro(disp, selection, level);
00076 }
00077 }
00078
00079 LOG_NG << "intro sequence finished...\n";
00080 }
00081
00082
00083
00084
00085
00086 static bool show_intro_part_helper(display &disp, const config& part,
00087 int textx, int texty,
00088 gui::button& next_button, gui::button& skip_button,
00089 CKey& key);
00090
00091 bool show_intro_part(display &disp, const config& part,
00092 const std::string& scenario)
00093 {
00094 LOG_NG << "showing intro part\n";
00095
00096 CVideo &video = disp.video();
00097 const std::string& music_file = part["music"];
00098
00099
00100 if(music_file != "") {
00101 sound::play_music_repeatedly(music_file);
00102 }
00103
00104 CKey key;
00105
00106 gui::button next_button(video,_("Next") + std::string(">>>"));
00107 gui::button skip_button(video,_("Skip"));
00108
00109 draw_solid_tinted_rectangle(0,0,video.getx(),video.gety(),
00110 0,0,0,1.0,video.getSurface());
00111
00112
00113 const std::string& background_name = part["background"];
00114 const bool show_title = utils::string_bool(part["show_title"]);
00115
00116 surface background(NULL);
00117 if(background_name.empty() == false) {
00118 background.assign(image::get_image(background_name));
00119 }
00120
00121 int textx = 200;
00122 int texty = 400;
00123
00124 SDL_Rect dstrect;
00125
00126 if(background.null() || background->w*background->h == 0) {
00127 background.assign(SDL_CreateRGBSurface(SDL_SWSURFACE,video.getx(),video.gety(),32,0xFF0000,0xFF00,0xFF,0xFF000000));
00128 }
00129
00130 double xscale = 1.0 * video.getx() / background->w;
00131 double yscale = 1.0 * video.gety() / background->h;
00132 double scale = minimum<double>(xscale,yscale);
00133
00134 background = scale_surface(background, static_cast<int>(background->w*scale), static_cast<int>(background->h*scale));
00135
00136 dstrect.x = (video.getx() - background->w) / 2;
00137 dstrect.y = (video.gety() - background->h) / 2;
00138 dstrect.w = background->w;
00139 dstrect.h = background->h;
00140
00141 SDL_BlitSurface(background,NULL,video.getSurface(),&dstrect);
00142
00143 #ifdef USE_TINY_GUI
00144 textx = 10;
00145 int xbuttons = video.getx() - 50;
00146
00147
00148 texty = 0;
00149 #else
00150 int xbuttons;
00151
00152 if (background->w > 500) {
00153 textx = dstrect.x + 150;
00154 xbuttons = dstrect.x+dstrect.w-140;
00155 } else {
00156 textx = 200;
00157 xbuttons = video.getx() - 200 - 40;
00158 }
00159
00160 texty = dstrect.y + dstrect.h - 200;
00161 #endif
00162
00163
00164 if(show_title == false) {
00165 draw_solid_tinted_rectangle(0,texty,video.getx(),video.gety()-texty,0,0,0,0.5,video.getSurface());
00166 }
00167
00168 #ifdef USE_TINY_GUI
00169 next_button.set_location(xbuttons,dstrect.y+dstrect.h-40);
00170 skip_button.set_location(xbuttons,dstrect.y+dstrect.h-20);
00171 #else
00172 next_button.set_location(xbuttons,dstrect.y+dstrect.h-70);
00173 skip_button.set_location(xbuttons,dstrect.y+dstrect.h-40);
00174 #endif
00175
00176
00177 if(show_title) {
00178 const SDL_Rect area = {0,0,video.getx(),video.gety()};
00179 const SDL_Rect txt_shadow_rect = font::line_size(scenario, font::SIZE_XLARGE);
00180 draw_solid_tinted_rectangle(dstrect.x + 15,dstrect.y + 15,txt_shadow_rect.w + 10,txt_shadow_rect.h + 10,0,0,0,0.5,video.getSurface());
00181
00182 font::draw_text(NULL,area,font::SIZE_XLARGE,font::BIGMAP_COLOUR,scenario,0,0);
00183 update_rect(font::draw_text(&video,area,font::SIZE_XLARGE,font::BIGMAP_COLOUR,scenario,
00184 dstrect.x + 20,dstrect.y + 20));
00185 }
00186
00187 events::raise_draw_event();
00188 update_whole_screen();
00189 disp.flip();
00190
00191 if(!background.null()) {
00192
00193 const config::child_list& images = part.get_children("image");
00194
00195 bool pass = false;
00196
00197 for(std::vector<config*>::const_iterator i = images.begin(); i != images.end(); ++i){
00198 const std::string& image_name = (**i)["file"];
00199 if(image_name == "") continue;
00200 surface img(image::get_image(image_name));
00201 if(img.null()) continue;
00202
00203 const std::string& xloc = (**i)["x"];
00204 const std::string& yloc = (**i)["y"];
00205 const std::string& delay_str = (**i)["delay"];
00206 const int delay = (delay_str == "") ? 0: atoi(delay_str.c_str());
00207 const int x = static_cast<int>(atoi(xloc.c_str())*scale);
00208 const int y = static_cast<int>(atoi(yloc.c_str())*scale);
00209
00210 if (utils::string_bool((**i)["scaled"])){
00211 img = scale_surface(img, static_cast<int>(img->w*scale), static_cast<int>(img->h*scale));
00212 }
00213
00214 SDL_Rect image_rect;
00215 image_rect.x = x + dstrect.x;
00216 image_rect.y = y + dstrect.y;
00217 image_rect.w = img->w;
00218 image_rect.h = img->h;
00219
00220 if (utils::string_bool((**i)["centered"])){
00221 image_rect.x -= image_rect.w/2;
00222 image_rect.y -= image_rect.h/2;
00223 }
00224
00225 SDL_BlitSurface(img,NULL,video.getSurface(),&image_rect);
00226
00227 update_rect(image_rect);
00228
00229 if(pass == false) {
00230 for(int i = 0; i != 50; ++i) {
00231 if(key[SDLK_ESCAPE] || next_button.pressed() || skip_button.pressed()) {
00232 return false;
00233 }
00234
00235 disp.delay(delay/50);
00236
00237 events::pump();
00238 events::raise_process_event();
00239 events::raise_draw_event();
00240
00241 int a, b;
00242 const int mouse_flags = SDL_GetMouseState(&a,&b);
00243 if(key[SDLK_RETURN] || key[SDLK_KP_ENTER] || key[SDLK_SPACE] || mouse_flags) {
00244 pass = true;
00245 continue;
00246 }
00247
00248 disp.flip();
00249 }
00250 }
00251
00252 if(key[SDLK_ESCAPE] || next_button.pressed() || skip_button.pressed()) {
00253 pass = true;
00254 continue;
00255 }
00256 }
00257 }
00258 try {
00259 return show_intro_part_helper(
00260 disp, part, textx, texty, next_button, skip_button, key);
00261
00262 } catch (utils::invalid_utf8_exception&) {
00263 LOG_STREAM(err, engine) << "Invalid utf-8 found, story message is ignored.\n";
00264
00265 return false;
00266 }
00267 }
00268
00269 static bool show_intro_part_helper(display &disp, const config& part,
00270 int textx, int texty,
00271 gui::button& next_button, gui::button& skip_button,
00272 CKey& key)
00273 {
00274 bool lang_rtl = current_language_rtl();
00275 CVideo &video = disp.video();
00276
00277
00278 const int max_width = next_button.location().x - 10 - textx;
00279 const std::string story =
00280 font::word_wrap_text(part["story"], font::SIZE_PLUS, max_width);
00281
00282 utils::utf8_iterator itor(story);
00283
00284 bool skip = false, last_key = true;
00285
00286 const SDL_Rect total_size = font::draw_text(NULL, screen_area(), font::SIZE_PLUS,
00287 font::NORMAL_COLOUR, story, 0, 0);
00288 if (texty + 20 + total_size.h > screen_area().h) {
00289 texty = screen_area().h > total_size.h + 1 ? screen_area().h - total_size.h - 21 : 0;
00290
00291 draw_solid_tinted_rectangle(textx, texty, total_size.w, total_size.h,
00292 0, 0, 0, 128, video.getSurface());
00293 update_rect(textx, texty, total_size.w, total_size.h);
00294 }
00295
00296 if(lang_rtl)
00297 textx += max_width;
00298
00299 #ifdef USE_TINY_GUI
00300 int xpos = textx, ypos = texty + 10;
00301 #else
00302 int xpos = textx, ypos = texty + 20;
00303 #endif
00304
00305
00306 size_t height = 0;
00307
00308 for(;;) {
00309 if(itor != utils::utf8_iterator::end(story)) {
00310 if(*itor == '\n') {
00311 xpos = textx;
00312 ypos += height;
00313 ++itor;
00314 }
00315
00316
00317
00318 std::string tmp;
00319 tmp.append(itor.substr().first, itor.substr().second);
00320 if(lang_rtl)
00321 xpos -= font::line_width(tmp, font::SIZE_PLUS);
00322 const SDL_Rect rect = font::draw_text(&video,
00323 screen_area(),font::SIZE_PLUS,
00324 font::NORMAL_COLOUR,tmp,xpos,ypos,
00325 false);
00326
00327 if(rect.h > height)
00328 height = rect.h;
00329 if(!lang_rtl)
00330 xpos += rect.w;
00331 update_rect(rect);
00332
00333 ++itor;
00334 if(itor == utils::utf8_iterator::end(story))
00335 skip = true;
00336
00337 }
00338
00339 const bool keydown = key[SDLK_SPACE] || key[SDLK_RETURN] || key[SDLK_KP_ENTER];
00340
00341 if((keydown && !last_key) || next_button.pressed()) {
00342 if(skip == true || itor == utils::utf8_iterator::end(story)) {
00343 break;
00344 } else {
00345 skip = true;
00346 }
00347 }
00348
00349 last_key = keydown;
00350
00351 if(key[SDLK_ESCAPE] || skip_button.pressed())
00352 return false;
00353
00354 events::pump();
00355 events::raise_process_event();
00356 events::raise_draw_event();
00357 disp.flip();
00358
00359 if(!skip || itor == utils::utf8_iterator::end(story))
00360 disp.delay(20);
00361 }
00362
00363 draw_solid_tinted_rectangle(0,0,video.getx(),video.gety(),0,0,0,1.0,
00364 video.getSurface());
00365
00366 return true;
00367 }
00368
00369
00370 void the_end(display &disp)
00371 {
00372 SDL_Rect area = screen_area();
00373 CVideo &video = disp.video();
00374 SDL_FillRect(video.getSurface(),&area,0);
00375
00376 update_whole_screen();
00377 disp.flip();
00378
00379 const std::string text = _("The End");
00380 const size_t font_size = font::SIZE_XLARGE;
00381
00382 area = font::text_area(text,font_size);
00383 area.x = screen_area().w/2 - area.w/2;
00384 area.y = screen_area().h/2 - area.h/2;
00385
00386 for(size_t n = 0; n < 255; n += 5) {
00387 const SDL_Color col = {n,n,n,n};
00388 font::draw_text(&video,area,font_size,col,text,area.x,area.y);
00389 update_rect(area);
00390 disp.flip();
00391
00392 SDL_FillRect(video.getSurface(),&area,0);
00393
00394 disp.delay(10);
00395 }
00396
00397 disp.delay(4000);
00398 }
00399