Skip to content

Commit

Permalink
add drawable unit class
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
cbeck88 committed Jun 17, 2014
1 parent ab23b03 commit 0be1d73
Show file tree
Hide file tree
Showing 15 changed files with 372 additions and 275 deletions.
2 changes: 2 additions & 0 deletions projectfiles/CodeBlocks-SCons/wesnoth.cbp
Expand Up @@ -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" />
Expand Down
2 changes: 2 additions & 0 deletions projectfiles/CodeBlocks/wesnoth.cbp
Expand Up @@ -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" />
Expand Down
8 changes: 8 additions & 0 deletions projectfiles/VC9/wesnoth.vcproj
Expand Up @@ -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"
>
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/SConscript
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/display.cpp
Expand Up @@ -18,6 +18,7 @@
*/

#include "cursor.hpp"
#include "drawable_unit.hpp"
#include "display.hpp"
#include "fake_unit_manager.hpp"
#include "game_preferences.hpp"
Expand Down Expand Up @@ -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();
}

}
Expand Down
2 changes: 2 additions & 0 deletions src/display.hpp
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/display_context.cpp
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/display_context.hpp
Expand Up @@ -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

Expand Down
294 changes: 294 additions & 0 deletions src/drawable_unit.cpp
@@ -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;
}

0 comments on commit 0be1d73

Please sign in to comment.