Exemple #1
0
static std::string format_stats(const unit& u)
{
	const std::string name = "<span size='large'>" + (!u.name().empty() ? u.name() : " ") + "</span>";
	std::string traits;

	BOOST_FOREACH(const std::string& trait, u.get_traits_list()) {
		traits += (traits.empty() ? "" : ", ") + trait;
	}

	if (traits.empty()) {
		traits = " ";
	}

	std::stringstream str;

	str << name << "\n";

	str << "<small>";

	str << "<span color='#f5e6c1'>" << u.type_name() << "</span>" << "\n";

	str << "Lvl " << u.level() << "\n";

	str << u.alignment() << "\n";

	str << traits << "\n";

	str << font::span_color(u.hp_color()) 
		<< _("HP: ") << u.hitpoints() << "/" << u.max_hitpoints() << "</span>" << "\n";
	str << font::span_color(u.xp_color()) 
		<< _("XP: ") << u.experience() << "/" << u.max_experience() << "</span>" << "\n";

	str << "</small>" << "\n";

	return str.str();
}
Exemple #2
0
void unit_drawer::redraw_unit (const unit & u) const
{
	unit_animation_component & ac = u.anim_comp();
	map_location loc = u.get_location();

	int side = u.side();

	bool hidden = u.get_hidden();
	bool is_flying = u.is_flying();
	map_location::DIRECTION facing = u.facing();
	int hitpoints = u.hitpoints();
	int max_hitpoints = u.max_hitpoints();
	int movement_left = u.movement_left();
	int total_movement = u.total_movement();

	bool can_recruit = u.can_recruit();
	bool can_advance = u.can_advance();

	int experience = u.experience();
	int max_experience = u.max_experience();

	bool emit_zoc = u.emits_zoc();

	SDL_Color hp_color=u.hp_color();
	SDL_Color xp_color=u.xp_color();

	std::string ellipse=u.image_ellipse();

	if ( hidden || is_blindfolded || !u.is_visible_to_team(viewing_team_ref,map, show_everything) )
	{
		ac.clear_haloes();
		if(ac.anim_) {
			ac.anim_->update_last_draw_time();
		}
		return;
	}

	if (!ac.anim_) {
		ac.set_standing();
		if (!ac.anim_) return;
	}

	if (ac.refreshing_) return;
	ac.refreshing_ = true;

	ac.anim_->update_last_draw_time();
	frame_parameters params;
	const t_translation::t_terrain terrain = map.get_terrain(loc);
	const terrain_type& terrain_info = map.get_terrain_info(terrain);

	// do not set to 0 so we can distinguish the flying from the "not on submerge terrain"
	// instead use -1.0 (as in "negative depth", it will be ignored by rendering)
	params.submerge= is_flying ? -1.0 : terrain_info.unit_submerge();

	if (u.invisible(loc) &&
			params.highlight_ratio > 0.5) {
		params.highlight_ratio = 0.5;
	}
	if (loc == sel_hex && params.highlight_ratio == 1.0) {
		params.highlight_ratio = 1.5;
	}

	int height_adjust = static_cast<int>(terrain_info.unit_height_adjust() * zoom_factor);
	if (is_flying && height_adjust < 0) {
		height_adjust = 0;
	}
	params.y -= height_adjust;
	params.halo_y -= height_adjust;

	int red = 0,green = 0,blue = 0,tints = 0;
	double blend_ratio = 0;
	// Add future colored states here
	if(u.poisoned()) {
		green += 255;
		blend_ratio += 0.25;
		tints += 1;
	}
	if(u.slowed()) {
		red += 191;
		green += 191;
		blue += 255;
		blend_ratio += 0.25;
		tints += 1;
	}
	if(tints > 0) {
		params.blend_with = disp.rgb((red/tints),(green/tints),(blue/tints));
		params.blend_ratio = ((blend_ratio/tints));
	}

	//hackish : see unit_frame::merge_parameters
	// we use image_mod on the primary image
	// and halo_mod on secondary images and all haloes
	params.image_mod = u.image_mods();
	params.halo_mod = u.TC_image_mods();
	params.image= u.default_anim_image();


	if(u.incapacitated()) params.image_mod +="~GS()";
	params.primary_frame = t_true;


	const frame_parameters adjusted_params = ac.anim_->get_current_params(params);

	const map_location dst = loc.get_direction(facing);
	const int xsrc = disp.get_location_x(loc);
	const int ysrc = disp.get_location_y(loc);
	const int xdst = disp.get_location_x(dst);
	const int ydst = disp.get_location_y(dst);

	const int x = static_cast<int>(adjusted_params.offset * xdst + (1.0-adjusted_params.offset) * xsrc) + hex_size_by_2;
	const int y = static_cast<int>(adjusted_params.offset * ydst + (1.0-adjusted_params.offset) * ysrc) + hex_size_by_2;

	bool has_halo = ac.unit_halo_ && ac.unit_halo_->valid();
	if(!has_halo && !u.image_halo().empty()) {
		ac.unit_halo_ = halo_man.add(0, 0, u.image_halo()+u.TC_image_mods(), map_location(-1, -1));
	}
	if(has_halo && u.image_halo().empty()) {
		halo_man.remove(ac.unit_halo_);
		ac.unit_halo_ = halo::handle(); //halo::NO_HALO;
	} else if(has_halo) {
		halo_man.set_location(ac.unit_halo_, x, y - height_adjust);
	}



	// We draw bars only if wanted, visible on the map view
	bool draw_bars = ac.draw_bars_ ;
	if (draw_bars) {
		SDL_Rect unit_rect = sdl::create_rect(xsrc, ysrc +adjusted_params.y, hex_size, hex_size);
		draw_bars = sdl::rects_overlap(unit_rect, disp.map_outside_area());
	}
#ifdef SDL_GPU
	sdl::timage ellipse_front;
	sdl::timage ellipse_back;
#else
	surface ellipse_front(nullptr);
	surface ellipse_back(nullptr);
#endif
	int ellipse_floating = 0;
	// Always show the ellipse for selected units
	if(draw_bars && (preferences::show_side_colors() || sel_hex == loc)) {
		if(adjusted_params.submerge > 0.0) {
			// The division by 2 seems to have no real meaning,
			// It just works fine with the current center of ellipse
			// and prevent a too large adjust if submerge = 1.0
			ellipse_floating = static_cast<int>(adjusted_params.submerge * hex_size_by_2);
		}

		if(ellipse.empty()){
			ellipse="misc/ellipse";
		}

		if(ellipse != "none") {
			// check if the unit has a ZoC or can recruit
			const char* const nozoc = emit_zoc ? "" : "nozoc-";
			const char* const leader = can_recruit ? "leader-" : "";
			const char* const selected = sel_hex == loc ? "selected-" : "";

			// Load the ellipse parts recolored to match team color
			char buf[100];
			std::string tc=team::get_side_color_index(side);
#ifdef SDL_GPU
			snprintf(buf,sizeof(buf),"%s-%s%s%stop.png~RC(ellipse_red>%s)",ellipse.c_str(),leader,nozoc,selected,tc.c_str());
			ellipse_back = image::get_texture(image::locator(buf), image::SCALED_TO_ZOOM);
			snprintf(buf,sizeof(buf),"%s-%s%s%sbottom.png~RC(ellipse_red>%s)",ellipse.c_str(),leader,nozoc,selected,tc.c_str());
			ellipse_front = image::get_texture(image::locator(buf), image::SCALED_TO_ZOOM);
#else
			snprintf(buf,sizeof(buf),"%s-%s%s%stop.png~RC(ellipse_red>%s)",ellipse.c_str(),leader,nozoc,selected,tc.c_str());
			ellipse_back.assign(image::get_image(image::locator(buf), image::SCALED_TO_ZOOM));
			snprintf(buf,sizeof(buf),"%s-%s%s%sbottom.png~RC(ellipse_red>%s)",ellipse.c_str(),leader,nozoc,selected,tc.c_str());
			ellipse_front.assign(image::get_image(image::locator(buf), image::SCALED_TO_ZOOM));
#endif
		}
	}
#ifdef SDL_GPU
	if (!ellipse_back.null()) {
		//disp.drawing_buffer_add(display::LAYER_UNIT_BG, loc,
		disp.drawing_buffer_add(display::LAYER_UNIT_FIRST, loc,
			xsrc, ysrc +adjusted_params.y-ellipse_floating, ellipse_back);
	}

	if (!ellipse_front.null()) {
		//disp.drawing_buffer_add(display::LAYER_UNIT_FG, loc,
		disp.drawing_buffer_add(display::LAYER_UNIT_FIRST, loc,
			xsrc, ysrc +adjusted_params.y-ellipse_floating, ellipse_front);
	}
#else
	if (ellipse_back != nullptr) {
		//disp.drawing_buffer_add(display::LAYER_UNIT_BG, loc,
		disp.drawing_buffer_add(display::LAYER_UNIT_FIRST, loc,
			xsrc, ysrc +adjusted_params.y-ellipse_floating, ellipse_back);
	}

	if (ellipse_front != nullptr) {
		//disp.drawing_buffer_add(display::LAYER_UNIT_FG, loc,
		disp.drawing_buffer_add(display::LAYER_UNIT_FIRST, loc,
			xsrc, ysrc +adjusted_params.y-ellipse_floating, ellipse_front);
	}
#endif
	if(draw_bars) {
		const image::locator* orb_img = nullptr;
		const surface unit_img = image::get_image(u.default_anim_image(), image::SCALED_TO_ZOOM);
		const int xoff = (hex_size - unit_img->w)/2;
		const int yoff = (hex_size - unit_img->h)/2;
		/*static*/ const image::locator partmoved_orb(game_config::images::orb + "~RC(magenta>" +
						preferences::partial_color() + ")"  );
		/*static*/ const image::locator moved_orb(game_config::images::orb + "~RC(magenta>" +
						preferences::moved_color() + ")"  );
		/*static*/ const image::locator ally_orb(game_config::images::orb + "~RC(magenta>" +
						preferences::allied_color() + ")"  );
		/*static*/ const image::locator enemy_orb(game_config::images::orb + "~RC(magenta>" +
						preferences::enemy_color() + ")"  );
		/*static*/ const image::locator unmoved_orb(game_config::images::orb + "~RC(magenta>" +
						preferences::unmoved_color() + ")"  );

		const std::string* energy_file = &game_config::images::energy;

		if(size_t(side) != viewing_team+1) {
			if(disp.team_valid() &&
			   viewing_team_ref.is_enemy(side)) {
				if (preferences::show_enemy_orb() && !u.incapacitated())
					orb_img = &enemy_orb;
				else
					orb_img = nullptr;
			} else {
				if (preferences::show_allied_orb())
					orb_img = &ally_orb;
				else orb_img = nullptr;
			}
		} else {
			if (preferences::show_moved_orb())
				orb_img = &moved_orb;
			else orb_img = nullptr;

			if(playing_team == viewing_team && !u.user_end_turn()) {
				if (movement_left == total_movement) {
					if (preferences::show_unmoved_orb())
						orb_img = &unmoved_orb;
					else orb_img = nullptr;
				} else if ( dc.unit_can_move(u) ) {
					if (preferences::show_partial_orb())
						orb_img = &partmoved_orb;
					else orb_img = nullptr;
				}
			}
		}

		if (orb_img != nullptr) {
			surface orb(image::get_image(*orb_img,image::SCALED_TO_ZOOM));
			disp.drawing_buffer_add(display::LAYER_UNIT_BAR,
				loc, xsrc + xoff, ysrc + yoff + adjusted_params.y, orb);
		}

		double unit_energy = 0.0;
		if(max_hitpoints > 0) {
			unit_energy = double(hitpoints)/double(max_hitpoints);
		}
		const int bar_shift = static_cast<int>(-5*zoom_factor);
		const int hp_bar_height = static_cast<int>(max_hitpoints * u.hp_bar_scaling());

		const fixed_t bar_alpha = (loc == mouse_hex || loc == sel_hex) ? ftofxp(1.0): ftofxp(0.8);

		draw_bar(*energy_file, xsrc+xoff+bar_shift, ysrc+yoff+adjusted_params.y,
			loc, hp_bar_height, unit_energy,hp_color, bar_alpha);

		if(experience > 0 && can_advance) {
			const double filled = double(experience)/double(max_experience);

			const int xp_bar_height = static_cast<int>(max_experience * u.xp_bar_scaling() / std::max<int>(u.level(),1));

			draw_bar(*energy_file, xsrc+xoff, ysrc+yoff+adjusted_params.y,
				loc, xp_bar_height, filled, xp_color, bar_alpha);
		}

		if (can_recruit) {
			surface crown(image::get_image(u.leader_crown(),image::SCALED_TO_ZOOM));
			if(!crown.null()) {
				//if(bar_alpha != ftofxp(1.0)) {
				//	crown = adjust_surface_alpha(crown, bar_alpha);
				//}
				disp.drawing_buffer_add(display::LAYER_UNIT_BAR,
					loc, xsrc+xoff, ysrc+yoff+adjusted_params.y, crown);
			}
		}

		for(std::vector<std::string>::const_iterator ov = u.overlays().begin(); ov != u.overlays().end(); ++ov) {
#ifdef SDL_GPU
			const sdl::timage ov_img(image::get_texture(*ov, image::SCALED_TO_ZOOM));
			if(!ov_img.null()) {
				disp.drawing_buffer_add(display::LAYER_UNIT_BAR,
					loc, xsrc, ysrc +adjusted_params.y, ov_img);
			}
#else
			const surface ov_img(image::get_image(*ov, image::SCALED_TO_ZOOM));
			if(ov_img != nullptr) {
				disp.drawing_buffer_add(display::LAYER_UNIT_BAR,
					loc, xsrc+xoff, ysrc+yoff+adjusted_params.y, ov_img);
			}
#endif
		}
	}

	// Smooth unit movements from terrain of different elevation.
	// Do this separately from above so that the health bar doesn't go up and down.

	const t_translation::t_terrain terrain_dst = map.get_terrain(dst);
	const terrain_type& terrain_dst_info = map.get_terrain_info(terrain_dst);

	int height_adjust_unit = static_cast<int>((terrain_info.unit_height_adjust() * (1.0 - adjusted_params.offset) +
											  terrain_dst_info.unit_height_adjust() * adjusted_params.offset) *
											  zoom_factor);
	if (is_flying && height_adjust_unit < 0) {
		height_adjust_unit = 0;
	}
	params.y -= height_adjust_unit - height_adjust;
	params.halo_y -= height_adjust_unit - height_adjust;

	ac.anim_->redraw(params, halo_man);
	ac.refreshing_ = false;
}
void tunit_preview_pane::set_displayed_unit(const unit& u)
{
	// Sets the current type id for the profile button callback to use
	current_type_ = u.type_id();

	if(icon_type_) {
		std::string mods = u.image_mods();

		if(u.can_recruit()) {
			mods += "~BLIT(" + unit::leader_crown() + ")";
		}

		for(const std::string& overlay : u.overlays()) {
			mods += "~BLIT(" + overlay + ")";
		}

		mods += "~SCALE_INTO_SHARP(144,144)" + image_mods_;

		icon_type_->set_label(u.absolute_image() + mods);
	}

	if(label_name_) {
		std::string name;
		if(!u.name().empty()) {
			name = "<span size='large'>" + u.name() + "</span>" + "\n" + "<small><span color='#a69275'>" + u.type_name() + "</span></small>";
		} else {
			name = "<span size='large'>" + u.type_name() + "</span>\n";
		}

		label_name_->set_label(name);
		label_name_->set_use_markup(true);
	}

	if(label_level_) {
		std::string l_str = vgettext("Lvl $lvl", {{"lvl", std::to_string(u.level())}});

		label_level_->set_label("<b>" + l_str + "</b>");
		label_level_->set_use_markup(true);
	}

	if(icon_race_) {
		icon_race_->set_label("icons/unit-groups/race_" + u.race()->id() + "_30.png");
		icon_race_->set_tooltip(u.race()->name(u.gender()));
	}

	if(icon_alignment_) {
		const std::string& alignment_name = u.alignment().to_string();

		icon_alignment_->set_label("icons/alignments/alignment_" + alignment_name + "_30.png");
		icon_alignment_->set_tooltip(unit_type::alignment_description(
			u.alignment(),
			u.gender()));
	}

	if(label_details_minimal_) {
		std::stringstream str;

		const std::string name = "<span size='large'>" + (!u.name().empty() ? u.name() : " ") + "</span>";
		str << name << "\n";

		str << "<span color='#a69275'>" << u.type_name() << "</span>" << "\n";

		str << "Lvl " << u.level() << "\n";

		str << u.alignment() << "\n";

		str << utils::join(u.trait_names(), ", ") << "\n";

		str << font::span_color(u.hp_color())
			<< _("HP: ") << u.hitpoints() << "/" << u.max_hitpoints() << "</span>" << "\n";

		str << font::span_color(u.xp_color())
			<< _("XP: ") << u.experience() << "/" << u.max_experience() << "</span>";

		label_details_minimal_->set_label(str.str());
		label_details_minimal_->set_use_markup(true);
	}

	if(tree_details_) {
		std::stringstream str;
		str << "<small>";

		str << font::span_color(u.hp_color())
			<< "<b>" << _("HP: ") << "</b>" << u.hitpoints() << "/" << u.max_hitpoints() << "</span>" << " | ";

		str << font::span_color(u.xp_color())
			<< "<b>" << _("XP: ") << "</b>" << u.experience() << "/" << u.max_experience() << "</span>" << " | ";

		str << "<b>" << _("MP: ") << "</b>"
			<< u.movement_left() << "/" << u.total_movement();

		str << "</small>";

		tree_details_->clear();

		add_name_tree_node(
			tree_details_->get_root_node(),
			"item",
			str.str()
		);

		if (!u.trait_names().empty()) {
			auto& header_node = add_name_tree_node(
				tree_details_->get_root_node(),
				"header",
				"<b>" + _("Traits") + "</b>"
			);

			assert(u.trait_names().size() == u.trait_descriptions().size());
			for (size_t i = 0; i < u.trait_names().size(); ++i) {
				add_name_tree_node(
					header_node,
					"item",
					u.trait_names()[i],
					u.trait_descriptions()[i]
				);
			}
		}
		if (!u.get_ability_list().empty()) {
			auto& header_node = add_name_tree_node(
				tree_details_->get_root_node(),
				"header",
				"<b>" + _("Abilities") + "</b>"
			);

			for (const auto& ab : u.ability_tooltips()) {
				add_name_tree_node(
					header_node,
					"item",
					std::get<1>(ab),
					std::get<2>(ab)
				);
			}
		}
		print_attack_details(u.attacks(), tree_details_->get_root_node());
	}
}