1 /*
2  * Copyright (C) 2010-2020 by the Widelands Development Team
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  */
19 
20 #ifndef WL_LOGIC_MAP_OBJECTS_TRIBES_SHIP_H
21 #define WL_LOGIC_MAP_OBJECTS_TRIBES_SHIP_H
22 
23 #include <memory>
24 
25 #include "base/macros.h"
26 #include "economy/shippingitem.h"
27 #include "graphic/animation/diranimations.h"
28 #include "logic/map_objects/bob.h"
29 
30 namespace Widelands {
31 
32 struct ShipFleet;
33 
34 // This can't be part of the Ship class because of forward declaration in game.h
35 // Keep the order of entries for savegame compatibility.
36 enum class IslandExploreDirection {
37 	kNotSet,
38 	kCounterClockwise,
39 	kClockwise,
40 };
41 
42 struct NoteShip {
43 	CAN_BE_SENT_AS_NOTE(NoteId::Ship)
44 
45 	Ship* ship;
46 
47 	enum class Action { kDestinationChanged, kWaitingForCommand, kNoPortLeft, kLost, kGained };
48 	Action action;
49 
NoteShipNoteShip50 	NoteShip(Ship* const init_ship, const Action& init_action)
51 	   : ship(init_ship), action(init_action) {
52 	}
53 };
54 
55 class ShipDescr : public BobDescr {
56 public:
57 	ShipDescr(const std::string& init_descname, const LuaTable& t);
~ShipDescr()58 	~ShipDescr() override {
59 	}
60 
61 	Bob& create_object() const override;
62 
63 	uint32_t movecaps() const override;
get_sail_anims()64 	const DirAnimations& get_sail_anims() const {
65 		return sail_anims_;
66 	}
67 
get_default_capacity()68 	Quantity get_default_capacity() const {
69 		return default_capacity_;
70 	}
71 
72 private:
73 	DirAnimations sail_anims_;
74 	Quantity default_capacity_;
75 	DISALLOW_COPY_AND_ASSIGN(ShipDescr);
76 };
77 
78 constexpr int32_t kShipInterval = 1500;
79 
80 constexpr uint32_t kInvalidDestination = std::numeric_limits<uint32_t>::max();
81 
82 /**
83  * Ships belong to a player and to an economy. The usually are in a (unique)
84  * fleet for a player, but only if they are on standard duty. Exploration ships
85  * are an economy of their own and are not part of a Fleet.
86  */
87 struct Ship : Bob {
88 	MO_DESCR(ShipDescr)
89 
90 	explicit Ship(const ShipDescr& descr);
91 	~Ship() override;
92 
93 	// Returns the fleet the ship is a part of.
94 	ShipFleet* get_fleet() const;
95 
get_destinationShip96 	PortDock* get_destination() const {
97 		return destination_;
98 	}
99 	void set_destination(Game&, PortDock*);
100 
101 	// Returns the last visited portdock of this ship or nullptr if there is none or
102 	// the last visited was removed.
103 	PortDock* get_lastdock(EditorGameBase& egbase) const;
104 
get_economyShip105 	Economy* get_economy(WareWorker type) const {
106 		return type == wwWARE ? ware_economy_ : worker_economy_;
107 	}
108 	void set_economy(Game&, Economy* e, WareWorker);
109 
110 	void init_auto_task(Game&) override;
111 
112 	bool init(EditorGameBase&) override;
113 	void cleanup(EditorGameBase&) override;
114 
115 	void start_task_ship(Game&);
116 	void start_task_movetodock(Game&, PortDock&);
117 	void start_task_expedition(Game&);
118 
119 	uint32_t calculate_sea_route(EditorGameBase&, PortDock&, Path* = nullptr) const;
120 
121 	void log_general_info(const EditorGameBase&) const override;
122 
get_nritemsShip123 	uint32_t get_nritems() const {
124 		return items_.size();
125 	}
get_itemShip126 	const ShippingItem& get_item(uint32_t idx) const {
127 		return items_[idx];
128 	}
129 
130 	void add_item(Game&, const ShippingItem&);
131 	bool withdraw_item(Game&, PortDock&);
132 
133 	// A ship with task expedition can be in four states: kExpeditionWaiting, kExpeditionScouting,
134 	// kExpeditionPortspaceFound or kExpeditionColonizing in the first states, the owning player of
135 	// this ship
136 	// can give direction change commands to change the direction of the moving ship / send the ship
137 	// in a
138 	// direction. Once the ship is on its way, it is in kExpeditionScouting state. In the backend, a
139 	// click
140 	// on a direction begins to the movement into that direction until a coast is reached or the user
141 	// cancels the direction through a direction change.
142 	//
143 	// The kExpeditionWaiting state means, that an event happend and thus the ship stopped and waits
144 	// for a
145 	// new command by the owner. An event leading to a kExpeditionWaiting state can be:
146 	// * expedition is ready to start
147 	// * new island appeared in vision range (only outer ring of vision range has to be checked due
148 	// to the
149 	//   always ongoing movement).
150 	// * island was completely surrounded
151 	//
152 	// The kExpeditionPortspaceFound state means, that a port build space was found.
153 	//
154 	enum class ShipStates : uint8_t {
155 		kTransport = 0,
156 		kExpeditionWaiting = 1,
157 		kExpeditionScouting = 2,
158 		kExpeditionPortspaceFound = 3,
159 		kExpeditionColonizing = 4,
160 		kSinkRequest = 8,
161 		kSinkAnimation = 9
162 	};
163 
164 	/// \returns the current state the ship is in
get_ship_stateShip165 	ShipStates get_ship_state() const {
166 		return ship_state_;
167 	}
168 
169 	/// \returns the current name of ship
get_shipnameShip170 	const std::string& get_shipname() const {
171 		return shipname_;
172 	}
173 
174 	/// \returns whether the ship is currently on an expedition
state_is_expeditionShip175 	bool state_is_expedition() const {
176 		return (ship_state_ == ShipStates::kExpeditionScouting ||
177 		        ship_state_ == ShipStates::kExpeditionWaiting ||
178 		        ship_state_ == ShipStates::kExpeditionPortspaceFound ||
179 		        ship_state_ == ShipStates::kExpeditionColonizing);
180 	}
181 	/// \returns whether the ship is in transport mode
state_is_transportShip182 	bool state_is_transport() const {
183 		return (ship_state_ == ShipStates::kTransport);
184 	}
185 	/// \returns whether a sink request for the ship is currently valid
state_is_sinkableShip186 	bool state_is_sinkable() const {
187 		return (ship_state_ != ShipStates::kSinkRequest &&
188 		        ship_state_ != ShipStates::kSinkAnimation &&
189 		        ship_state_ != ShipStates::kExpeditionColonizing);
190 	}
191 
192 	/// \returns (in expedition mode only!) whether the next field in direction \arg dir is swimmable
exp_dir_swimmableShip193 	bool exp_dir_swimmable(Direction dir) const {
194 		if (!expedition_)
195 			return false;
196 		return expedition_->swimmable[dir - 1];
197 	}
198 
199 	// whether the ship's expedition is in state "island-exploration" (circular movement)
is_exploring_islandShip200 	bool is_exploring_island() const {
201 		return expedition_->island_exploration;
202 	}
203 
204 	/// \returns whether the expedition ship is close to the coast
exp_close_to_coastShip205 	bool exp_close_to_coast() const {
206 		if (!expedition_)
207 			return false;
208 		for (uint8_t dir = FIRST_DIRECTION; dir <= LAST_DIRECTION; ++dir)
209 			if (!expedition_->swimmable[dir - 1])
210 				return true;
211 		return false;
212 	}
213 
214 	/// \returns (in expedition mode only!) the list of currently seen port build spaces
exp_port_spacesShip215 	const std::vector<Coords>& exp_port_spaces() const {
216 		return expedition_->seen_port_buildspaces;
217 	}
218 
219 	void exp_scouting_direction(Game&, WalkingDir);
220 	void exp_construct_port(Game&, const Coords&);
221 	void exp_explore_island(Game&, IslandExploreDirection);
222 
223 	// Returns integer of direction, or WalkingDir::IDLE if query invalid
224 	// Intended for LUA scripting
225 	WalkingDir get_scouting_direction() const;
226 
227 	// Returns integer of direction, or IslandExploreDirection::kNotSet
228 	// if query invalid
229 	// Intended for LUA scripting
230 	IslandExploreDirection get_island_explore_direction() const;
231 
232 	void exp_cancel(Game&);
233 	void sink_ship(Game&);
234 
get_capacityShip235 	Quantity get_capacity() const {
236 		return capacity_;
237 	}
set_capacityShip238 	void set_capacity(Quantity c) {
239 		capacity_ = c;
240 	}
241 
242 protected:
243 	void draw(const EditorGameBase&,
244 	          const InfoToDraw& info_to_draw,
245 	          const Vector2f& point_on_dst,
246 	          const Coords& coords,
247 	          float scale,
248 	          RenderTarget* dst) const override;
249 
250 private:
251 	friend struct ShipFleet;
252 	friend struct ShippingSchedule;
253 
254 	void wakeup_neighbours(Game&);
255 
256 	static const Task taskShip;
257 
258 	void ship_update(Game&, State&);
259 	void ship_wakeup(Game&);
260 
261 	bool ship_update_transport(Game&, State&);
262 	void ship_update_expedition(Game&, State&);
263 	void ship_update_idle(Game&, State&);
264 	/// Set the ship's state to 'state' and if the ship state has changed, publish a notification.
265 	void set_ship_state_and_notify(ShipStates state, NoteShip::Action action);
266 
267 	bool init_fleet(EditorGameBase&);
268 	void set_fleet(ShipFleet* fleet);
269 
270 	void send_message(Game& game,
271 	                  const std::string& title,
272 	                  const std::string& heading,
273 	                  const std::string& description,
274 	                  const std::string& picture);
275 
276 	ShipFleet* fleet_;
277 	Economy* ware_economy_;
278 	Economy* worker_economy_;
279 	OPtr<PortDock> lastdock_;
280 	std::vector<ShippingItem> items_;
281 	ShipStates ship_state_;
282 	std::string shipname_;
283 
284 	PortDock* destination_;
285 
286 	struct Expedition {
287 		~Expedition();
288 
289 		std::vector<Coords> seen_port_buildspaces;
290 		bool swimmable[LAST_DIRECTION];
291 		bool island_exploration;
292 		WalkingDir scouting_direction;
293 		Coords exploration_start;
294 		IslandExploreDirection island_explore_direction;
295 		Economy* ware_economy;  // Owned by Player
296 		Economy* worker_economy;
297 	};
298 	std::unique_ptr<Expedition> expedition_;
299 
300 	Quantity capacity_;
301 
302 	// saving and loading
303 protected:
304 	struct Loader : Bob::Loader {
305 
306 		const Task* get_task(const std::string& name) override;
307 
308 		void load(FileRead& fr, uint8_t);
309 		void load_pointers() override;
310 		void load_finish() override;
311 
312 	private:
313 		// Initialize everything to make cppcheck happy.
314 		uint32_t lastdock_ = 0U;
315 		Serial ware_economy_serial_;
316 		Serial worker_economy_serial_;
317 		uint32_t destination_;
318 		uint32_t capacity_ = 0U;
319 		ShipStates ship_state_ = ShipStates::kTransport;
320 		std::string shipname_;
321 		std::unique_ptr<Expedition> expedition_;
322 		std::vector<ShippingItem::Loader> items_;
323 		uint8_t packet_version_ = 0;
324 	};
325 
326 public:
327 	void save(EditorGameBase&, MapObjectSaver&, FileWrite&) override;
328 
329 	static MapObject::Loader* load(EditorGameBase&, MapObjectLoader&, FileRead&);
330 };
331 
332 }  // namespace Widelands
333 
334 #endif  // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_SHIP_H
335