1 /*
2    Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.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 #pragma once
16 
17 #include "display_context.hpp"
18 #include "team.hpp"
19 #include "terrain/type_data.hpp"
20 #include "units/map.hpp"
21 #include "units/id.hpp"
22 
23 #include <boost/optional.hpp>
24 #include <set>
25 #include <vector>
26 
27 class config;
28 class gamemap;
29 
30 namespace events {
31 	class mouse_handler;
32 	class menu_handler;
33 }
34 
35 /**
36  *
37  * Game board class.
38  *
39  * The purpose of this class is to encapsulate some of the core game logic, including the unit map,
40  * the list of teams, and the game map.
41  *
42  * This should eventually become part of the game state object IMO, which should be a child of play_controller.
43  *
44  * I also intend to move the pathfinding module to be housed within this class -- this way, we can implement a
45  * sound pathfinding data structure to speed up path computations for AI, without having to make "update event"
46  * code at all points in the engine which modify the relevant data.
47  *
48  **/
49 
50 class game_board : public display_context
51 {
52 
53 	std::vector<team> teams_;
54 	std::vector<std::string> labels_;
55 
56 	std::unique_ptr<gamemap> map_;
57 	n_unit::id_manager unit_id_manager_;
58 	unit_map units_;
59 
60 	//TODO: Remove these when we have refactored enough to make it possible.
61 	friend class play_controller;
62 	friend class events::mouse_handler;
63 	friend class events::menu_handler;
64 	friend class game_state;
65 	friend class game_lua_kernel;
66 
67 	/**
68 	 * Temporary unit move structs:
69 	 *
70 	 * Probably don't remove these friends, this is actually fairly useful. These structs are used by:
71 	 *  - AI
72 	 *  - Whiteboard
73 	 *  - I think certain wml actions
74 	 * For AI, the ai wants to move two units next to eachother so it can ask for attack calculations. This should not trigger
75 	 * pathfinding modifications, so the version that directly changes the unit map is probably preferable, although it should be
76 	 * refactored.
77 	 * For whiteboard and wml actions, we generally do want pathfinding to be updated, so use the game_board constructors which I
78 	 * have added to these structs instead.
79 	 *
80 	 **/
81 	friend struct temporary_unit_placer;
82 	friend struct temporary_unit_mover;
83 	friend struct temporary_unit_remover;
84 
85 public:
unit_id_manager()86 	n_unit::id_manager& unit_id_manager() { return unit_id_manager_; }
87 	// Constructors, trivial dtor, and const accessors
88 
89 	game_board(const ter_data_cache & tdata, const config & level);
90 	virtual ~game_board();
91 
teams() const92 	virtual const std::vector<team>& teams() const override
93 	{
94 		return teams_;
95 	}
96 
teams()97 	std::vector<team>& teams()
98 	{
99 		return teams_;
100 	}
101 
102 	using display_context::get_team; // so as not to hide the const version
103 
get_team(int i)104 	team& get_team(int i)
105 	{
106 		return teams_.at(i - 1);
107 	}
108 
map() const109 	virtual const gamemap& map() const override
110 	{
111 		return *map_;
112 	}
113 
units() const114 	virtual const unit_map& units() const override
115 	{
116 		return units_;
117 	}
118 
units()119 	unit_map& units()
120 	{
121 		return units_;
122 	}
123 
hidden_label_categories() const124 	virtual const std::vector<std::string>& hidden_label_categories() const override
125 	{
126 		return labels_;
127 	}
128 
hidden_label_categories()129 	virtual std::vector<std::string>& hidden_label_categories() override
130 	{
131 		return labels_;
132 	}
133 
134 	// Copy and swap idiom, because we have a scoped pointer.
135 
136 	game_board(const game_board & other);
137 	game_board& operator=(const game_board& other) = delete;
138 
139 	friend void swap(game_board & one, game_board & other);
140 
141 	// Saving
142 
143 	void write_config(config & cfg) const;
144 
145 	// Manipulators from play_controller
146 
147 	void new_turn(int pnum);
148 	void end_turn(int pnum);
149 	void set_all_units_user_end_turn();
150 
151 	void heal_all_survivors();
152 
153 	void check_victory(bool &, bool &, bool &, bool &, std::set<unsigned> &, bool);
154 
155 	// Manipulator from playturn
156 
157 	void side_drop_to (int side_num, team::CONTROLLER ctrl, team::PROXY_CONTROLLER proxy = team::PROXY_CONTROLLER::PROXY_HUMAN);
158 	void side_change_controller (int side_num, bool is_local, const std::string& pname = "");
159 
160 	// Manipulator from actionwml
161 
162 	bool try_add_unit_to_recall_list(const map_location& loc, const unit_ptr u);
163 	boost::optional<std::string> replace_map (const gamemap & r);
164 	void overlay_map (const gamemap & o, const config & cfg, map_location loc);
165 
166 	bool change_terrain(const map_location &loc, const std::string &t,
167 	                    const std::string & mode, bool replace_if_failed); //used only by lua
168 
169 	// Global accessor from unit.hpp
170 
171 	unit_map::iterator find_visible_unit(const map_location &loc, const team& current_team, bool see_all = false);
find_visible_unit(const map_location & loc,size_t team,bool see_all=false)172 	unit_map::iterator find_visible_unit(const map_location & loc, size_t team, bool see_all = false) { return find_visible_unit(loc, teams_[team], see_all); }
173 	bool has_visible_unit (const map_location & loc, const team & team, bool see_all = false) const;
has_visible_unit(const map_location & loc,size_t team,bool see_all=false) const174 	bool has_visible_unit (const map_location & loc, size_t team, bool see_all = false) const { return has_visible_unit(loc, teams_[team], see_all); }
175 
176 	unit* get_visible_unit(const map_location &loc, const team &current_team, bool see_all = false); //TODO: can this not return a pointer?
177 
178 	// Wrapped functions from unit_map. These should ultimately provide notification to observers, pathfinding.
179 
find_unit(const map_location & loc)180 	unit_map::iterator find_unit(const map_location & loc) { return units_.find(loc); }
181 	/// Calculates whether a team is defeated
182 	bool team_is_defeated(const team& t) const;
183 };
184 
185 void swap(game_board & one, game_board & other);
186 
187 
188 /**
189  * This object is used to temporary place a unit in the unit map, swapping out
190  * any unit that is already there.  On destruction, it restores the unit map to
191  * its original.
192  */
193 struct temporary_unit_placer
194 {
195 	temporary_unit_placer(unit_map& m, const map_location& loc, unit& u);
196 	temporary_unit_placer(game_board& m, const map_location& loc, unit& u);
197 	virtual  ~temporary_unit_placer();
198 
199 private:
200 	unit_map& m_;
201 	const map_location loc_;
202 	unit_ptr temp_;
203 };
204 
205 // Begin Temporary Unit Move Structs
206 // TODO: Fix up the implementations which use game_board
207 
208 /**
209  * This object is used to temporary remove a unit from the unit map.
210  * On destruction, it restores the unit map to its original.
211  * unit_map iterators to this unit must not be accessed while the unit is temporarily
212  * removed, otherwise a collision will happen when trying to reinsert the unit.
213  */
214 struct temporary_unit_remover
215 {
216 	temporary_unit_remover(unit_map& m, const map_location& loc);
217 	temporary_unit_remover(game_board& m, const map_location& loc);
218 	virtual  ~temporary_unit_remover();
219 
220 private:
221 	unit_map& m_;
222 	const map_location loc_;
223 	unit_ptr temp_;
224 };
225 
226 
227 /**
228  * This object is used to temporary move a unit in the unit map, swapping out
229  * any unit that is already there.  On destruction, it restores the unit map to
230  * its original.
231  */
232 struct temporary_unit_mover
233 {
234 	temporary_unit_mover(unit_map& m, const map_location& src,
235 	                     const map_location& dst, int new_moves);
236 	temporary_unit_mover(unit_map& m, const map_location& src,
237 	                     const map_location& dst);
238 	temporary_unit_mover(game_board& b, const map_location& src,
239 	                     const map_location& dst, int new_moves);
240 	temporary_unit_mover(game_board& b, const map_location& src,
241 	                     const map_location& dst);
242 	virtual  ~temporary_unit_mover();
243 
244 private:
245 	unit_map& m_;
246 	const map_location src_;
247 	const map_location dst_;
248 	int old_moves_;
249 	unit_ptr temp_;
250 };
251