whiteboard/highlight_visitor.cpp

Go to the documentation of this file.
00001 /* $Id: highlight_visitor.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003  Copyright (C) 2010 - 2012 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
00004  Part of the Battle for Wesnoth Project http://www.wesnoth.org
00005 
00006  This program is free software; you can redistribute it and/or modify
00007  it under the terms of the GNU General Public License as published by
00008  the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010  This program is distributed in the hope that it will be useful,
00011  but WITHOUT ANY WARRANTY.
00012 
00013  See the COPYING file for more details.
00014  */
00015 
00016 /**
00017  * @file
00018  */
00019 
00020 #include "highlight_visitor.hpp"
00021 
00022 #include "action.hpp"
00023 #include "attack.hpp"
00024 #include "manager.hpp"
00025 #include "move.hpp"
00026 #include "recall.hpp"
00027 #include "recruit.hpp"
00028 #include "side_actions.hpp"
00029 #include "suppose_dead.hpp"
00030 
00031 #include "arrow.hpp"
00032 #include "foreach.hpp"
00033 #include "play_controller.hpp"
00034 #include "resources.hpp"
00035 #include "unit_map.hpp"
00036 
00037 namespace wb
00038 {
00039 
00040 highlight_visitor::highlight_visitor(unit_map& unit_map, side_actions_ptr side_actions)
00041     : visitor()
00042     , mode_(NONE)
00043     , unit_map_(unit_map)
00044     , mouseover_hex_()
00045     , exclusive_display_hexes_()
00046     , owner_unit_(NULL)
00047     , selection_candidate_(NULL)
00048     , selected_action_()
00049     , main_highlight_()
00050     , secondary_highlights_()
00051     , side_actions_(side_actions)
00052 {
00053 }
00054 
00055 highlight_visitor::~highlight_visitor()
00056 {
00057     if (resources::screen && owner_unit_)
00058         unhighlight();
00059 }
00060 
00061 void highlight_visitor::set_mouseover_hex(const map_location& hex)
00062 {
00063     clear();
00064 
00065     if (!hex.valid())
00066         return;
00067 
00068     real_map ensure_real_map;
00069     mouseover_hex_ = hex;
00070     //if we're right over a unit, just highlight all of this unit's actions
00071     unit_map::iterator it = unit_map_.find(hex);
00072     if (it != unit_map_.end())
00073     {
00074         selection_candidate_ = &(*it);
00075 
00076         if(resources::teams->at(it->side()-1).get_side_actions()->unit_has_actions(&*it))
00077         {
00078             owner_unit_ = &(*it);
00079         }
00080 
00081         //commented code below is to also select the first action of this unit as
00082         //the main highlight; it doesn't fit too well in the UI
00083 //      side_actions::iterator action_it = side_actions_->find_first_action_of(*it);
00084 //      if (action_it != side_actions_->end())
00085 //      {
00086 //          main_highlight_ = *action_it;
00087 //      }
00088     }
00089 
00090     //Set the execution/deletion/bump targets.
00091     if(owner_unit_)
00092     {
00093         side_actions::iterator itor = side_actions_->find_first_action_of(owner_unit_);
00094         if(itor != side_actions_->end())
00095             selected_action_ = *itor;
00096     }
00097 
00098     //Overwrite the above selected_action_ if we find a better one
00099     if(side_actions_->empty()) {
00100         return;
00101     }
00102     BOOST_REVERSE_FOREACH(action_ptr act, *side_actions_)
00103     {
00104         /**@todo "is_numbering_hex" is not the "correct" criterion by which to
00105          * select the hightlighted/selected action. It's just convenient for me
00106          * to use at the moment since it happens to coincide with the "correct"
00107          * criterion, which is to use FIND_MAIN_HIGHLIGHT mode.*/
00108         if(act->is_numbering_hex(hex))
00109         {
00110             selected_action_ = act;
00111             break;
00112         }
00113     }
00114 }
00115 
00116 void highlight_visitor::clear()
00117 {
00118     unhighlight();
00119     main_highlight_.reset();
00120     owner_unit_ = NULL;
00121     secondary_highlights_.clear();
00122     selected_action_.reset();
00123 }
00124 
00125 void highlight_visitor::highlight()
00126 {
00127     //Find main action to highlight if any, as well as owner unit
00128     find_main_highlight();
00129 
00130     if (action_ptr main = main_highlight_.lock())
00131     {
00132         //Highlight main highlight
00133         mode_ = HIGHLIGHT_MAIN;
00134         main->accept(*this);
00135     }
00136 
00137     if (owner_unit_)
00138     {
00139         //Find secondary actions to highlight
00140         find_secondary_highlights();
00141 
00142         //Make sure owner unit is the only one displayed in its hex
00143         resources::screen->add_exclusive_draw(owner_unit_->get_location(), *owner_unit_);
00144         exclusive_display_hexes_.insert(owner_unit_->get_location());
00145 
00146         if (!secondary_highlights_.empty())
00147         {
00148             //Highlight secondary highlights
00149             mode_ = HIGHLIGHT_SECONDARY;
00150             foreach(weak_action_ptr weak, secondary_highlights_)
00151             {
00152                 if (action_ptr action = weak.lock())
00153                 {
00154                     action->accept(*this);
00155                 }
00156             }
00157         }
00158     }
00159 }
00160 
00161 void highlight_visitor::unhighlight()
00162 {
00163     //unhighlight main highlight
00164     if (action_ptr main = main_highlight_.lock() )
00165     {
00166         mode_ = UNHIGHLIGHT_MAIN;
00167         main->accept(*this);
00168     }
00169 
00170     //unhighlight secondary highlights
00171     mode_ = UNHIGHLIGHT_SECONDARY;
00172     foreach(weak_action_ptr weak, secondary_highlights_)
00173     {
00174         if (action_ptr action = weak.lock())
00175         {
00176             action->accept(*this);
00177         }
00178     }
00179 
00180     //unhide other units if needed
00181     foreach(map_location hex, exclusive_display_hexes_)
00182     {
00183         resources::screen->remove_exclusive_draw(hex);
00184     }
00185     exclusive_display_hexes_.clear();
00186 }
00187 
00188 action_ptr highlight_visitor::get_execute_target()
00189 {
00190     if(action_ptr locked = selected_action_.lock())
00191         return *side_actions_->find_first_action_of(locked->get_unit());
00192     else
00193         return action_ptr();
00194 }
00195 action_ptr highlight_visitor::get_delete_target()
00196 {
00197     if(action_ptr locked = selected_action_.lock())
00198         return *side_actions_->find_last_action_of(locked->get_unit());
00199     else
00200         return action_ptr();
00201 }
00202 
00203 action_ptr highlight_visitor::get_bump_target()
00204 {
00205     return selected_action_.lock();
00206 }
00207 
00208 unit* highlight_visitor::get_selection_target()
00209 {
00210     if (owner_unit_)
00211         return owner_unit_;
00212     else
00213         return selection_candidate_;
00214 }
00215 
00216 void highlight_visitor::visit(move_ptr move)
00217 {
00218     switch (mode_)
00219     {
00220     case FIND_MAIN_HIGHLIGHT:
00221         if (move->get_dest_hex() == mouseover_hex_)
00222         {
00223             main_highlight_ = move;
00224         }
00225         break;
00226     case FIND_SECONDARY_HIGHLIGHTS:
00227         if (move->get_unit() == owner_unit_
00228                 && move != main_highlight_.lock())
00229         {
00230             secondary_highlights_.push_back(move);
00231         }
00232         break;
00233     case HIGHLIGHT_MAIN:
00234         if (move->arrow_)
00235         {
00236             move->set_arrow_brightness(move::ARROW_BRIGHTNESS_FOCUS);
00237         }
00238         if (move->fake_unit_)
00239         {
00240             ///@todo find some highlight animation
00241             move->fake_unit_->set_ghosted(true);
00242             //Make sure the fake unit is the only one displayed in its hex
00243             resources::screen->add_exclusive_draw(move->fake_unit_->get_location(), *move->fake_unit_);
00244             exclusive_display_hexes_.insert(move->fake_unit_->get_location());
00245         }
00246         break;
00247     case HIGHLIGHT_SECONDARY:
00248         if (move->arrow_)
00249         {
00250             move->set_arrow_brightness(move::ARROW_BRIGHTNESS_HIGHLIGHTED);
00251         }
00252         if (move->fake_unit_)
00253         {
00254             move->fake_unit_->set_ghosted(true);
00255             //Make sure the fake unit is the only one displayed in its hex
00256             resources::screen->add_exclusive_draw(move->fake_unit_->get_location(), *move->fake_unit_);
00257             exclusive_display_hexes_.insert(move->fake_unit_->get_location());
00258         }
00259         break;
00260     case UNHIGHLIGHT_MAIN: // fall-through
00261     case UNHIGHLIGHT_SECONDARY:
00262         if (move->arrow_)
00263         {
00264             move->set_arrow_brightness(move::ARROW_BRIGHTNESS_STANDARD);
00265         }
00266         if (move->fake_unit_)
00267         {
00268             move->fake_unit_->set_disabled_ghosted(false);
00269         }
00270         break;
00271     default:
00272         assert (false);
00273         break;
00274     }
00275 
00276     //Last action with a fake unit always gets normal appearance
00277     //Override choices above
00278     if (move->fake_unit_)
00279     {
00280         side_actions& sa = *resources::teams->at(move->team_index()).get_side_actions();
00281         side_actions::iterator last_action = sa.find_last_action_of(move->get_unit());
00282         side_actions::iterator second_to_last_action =
00283                 last_action != sa.end() && last_action != sa.begin() ? last_action - 1 : sa.end();
00284         bool this_is_last_action = last_action != sa.end() && move == *last_action;
00285         bool last_action_has_fake_unit = last_action != sa.end() && (*last_action)->get_fake_unit();
00286         bool this_is_second_to_last_action = (second_to_last_action != sa.end()
00287                 && move == *second_to_last_action);
00288 
00289         if (this_is_last_action
00290                 || (this_is_second_to_last_action && !last_action_has_fake_unit))
00291         {
00292             move->fake_unit_->set_standing(true);
00293         }
00294     }
00295 }
00296 
00297 void highlight_visitor::visit(attack_ptr attack)
00298 {
00299     visit(boost::static_pointer_cast<move>(attack));
00300     //@todo: highlight the attack indicator
00301 }
00302 
00303 void highlight_visitor::visit(recruit_ptr recruit)
00304 {
00305     switch (mode_)
00306     {
00307     case FIND_MAIN_HIGHLIGHT:
00308         if (recruit->recruit_hex_ == mouseover_hex_)
00309         {
00310             main_highlight_ = recruit;
00311         }
00312         break;
00313     case FIND_SECONDARY_HIGHLIGHTS:
00314         break;
00315     case HIGHLIGHT_MAIN:
00316         if (recruit->fake_unit_)
00317         {
00318             //@todo: find some suitable effect for mouseover on planned recruit.
00319 
00320             //Make sure the fake unit is the only one displayed in its hex
00321             resources::screen->add_exclusive_draw(recruit->fake_unit_->get_location(), *recruit->fake_unit_);
00322             exclusive_display_hexes_.insert(recruit->fake_unit_->get_location());
00323         }
00324         break;
00325     case HIGHLIGHT_SECONDARY:
00326         break;
00327     case UNHIGHLIGHT_MAIN:
00328     case UNHIGHLIGHT_SECONDARY:
00329         if (recruit->fake_unit_)
00330         {
00331             //@todo: find some suitable effect for mouseover on planned recruit.
00332         }
00333         break;
00334     default:
00335         assert (false);
00336     }
00337 }
00338 
00339 void highlight_visitor::visit(recall_ptr recall)
00340 {
00341     switch (mode_)
00342     {
00343     case FIND_MAIN_HIGHLIGHT:
00344         if (recall->recall_hex_ == mouseover_hex_)
00345         {
00346             main_highlight_ = recall;
00347         }
00348         break;
00349     case FIND_SECONDARY_HIGHLIGHTS:
00350         break;
00351     case HIGHLIGHT_MAIN:
00352         if (recall->fake_unit_)
00353         {
00354             //@todo: find some suitable effect for mouseover on planned recall.
00355         }
00356         break;
00357     case HIGHLIGHT_SECONDARY:
00358         break;
00359     case UNHIGHLIGHT_MAIN:
00360     case UNHIGHLIGHT_SECONDARY:
00361         if (recall->fake_unit_)
00362         {
00363             //@todo: find some suitable effect for mouseover on planned recall.
00364 
00365             //Make sure the fake unit is the only one displayed in its hex
00366             resources::screen->add_exclusive_draw(recall->fake_unit_->get_location(), *recall->fake_unit_);
00367             exclusive_display_hexes_.insert(recall->fake_unit_->get_location());
00368         }
00369         break;
00370     default:
00371         assert (false);
00372     }
00373 }
00374 
00375 void highlight_visitor::visit(suppose_dead_ptr sup_d)
00376 {
00377     switch(mode_)
00378     {
00379     case FIND_MAIN_HIGHLIGHT:
00380         if (sup_d->get_source_hex() == mouseover_hex_)
00381         {
00382             main_highlight_ = sup_d;
00383         }
00384         break;
00385     case FIND_SECONDARY_HIGHLIGHTS:
00386         break;
00387     case HIGHLIGHT_MAIN:
00388         break;
00389     case HIGHLIGHT_SECONDARY:
00390         break;
00391     case UNHIGHLIGHT_MAIN:
00392         break;
00393     case UNHIGHLIGHT_SECONDARY:
00394         break;
00395     default:
00396         assert (false);
00397     }
00398 }
00399 
00400 void highlight_visitor::find_main_highlight()
00401 {
00402     // Even if we already found an owner_unit_ in the mouseover hex,
00403     // action destination hexes usually take priority over that
00404     mode_ = FIND_MAIN_HIGHLIGHT;
00405     assert(main_highlight_.expired());
00406     //@todo re-enable the following assert once I find out what happends to
00407     // viewing side assignments after victory
00408     //assert(side_actions_->team_index() == resources::screen->viewing_team());
00409 
00410     //Find the main highlight -- see visit(), below.
00411     reverse_visit_all();
00412 }
00413 
00414 //Used only by find_main_highlight()
00415 bool highlight_visitor::process(size_t, team&, side_actions&, side_actions::iterator itor)
00416 {
00417     (*itor)->accept(*this);
00418     if (action_ptr main = main_highlight_.lock())
00419     {
00420         owner_unit_ = main->get_unit();
00421         return false;
00422     }
00423     return true;
00424 }
00425 
00426 void highlight_visitor::find_secondary_highlights()
00427 {
00428     assert(owner_unit_);
00429     assert(secondary_highlights_.empty());
00430     mode_ = FIND_SECONDARY_HIGHLIGHTS;
00431     visit_all_actions(); //< protected fcn from visitor
00432 }
00433 
00434 } // end namespace wb
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:15 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs