1 /*
2  Copyright (C) 2010 - 2018 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13  */
14 
15 /**
16  * @file
17  */
18 
19 #include <algorithm>
20 #include <iterator>
21 #include <limits>
22 
23 #include "whiteboard/utility.hpp"
24 
25 #include "whiteboard/manager.hpp"
26 #include "whiteboard/side_actions.hpp"
27 
28 #include "actions/create.hpp"
29 #include "display.hpp"
30 #include "map/map.hpp"
31 #include "play_controller.hpp"
32 #include "resources.hpp"
33 #include "team.hpp"
34 #include "units/unit.hpp"
35 #include "units/animation_component.hpp"
36 #include "utils/iterable_pair.hpp"
37 
38 namespace wb {
39 
viewer_team()40 size_t viewer_team()
41 {
42 	return display::get_singleton()->viewing_team();
43 }
44 
viewer_side()45 int viewer_side()
46 {
47 	return display::get_singleton()->viewing_side();
48 }
49 
viewer_actions()50 side_actions_ptr viewer_actions()
51 {
52 	side_actions_ptr side_actions =
53 			resources::gameboard->teams()[display::get_singleton()->viewing_team()].get_side_actions();
54 	return side_actions;
55 }
56 
current_side_actions()57 side_actions_ptr current_side_actions()
58 {
59 	side_actions_ptr side_actions =
60 			resources::gameboard->get_team(resources::controller->current_side()).get_side_actions();
61 	return side_actions;
62 }
63 
find_backup_leader(const unit & leader)64 unit_const_ptr find_backup_leader(const unit & leader)
65 {
66 	assert(leader.can_recruit());
67 	assert(resources::gameboard->map().is_keep(leader.get_location()));
68 	for (unit_map::const_iterator unit = resources::gameboard->units().begin(); unit != resources::gameboard->units().end(); ++unit)
69 	{
70 		if (unit->can_recruit() && unit->id() != leader.id())
71 		{
72 			if (dynamic_cast<game_state&>(*resources::filter_con).can_recruit_on(*unit, leader.get_location()))
73 				return unit.get_shared_ptr();
74 		}
75 	}
76 	return unit_const_ptr();
77 }
78 
find_recruiter(size_t team_index,const map_location & hex)79 unit* find_recruiter(size_t team_index, const map_location& hex)
80 {
81 	if ( !resources::gameboard->map().is_castle(hex) )
82 		return nullptr;
83 
84 	for(unit& u : resources::gameboard->units())
85 		if(u.can_recruit()
86 				&& u.side() == static_cast<int>(team_index+1)
87 				&& dynamic_cast<game_state&>(*resources::filter_con).can_recruit_on(u, hex))
88 			return &u;
89 	return nullptr;
90 }
91 
any_recruiter(int team_num,const map_location & loc,std::function<bool (unit &)> func)92 bool any_recruiter(int team_num, const map_location& loc, std::function<bool(unit&)> func)
93 {
94 	if ( !resources::gameboard->map().is_castle(loc) ) {
95 		return false;
96 	}
97 
98 	for(unit& u : resources::gameboard->units()) {
99 		if(u.can_recruit() && u.side() == team_num && dynamic_cast<game_state&>(*resources::filter_con).can_recruit_on(u, loc)) {
100 			if(func(u)) {
101 				return true;
102 			}
103 		}
104 	}
105 	return false;
106 }
107 
future_visible_unit(map_location hex,int viewer_side)108 unit* future_visible_unit(map_location hex, int viewer_side)
109 {
110 	future_map planned_unit_map;
111 	if(!resources::whiteboard->has_planned_unit_map())
112 	{
113 		ERR_WB << "future_visible_unit cannot find unit, future unit map failed to build." << std::endl;
114 		return nullptr;
115 	}
116 	//use global method get_visible_unit
117 	return resources::gameboard->get_visible_unit(hex, resources::gameboard->get_team(viewer_side), false);
118 }
119 
future_visible_unit(int on_side,map_location hex,int viewer_side)120 unit* future_visible_unit(int on_side, map_location hex, int viewer_side)
121 {
122 	unit* unit = future_visible_unit(hex, viewer_side);
123 	if (unit && unit->side() == on_side)
124 		return unit;
125 	else
126 		return nullptr;
127 }
128 
path_cost(const std::vector<map_location> & path,const unit & u)129 int path_cost(const std::vector<map_location>& path, const unit& u)
130 {
131 	if(path.size() < 2)
132 		return 0;
133 
134 	const team& u_team = resources::gameboard->get_team(u.side());
135 	const map_location& dest = path.back();
136 	if ( (resources::gameboard->map().is_village(dest) && !u_team.owns_village(dest))
137 	     || pathfind::enemy_zoc(u_team, dest, u_team) )
138 		return u.total_movement();
139 
140 	int result = 0;
141 	const gamemap& map = resources::gameboard->map();
142 	for(const map_location& loc : std::make_pair(path.begin()+1,path.end())) {
143 		result += u.movement_cost(map[loc]);
144 	}
145 	return result;
146 }
147 
temporary_unit_hider(unit & u)148 temporary_unit_hider::temporary_unit_hider(unit& u)
149 		: unit_(&u)
150 	{unit_->set_hidden(true);}
~temporary_unit_hider()151 temporary_unit_hider::~temporary_unit_hider()
152 {
153 	try {
154 		unit_->set_hidden(false);
155 	} catch (...) {}
156 }
157 
ghost_owner_unit(unit * unit)158 void ghost_owner_unit(unit* unit)
159 {
160 	unit->anim_comp().set_disabled_ghosted(false);
161 	display::get_singleton()->invalidate(unit->get_location());
162 }
163 
unghost_owner_unit(unit * unit)164 void unghost_owner_unit(unit* unit)
165 {
166 	unit->anim_comp().set_standing(true);
167 	display::get_singleton()->invalidate(unit->get_location());
168 }
169 
has_actions()170 bool has_actions()
171 {
172 	for (team& t : resources::gameboard->teams()) {
173 		if (!t.get_side_actions()->empty())
174 			return true;
175 	}
176 
177 	return false;
178 }
179 
team_has_visible_plan(team & t)180 bool team_has_visible_plan(team &t)
181 {
182 	return !t.get_side_actions()->hidden();
183 }
184 
for_each_action(std::function<void (action *)> function,team_filter team_filter)185 void for_each_action(std::function<void(action*)> function, team_filter team_filter)
186 {
187 	bool end = false;
188 	for(size_t turn=0; !end; ++turn) {
189 		end = true;
190 		for(team &side : resources::gameboard->teams()) {
191 			side_actions &actions = *side.get_side_actions();
192 			if(turn < actions.num_turns() && team_filter(side)) {
193 				for(auto iter = actions.turn_begin(turn); iter != actions.turn_end(turn); ++iter) {
194 					function(iter->get());
195 				}
196 				end = false;
197 			}
198 		}
199 	}
200 }
201 
find_action_at(map_location hex,team_filter team_filter)202 action_ptr find_action_at(map_location hex, team_filter team_filter)
203 {
204 	action_ptr result;
205 	size_t result_turn = std::numeric_limits<size_t>::max();
206 
207 	for(team &side : resources::gameboard->teams()) {
208 		side_actions &actions = *side.get_side_actions();
209 		if(team_filter(side)) {
210 			side_actions::iterator chall = actions.find_first_action_at(hex);
211 			if(chall == actions.end()) {
212 				continue;
213 			}
214 
215 			size_t chall_turn = actions.get_turn(chall);
216 			if(chall_turn < result_turn) {
217 				result = *chall;
218 				result_turn = chall_turn;
219 			}
220 		}
221 	}
222 
223 	return result;
224 }
225 
find_actions_of(const unit & target)226 std::deque<action_ptr> find_actions_of(const unit& target)
227 {
228 	return resources::gameboard->get_team(target.side()).get_side_actions()->actions_of(target);
229 }
230 
231 } //end namespace wb
232