The Battle for Wesnoth  1.17.0-dev
mapbuilder.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2021
3  by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  */
19 
21 
22 #include "whiteboard/action.hpp"
23 #include "whiteboard/move.hpp"
25 #include "whiteboard/utility.hpp"
26 
27 #include "game_board.hpp"
28 #include "play_controller.hpp"
29 #include "resources.hpp"
30 #include "units/unit.hpp"
31 #include "units/map.hpp"
32 #include "utils/ranges.hpp"
33 
34 namespace wb
35 {
36 
38  : unit_map_(unit_map)
39  , applied_actions_()
40  , applied_actions_this_turn_()
41  , resetters_()
42  , removers_()
43  , acted_this_turn_()
44  , has_invalid_actions_()
45  , invalid_actions_()
46 {
47 }
48 
50 {
51  try {
53  //Remember that the member variable resetters_ is destructed here
54  } catch (...) {}
55 }
56 
58 {
59  for (team& t : resources::gameboard->teams()) {
60  //Reset spent gold to zero, it'll be recalculated during the map building
61  t.get_side_actions()->reset_gold_spent();
62  }
63 
64  int current_side = resources::controller->current_side();
65  for (unit& u : resources::gameboard->units()) {
66  bool on_current_side = (u.side() == current_side);
67 
68  //Remove any unit the current side cannot see to avoid their detection by planning
69  //Units will be restored to the unit map by destruction of removers_
70 
71  if(!on_current_side && !u.is_visible_to_team(resources::gameboard->teams()[viewer_team()], false)) {
72  removers_.emplace_back(new temporary_unit_remover(resources::gameboard->units(), u.get_location()));
73 
74  //Don't do anything else to the removed unit!
75  continue;
76  }
77 
78  //Reset movement points, to be restored by destruction of resetters_
79 
80  //restore movement points only to units not on the current side
81  resetters_.emplace_back(new unit_movement_resetter(u,!on_current_side));
82  //make sure current side's units are not reset to full moves on first turn
83  if(on_current_side) {
84  acted_this_turn_.insert(&u);
85  }
86  }
87 }
88 
90 {
91  pre_build();
92  if(!wb::has_actions()) {
93  return;
94  }
95 
96  bool stop = false;
97  for(std::size_t turn=0; !stop; ++turn) {
98  stop = true;
99  for (team &side : resources::gameboard->teams()) {
100  side_actions &actions = *side.get_side_actions();
101  if(turn < actions.num_turns() && team_has_visible_plan(side)) {
102  stop = false;
103  side_actions::iterator it = actions.turn_begin(turn), next = it, end = actions.turn_end(turn);
104  while(it != end) {
105  std::advance(next, 1);
106  process(actions, it, side.is_local());
107  it = next;
108  }
109 
110  post_visit_team(turn);
111  }
112  }
113  }
114 }
115 
116 void mapbuilder::process(side_actions &sa, side_actions::iterator action_it, bool is_local_side)
117 {
118  action_ptr action = *action_it;
119  bool acted=false;
120  unit_ptr unit = action->get_unit();
121  if(!unit) {
122  return;
123  }
124 
125 
126  if(acted_this_turn_.find(unit.get()) == acted_this_turn_.end() && !action->places_new_unit()) {
127  //reset MP
128  unit->set_movement(unit->total_movement());
129  acted=true;
130  }
131 
132  // Validity check
133  action::error erval = action->check_validity();
134  action->redraw();
135 
136  if(erval != action::OK) {
137  // We do not delete obstructed moves, nor invalid actions caused by obstructed moves.
138  if(has_invalid_actions_.find(unit.get()) == has_invalid_actions_.end()) {
139  if(!is_local_side || erval == action::TOO_FAR || (erval == action::LOCATION_OCCUPIED && std::dynamic_pointer_cast<move>(action))) {
140  has_invalid_actions_.insert(unit.get());
141  invalid_actions_.push_back(action_it);
142  } else {
143  sa.remove_action(action_it, false);
144  return;
145  }
146  } else {
147  invalid_actions_.push_back(action_it);
148  }
149  return;
150  }
151 
152  // We do not keep invalid actions replaced by a valid one.
153  if(is_local_side) {
154  std::set<class unit const*>::iterator invalid_it = has_invalid_actions_.find(unit.get());
155  if(invalid_it != has_invalid_actions_.end()) {
157  if((**it)->get_unit().get() == unit.get()) {
158  sa.remove_action(*it, false);
159  it = invalid_actions_.erase(it);
160  } else {
161  ++it;
162  }
163  }
164  has_invalid_actions_.erase(invalid_it);
165  }
166  }
167 
168  if(acted || action->places_new_unit()) {
169  acted_this_turn_.insert(unit.get());
170  }
171 
172  action->apply_temp_modifier(unit_map_);
173  applied_actions_.push_back(action);
174  applied_actions_this_turn_.push_back(action);
175 }
176 
177 void mapbuilder::post_visit_team(std::size_t turn)
178 {
179  std::set<unit const*> seen;
180 
181  // Go backwards through the actions of this turn to identify
182  // which ones are moves that end a turn.
184  move_ptr move = std::dynamic_pointer_cast<class move>(action);
185  if(move) {
186  move->set_turn_number(0);
187  if(move->get_route().steps.size() > 1 && seen.count(move->get_unit().get()) == 0) {
188  seen.insert(move->get_unit().get());
189  move->set_turn_number(turn + 1);
190  }
191  }
192  }
193 
194  // Clear list of planned actions applied this turn
196  // Clear the list of units of this team that have acted this turn
197  acted_this_turn_.clear();
198 }
199 
201 {
202  //applied_actions_ contain only the actions that we applied to the unit map
204  act->remove_temp_modifier(unit_map_);
205  }
206 }
207 
208 } // end namespace wb
virtual void set_turn_number(int turn)
Assigns a turn number to display to this planned move.
Definition: move.hpp:90
container::iterator iterator
play_controller * controller
Definition: resources.cpp:22
bool team_has_visible_plan(team &t)
Returns whether a given team&#39;s plan is visible.
Definition: utility.cpp:181
void set_movement(int moves, bool unit_action=false)
Set this unit&#39;s remaining movement to moves.
Definition: unit.cpp:1176
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:85
This class represents a single unit of a specific type.
Definition: unit.hpp:121
auto reversed_view(T &container)
Definition: ranges.hpp:28
bool has_actions()
Return whether the whiteboard has actions.
Definition: utility.cpp:171
std::set< unit const * > acted_this_turn_
Definition: mapbuilder.hpp:73
std::set< unit const * > has_invalid_actions_
Definition: mapbuilder.hpp:74
std::vector< std::unique_ptr< unit_movement_resetter > > resetters_
Definition: mapbuilder.hpp:69
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
void process(side_actions &sa, side_actions::iterator action_it, bool is_local_side)
Function called on each action.
Definition: mapbuilder.cpp:116
void restore_normal_map()
Definition: mapbuilder.cpp:200
iterator remove_action(iterator position, bool validate_after_delete=true)
Deletes the action at the specified position.
void pre_build()
Does various preliminary actions on the unit map such as resetting moves for some units...
Definition: mapbuilder.cpp:57
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:72
error
Possible errors.
Definition: action.hpp:106
game_board * gameboard
Definition: resources.cpp:21
unit_map & unit_map_
Definition: mapbuilder.hpp:63
std::shared_ptr< action > action_ptr
Definition: typedefs.hpp:62
Object which temporarily resets a unit&#39;s movement.
Definition: unit.hpp:1992
mapbuilder(unit_map &unit_map)
Definition: mapbuilder.cpp:37
action_queue applied_actions_
Definition: mapbuilder.hpp:65
This object is used to temporary remove a unit from the unit map.
Definition: game_board.hpp:211
iterator turn_begin(std::size_t turn_num)
std::list< side_actions::iterator > invalid_actions_
Conserved invalid actions.
Definition: mapbuilder.hpp:76
void post_visit_team(std::size_t turn)
Function called after visiting a team.
Definition: mapbuilder.cpp:177
std::shared_ptr< move > move_ptr
Definition: typedefs.hpp:68
#define next(ls)
Definition: llex.cpp:32
virtual ~mapbuilder()
Definition: mapbuilder.cpp:49
double t
Definition: astarsearch.cpp:65
iterator turn_end(std::size_t turn_num)
action_queue applied_actions_this_turn_
Definition: mapbuilder.hpp:66
int current_side() const
Returns the number of the side whose turn it is.
Container associating units to locations.
Definition: map.hpp:98
void build_map()
Builds every team&#39;s actions as far into the future as possible, in the correct order.
Definition: mapbuilder.cpp:89
std::size_t num_turns() const
Returns the number of turns that have plans.
Abstract base class for all the whiteboard planned actions.
Definition: action.hpp:33
std::vector< std::unique_ptr< temporary_unit_remover > > removers_
Definition: mapbuilder.hpp:70
This internal whiteboard class holds the planned action queues for a team, and offers many utility me...
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
A planned move, represented on the map by an arrow and a ghosted unit in the destination hex...
Definition: move.hpp:35
Definition: display.hpp:49
std::size_t viewer_team()
Definition: utility.cpp:41