void textbox::draw_contents() { SDL_Rect const &loc = inner_location(); surface surf = video().getSurface(); draw_solid_tinted_rectangle(loc.x,loc.y,loc.w,loc.h,0,0,0, focus(NULL) ? alpha_focus_ : alpha_, surf); SDL_Rect src; if(text_image_ == NULL) { update_text_cache(true); } if(text_image_ != NULL) { src.y = yscroll_; src.w = std::min<size_t>(loc.w,text_image_->w); src.h = std::min<size_t>(loc.h,text_image_->h); src.x = text_pos_; SDL_Rect dest = screen_area(); dest.x = loc.x; dest.y = loc.y; // Fills the selected area if(is_selection()) { const int start = std::min<int>(selstart_,selend_); const int end = std::max<int>(selstart_,selend_); int startx = char_x_[start]; int starty = char_y_[start]; const int endx = char_x_[end]; const int endy = char_y_[end]; while(starty <= endy) { const size_t right = starty == endy ? endx : text_image_->w; if(right <= size_t(startx)) { break; } SDL_Rect rect = create_rect(loc.x + startx , loc.y + starty - src.y , right - startx , line_height_); const clip_rect_setter clipper(surf, &loc); Uint32 color = SDL_MapRGB(surf->format, 0, 0, 160); fill_rect_alpha(rect, color, 140, surf); starty += int(line_height_); startx = 0; } } sdl_blit(text_image_, &src, surf, &dest); } draw_cursor((cursor_pos_ == 0 ? 0 : cursor_pos_ - 1), video()); update_rect(loc); }
void part_ui::render_background() { draw_solid_tinted_rectangle( 0, 0, video_.getx(), video_.gety(), 0, 0, 0, 1.0, video_.getSurface() ); sdl_blit(background_, NULL, video_.getSurface(), &base_rect_); }
void menu::draw_row(const size_t row_index, const SDL_Rect& rect, ROW_TYPE type) { //called from style, draws one row's contents in a generic and adaptable way const std::vector<std::string>& row = (type == HEADING_ROW) ? heading_ : items_[row_index].fields; SDL_Rect const &area = screen_area(); SDL_Rect const &loc = inner_location(); const std::vector<int>& widths = column_widths(); bool lang_rtl = current_language_rtl(); int dir = (lang_rtl) ? -1 : 1; SDL_Rect column = loc; int xpos = rect.x; if(lang_rtl) xpos += rect.w; for(size_t i = 0; i != row.size(); ++i) { if(lang_rtl) xpos -= widths[i]; if(type == HEADING_ROW && highlight_heading_ == int(i)) { draw_solid_tinted_rectangle(xpos,rect.y,widths[i],rect.h,255,255,255,0.3,video().getSurface()); } const int last_x = xpos; column.w = widths[i]; std::string str = row[i]; std::vector<std::string> img_text_items = utils::split(str, IMG_TEXT_SEPARATOR, utils::REMOVE_EMPTY); for (std::vector<std::string>::const_iterator it = img_text_items.begin(); it != img_text_items.end(); it++) { str = *it; if (!str.empty() && str[0] == IMAGE_PREFIX) { const std::string image_name(str.begin()+1,str.end()); const surface img = style_->get_item_image(image_name); const int remaining_width = max_width_ < 0 ? area.w : std::min<int>(max_width_, ((lang_rtl)? xpos - rect.x : rect.x + rect.w - xpos)); if(img != NULL && img->w <= remaining_width && rect.y + img->h < area.h) { const size_t y = rect.y + (rect.h - img->h)/2; const size_t w = img->w + 5; const size_t x = xpos + ((lang_rtl) ? widths[i] - w : 0); video().blit_surface(x,y,img); if(!lang_rtl) xpos += w; column.w -= w; } } else { column.x = xpos; const bool has_wrap = (str.find_first_of("\r\n") != std::string::npos); //prevent ellipsis calculation if there is any line wrapping const std::string to_show = (use_ellipsis_ && !has_wrap) ? font::make_text_ellipsis(str, style_->get_font_size(), loc.w - (xpos - rect.x) - 2*style_->get_thickness(), false, true) : str; const SDL_Rect& text_size = font::text_area(str,style_->get_font_size()); const size_t y = rect.y + (rect.h - text_size.h)/2; font::draw_text(&video(),column,style_->get_font_size(),font::NORMAL_COLOUR,to_show,xpos,y); if(type == HEADING_ROW && sortby_ == int(i)) { const surface sort_img = image::get_image(sortreversed_ ? "misc/sort-arrow.png" : "misc/sort-arrow-reverse.png"); if(sort_img != NULL && sort_img->w <= widths[i] && sort_img->h <= rect.h) { const size_t sort_x = xpos + widths[i] - sort_img->w; const size_t sort_y = rect.y + rect.h/2 - sort_img->h/2; video().blit_surface(sort_x,sort_y,sort_img); } } xpos += dir * (text_size.w + 5); } } if(lang_rtl) xpos = last_x; else xpos = last_x + widths[i]; } }
LEVEL_RESULT playsingle_controller::play_scenario( const config::const_child_itors &story, bool skip_replay) { LOG_NG << "in playsingle_controller::play_scenario()...\n"; // Start music. foreach (const config &m, level_.child_range("music")) { sound::play_music_config(m); } sound::commit_music_changes(); if(!skip_replay) { show_story(*gui_, level_["name"], story); } gui_->labels().read(level_); // Read sound sources assert(soundsources_manager_ != NULL); foreach (const config &s, level_.child_range("sound_source")) { soundsource::sourcespec spec(s); soundsources_manager_->add(spec); } set_victory_when_enemies_defeated(level_["victory_when_enemies_defeated"].to_bool(true)); end_level_data &end_level = get_end_level_data(); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carryover_add"].to_bool(); bool past_prestart = false; LOG_NG << "entering try... " << (SDL_GetTicks() - ticks_) << "\n"; try { fire_prestart(!loading_game_); init_gui(); past_prestart = true; LOG_NG << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n"; events::raise_draw_event(); fire_start(!loading_game_); gui_->recalculate_minimap(); replaying_ = (recorder.at_end() == false); LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n"; // Initialize countdown clock. std::vector<team>::iterator t; for(t = teams_.begin(); t != teams_.end(); ++t) { if (gamestate_.mp_settings().mp_countdown && !loading_game_ ){ t->set_countdown_time(1000 * gamestate_.mp_settings().mp_countdown_init_time); } } // if we loaded a save file in linger mode, skip to it. if (linger_) { //determine the bonus gold handling for this scenario end_level.read(level_.child_or_empty("endlevel")); end_level.carryover_report = false; end_level.disabled = true; throw end_level_exception(SKIP_TO_LINGER); } // Avoid autosaving after loading, but still // allow the first turn to have an autosave. bool save = !loading_game_; ai_testing::log_game_start(); for(; ; first_player_ = 1) { play_turn(save); save = true; } //end for loop #ifdef _MSC_VER //MSVC claims that const game::load_game_exception& lge would be unreferenced... #pragma warning (push) #pragma warning (disable : 4101) #endif } catch(const game::load_game_exception& lge) { // Loading a new game is effectively a quit. // if (lge.game != "") { gamestate_ = game_state(); } throw; } catch (end_level_exception &end_level_exn) { if(!past_prestart) { draw_solid_tinted_rectangle( 0, 0, gui_->video().getx(), gui_->video().gety(), 0, 0, 0, 1.0, gui_->video().getSurface() ); update_rect(0, 0, gui_->video().getx(), gui_->video().gety()); } ai_testing::log_game_end(); LEVEL_RESULT end_level_result = end_level_exn.result; if (!end_level.custom_endlevel_music.empty()) { if (end_level_result == DEFEAT) { set_defeat_music_list(end_level.custom_endlevel_music); } else { set_victory_music_list(end_level.custom_endlevel_music); } } if (teams_.empty()) { //store persistent teams gamestate_.snapshot = config(); store_recalls(); return VICTORY; // this is probably only a story scenario, i.e. has its endlevel in the prestart event } const bool obs = is_observer(); if (game_config::exit_at_end) { exit(0); } if (end_level_result == DEFEAT || end_level_result == VICTORY) { gamestate_.classification().completion = (end_level_exn.result == VICTORY) ? "victory" : "defeat"; // If we're a player, and the result is victory/defeat, then send // a message to notify the server of the reason for the game ending. if (!obs) { config cfg; config& info = cfg.add_child("info"); info["type"] = "termination"; info["condition"] = "game over"; info["result"] = gamestate_.classification().completion; network::send_data(cfg, 0); } else { gui2::show_transient_message(gui_->video(),_("Game Over"), _("The game is over.")); return OBSERVER_END; } } if (end_level_result == QUIT) { return QUIT; } else if (end_level_result == DEFEAT) { gamestate_.classification().completion = "defeat"; game_events::fire("defeat"); if (!obs) { const std::string& defeat_music = select_defeat_music(); if(defeat_music.empty() != true) sound::play_music_once(defeat_music); return DEFEAT; } else { return QUIT; } } else if (end_level_result == VICTORY) { gamestate_.classification().completion = !end_level.linger_mode ? "running" : "victory"; game_events::fire("victory"); // // Play victory music once all victory events // are finished, if we aren't observers. // // Some scenario authors may use 'continue' // result for something that is not story-wise // a victory, so let them use [music] tags // instead should they want special music. // if (!obs && end_level.linger_mode) { const std::string& victory_music = select_victory_music(); if(victory_music.empty() != true) sound::play_music_once(victory_music); } // Add all the units that survived the scenario. LOG_NG << "Add units that survived the scenario to the recall list.\n"; for(unit_map::iterator un = units_.begin(); un != units_.end(); ++un) { if (teams_[un->side() - 1].persistent()) { LOG_NG << "Added unit " << un->id() << ", " << un->name() << "\n"; un->new_turn(); un->new_scenario(); teams_[un->side() - 1].recall_list().push_back(*un); } } //store all units that survived (recall list for the next scenario) in snapshot gamestate_.snapshot = config(); store_recalls(); //store gold and report victory store_gold(obs); return VICTORY; } else if (end_level_result == SKIP_TO_LINGER) { LOG_NG << "resuming from loaded linger state...\n"; //as carryover information is stored in the snapshot, we have to re-store it after loading a linger state gamestate_.snapshot = config(); store_recalls(); store_gold(); return VICTORY; } } // end catch catch(network::error& e) { bool disconnect = false; if(e.socket) { e.disconnect(); disconnect = true; } savegame::game_savegame save(gamestate_, *gui_, to_config(), preferences::compress_saves()); save.save_game_interactive(gui_->video(), _("A network disconnection has occurred, and the game cannot continue. Do you want to save the game?"), gui::YES_NO); if(disconnect) { throw network::error(); } else { return QUIT; } } return QUIT; }
void part_ui::render_story_box() { LOG_NG << "ENTER part_ui()::render_story_box()\n"; const std::string& storytxt = p_.text(); if(storytxt.empty()) { wait_for_input(); return; } const part::BLOCK_LOCATION tbl = p_.story_text_location(); const int max_width = buttons_x_ - storybox_padding - text_x_; const int max_height = screen_area().h - storybox_padding; skip_ = false; last_key_ = true; font::ttext t; if(!t.set_text(p_.text(), true)) { ERR_NG << "Text: Invalid markup in '" << p_.text() << "' rendered as is.\n"; t.set_text(p_.text(), false); } t.set_font_style(font::ttext::STYLE_NORMAL) .set_font_size(storybox_font_size) .set_foreground_color(storybox_font_color) .set_maximum_width(max_width) .set_maximum_height(max_height); surface txtsurf = t.render(); if(txtsurf.null()) { ERR_NG << "storyscreen text area rendering resulted in a null surface\n"; return; } int fix_text_y = text_y_; if(fix_text_y + storybox_padding + txtsurf->h > screen_area().h && tbl != part::BLOCK_TOP) { fix_text_y = (screen_area().h > txtsurf->h + 1) ? (std::max(0, screen_area().h - txtsurf->h - (storybox_padding+1))) : (0); } int fix_text_h; switch(tbl) { case part::BLOCK_TOP: fix_text_h = std::max(txtsurf->h + 2*storybox_padding, screen_area().h/4); break; case part::BLOCK_MIDDLE: fix_text_h = std::max(txtsurf->h + 2*storybox_padding, screen_area().h/3); break; default: fix_text_h = screen_area().h - fix_text_y; break; } SDL_Rect update_area = create_rect(0 , fix_text_y , screen_area().w , fix_text_h); /* do */ { // this should kill the tiniest flickering caused // by the buttons being hidden and unhidden in this scope. update_locker locker(video_); next_button_.hide(); back_button_.hide(); play_button_.hide(); #ifndef LOW_MEM blur_area(video_, fix_text_y, fix_text_h); #endif draw_solid_tinted_rectangle( 0, fix_text_y, screen_area().w, fix_text_h, storyshadow_r, storyshadow_g, storyshadow_b, storyshadow_opacity, video_.getSurface() ); render_story_box_borders(update_area); // no-op if LOW_MEM is defined next_button_.hide(false); back_button_.hide(false); play_button_.hide(false); } if(imgs_.empty()) { update_whole_screen(); } else if(update_area.h > 0) { update_rect(update_area); } // Time to do some f*****g visual effect. const int scan_height = 1, scan_width = txtsurf->w; SDL_Rect scan = create_rect(0, 0, scan_width, scan_height); SDL_Rect dstrect = create_rect(text_x_, 0, scan_width, scan_height); surface scan_dst = video_.getSurface(); bool scan_finished = false; while(true) { scan_finished = scan.y >= txtsurf->h; if (!scan_finished) { //dstrect.x = text_x_; dstrect.y = fix_text_y + scan.y + storybox_padding; // NOTE: ::blit_surface() screws up with antialiasing and hinting when // on backgroundless (e.g. black) screens; ttext::draw() // uses it nonetheless, no idea why... // Here we'll use CVideo::blit_surface() instead. video_.blit_surface(dstrect.x, dstrect.y, txtsurf, &scan); update_rect(dstrect); ++scan.y; } else skip_ = true; if (handle_interface()) break; if (!skip_ || scan_finished) { disp_.delay(20); } } draw_solid_tinted_rectangle( 0, 0, video_.getx(), video_.gety(), 0, 0, 0, 1.0, video_.getSurface() ); }
void part_ui::render_title_box() { const std::string& titletxt = p_.title(); if(titletxt.empty()) { return; } int titlebox_x, titlebox_y, titlebox_max_w, titlebox_max_h; // We later correct these according to the storytext box location. // The text box is always aligned according to the base_rect_ // (effective background area) at the end. titlebox_x = titlebox_padding; titlebox_max_w = base_rect_.w - 2*titlebox_padding; titlebox_y = titlebox_padding; titlebox_max_h = base_rect_.h - 2*titlebox_padding; font::ttext t; if(!t.set_text(titletxt, true)) { ERR_NG << "Text: Invalid markup in '" << titletxt << "' rendered as is.\n"; t.set_text(titletxt, false); } t.set_font_style(font::ttext::STYLE_NORMAL) .set_font_size(titlebox_font_size) .set_foreground_color(titlebox_font_color) .set_maximum_width(titlebox_max_w) .set_maximum_height(titlebox_max_h); surface txtsurf = t.render(); if(txtsurf.null()) { ERR_NG << "storyscreen titlebox rendering resulted in a null surface\n"; return; } const int titlebox_w = txtsurf->w; const int titlebox_h = txtsurf->h; switch(p_.title_text_alignment()) { case part::TEXT_CENTERED: titlebox_x = base_rect_.w / 2 - titlebox_w / 2 - titlebox_padding; break; case part::TEXT_RIGHT: titlebox_x = base_rect_.w - titlebox_padding - titlebox_w; break; default: break; // already set before } draw_solid_tinted_rectangle( base_rect_.x + titlebox_x - titleshadow_padding, base_rect_.y + titlebox_y - titleshadow_padding, titlebox_w + 2*titleshadow_padding, titlebox_h + 2*titleshadow_padding, titleshadow_r, titleshadow_g, titleshadow_b, titleshadow_opacity, video_.getSurface() ); video_.blit_surface(base_rect_.x + titlebox_x, base_rect_.y + titlebox_y, txtsurf); update_rect( static_cast<size_t>(std::max(0, base_rect_.x + titlebox_x)), static_cast<size_t>(std::max(0, base_rect_.y + titlebox_y)), static_cast<size_t>(std::max(0, titlebox_w)), static_cast<size_t>(std::max(0, titlebox_h)) ); }
void textbox::draw_contents() { SDL_Rect const &loc = inner_location(); surface surf = video().getSurface(); draw_solid_tinted_rectangle(loc.x,loc.y,loc.w,loc.h,0,0,0, focus(NULL) ? alpha_focus_ : alpha_, surf); SDL_Rect src; if(text_image_ == NULL) { update_text_cache(true); } if(text_image_ != NULL) { src.y = yscroll_; src.w = std::min<size_t>(loc.w,text_image_->w); src.h = std::min<size_t>(loc.h,text_image_->h); src.x = text_pos_; SDL_Rect dest = screen_area(); dest.x = loc.x; dest.y = loc.y; // Fills the selected area if(enabled() && is_selection()) { const int start = std::min<int>(selstart_,selend_); const int end = std::max<int>(selstart_,selend_); int startx = char_x_[start]; int starty = char_y_[start]; const int endx = char_x_[end]; const int endy = char_y_[end]; while(starty <= endy) { const size_t right = starty == endy ? endx : text_image_->w; if(right <= size_t(startx)) { break; } SDL_Rect rect = create_rect(loc.x + startx , loc.y + starty - src.y , right - startx , line_height_); const clip_rect_setter clipper(surf, &loc); Uint32 color = SDL_MapRGB(surf->format, 0, 0, 160); fill_rect_alpha(rect, color, 140, surf); starty += int(line_height_); startx = 0; } } if(enabled()) { sdl_blit(text_image_, &src, surf, &dest); } else { // HACK: using 30% opacity allows white text to look as though it is grayed out, // while not changing any applicable non-grayscale AA. Actual colored text will // not look as good, but this is not currently a concern since GUI1 textboxes // are not used much nowadays, and they will eventually all go away. sdl_blit(adjust_surface_alpha(text_image_, ftofxp(0.3)), &src, surf, &dest); } } draw_cursor((cursor_pos_ == 0 ? 0 : cursor_pos_ - 1), video()); update_rect(loc); }