whiteboard/side_actions.cpp

Go to the documentation of this file.
00001 /* $Id: side_actions.cpp 53780 2012-04-05 11:04:20Z gabba $ */
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 "side_actions.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 "suppose_dead.hpp"
00029 #include "highlight_visitor.hpp"
00030 #include "utility.hpp"
00031 #include "validate_visitor.hpp"
00032 
00033 #include "actions.hpp"
00034 #include "foreach.hpp"
00035 #include "game_display.hpp"
00036 #include "game_end_exceptions.hpp"
00037 #include "map.hpp"
00038 #include "resources.hpp"
00039 
00040 #include <set>
00041 #include <sstream>
00042 
00043 namespace wb
00044 {
00045 
00046 /** Dumps side_actions on a stream, for debug purposes. */
00047 std::ostream &operator<<(std::ostream &s, wb::side_actions const& side_actions)
00048 {
00049     s << "Content of side_actions:";
00050     int turn = 1;
00051     foreach(action_queue const& turn_queue, side_actions.actions())
00052     {
00053         s << "\n  Turn " << turn;
00054         ++turn;
00055 
00056         int count = 1;
00057         foreach(action_ptr const& action, turn_queue)
00058         {
00059             s << "\n    (" << count << ") " << action;
00060             ++count;
00061         }
00062     }
00063     if (turn == 1) s << " (empty)";
00064     return s;
00065 }
00066 
00067 side_actions::side_actions()
00068     : actions_()
00069     , team_index_(0)
00070     , team_index_defined_(false)
00071     , gold_spent_(0)
00072     , hidden_(false)
00073 {
00074 }
00075 
00076 side_actions::~side_actions()
00077 {
00078 }
00079 
00080 void side_actions::set_team_index(size_t team_index)
00081 {
00082     assert(!team_index_defined_);
00083     team_index_ = team_index;
00084     team_index_defined_ = true;
00085 }
00086 
00087 void side_actions::get_numbers(const map_location& hex, numbers_t& result)
00088 {
00089     if(empty()) {
00090         return;
00091     }
00092 
00093     std::vector<int>& numbers_to_draw = result.numbers_to_draw;
00094     std::vector<size_t>& team_numbers = result.team_numbers;
00095     int& main_number = result.main_number;
00096     std::set<size_t>& secondary_numbers = result.secondary_numbers;
00097     boost::shared_ptr<highlight_visitor> highlighter =
00098                         resources::whiteboard->get_highlighter().lock();
00099 
00100     const_iterator it;
00101     for(it = begin(); it != end(); ++it)
00102     {
00103         if((*it)->is_numbering_hex(hex))
00104         {
00105             //store number corresponding to iterator's position + 1
00106             size_t number = (it - begin()) + 1;
00107             size_t index = numbers_to_draw.size();
00108             numbers_to_draw.push_back(number);
00109             team_numbers.push_back(team_index());
00110 
00111             if (highlighter)
00112             {
00113                 if (highlighter->get_main_highlight().lock() == *it) {
00114                     main_number = index;
00115                 }
00116 
00117                 foreach(weak_action_ptr action, highlighter->get_secondary_highlights())
00118                 {
00119                     if (action.lock() == *it)
00120                     {
00121                         secondary_numbers.insert(index);
00122                     }
00123                 }
00124             }
00125         }
00126     }
00127 }
00128 
00129 bool side_actions::execute_next()
00130 {
00131     if(!empty() && !actions_.front().empty())
00132         return execute(begin());
00133     else //nothing is executable right now
00134         return false;
00135 }
00136 
00137 bool side_actions::execute(side_actions::iterator position)
00138 {
00139     if (resources::whiteboard->has_planned_unit_map())
00140     {
00141         ERR_WB << "Modifying action queue while temp modifiers are applied!!!\n";
00142     }
00143 
00144     assert(position.turn_num_ == 0); //can't execute actions from future turns
00145 
00146     if(actions_.empty() || !validate_iterator(position))
00147         return false;
00148 
00149     LOG_WB << "Before execution, " << *this << "\n";
00150 
00151     action_ptr action = *position;
00152 
00153     if (!action->is_valid())
00154     {
00155         LOG_WB << "Invalid action sent to execution, deleting.\n";
00156         synced_erase(position);
00157         return true;
00158     }
00159 
00160     bool action_successful;
00161     // Determines whether action should be deleted. Interrupted moves return action_complete == false.
00162     bool action_complete;
00163     try {
00164          action->execute(action_successful,action_complete);
00165     } catch (end_turn_exception&) {
00166         synced_erase(position);
00167         LOG_WB << "End turn exception caught during execution, deleting action. " << *this << "\n";
00168         //validate actions at next map rebuild
00169         resources::whiteboard->on_gamestate_change();
00170         throw;
00171     }
00172 
00173     if(resources::whiteboard->should_clear_undo())
00174         resources::whiteboard->clear_undo();
00175 
00176     std::stringstream ss;
00177     ss << "After " << (action_successful? "successful": "failed") << " execution ";
00178     if(action_complete)
00179     {
00180         ss << "with deletion, ";
00181         synced_erase(position);
00182     }
00183     else //action may have revised itself; let's tell our allies.
00184     {
00185         ss << "without deletion, ";
00186         resources::whiteboard->queue_net_cmd(team_index_,make_net_cmd_replace(position,*position));
00187 
00188         //Idea that needs refining: move action at the end of the queue if it failed executing:
00189             //actions_.erase(position);
00190             //actions_.insert(end(), action);
00191     }
00192     ss << *this << "\n";
00193     LOG_WB << ss.str();
00194 
00195     validate_actions();
00196     return action_successful;
00197 }
00198 
00199 size_t side_actions::size() const
00200 {
00201     size_t result = 0;
00202     foreach(action_queue const& queue, actions_)
00203         result += queue.size();
00204     return result;
00205 }
00206 
00207 side_actions::iterator side_actions::turn_begin(size_t turn_num)
00208 {
00209     if(turn_num < num_turns())
00210         return iterator(actions_[turn_num].begin(),turn_num,*this);
00211     else //turn_num out of range
00212         return end();
00213 }
00214 side_actions::iterator side_actions::turn_end(size_t turn_num)
00215     {return turn_begin(turn_num+1);}
00216 side_actions::reverse_iterator side_actions::turn_rbegin(size_t turn_num)
00217     {return reverse_iterator(turn_end(turn_num));}
00218 side_actions::reverse_iterator side_actions::turn_rend(size_t turn_num)
00219     {return reverse_iterator(turn_begin(turn_num));}
00220 
00221 side_actions::range_t side_actions::iter_turn(size_t turn_num)
00222     {return range_t(turn_begin(turn_num),turn_end(turn_num));}
00223 side_actions::rrange_t side_actions::riter_turn(size_t turn_num)
00224     {return rrange_t(turn_rbegin(turn_num),turn_rend(turn_num));}
00225 
00226 void side_actions::hide()
00227 {
00228     if(hidden_)
00229         return;
00230 
00231     hidden_ = true;
00232 
00233     if(empty()) {
00234         return;
00235     }
00236 
00237     foreach(action_ptr act, *this)
00238         act->hide();
00239 }
00240 void side_actions::show()
00241 {
00242     if(!hidden_)
00243         return;
00244 
00245     hidden_ = false;
00246 
00247     foreach(action_ptr act, *this)
00248         act->show();
00249 }
00250 
00251 side_actions::iterator side_actions::queue_move(size_t turn, unit& mover, const pathfind::marked_route& route, arrow_ptr arrow, fake_unit_ptr fake_unit)
00252 {
00253     move_ptr new_move(new move(team_index(), hidden_, mover, route, arrow, fake_unit));
00254     return queue_action(turn,new_move);
00255 }
00256 
00257 side_actions::iterator side_actions::queue_attack(size_t turn, unit& mover, const map_location& target_hex, int weapon_choice,
00258         const pathfind::marked_route& route,
00259         arrow_ptr arrow, fake_unit_ptr fake_unit)
00260 {
00261     attack_ptr new_attack(new attack(team_index(), hidden_, mover, target_hex, weapon_choice, route, arrow, fake_unit));
00262     return queue_action(turn,new_attack);
00263 }
00264 
00265 side_actions::iterator side_actions::queue_recruit(size_t turn, const std::string& unit_name, const map_location& recruit_hex)
00266 {
00267     recruit_ptr new_recruit(new recruit(team_index(), hidden_, unit_name, recruit_hex));
00268     return queue_action(turn,new_recruit);
00269 }
00270 
00271 side_actions::iterator side_actions::queue_recall(size_t turn, const unit& unit, const map_location& recall_hex)
00272 {
00273     recall_ptr new_recall(new recall(team_index(), hidden_, unit, recall_hex));
00274     return queue_action(turn,new_recall);
00275 }
00276 
00277 side_actions::iterator side_actions::queue_suppose_dead(size_t turn, unit& curr_unit, map_location const& loc)
00278 {
00279     suppose_dead_ptr new_suppose_dead(new suppose_dead(team_index(),hidden_,curr_unit,loc));
00280     return queue_action(turn,new_suppose_dead);
00281 }
00282 
00283 side_actions::iterator side_actions::insert_action(iterator position, action_ptr action)
00284 {
00285     if (resources::whiteboard->has_planned_unit_map())
00286     {
00287         ERR_WB << "Modifying action queue while temp modifiers are applied!!!\n";
00288     }
00289     iterator valid_position = synced_insert(position, action);
00290     LOG_WB << "Inserted into turn #" << (valid_position.turn_num_+1) << " at position #"
00291             << (valid_position.base_-actions_[valid_position.turn_num_].begin()+1) << " : " << action <<"\n";
00292     validate_actions();
00293     return valid_position;
00294 }
00295 
00296 side_actions::iterator side_actions::queue_action(size_t turn_num, action_ptr action)
00297 {
00298     if(resources::whiteboard->has_planned_unit_map())
00299     {
00300         ERR_WB << "Modifying action queue while temp modifiers are applied!!!\n";
00301     }
00302     iterator result = synced_enqueue(turn_num, action);
00303     LOG_WB << "Inserted into turn #" << (turn_num+1) << " at position #" << actions_[turn_num].size()
00304             << " : " << action <<"\n";
00305     validate_actions();
00306     return result;
00307 }
00308 
00309 //move action toward front of queue
00310 side_actions::iterator side_actions::bump_earlier(side_actions::iterator position)
00311 {
00312     if (resources::whiteboard->has_planned_unit_map())
00313     {
00314         ERR_WB << "Modifying action queue while temp modifiers are applied!!!\n";
00315     }
00316 
00317     assert(validate_iterator(position));
00318 
00319     //Don't allow bumping the very first action any earlier, of course.
00320     //Also, don't allow bumping an action into a previous turn queue
00321     if(position.base_ == actions_[position.turn_num_].begin())
00322         return end();
00323 
00324     side_actions::iterator previous = position - 1;
00325     //Verify we're not moving an action out-of-order compared to other action of the same unit
00326     {
00327         unit const* previous_ptr = (*previous)->get_unit();
00328         unit const* current_ptr = (*position)->get_unit();
00329         if (previous_ptr && current_ptr && previous_ptr == current_ptr)
00330             return end();
00331     }
00332 
00333     {
00334         using boost::dynamic_pointer_cast;
00335         //If this is a move, verify that it doesn't depend on a previous move for freeing its destination
00336         if (move_ptr bump_earlier = dynamic_pointer_cast<move>(*position))
00337         {
00338             if (move_ptr previous_move = dynamic_pointer_cast<move>(*previous))
00339             {
00340                 if (bump_earlier->get_dest_hex() == previous_move->get_source_hex())
00341                 {
00342                     return end();
00343                 }
00344             }
00345             //Also check the case of reordering a leader's move with respect to a recruit that depend on him
00346             map_location recruit_recall_loc;
00347             if (recruit_ptr previous_recruit = dynamic_pointer_cast<recruit>(*previous))
00348             {
00349                 recruit_recall_loc = previous_recruit->get_recruit_hex();
00350             } else if (recall_ptr previous_recall = dynamic_pointer_cast<recall>(*previous))
00351             {
00352                 recruit_recall_loc = previous_recall->get_recall_hex();
00353             }
00354             if (recruit_recall_loc.valid())
00355             {
00356                 unit const* leader = bump_earlier->get_unit();
00357                 if(leader->can_recruit() &&
00358                         resources::game_map->is_keep(leader->get_location()) &&
00359                         can_recruit_on(*resources::game_map, leader->get_location(), recruit_recall_loc))
00360                 {
00361                     if(unit const* backup_leader = find_backup_leader(*leader))
00362                     {
00363                         side_actions::iterator it = find_first_action_of(backup_leader);
00364                         if (!(it == end() || position < it))
00365                             return end(); //backup leader but he moves before us, refuse bump
00366                     }
00367                     else
00368                     {
00369                         return end(); //no backup leader, refuse bump
00370                     }
00371                 }
00372             }
00373         }
00374     }
00375 
00376     LOG_WB << "Before bumping earlier, " << *this << "\n";
00377 
00378     int action_number = std::distance(actions_[position.turn_num_].begin(), position.base_) + 1;
00379     int last_position = actions_[position.turn_num_].size();
00380     LOG_WB << "In turn-queue #" << (position.turn_num_+1)
00381             << ", bumping action #" << action_number << "/" << last_position
00382             << " to position #" << action_number - 1  << "/" << last_position << ".\n";
00383 
00384     action_ptr action = *position;
00385     resources::whiteboard->queue_net_cmd(team_index_,make_net_cmd_bump_later(position-1));
00386     iterator after = raw_erase(position);
00387     //be careful, previous iterators have just been invalidated by raw_erase()
00388     iterator destination = after - 1;
00389     iterator valid_position = raw_insert(destination, action);
00390     assert(validate_iterator(valid_position));
00391     validate_actions();
00392     LOG_WB << "After bumping earlier, " << *this << "\n";
00393     return valid_position;
00394 }
00395 
00396 //move action toward back of queue
00397 side_actions::iterator side_actions::bump_later(side_actions::iterator position)
00398 {
00399     iterator end_itor = end();
00400     assert(position != end_itor);
00401 
00402     ++position;
00403     if(position == end_itor)
00404         return end_itor;
00405     position = bump_earlier(position);
00406     if(position == end())
00407         return end_itor;
00408     return position+1;
00409 }
00410 
00411 side_actions::iterator side_actions::remove_action(side_actions::iterator position, bool validate_after_delete)
00412 {
00413     if (resources::whiteboard->has_planned_unit_map())
00414     {
00415         ERR_WB << "Modifying action queue while temp modifiers are applied!!!\n";
00416     }
00417 
00418     assert(!actions_.empty());
00419     assert(validate_iterator(position));
00420     size_t distance = std::distance(begin(), position);
00421     if (!actions_.empty() && validate_iterator(position))
00422     {
00423         LOG_WB << "Erasing action at position #" << distance + 1 << "\n";
00424 
00425         synced_erase(position);
00426 
00427         if (validate_after_delete)
00428         {
00429             validate_actions();
00430         }
00431     }
00432     return begin() + distance;
00433 }
00434 
00435 side_actions::iterator side_actions::get_position_of(action_ptr action)
00436 {
00437     if (!actions_.empty())
00438     {
00439         iterator position = begin();
00440         iterator end_itor = end();
00441         for(; position != end_itor; ++position)
00442             if (*position == action)
00443                 return position;
00444     }
00445     return end();
00446 }
00447 
00448 side_actions::iterator side_actions::find_first_action_of(unit const* unit, side_actions::iterator start_position)
00449 {
00450     if (!empty() && validate_iterator(start_position))
00451     {
00452         side_actions::iterator position;
00453         for (position = start_position; position != end(); ++position)
00454         {
00455             action_ptr action = *position;
00456             if (action->get_unit() == unit)
00457             {
00458                 return position;
00459             }
00460         }
00461     }
00462     return end();
00463 }
00464 
00465 side_actions::iterator side_actions::find_first_action_of(unit const* unit)
00466 {
00467     if (empty())
00468         return end();
00469     else
00470         return find_first_action_of(unit, begin());
00471 }
00472 
00473 side_actions::iterator side_actions::find_last_action_of(unit const* unit, side_actions::iterator start_position)
00474 {
00475     if (!empty() && validate_iterator(start_position))
00476     {
00477         reverse_iterator position(start_position);
00478         for (--position ; position != rend(); ++position)
00479         {
00480             if ((*position)->get_unit() == unit)
00481             {
00482                 iterator found_position(position);
00483                 //need to decrement after changing from reverse to regular iterator
00484                 return --found_position;
00485             }
00486         }
00487     }
00488     return end();
00489 }
00490 
00491 side_actions::iterator side_actions::find_last_action_of(unit const* unit)
00492 {
00493     if (empty())
00494         return end();
00495     else
00496         return find_last_action_of(unit, end() - 1);
00497 }
00498 
00499 bool side_actions::unit_has_actions(unit const* unit)
00500 {
00501     if (empty())
00502         return false;
00503     else
00504         return find_first_action_of(unit) != end();
00505 }
00506 
00507 size_t side_actions::count_actions_of(unit const* unit)
00508 {
00509     size_t count = 0;
00510     foreach(action_ptr action, *this)
00511     {
00512         if (action->get_unit() == unit)
00513         {
00514             ++count;
00515         }
00516     }
00517     return count;
00518 }
00519 
00520 void side_actions::remove_invalid_of(unit const* u)
00521 {
00522     iterator i = begin();
00523     while(i != end())
00524     {
00525         action& act = **i;
00526         if(!act.is_valid() && u == act.get_unit())
00527             i = remove_action(i,false);
00528         else ++i;
00529     }
00530 }
00531 
00532 static side_actions::const_iterator find_last_valid_of(unit const& u, side_actions const& sa_const)
00533 {
00534     side_actions& sa = const_cast<side_actions&>(sa_const);
00535     side_actions::iterator end = sa.end();
00536 
00537     if(sa.empty())
00538         return sa.end();
00539 
00540     side_actions::iterator begin = sa.begin();
00541     side_actions::iterator itor  = end;
00542     do {
00543         if(itor==begin && !(*itor)->is_valid())
00544             return end; //this unit has no valid actions!
00545         itor = sa.find_last_action_of(&u,itor - 1);
00546     } while(itor!=end && !(*itor)->is_valid());
00547 
00548     return itor;
00549 }
00550 size_t side_actions::get_turn_num_of(unit const& u) const
00551 {
00552     const_iterator itor = find_last_valid_of(u,*this); //helper fcn -- above
00553     if(itor == end())
00554         return 0;
00555     return itor.base_.turn_num_;
00556 }
00557 
00558 void side_actions::validate_actions()
00559 {
00560     assert(!resources::whiteboard->has_planned_unit_map());
00561 
00562     bool validation_finished = false;
00563     int passes = 1;
00564     while(!validation_finished){
00565         log_scope2("whiteboard", "Validating actions for side "
00566                 + lexical_cast<std::string>(team_index() + 1) + ", pass "
00567                 + lexical_cast<std::string>(passes));
00568         validate_visitor validator(*resources::units);
00569         validation_finished = validator.validate_actions();
00570         ++passes;
00571     }
00572 }
00573 
00574 void side_actions::change_gold_spent_by(int difference)
00575 {
00576     DBG_WB << "Changing gold spent for side " << (team_index() + 1) << "; old value: "
00577             << gold_spent_ << "; new value: " << (gold_spent_ + difference) << "\n";
00578     gold_spent_ += difference; assert(gold_spent_ >= 0);
00579 }
00580 
00581 void side_actions::reset_gold_spent()
00582 {
00583     DBG_WB << "Resetting gold spent for side " << (team_index() + 1) << " to 0.\n";
00584     gold_spent_ = 0;
00585 }
00586 
00587 /* private */
00588 void side_actions::update_size()
00589 {
00590     while(!actions_.empty() && actions_.back().empty())
00591         actions_.pop_back();
00592 }
00593 
00594 side_actions::iterator side_actions::raw_erase(iterator itor)
00595 {
00596     //precondition
00597     assert(itor!=end());
00598 
00599     //prepare
00600     iterator next = itor+1;
00601     bool deleting_last_element = (next == end());
00602     size_t turn_num = itor.turn_num_;
00603     bool next_is_still_valid = (turn_num != next.turn_num_);
00604 
00605     //erase!
00606     action_queue::iterator after_erase = actions_[turn_num].erase(itor.base_);
00607 
00608     //post-processing (determine return value, possibly resize container)
00609     if(deleting_last_element)
00610     {
00611         update_size(); //might need to shrink the container
00612         return end();
00613     }
00614     else if(next_is_still_valid)
00615         return next;
00616     else
00617         return iterator(after_erase, turn_num, *this);
00618 }
00619 
00620 side_actions::iterator side_actions::raw_insert(iterator itor, action_ptr act)
00621 {
00622     size_t turn_num = itor.turn_num_;
00623     action_queue::iterator new_itor = actions_[itor.turn_num_].insert(itor.base_,act);
00624     return iterator(new_itor,turn_num,*this);
00625 }
00626 
00627 side_actions::iterator side_actions::raw_enqueue(size_t turn_num, action_ptr act)
00628 {
00629     //for a little extra safety, since we should never resize by much at a time
00630     assert(turn_num <= actions_.size() || turn_num <= 2);
00631 
00632     if(turn_num >= actions_.size())
00633         actions_.resize(turn_num+1);
00634     actions_[turn_num].push_back(act);
00635     return iterator(actions_[turn_num].end()-1,turn_num,*this);
00636 }
00637 
00638 side_actions::iterator side_actions::safe_insert(size_t turn, size_t pos, action_ptr act)
00639 {
00640     assert(act);
00641 
00642     iterator result;
00643 
00644     size_t queue_count = actions_.size();
00645     if((turn == queue_count   &&   pos == 0)
00646             || (turn < queue_count   &&   pos == actions_[turn].size()))
00647         result = raw_enqueue(turn,act);
00648     else if(turn < queue_count   &&   pos < actions_[turn].size())
00649     {
00650         result = iterator(actions_[turn].begin()+pos,turn,*this);
00651         result = raw_insert(result,act);
00652     }
00653     else //bad position
00654         result = end();
00655 
00656     return result;
00657 }
00658 
00659 side_actions::iterator side_actions::synced_erase(iterator itor)
00660 {
00661     resources::whiteboard->queue_net_cmd(team_index_,make_net_cmd_remove(itor));
00662     return safe_erase(itor);
00663 }
00664 
00665 side_actions::iterator side_actions::synced_insert(iterator itor, action_ptr act)
00666 {
00667     resources::whiteboard->queue_net_cmd(team_index_,make_net_cmd_insert(itor,act));
00668     return raw_insert(itor,act);
00669 }
00670 
00671 side_actions::iterator side_actions::synced_enqueue(size_t turn_num, action_ptr act)
00672 {
00673     //raw_enqueue() creates actions_[turn_num] if it doesn't exist already, so we
00674     //have to do it first -- before subsequently calling actions_[turn_num].size().
00675     iterator result = raw_enqueue(turn_num,act);
00676     resources::whiteboard->queue_net_cmd(team_index_,make_net_cmd_insert(turn_num,actions_[turn_num].size()-1,act));
00677     return result;
00678 }
00679 
00680 side_actions::iterator side_actions::safe_erase(iterator const& itor)
00681 {
00682     action_ptr action = *itor;
00683     resources::whiteboard->pre_delete_action(action); //misc cleanup
00684     iterator return_itor = raw_erase(itor);
00685     resources::whiteboard->post_delete_action(action);
00686     return return_itor;
00687 }
00688 
00689 void side_actions::execute_net_cmd(net_cmd const& cmd)
00690 {
00691     std::string type = cmd["type"];
00692 
00693     if(type=="insert")
00694     {
00695         size_t turn = cmd["turn"].to_int();
00696         size_t pos = cmd["pos"].to_int();
00697         action_ptr act = action::from_config(cmd.child("action"),hidden_);
00698         if(!act)
00699         {
00700             ERR_WB << "side_actions::execute_network_command(): received invalid action data!\n";
00701             return;
00702         }
00703 
00704         iterator itor = safe_insert(turn,pos,act);
00705         if(itor == end())
00706         {
00707             ERR_WB << "side_actions::execute_network_command(): received invalid insertion position!\n";
00708             return;
00709         }
00710 
00711         //update numbering hexes as necessary
00712         ++itor;
00713         iterator end_itor = end();
00714         for( ; itor!=end_itor; ++itor)
00715             resources::screen->invalidate((*itor)->get_numbering_hex());
00716     }
00717     else if(type=="replace")
00718     {
00719         size_t turn = cmd["turn"].to_int();
00720         size_t pos = cmd["pos"].to_int();
00721         action_ptr act = action::from_config(cmd.child("action"),hidden_);
00722         if(!act)
00723         {
00724             ERR_WB << "side_actions::execute_network_command(): received invalid action data!\n";
00725             return;
00726         }
00727 
00728         if(turn >= actions_.size()
00729                 || pos >= actions_[turn].size())
00730         {
00731             ERR_WB << "side_actions::execute_network_command(): received invalid pos!\n";
00732             return;
00733         }
00734 
00735         iterator itor = turn_begin(turn)+pos;
00736         itor = raw_insert(itor,act);
00737         safe_erase(++itor);
00738     }
00739     else if(type=="remove")
00740     {
00741         size_t turn = cmd["turn"].to_int();
00742         size_t pos = cmd["pos"].to_int();
00743         if(turn >= actions_.size()
00744                 || pos >= actions_[turn].size())
00745         {
00746             ERR_WB << "side_actions::execute_network_command(): received invalid pos!\n";
00747             return;
00748         }
00749 
00750         iterator itor = turn_begin(turn)+pos;
00751         itor = safe_erase(itor);
00752 
00753         //update numbering hexes as necessary
00754         iterator end_itor = end();
00755         for( ; itor!=end_itor; ++itor)
00756             resources::screen->invalidate((*itor)->get_numbering_hex());
00757     }
00758     else if(type=="bump_later")
00759     {
00760         size_t turn = cmd["turn"].to_int();
00761         size_t pos = cmd["pos"].to_int();
00762         if(turn >= actions_.size()
00763                 || pos+1 >= actions_[turn].size())
00764         {
00765             ERR_WB << "side_actions::execute_network_command(): received invalid pos!\n";
00766             return;
00767         }
00768 
00769         action_queue::iterator itor = actions_[turn].begin()+pos;
00770         action_ptr first_action = *itor;
00771         itor = actions_[turn].erase(itor);
00772         action_ptr second_action = *itor;
00773         actions_[turn].insert(++itor,first_action);
00774 
00775         //update numbering hexes as necessary
00776         resources::screen->invalidate(first_action->get_numbering_hex());
00777         resources::screen->invalidate(second_action->get_numbering_hex());
00778     }
00779     else if(type=="clear")
00780     {
00781         safe_clear();
00782     }
00783     else if(type=="refresh")
00784     {
00785         safe_clear();
00786         foreach(net_cmd const& sub_cmd, cmd.child_range("net_cmd"))
00787             execute_net_cmd(sub_cmd);
00788     }
00789     else
00790     {
00791         ERR_WB << "side_actions::execute_network_command(): received invalid type!\n";
00792         return;
00793     }
00794 
00795     validate_actions();
00796 }
00797 
00798 side_actions::net_cmd side_actions::make_net_cmd_insert(size_t turn_num, size_t pos, action_const_ptr act) const
00799 {
00800     net_cmd result;
00801     result["type"] = "insert";
00802     result["turn"] = static_cast<int>(turn_num);
00803     result["pos"] = static_cast<int>(pos);
00804     result.add_child("action",act->to_config());
00805     return result;
00806 }
00807 side_actions::net_cmd side_actions::make_net_cmd_insert(const_iterator const& pos, action_const_ptr act) const
00808 {
00809     return make_net_cmd_insert(pos.base_.turn_num_,std::distance<action_queue::const_iterator>(actions_[pos.base_.turn_num_].begin(),pos.base_.base_),act);
00810 }
00811 side_actions::net_cmd side_actions::make_net_cmd_replace(const_iterator const& pos, action_const_ptr act) const
00812 {
00813     net_cmd result;
00814     result["type"] = "replace";
00815     result["turn"] = static_cast<int>(pos.base_.turn_num_);
00816     result["pos"] = static_cast<int>(std::distance<action_queue::const_iterator>(actions_[pos.base_.turn_num_].begin(),pos.base_.base_));
00817     result.add_child("action",act->to_config());
00818     return result;
00819 }
00820 side_actions::net_cmd side_actions::make_net_cmd_remove(const_iterator const& pos) const
00821 {
00822     net_cmd result;
00823     result["type"] = "remove";
00824     result["turn"] = static_cast<int>(pos.base_.turn_num_);
00825     result["pos"] = static_cast<int>(std::distance<action_queue::const_iterator>(actions_[pos.base_.turn_num_].begin(),pos.base_.base_));
00826     return result;
00827 }
00828 side_actions::net_cmd side_actions::make_net_cmd_bump_later(const_iterator const& pos) const
00829 {
00830     net_cmd result;
00831     result["type"] = "bump_later";
00832     result["turn"] = static_cast<int>(pos.base_.turn_num_);
00833     result["pos"] = static_cast<int>(std::distance<action_queue::const_iterator>(actions_[pos.base_.turn_num_].begin(),pos.base_.base_));
00834     return result;
00835 }
00836 side_actions::net_cmd side_actions::make_net_cmd_clear() const
00837 {
00838     net_cmd result;
00839     result["type"] = "clear";
00840     return result;
00841 }
00842 side_actions::net_cmd side_actions::make_net_cmd_refresh() const
00843 {
00844     net_cmd result;
00845     result["type"] = "refresh";
00846 
00847     const_iterator end = this->end();
00848     for(const_iterator itor=begin(); itor!=end; ++itor)
00849         result.add_child("net_cmd",make_net_cmd_insert(itor.base_.turn_num_,std::distance<action_queue::const_iterator>(actions_[itor.base_.turn_num_].begin(),itor.base_.base_),*itor));
00850 
00851     return result;
00852 }
00853 
00854 //initialize static member
00855 side_actions::iterator side_actions::null(action_queue::iterator(),0,NULL);
00856 
00857 bool side_actions::validate_iterator(iterator position) { return position != end(); }
00858 
00859 side_actions::iterator side_actions::begin()
00860 {
00861     if(actions_.empty())
00862         return null;
00863     return iterator(actions_.front().begin(),0,*this);
00864 }
00865 side_actions::reverse_iterator side_actions::rbegin()
00866     { return reverse_iterator(end()); }
00867 side_actions::const_iterator side_actions::begin() const
00868     { return const_iterator(const_cast<side_actions*>(this)->begin()); }
00869 side_actions::const_reverse_iterator side_actions::rbegin() const
00870     { return const_reverse_iterator(const_cast<side_actions*>(this)->rbegin()); }
00871 
00872 side_actions::iterator side_actions::end()
00873 {
00874     if(actions_.empty())
00875         return null;
00876     return iterator(actions_.back().end(),actions_.size()-1,*this);
00877 }
00878 side_actions::reverse_iterator side_actions::rend()
00879     { return reverse_iterator(begin()); }
00880 side_actions::const_iterator side_actions::end() const
00881     { return const_iterator(const_cast<side_actions*>(this)->end()); }
00882 side_actions::const_reverse_iterator side_actions::rend() const
00883     { return const_reverse_iterator(const_cast<side_actions*>(this)->rend()); }
00884 
00885 void side_actions::raw_turn_shift()
00886 {
00887     //optimization
00888     if(actions_.size() < 2)
00889         return;
00890 
00891     //find units who still have plans for turn 0 (i.e. were too lazy to finish their jobs)
00892     std::set<unit const*> lazy_units;
00893     foreach(action_ptr const& act, iter_turn(0))
00894     {
00895         unit const* u = act->get_unit();
00896         if(u)
00897             lazy_units.insert(u);
00898     }
00899 
00900     //push their plans back one turn
00901     std::set<unit const*>::iterator lazy_end = lazy_units.end();
00902     iterator itor = end();
00903     while(itor != begin())
00904     {
00905         --itor;
00906         action_ptr act = *itor;
00907 
00908         if(lazy_units.find(act->get_unit()) != lazy_end)
00909         {
00910             safe_insert(itor.turn_num_+1,0,act);
00911             itor = raw_erase(itor);
00912         }
00913     }
00914 
00915     //push any remaining first-turn plans into the second turn
00916     foreach(action_ptr act, actions_.front())
00917         actions_[1].push_front(act);
00918     actions_.front().clear();
00919 
00920     //shift everything forward one turn
00921     actions_.pop_front();
00922 }
00923 
00924 void side_actions::synced_turn_shift()
00925 {
00926     raw_turn_shift();
00927     resources::whiteboard->queue_net_cmd(team_index(),make_net_cmd_refresh());
00928 }
00929 
00930 } //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