Merge branch 'drawable_units'

This commit is contained in:
Chris Beck 2014-06-16 22:11:33 -04:00
commit f0fc9ff5c7
19 changed files with 419 additions and 315 deletions

View file

@ -193,6 +193,8 @@
<Unit filename="../../src/display.hpp" />
<Unit filename="../../src/display_context.cpp" />
<Unit filename="../../src/display_context.hpp" />
<Unit filename="../../src/drawable_unit.cpp" />
<Unit filename="../../src/drawable_unit.hpp" />
<Unit filename="../../src/editor/action/action_base.hpp" />
<Unit filename="../../src/editor/action/action.cpp" />
<Unit filename="../../src/editor/action/action.hpp" />

View file

@ -231,6 +231,8 @@
<Unit filename="..\..\src\display.hpp" />
<Unit filename="..\..\src\display_context.cpp" />
<Unit filename="..\..\src\display_context.hpp" />
<Unit filename="..\..\src\drawable_unit.cpp" />
<Unit filename="..\..\src\drawable_unit.hpp" />
<Unit filename="..\..\src\editor\action\action.cpp" />
<Unit filename="..\..\src\editor\action\action.hpp" />
<Unit filename="..\..\src\editor\action\action_base.hpp" />

View file

@ -20060,6 +20060,14 @@
RelativePath="..\..\src\display_context.hpp"
>
</File>
<File
RelativePath="..\..\src\drawable_unit.cpp"
>
</File>
<File
RelativePath="..\..\src\drawable_unit.hpp"
>
</File>
<File
RelativePath="..\..\src\events.cpp"
>

View file

@ -700,6 +700,7 @@ set(wesnoth-main_SRC
controller_base.cpp
desktop_util.cpp
dialogs.cpp
drawable_unit.cpp
editor/action/action.cpp
editor/action/action_item.cpp
editor/action/action_label.cpp

View file

@ -233,6 +233,7 @@ wesnoth_sources = Split("""
controller_base.cpp
desktop_util.cpp
dialogs.cpp
drawable_unit.cpp
editor/action/action.cpp
editor/action/action_unit.cpp
editor/action/action_label.cpp

View file

@ -1288,37 +1288,5 @@ size_t move_unit_from_replay(const std::vector<map_location> &steps,
return move_unit_internal(undo_stack, show_move, NULL, mover);
}
bool unit_can_move(const unit &u)
{
const team &current_team = (*resources::teams)[u.side() - 1];
if(!u.attacks_left() && u.movement_left()==0)
return false;
// Units with goto commands that have already done their gotos this turn
// (i.e. don't have full movement left) should have red globes.
if(u.has_moved() && u.has_goto()) {
return false;
}
map_location locs[6];
get_adjacent_tiles(u.get_location(), locs);
for(int n = 0; n != 6; ++n) {
if (resources::gameboard->map().on_board(locs[n])) {
const unit_map::const_iterator i = resources::units->find(locs[n]);
if (i.valid() && !i->incapacitated() &&
current_team.is_enemy(i->side())) {
return true;
}
if (u.movement_cost((resources::gameboard->map())[locs[n]]) <= u.movement_left()) {
return true;
}
}
}
return false;
}
}//namespace actions

View file

@ -114,13 +114,6 @@ size_t move_unit_from_replay(const std::vector<map_location> &steps,
bool continued_move, bool skip_ally_sighted,
bool show_move = true);
/**
* Will return true iff the unit @a u has any possible moves
* it can do (including attacking etc).
*/
bool unit_can_move(const unit &u);
}//namespace actions

View file

@ -18,6 +18,7 @@
*/
#include "cursor.hpp"
#include "drawable_unit.hpp"
#include "display.hpp"
#include "fake_unit_manager.hpp"
#include "game_preferences.hpp"
@ -2553,7 +2554,7 @@ void display::draw_invalidated() {
exclusive_unit_draw_requests_t::iterator request = exclusive_unit_draw_requests_.find(loc);
if (u_it != dc_->units().end()
&& (request == exclusive_unit_draw_requests_.end() || request->second == u_it->id()))
u_it->redraw_unit();
(static_cast<const drawable_unit*> (&*u_it))->redraw_unit();
}
}

View file

@ -165,6 +165,8 @@ public:
void change_display_context(const display_context * dc);
const display_context & get_disp_context() { return *dc_; }
static Uint32 rgb(Uint8 red, Uint8 green, Uint8 blue)
{ return 0xFF000000 | (red << 16) | (green << 8) | blue; }
static Uint8 red(Uint32 color)

View file

@ -29,3 +29,41 @@ const unit * display_context::get_visible_unit(const map_location & loc, const t
}
return &*u;
}
/**
* Will return true iff the unit @a u has any possible moves
* it can do (including attacking etc).
*/
bool display_context::unit_can_move(const unit &u) const
{
if(!u.attacks_left() && u.movement_left()==0)
return false;
// Units with goto commands that have already done their gotos this turn
// (i.e. don't have full movement left) should have red globes.
if(u.has_moved() && u.has_goto()) {
return false;
}
const team &current_team = teams()[u.side() - 1];
map_location locs[6];
get_adjacent_tiles(u.get_location(), locs);
for(int n = 0; n != 6; ++n) {
if (map().on_board(locs[n])) {
const unit_map::const_iterator i = units().find(locs[n]);
if (i.valid() && !i->incapacitated() &&
current_team.is_enemy(i->side())) {
return true;
}
if (u.movement_cost(map()[locs[n]]) <= u.movement_left()) {
return true;
}
}
}
return false;
}

View file

@ -37,8 +37,16 @@ public:
virtual const gamemap & map() const = 0;
virtual const unit_map & units() const = 0;
// Needed for reports
const unit * get_visible_unit(const map_location &loc, const team &current_team, bool see_all = false) const;
// From actions:: namespace
bool unit_can_move(const unit & u) const;
// Dtor
virtual ~display_context() {}
};

294
src/drawable_unit.cpp Normal file
View file

@ -0,0 +1,294 @@
/*
Copyright (C) 2014 by Chris Beck <render787@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "drawable_unit.hpp"
#include "display.hpp"
#include "display_context.hpp"
#include "game_preferences.hpp"
#include "halo.hpp"
#include "map.hpp"
#include "team.hpp"
#include "unit_animation.hpp"
#include "unit_frame.hpp"
#include <boost/foreach.hpp>
void drawable_unit::redraw_unit () const
{
display &disp = *display::get_singleton();
const gamemap &map = disp.get_map();
if ( hidden_ || disp.is_blindfolded() || !is_visible_to_team(disp.get_teams()[disp.viewing_team()],map, disp.show_everything()) )
{
clear_haloes();
if(anim_) {
anim_->update_last_draw_time();
}
return;
}
if (!anim_) {
set_standing();
if (!anim_) return;
}
if (refreshing_) return;
refreshing_ = true;
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 (invisible(loc_) &&
params.highlight_ratio > 0.5) {
params.highlight_ratio = 0.5;
}
if (loc_ == disp.selected_hex() && params.highlight_ratio == 1.0) {
params.highlight_ratio = 1.5;
}
int height_adjust = static_cast<int>(terrain_info.unit_height_adjust() * disp.get_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(get_state(STATE_POISONED)) {
green += 255;
blend_ratio += 0.25;
tints += 1;
}
if(get_state(STATE_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 = image_mods();
params.halo_mod = TC_image_mods();
params.image= absolute_image();
if(get_state(STATE_PETRIFIED)) params.image_mod +="~GS()";
params.primary_frame = t_true;
const frame_parameters adjusted_params = 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);
int d2 = disp.hex_size() / 2;
const int x = static_cast<int>(adjusted_params.offset * xdst + (1.0-adjusted_params.offset) * xsrc) + d2;
const int y = static_cast<int>(adjusted_params.offset * ydst + (1.0-adjusted_params.offset) * ysrc) + d2;
if(unit_halo_ == halo::NO_HALO && !image_halo().empty()) {
unit_halo_ = halo::add(0, 0, image_halo()+TC_image_mods(), map_location(-1, -1));
}
if(unit_halo_ != halo::NO_HALO && image_halo().empty()) {
halo::remove(unit_halo_);
unit_halo_ = halo::NO_HALO;
} else if(unit_halo_ != halo::NO_HALO) {
halo::set_location(unit_halo_, x, y - height_adjust);
}
// We draw bars only if wanted, visible on the map view
bool draw_bars = draw_bars_ ;
if (draw_bars) {
const int d = disp.hex_size();
SDL_Rect unit_rect = sdl::create_rect(xsrc, ysrc +adjusted_params.y, d, d);
draw_bars = sdl::rects_overlap(unit_rect, disp.map_outside_area());
}
surface ellipse_front(NULL);
surface ellipse_back(NULL);
int ellipse_floating = 0;
// Always show the ellipse for selected units
if(draw_bars && (preferences::show_side_colors() || disp.selected_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 * disp.hex_size() / 2);
}
std::string ellipse=image_ellipse();
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 = disp.selected_hex() == loc_ ? "selected-" : "";
// Load the ellipse parts recolored to match team color
char buf[100];
std::string tc=team::get_side_color_index(side_);
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));
}
}
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);
}
if(draw_bars) {
const image::locator* orb_img = NULL;
/*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()) != disp.viewing_team()+1) {
if(disp.team_valid() &&
disp.get_teams()[disp.viewing_team()].is_enemy(side())) {
if (preferences::show_enemy_orb() && !get_state(STATE_PETRIFIED))
orb_img = &enemy_orb;
else
orb_img = NULL;
} else {
if (preferences::show_allied_orb())
orb_img = &ally_orb;
else orb_img = NULL;
}
} else {
if (preferences::show_moved_orb())
orb_img = &moved_orb;
else orb_img = NULL;
if(disp.playing_team() == disp.viewing_team() && !user_end_turn()) {
if (movement_left() == total_movement()) {
if (preferences::show_unmoved_orb())
orb_img = &unmoved_orb;
else orb_img = NULL;
} else if ( disp.get_disp_context().unit_can_move(*this) ) {
if (preferences::show_partial_orb())
orb_img = &partmoved_orb;
else orb_img = NULL;
}
}
}
if (orb_img != NULL) {
surface orb(image::get_image(*orb_img,image::SCALED_TO_ZOOM));
disp.drawing_buffer_add(display::LAYER_UNIT_BAR,
loc_, xsrc, ysrc +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*disp.get_zoom_factor());
const int hp_bar_height = static_cast<int>(max_hitpoints() * hp_bar_scaling_);
const fixed_t bar_alpha = (loc_ == disp.mouseover_hex() || loc_ == disp.selected_hex()) ? ftofxp(1.0): ftofxp(0.8);
disp.draw_bar(*energy_file, xsrc+bar_shift, ysrc +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() * xp_bar_scaling_ / std::max<int>(level_,1));
SDL_Color color=xp_color();
disp.draw_bar(*energy_file, xsrc, ysrc +adjusted_params.y,
loc_, xp_bar_height, filled, color, bar_alpha);
}
if (can_recruit()) {
surface crown(image::get_image(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, ysrc +adjusted_params.y, crown);
}
}
for(std::vector<std::string>::const_iterator ov = overlays().begin(); ov != overlays().end(); ++ov) {
const surface ov_img(image::get_image(*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);
}
}
}
// 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) *
disp.get_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;
anim_->redraw(params);
refreshing_ = false;
}

41
src/drawable_unit.hpp Normal file
View file

@ -0,0 +1,41 @@
/*
Copyright (C) 2014 by Chris Beck <render787@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
*
* This wrapper class should be held by the display object when it needs to draw a unit.
* The purpose of this is to improve encapsulation -- other parts of the engine like AI
* don't need to be exposed to the unit drawing code, and encapsulation like this will
* help us to reduce unnecessary includes.
*
**/
#ifndef DRAWABLE_UNIT_H_INCLUDED
#define DRAWABLE_UNIT_H_INCLUDED
#include "unit.hpp"
class display;
class game_display;
class drawable_unit : protected unit //TODO: Get rid of inheritance and use composition instead.
{ //IMO, it would be better for drawable unit to hold a unit reference, and be marked as a friend class.
//But I don't want to rewrite the redraw() function right now.
/** draw a unit. */
void redraw_unit() const;
friend class display;
friend class game_display;
};
#endif

View file

@ -34,6 +34,7 @@ Growl_Delegate growl_obj;
#endif
#include "cursor.hpp"
#include "drawable_unit.hpp"
#include "fake_unit.hpp"
#include "fake_unit_manager.hpp"
#include "game_board.hpp"
@ -246,12 +247,12 @@ void game_display::draw_invalidated()
halo::unrender(invalidated_);
display::draw_invalidated();
BOOST_FOREACH(unit* temp_unit, fake_unit_man_->get_fake_unit_list_for_invalidation()) {
BOOST_FOREACH(const unit* temp_unit, fake_unit_man_->get_fake_unit_list_for_invalidation()) {
const map_location& loc = temp_unit->get_location();
exclusive_unit_draw_requests_t::iterator request = exclusive_unit_draw_requests_.find(loc);
if (invalidated_.find(loc) != invalidated_.end()
&& (request == exclusive_unit_draw_requests_.end() || request->second == temp_unit->id()))
temp_unit->redraw_unit();
(static_cast<const drawable_unit*> (temp_unit))->redraw_unit();
}
}

View file

@ -810,7 +810,7 @@ namespace { // Helpers for menu_handler::end_turn()
if ( un->side() == side_num ) {
// @todo whiteboard should take into consideration units that have
// a planned move but can still plan more movement in the same turn
if ( actions::unit_can_move(*un) && !un->user_end_turn()
if ( resources::gameboard->unit_can_move(*un) && !un->user_end_turn()
&& !resources::whiteboard->unit_has_actions(&*un) )
return true;
}
@ -825,7 +825,7 @@ namespace { // Helpers for menu_handler::end_turn()
{
for ( unit_map::const_iterator un = units.begin(); un != units.end(); ++un ) {
if ( un->side() == side_num ) {
if ( actions::unit_can_move(*un) && !un->has_moved() && !un->user_end_turn()
if ( resources::gameboard->unit_can_move(*un) && !un->has_moved() && !un->user_end_turn()
&& !resources::whiteboard->unit_has_actions(&*un) )
return true;
}

View file

@ -1192,7 +1192,7 @@ bool mouse_handler::unit_in_cycle(unit_map::const_iterator it)
return false;
if (it->side() != side_num_ || it->user_end_turn()
|| gui().fogged(it->get_location()) || !actions::unit_can_move(*it))
|| gui().fogged(it->get_location()) || !board_.unit_can_move(*it))
return false;
if (current_team().is_enemy(int(gui().viewing_team()+1)) &&

View file

@ -1840,273 +1840,6 @@ void unit::set_facing(map_location::DIRECTION dir) const {
// Else look at yourself (not available so continue to face the same direction)
}
void unit::redraw_unit () const
{
display &disp = *display::get_singleton();
const gamemap &map = disp.get_map();
if ( hidden_ || disp.is_blindfolded() || !is_visible_to_team(disp.get_teams()[disp.viewing_team()],map, disp.show_everything()) )
{
clear_haloes();
if(anim_) {
anim_->update_last_draw_time();
}
return;
}
if (!anim_) {
set_standing();
if (!anim_) return;
}
if (refreshing_) return;
refreshing_ = true;
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 (invisible(loc_) &&
params.highlight_ratio > 0.5) {
params.highlight_ratio = 0.5;
}
if (loc_ == disp.selected_hex() && params.highlight_ratio == 1.0) {
params.highlight_ratio = 1.5;
}
int height_adjust = static_cast<int>(terrain_info.unit_height_adjust() * disp.get_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(get_state(STATE_POISONED)) {
green += 255;
blend_ratio += 0.25;
tints += 1;
}
if(get_state(STATE_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 = image_mods();
params.halo_mod = TC_image_mods();
params.image= absolute_image();
if(get_state(STATE_PETRIFIED)) params.image_mod +="~GS()";
params.primary_frame = t_true;
const frame_parameters adjusted_params = 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);
int d2 = disp.hex_size() / 2;
const int x = static_cast<int>(adjusted_params.offset * xdst + (1.0-adjusted_params.offset) * xsrc) + d2;
const int y = static_cast<int>(adjusted_params.offset * ydst + (1.0-adjusted_params.offset) * ysrc) + d2;
if(unit_halo_ == halo::NO_HALO && !image_halo().empty()) {
unit_halo_ = halo::add(0, 0, image_halo()+TC_image_mods(), map_location(-1, -1));
}
if(unit_halo_ != halo::NO_HALO && image_halo().empty()) {
halo::remove(unit_halo_);
unit_halo_ = halo::NO_HALO;
} else if(unit_halo_ != halo::NO_HALO) {
halo::set_location(unit_halo_, x, y - height_adjust);
}
// We draw bars only if wanted, visible on the map view
bool draw_bars = draw_bars_ ;
if (draw_bars) {
const int d = disp.hex_size();
SDL_Rect unit_rect = sdl::create_rect(xsrc, ysrc +adjusted_params.y, d, d);
draw_bars = sdl::rects_overlap(unit_rect, disp.map_outside_area());
}
surface ellipse_front(NULL);
surface ellipse_back(NULL);
int ellipse_floating = 0;
// Always show the ellipse for selected units
if(draw_bars && (preferences::show_side_colors() || disp.selected_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 * disp.hex_size() / 2);
}
std::string ellipse=image_ellipse();
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 = disp.selected_hex() == loc_ ? "selected-" : "";
// Load the ellipse parts recolored to match team color
char buf[100];
std::string tc=team::get_side_color_index(side_);
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));
}
}
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);
}
if(draw_bars) {
const image::locator* orb_img = NULL;
/*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()) != disp.viewing_team()+1) {
if(disp.team_valid() &&
disp.get_teams()[disp.viewing_team()].is_enemy(side())) {
if (preferences::show_enemy_orb() && !get_state(STATE_PETRIFIED))
orb_img = &enemy_orb;
else
orb_img = NULL;
} else {
if (preferences::show_allied_orb())
orb_img = &ally_orb;
else orb_img = NULL;
}
} else {
if (preferences::show_moved_orb())
orb_img = &moved_orb;
else orb_img = NULL;
if(disp.playing_team() == disp.viewing_team() && !user_end_turn()) {
if (movement_left() == total_movement()) {
if (preferences::show_unmoved_orb())
orb_img = &unmoved_orb;
else orb_img = NULL;
} else if ( actions::unit_can_move(*this) ) {
if (preferences::show_partial_orb())
orb_img = &partmoved_orb;
else orb_img = NULL;
}
}
}
if (orb_img != NULL) {
surface orb(image::get_image(*orb_img,image::SCALED_TO_ZOOM));
disp.drawing_buffer_add(display::LAYER_UNIT_BAR,
loc_, xsrc, ysrc +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*disp.get_zoom_factor());
const int hp_bar_height = static_cast<int>(max_hitpoints() * hp_bar_scaling_);
const fixed_t bar_alpha = (loc_ == disp.mouseover_hex() || loc_ == disp.selected_hex()) ? ftofxp(1.0): ftofxp(0.8);
disp.draw_bar(*energy_file, xsrc+bar_shift, ysrc +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() * xp_bar_scaling_ / std::max<int>(level_,1));
SDL_Color color=xp_color();
disp.draw_bar(*energy_file, xsrc, ysrc +adjusted_params.y,
loc_, xp_bar_height, filled, color, bar_alpha);
}
if (can_recruit()) {
surface crown(image::get_image(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, ysrc +adjusted_params.y, crown);
}
}
for(std::vector<std::string>::const_iterator ov = overlays().begin(); ov != overlays().end(); ++ov) {
const surface ov_img(image::get_image(*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);
}
}
}
// 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) *
disp.get_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;
anim_->redraw(params);
refreshing_ = false;
}
void unit::clear_haloes () const
{
if(unit_halo_ != halo::NO_HALO) {

View file

@ -248,8 +248,6 @@ public:
/** A SDL surface, ready for display for place where we need a still-image of the unit. */
const surface still_image(bool scaled = false) const;
/** draw a unit. */
void redraw_unit() const;
/** Clear unit_halo_ */
void clear_haloes() const;
@ -420,7 +418,9 @@ private:
void set_underlying_id();
config cfg_;
protected:
map_location loc_;
private:
std::vector<std::string> advances_to_;
const unit_type * type_;/// Never NULL. Adjusted for gender and variation.
@ -436,7 +436,9 @@ private:
int max_hit_points_;
int experience_;
int max_experience_;
protected:
int level_;
private:
int recall_cost_;
bool canrecruit_;
std::vector<std::string> recruit_list_;
@ -445,7 +447,9 @@ private:
std::string image_mods_;
bool unrenamable_;
protected:
int side_;
private:
const unit_race::GENDER gender_;
fixed_t alpha_;
@ -469,16 +473,20 @@ private:
config variables_;
config events_;
config filter_recall_;
protected:
bool emit_zoc_;
mutable STATE state_; //animation state
private:
std::vector<std::string> overlays_;
std::string role_;
std::vector<attack_type> attacks_;
protected:
mutable map_location::DIRECTION facing_; //TODO: I think we actually consider this to be part of the gamestate, so it might be better if it's not mutable
//But it's not easy to separate this guy from the animation code right now.
private:
std::vector<t_string> trait_names_;
std::vector<t_string> trait_descriptions_;
@ -489,6 +497,7 @@ private:
utils::string_map modification_descriptions_;
// Animations:
protected:
std::vector<unit_animation> animations_;
mutable boost::scoped_ptr<unit_animation> anim_;
@ -503,6 +512,7 @@ private:
mutable bool draw_bars_; // flag used for drawing / animation
double hp_bar_scaling_, xp_bar_scaling_;
private:
config modifications_;
/**

View file

@ -67,6 +67,7 @@ class unit_animation
friend std::ostream& operator << (std::ostream& outstream, const unit_animation& u_animation);
friend class unit;
friend class drawable_unit;
explicit unit_animation(const config &cfg, const std::string &frame_string = "");