From 0be1d731d5ced297817aacdd023f47ec51f8cd5d Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Mon, 16 Jun 2014 22:10:31 -0400 Subject: [PATCH] add drawable unit class drawable unit inherits from unit, and implements the draw function, used only by the display. when the display wants to use the function, it casts a unit pointer to a drawable_unit, and draws it. this improves encapsulation. --- projectfiles/CodeBlocks-SCons/wesnoth.cbp | 2 + projectfiles/CodeBlocks/wesnoth.cbp | 2 + projectfiles/VC9/wesnoth.vcproj | 8 + src/CMakeLists.txt | 1 + src/SConscript | 1 + src/display.cpp | 3 +- src/display.hpp | 2 + src/display_context.cpp | 2 +- src/display_context.hpp | 2 +- src/drawable_unit.cpp | 294 ++++++++++++++++++++++ src/drawable_unit.hpp | 41 +++ src/game_display.cpp | 5 +- src/unit.cpp | 267 -------------------- src/unit.hpp | 16 +- src/unit_animation.hpp | 1 + 15 files changed, 372 insertions(+), 275 deletions(-) create mode 100644 src/drawable_unit.cpp create mode 100644 src/drawable_unit.hpp diff --git a/projectfiles/CodeBlocks-SCons/wesnoth.cbp b/projectfiles/CodeBlocks-SCons/wesnoth.cbp index e13a17367ad4..e3eb1844b5b0 100644 --- a/projectfiles/CodeBlocks-SCons/wesnoth.cbp +++ b/projectfiles/CodeBlocks-SCons/wesnoth.cbp @@ -193,6 +193,8 @@ + + diff --git a/projectfiles/CodeBlocks/wesnoth.cbp b/projectfiles/CodeBlocks/wesnoth.cbp index 568ddc4f674b..5d94e32a01e7 100644 --- a/projectfiles/CodeBlocks/wesnoth.cbp +++ b/projectfiles/CodeBlocks/wesnoth.cbp @@ -231,6 +231,8 @@ + + diff --git a/projectfiles/VC9/wesnoth.vcproj b/projectfiles/VC9/wesnoth.vcproj index 83de26d6acee..e773a6d56fdb 100644 --- a/projectfiles/VC9/wesnoth.vcproj +++ b/projectfiles/VC9/wesnoth.vcproj @@ -20060,6 +20060,14 @@ RelativePath="..\..\src\display_context.hpp" > + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 127f88b3609d..7e8819a89265 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/SConscript b/src/SConscript index a0b8110fd66f..8d5c728f917c 100644 --- a/src/SConscript +++ b/src/SConscript @@ -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 diff --git a/src/display.cpp b/src/display.cpp index 4bbaf7cfd56d..f0dca0a650f0 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -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 (&*u_it))->redraw_unit(); } } diff --git a/src/display.hpp b/src/display.hpp index fca374f5d79c..e4ac9227a5e5 100644 --- a/src/display.hpp +++ b/src/display.hpp @@ -165,6 +165,8 @@ class display 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) diff --git a/src/display_context.cpp b/src/display_context.cpp index 7385e1d6fdd8..221cd80f7b0b 100644 --- a/src/display_context.cpp +++ b/src/display_context.cpp @@ -35,7 +35,7 @@ const unit * display_context::get_visible_unit(const map_location & loc, const t * it can do (including attacking etc). */ -bool display_context::unit_can_move(const unit &u) +bool display_context::unit_can_move(const unit &u) const { if(!u.attacks_left() && u.movement_left()==0) return false; diff --git a/src/display_context.hpp b/src/display_context.hpp index 218f101b7c7b..f2a3d56b6612 100644 --- a/src/display_context.hpp +++ b/src/display_context.hpp @@ -43,7 +43,7 @@ class display_context { // From actions:: namespace - bool unit_can_move(const unit & u); + bool unit_can_move(const unit & u) const; // Dtor diff --git a/src/drawable_unit.cpp b/src/drawable_unit.cpp new file mode 100644 index 000000000000..e2033da882c8 --- /dev/null +++ b/src/drawable_unit.cpp @@ -0,0 +1,294 @@ +/* + Copyright (C) 2014 by Chris Beck + 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 + +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(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(adjusted_params.offset * xdst + (1.0-adjusted_params.offset) * xsrc) + d2; + const int y = static_cast(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(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(-5*disp.get_zoom_factor()); + const int hp_bar_height = static_cast(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(max_experience() * xp_bar_scaling_ / std::max(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::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((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; +} + diff --git a/src/drawable_unit.hpp b/src/drawable_unit.hpp new file mode 100644 index 000000000000..397549084e37 --- /dev/null +++ b/src/drawable_unit.hpp @@ -0,0 +1,41 @@ +/* + Copyright (C) 2014 by Chris Beck + 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 diff --git a/src/game_display.cpp b/src/game_display.cpp index dfc27f46c4ea..3597cf141269 100644 --- a/src/game_display.cpp +++ b/src/game_display.cpp @@ -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 (temp_unit))->redraw_unit(); } } diff --git a/src/unit.cpp b/src/unit.cpp index ea156ed97e8d..0e506b413b0d 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -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(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(adjusted_params.offset * xdst + (1.0-adjusted_params.offset) * xsrc) + d2; - const int y = static_cast(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(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 ( resources::gameboard->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(-5*disp.get_zoom_factor()); - const int hp_bar_height = static_cast(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(max_experience() * xp_bar_scaling_ / std::max(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::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((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) { diff --git a/src/unit.hpp b/src/unit.hpp index 7af60646ab36..365bf389018f 100644 --- a/src/unit.hpp +++ b/src/unit.hpp @@ -248,8 +248,6 @@ class unit /** 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 @@ class unit void set_underlying_id(); config cfg_; +protected: map_location loc_; +private: std::vector advances_to_; const unit_type * type_;/// Never NULL. Adjusted for gender and variation. @@ -436,7 +436,9 @@ class unit int max_hit_points_; int experience_; int max_experience_; +protected: int level_; +private: int recall_cost_; bool canrecruit_; std::vector recruit_list_; @@ -445,7 +447,9 @@ class unit std::string image_mods_; bool unrenamable_; +protected: int side_; +private: const unit_race::GENDER gender_; fixed_t alpha_; @@ -469,16 +473,20 @@ class unit config variables_; config events_; config filter_recall_; + +protected: bool emit_zoc_; mutable STATE state_; //animation state - +private: std::vector overlays_; std::string role_; std::vector 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 trait_names_; std::vector trait_descriptions_; @@ -489,6 +497,7 @@ class unit utils::string_map modification_descriptions_; // Animations: +protected: std::vector animations_; mutable boost::scoped_ptr anim_; @@ -503,6 +512,7 @@ class unit mutable bool draw_bars_; // flag used for drawing / animation double hp_bar_scaling_, xp_bar_scaling_; +private: config modifications_; /** diff --git a/src/unit_animation.hpp b/src/unit_animation.hpp index 124835159514..239a1ad248d5 100644 --- a/src/unit_animation.hpp +++ b/src/unit_animation.hpp @@ -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 = "");