Skip to content

Commit

Permalink
add fake_unit_manager, split off from game_display object
Browse files Browse the repository at this point in the history
This commit adds two classes -- fake_unit, and fake_unit_manager,
both split off from code contained in game_display. The display
object is reconfigured to hold a pointer to the manager and
display the units it contains. The rest of the code is configured
to add fake units to the manager, not the display.

This improves encapsulation and helps to reduce the game_display
class.
  • Loading branch information
cbeck88 committed Jun 16, 2014
1 parent 13155c4 commit 06f02b5
Show file tree
Hide file tree
Showing 31 changed files with 332 additions and 208 deletions.
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Expand Up @@ -728,6 +728,8 @@ set(wesnoth-main_SRC
editor/editor_preferences.cpp
editor/toolkit/editor_toolkit.cpp
editor/map/context_manager.cpp
fake_unit.cpp
fake_unit_manager.cpp
filechooser.cpp
flg_manager.cpp
floating_textbox.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/SConscript
Expand Up @@ -261,6 +261,8 @@ wesnoth_sources = Split("""
editor/editor_preferences.cpp
editor/toolkit/brush.cpp
editor/toolkit/editor_toolkit.cpp
fake_unit.cpp
fake_unit_manager.cpp
filechooser.cpp
flg_manager.cpp
floating_textbox.cpp
Expand Down
1 change: 1 addition & 0 deletions src/ai/akihara/recruitment.cpp
Expand Up @@ -28,6 +28,7 @@
#include "../../log.hpp"
#include "../../map.hpp"
#include "../../team.hpp"
#include "../../unit.hpp"
#include "../../unit_display.hpp"
#include "../../unit_map.hpp"
#include "../../unit_types.hpp"
Expand Down
12 changes: 6 additions & 6 deletions src/display.cpp
Expand Up @@ -19,6 +19,7 @@

#include "cursor.hpp"
#include "display.hpp"
#include "fake_unit_manager.hpp"
#include "game_preferences.hpp"
#include "gettext.hpp"
#include "halo.hpp"
Expand Down Expand Up @@ -150,6 +151,7 @@ display::display(const display_context * dc, CVideo& video, boost::weak_ptr<wb::
view_locked_(false),
theme_(theme_cfg, screen_area()),
zoom_(DefaultZoom),
fake_unit_man_(new fake_unit_manager(*this)),
builder_(new terrain_builder(level, &dc_->map(), theme_.border().tile_image)),
minimap_(NULL),
minimap_location_(sdl::empty_rect),
Expand Down Expand Up @@ -209,6 +211,8 @@ display::display(const display_context * dc, CVideo& video, boost::weak_ptr<wb::
{
singleton_ = this;

resources::fake_units = fake_unit_man_.get();

blindfold_ctr_ = 0;

read(level.child_or_empty("display"));
Expand Down Expand Up @@ -246,6 +250,7 @@ display::display(const display_context * dc, CVideo& video, boost::weak_ptr<wb::
display::~display()
{
singleton_ = NULL;
resources::fake_units = NULL;
}


Expand Down Expand Up @@ -3032,11 +3037,6 @@ void display::invalidate_animations_location(const map_location& loc) {
}
}


const std::deque<unit*> & display::get_fake_unit_list_for_invalidation() {
static const std::deque<unit*> blah;
return blah;
}
void display::invalidate_animations()
{
new_animation_frame();
Expand All @@ -3052,7 +3052,7 @@ void display::invalidate_animations()
}
}
}
const std::deque<unit*> & unit_list=get_fake_unit_list_for_invalidation();
const std::deque<unit*> & unit_list = fake_unit_man_->get_fake_unit_list_for_invalidation();
BOOST_FOREACH(const unit* u, unit_list) {
u->refresh();
}
Expand Down
7 changes: 2 additions & 5 deletions src/display.hpp
Expand Up @@ -34,6 +34,7 @@
#define DISPLAY_H_INCLUDED

class config;
class fake_unit_manager;
class terrain_builder;
struct time_of_day;
class map_labels;
Expand Down Expand Up @@ -419,11 +420,6 @@ class display
* Function to invalidate animated terrains and units which may have changed.
*/
void invalidate_animations();
/**
* helper function for invalidate_animations
* returns a list of units to check for invalidation
*/
virtual const std::deque<unit*> & get_fake_unit_list_for_invalidation();

/**
* Per-location invalidation called by invalidate_animations()
Expand Down Expand Up @@ -740,6 +736,7 @@ class display
theme theme_;
int zoom_;
static int last_zoom_;
boost::scoped_ptr<fake_unit_manager> fake_unit_man_;
boost::scoped_ptr<terrain_builder> builder_;
surface minimap_;
SDL_Rect minimap_location_;
Expand Down
84 changes: 84 additions & 0 deletions src/fake_unit.cpp
@@ -0,0 +1,84 @@
/*
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 "fake_unit.hpp"

#include "fake_unit_manager.hpp"

/**
* Assignment operator, taking a unit.
* If already in the queue, @a this will be moved to the end of the
* queue (drawn last).
*
* This function is unsuitable for derived classes and MUST be overridden.
* Furthermore, derived classes must not explicitly call this version.
*
* The overriding function can be almost the same, except "new (this)" should
* be followed by the derived class instead of "fake_unit(a)".
*/
fake_unit & fake_unit::operator=(unit const & a)
{
if ( this != &a ) {
fake_unit_manager * mgr = my_manager_;

// Use the copy constructor to make sure we are coherent.
// (Methodology copied from unit::operator=)
this->~fake_unit();
new (this) fake_unit(a);
// Restore our old manager.
if ( mgr != NULL )
place_on_fake_unit_manager(mgr);
}
return *this;
}

/**
* Removes @a this from the fake_units_ list if necessary.
*/
fake_unit::~fake_unit()
{
try {
// The fake_unit class exists for this one line, which removes the
// fake_unit from the managers's fake_units_ dequeue in the event of an
// exception.
if(my_manager_){remove_from_fake_unit_manager();}

} catch (...) {}
}

/**
* Place @a this on @a manager's fake_units_ dequeue.
* This will be added at the end (drawn last, over all other units).
* Duplicate additions are not allowed.
*/
void fake_unit::place_on_fake_unit_manager(fake_unit_manager * manager){
assert(my_manager_ == NULL); //Can only be placed on 1 fake_unit_manager
my_manager_=manager;
my_manager_->place_temporary_unit(this);
}

/**
* Removes @a this from whatever fake_units_ list it is on (if any).
* @returns the number of fake_units deleted, which should be 0 or 1
* (any other number indicates an error).
*/
int fake_unit::remove_from_fake_unit_manager(){
int ret(0);
if(my_manager_ != NULL){
ret = my_manager_->remove_temporary_unit(this);
my_manager_=NULL;
}
return ret;
}

57 changes: 57 additions & 0 deletions src/fake_unit.hpp
@@ -0,0 +1,57 @@
/*
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.
*/

#ifndef INCL_FAKE_UNIT_HPP_
#define INCL_FAKE_UNIT_HPP_

#include "unit.hpp"

class fake_unit_manager;

/** A temporary unit that can be placed on the map.
Temporary units can overlap units.
Adding the same unit twice isn't allowed.
The fake_unit owns its underlying unit and when
it goes out of scope it removes itself from the fake_units list.
The intent is to provide exception safety when the code
creating the temp unit is unexpectedly forced out of scope.
*/
class fake_unit : public unit {
public:
explicit fake_unit(unit const & u) : unit(u), my_manager_(NULL) {}
fake_unit(fake_unit const & u) : unit(u), my_manager_(NULL) {}
fake_unit(const unit_type& t, int side, unit_race::GENDER gender = unit_race::NUM_GENDERS)
: unit(t, side, false, gender)
, my_manager_(NULL)
{}
/// Assignment operator, taking a fake_unit.
/// If already in the queue, @a this will be moved to the end of the
/// queue (drawn last). The queue (if any) of the parameter is ignored.
fake_unit & operator=(fake_unit const & u)
{ return operator=(static_cast<unit const &>(u)); }
/// Assignment operator, taking a unit.
virtual fake_unit & operator=(unit const & u);
/// Removes @a this from the fake_units_ list if necessary.
~fake_unit();

/// Place @a this on @a manager's fake_units_ dequeue.
void place_on_fake_unit_manager(fake_unit_manager * d);
/// Removes @a this from whatever fake_units_ list it is on (if any).
int remove_from_fake_unit_manager();

private :
fake_unit_manager * my_manager_;
};

#endif
53 changes: 53 additions & 0 deletions src/fake_unit_manager.cpp
@@ -0,0 +1,53 @@
/*
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 "fake_unit_manager.hpp"

#include "display.hpp"
#include "fake_unit.hpp"
#include "log.hpp"
#include "unit.hpp"

static lg::log_domain log_engine("engine");
#define ERR_NG LOG_STREAM(err, log_engine)

void fake_unit_manager::place_temporary_unit(unit *u)
{
if(std::find(fake_units_.begin(),fake_units_.end(), u) != fake_units_.end()) {
ERR_NG << "In fake_unit_manager::place_temporary_unit: attempt to add duplicate fake unit." << std::endl;
} else {
fake_units_.push_back(u);
my_display_.invalidate(u->get_location());
}
}

int fake_unit_manager::remove_temporary_unit(unit *u)
{
int removed = 0;
std::deque<unit*>::iterator it =
std::remove(fake_units_.begin(), fake_units_.end(), u);
if (it != fake_units_.end()) {
removed = std::distance(it, fake_units_.end());
//std::remove doesn't remove anything without using erase afterwards.
fake_units_.erase(it, fake_units_.end());
my_display_.invalidate(u->get_location());
// Redraw with no location to get rid of haloes
u->clear_haloes();
}
if (removed > 1) {
ERR_NG << "Error: duplicate temp unit found in fake_unit_manager::remove_temporary_unit" << std::endl;
}
return removed;
}

51 changes: 51 additions & 0 deletions src/fake_unit_manager.hpp
@@ -0,0 +1,51 @@
/*
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.
*/

#ifndef INCL_FAKE_UNIT_MGR_HPP_
#define INCL_FAKE_UNIT_MGR_HPP_

#include <deque>

class display;
class unit;
class fake_unit;

class fake_unit_manager {
public:
fake_unit_manager(display & disp) : fake_units_(), my_display_(disp) {}

//Anticipate making place_temporary_unit and remove_temporary_unit private to force exception safety
friend class fake_unit;

const std::deque<unit*> & get_fake_unit_list_for_invalidation() {return fake_units_; }

private:
/** Temporarily place a unit on map (moving: can overlap others).
* The temp unit is added at the end of the temporary unit dequeue,
* and therefore gets drawn last, over other units and temp units.
* Adding the same unit twice isn't allowed.
*/
void place_temporary_unit(unit *u);

/** Removes any instances of this temporary unit from the temporary unit vector.
* Returns the number of temp units deleted (0 or 1, any other number indicates an error).
*/
int remove_temporary_unit(unit *u);

/// collection of units destined to be drawn but not put into the unit map
std::deque<unit*> fake_units_;
display & my_display_;
};

#endif

0 comments on commit 06f02b5

Please sign in to comment.