1 /*
2  * Copyright (C) 2002-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_H
21 #define WL_LOGIC_MAP_H
22 
23 #include <memory>
24 
25 #include "base/i18n.h"
26 #include "economy/itransport_cost_calculator.h"
27 #include "logic/field.h"
28 #include "logic/map_objects/findimmovable.h"
29 #include "logic/map_objects/tribes/wareworker.h"
30 #include "logic/map_objects/walkingdir.h"
31 #include "logic/map_revision.h"
32 #include "logic/objective.h"
33 #include "logic/widelands.h"
34 #include "logic/widelands_geometry.h"
35 #include "notifications/note_ids.h"
36 #include "notifications/notifications.h"
37 
38 class FileSystem;
39 struct S2MapLoader;
40 
41 namespace Widelands {
42 
43 class MapLoader;
44 struct MapGenerator;
45 struct PathfieldManager;
46 class World;
47 
48 // Global list of available map dimensions.
49 const std::vector<int32_t> kMapDimensions = {64,  80,  96,  112, 128, 144, 160, 176, 192, 208,
50                                              224, 240, 256, 272, 288, 304, 320, 336, 352, 368,
51                                              384, 400, 416, 432, 448, 464, 480, 496, 512};
52 
53 struct Path;
54 class Immovable;
55 
56 struct NoteFieldTerrainChanged {
57 	CAN_BE_SENT_AS_NOTE(NoteId::FieldTerrainChanged)
58 
59 	FCoords fc;
60 	MapIndex map_index;
61 };
62 
63 struct ImmovableFound {
64 	BaseImmovable* object;
65 	Coords coords;
66 };
67 
68 /*
69 FindImmovable
70 FindBob
71 FindNode
72 FindResource
73 CheckStep
74 
75 Predicates used in path finding and find functions.
76 */
77 
78 struct FindBob {
79 	//  Return true if this bob should be returned by find_bobs.
80 	virtual bool accept(Bob*) const = 0;
~FindBobFindBob81 	virtual ~FindBob() {
82 	}  // make gcc shut up
83 };
84 struct FindNode;
85 struct CheckStep;
86 
87 /*
88 Some very simple default predicates (more predicates below Map).
89 */
90 struct FindBobAlwaysTrue : public FindBob {
acceptFindBobAlwaysTrue91 	bool accept(Bob*) const override {
92 		return true;
93 	}
~FindBobAlwaysTrueFindBobAlwaysTrue94 	~FindBobAlwaysTrue() override {
95 	}  // make gcc shut up
96 };
97 
98 // Helper struct to save certain elemental data of a field without an actual instance of Field
99 struct FieldData {
100 	FieldData(const Field& f);
101 
102 	std::string immovable;
103 	std::list<std::string> bobs;
104 	uint8_t height;
105 	DescriptionIndex resources;
106 	uint8_t resource_amount;
107 	Field::Terrains terrains;
108 };
109 // used for undoing map resize
110 struct ResizeHistory {
ResizeHistoryResizeHistory111 	ResizeHistory() : size(0, 0) {
112 	}
113 
114 	Extent size;
115 	std::list<FieldData> fields;
116 	std::set<Coords> port_spaces;
117 	std::vector<Coords> starting_positions;
118 };
119 
120 /** class Map
121  *
122  * This really identifies a map like it is in the game
123  *
124  * Odd rows are shifted FIELD_WIDTH/2 to the right. This means that moving
125  * up and down depends on the row numbers:
126  *               even   odd
127  * top-left      -1/-1   0/-1
128  * top-right      0/-1  +1/-1
129  * bottom-left   -1/+1   0/+1
130  * bottom-right   0/+1  +1/+1
131  *
132  * Warning: width and height must be even
133  */
134 class Map : public ITransportCostCalculator {
135 public:
136 	friend class EditorGameBase;
137 	friend class MapLoader;
138 	friend class MapVersionPacket;
139 	friend struct ::S2MapLoader;
140 	friend struct MainMenuNewMap;
141 	friend struct MapAStarBase;
142 	friend struct MapGenerator;
143 	friend struct MapElementalPacket;
144 	friend struct WidelandsMapLoader;
145 
146 	using PortSpacesSet = std::set<Coords>;
147 	using Objectives = std::map<std::string, std::unique_ptr<Objective>>;
148 
149 	enum {  // flags for findpath()
150 
151 		//  use bidirection cost instead of normal cost calculations
152 		//  should be used for road building
153 		fpBidiCost = 1,
154 	};
155 
156 	// ORed bits for scenario types
157 	using ScenarioTypes = size_t;
158 	enum { NO_SCENARIO = 0, SP_SCENARIO = 1, MP_SCENARIO = 2 };
159 
160 	Map();
161 	~Map() override;
162 
163 	/// Returns the correct initialized loader for the given mapfile
164 	std::unique_ptr<MapLoader> get_correct_loader(const std::string& filename);
165 
166 	void cleanup();
167 
168 	void create_empty_map  // for editor
169 	   (const EditorGameBase&,
170 	    uint32_t w = 64,
171 	    uint32_t h = 64,
172 	    const Widelands::DescriptionIndex default_terrain = 0,
173 	    const std::string& name = _("No Name"),
174 	    const std::string& author = pgettext("author_name", "Unknown"),
175 	    const std::string& description = _("No description defined"));
176 
177 	void recalc_whole_map(const EditorGameBase&);
178 	void recalc_for_field_area(const EditorGameBase&, Area<FCoords>);
179 
180 	/**
181 	 *  If the valuable fields are empty, calculates all fields that could be conquered by a player
182 	 * throughout a game. Useful for territorial win conditions. Returns the amount of valuable
183 	 * fields.
184 	 */
185 	size_t count_all_conquerable_fields();
186 
187 	/**
188 	 *  If the valuable fields are empty, calculates which fields do not have the given caps and adds
189 	 * the to the list of valuable fields. Useful for win conditions. Returns the amount of valuable
190 	 * fields.
191 	 */
192 	size_t count_all_fields_excluding_caps(NodeCaps caps);
193 
194 	/**
195 	 * Counts the valuable fields that are owned by each player. Only players that currently own a
196 	 * field are added. Returns a map of <player number, number of owned fields>.
197 	 */
198 	std::map<PlayerNumber, size_t>
199 	count_owned_valuable_fields(const std::string& immovable_attribute) const;
200 
201 	/***
202 	 * Ensures that resources match their adjacent terrains.
203 	 */
204 	void ensure_resource_consistency(const World&);
205 
206 	/***
207 	 * Recalculates all default resources.
208 	 *
209 	 * This is just needed for the game, not for
210 	 * the editor. Since there, default resources
211 	 * are not shown.
212 	 */
213 	void recalc_default_resources(const World&);
214 
215 	void set_nrplayers(PlayerNumber);
216 
217 	void set_starting_pos(PlayerNumber, const Coords&);
get_starting_pos(PlayerNumber const p)218 	Coords get_starting_pos(PlayerNumber const p) const {
219 		assert(1 <= p && p <= get_nrplayers());
220 		return starting_pos_[p - 1];
221 	}
222 
223 	void set_filename(const std::string& filename);
224 	void set_author(const std::string& author);
225 	void set_name(const std::string& name);
226 	void set_description(const std::string& description);
227 	void set_hint(const std::string& hint);
228 	void set_background(const std::string& image_path);
229 	void add_tag(const std::string& tag);
230 	void delete_tag(const std::string& tag);
set_scenario_types(ScenarioTypes t)231 	void set_scenario_types(ScenarioTypes t) {
232 		scenario_types_ = t;
233 	}
234 
235 	// Allows access to the filesystem of the map to access auxiliary files.
236 	// This can be nullptr if this file is new.
237 	FileSystem* filesystem() const;
238 	// swap the filesystem after load / save
239 	void swap_filesystem(std::unique_ptr<FileSystem>& fs);
240 	void reset_filesystem();
241 
242 	// informational functions
get_filename()243 	const std::string& get_filename() const {
244 		return filename_;
245 	}
get_author()246 	const std::string& get_author() const {
247 		return author_;
248 	}
get_name()249 	const std::string& get_name() const {
250 		return name_;
251 	}
get_description()252 	const std::string& get_description() const {
253 		return description_;
254 	}
get_hint()255 	const std::string& get_hint() const {
256 		return hint_;
257 	}
get_background()258 	const std::string& get_background() const {
259 		return background_;
260 	}
261 
262 	using Tags = std::set<std::string>;
get_tags()263 	const Tags& get_tags() const {
264 		return tags_;
265 	}
clear_tags()266 	void clear_tags() {
267 		tags_.clear();
268 	}
has_tag(const std::string & s)269 	bool has_tag(const std::string& s) const {
270 		return tags_.count(s);
271 	}
272 
get_suggested_teams()273 	const std::vector<SuggestedTeamLineup>& get_suggested_teams() const {
274 		return suggested_teams_;
275 	}
276 
get_nrplayers()277 	PlayerNumber get_nrplayers() const {
278 		return nrplayers_;
279 	}
scenario_types()280 	ScenarioTypes scenario_types() const {
281 		return scenario_types_;
282 	}
extent()283 	Extent extent() const {
284 		return Extent(width_, height_);
285 	}
get_width()286 	int16_t get_width() const {
287 		return width_;
288 	}
get_height()289 	int16_t get_height() const {
290 		return height_;
291 	}
292 
293 	// Map compatibility information for the website
294 	int needs_widelands_version_after() const;
295 
296 	//  The next few functions are only valid when the map is loaded as a
297 	//  scenario.
298 	const std::string& get_scenario_player_tribe(PlayerNumber) const;
299 	const std::string& get_scenario_player_name(PlayerNumber) const;
300 	const std::string& get_scenario_player_ai(PlayerNumber) const;
301 	bool get_scenario_player_closeable(PlayerNumber) const;
302 	void set_scenario_player_tribe(PlayerNumber, const std::string&);
303 	void set_scenario_player_name(PlayerNumber, const std::string&);
304 	void set_scenario_player_ai(PlayerNumber, const std::string&);
305 	void set_scenario_player_closeable(PlayerNumber, bool);
306 
307 	/// \returns the maximum theoretical possible nodecaps (no blocking bobs, immovables etc.)
308 	NodeCaps get_max_nodecaps(const EditorGameBase&, const FCoords&) const;
309 
310 	BaseImmovable* get_immovable(const Coords&) const;
311 	uint32_t find_bobs(const EditorGameBase&,
312 	                   const Area<FCoords>,
313 	                   std::vector<Bob*>* list,
314 	                   const FindBob& functor = FindBobAlwaysTrue()) const;
315 	uint32_t find_reachable_bobs(const EditorGameBase&,
316 	                             const Area<FCoords>,
317 	                             std::vector<Bob*>* list,
318 	                             const CheckStep&,
319 	                             const FindBob& functor = FindBobAlwaysTrue()) const;
320 	uint32_t find_immovables(const EditorGameBase&,
321 	                         const Area<FCoords>,
322 	                         std::vector<ImmovableFound>* list,
323 	                         const FindImmovable& = find_immovable_always_true()) const;
324 	uint32_t find_reachable_immovables(const EditorGameBase&,
325 	                                   const Area<FCoords>,
326 	                                   std::vector<ImmovableFound>* list,
327 	                                   const CheckStep&,
328 	                                   const FindImmovable& = find_immovable_always_true()) const;
329 	uint32_t
330 	find_reachable_immovables_unique(const EditorGameBase&,
331 	                                 const Area<FCoords>,
332 	                                 std::vector<BaseImmovable*>& list,
333 	                                 const CheckStep&,
334 	                                 const FindImmovable& = find_immovable_always_true()) const;
335 	uint32_t find_fields(const EditorGameBase&,
336 	                     const Area<FCoords>,
337 	                     std::vector<Coords>* list,
338 	                     const FindNode& functor) const;
339 	uint32_t find_reachable_fields(const EditorGameBase&,
340 	                               const Area<FCoords>,
341 	                               std::vector<Coords>* list,
342 	                               const CheckStep&,
343 	                               const FindNode&) const;
344 
345 	// Field logic
346 	static MapIndex get_index(const Coords&, int16_t width);
347 	MapIndex get_index(const Coords&) const;
max_index()348 	MapIndex max_index() const {
349 		return width_ * height_;
350 	}
351 	Field& operator[](MapIndex) const;
352 	Field& operator[](const Coords&) const;
353 	FCoords get_fcoords(const Coords&) const;
354 	static void normalize_coords(Coords&, int16_t, int16_t);
355 	void normalize_coords(Coords&) const;
356 	FCoords get_fcoords(Field&) const;
357 	void get_coords(Field& f, Coords& c) const;
358 
359 	uint32_t calc_distance(const Coords&, const Coords&) const;
360 
361 	int32_t calc_cost_estimate(const Coords&, const Coords&) const override;
362 	int32_t calc_cost_lowerbound(const Coords&, const Coords&) const;
363 	int32_t calc_cost(int32_t slope) const;
364 	int32_t calc_cost(const Coords&, int32_t dir) const;
365 	int32_t calc_bidi_cost(const Coords&, int32_t dir) const;
366 	void calc_cost(const Path&, int32_t* forward, int32_t* backward) const;
367 
368 	void get_ln(const Coords&, Coords*) const;
369 	void get_ln(const FCoords&, FCoords*) const;
370 	Coords l_n(const Coords&) const;
371 	FCoords l_n(const FCoords&) const;
372 	void get_rn(const Coords&, Coords*) const;
373 	void get_rn(const FCoords&, FCoords*) const;
374 	Coords r_n(const Coords&) const;
375 	FCoords r_n(const FCoords&) const;
376 	void get_tln(const Coords&, Coords*) const;
377 	void get_tln(const FCoords&, FCoords*) const;
378 	Coords tl_n(const Coords&) const;
379 	FCoords tl_n(const FCoords&) const;
380 	void get_trn(const Coords&, Coords*) const;
381 	void get_trn(const FCoords&, FCoords*) const;
382 	Coords tr_n(const Coords&) const;
383 	FCoords tr_n(const FCoords&) const;
384 	void get_bln(const Coords&, Coords*) const;
385 	void get_bln(const FCoords&, FCoords*) const;
386 	Coords bl_n(const Coords&) const;
387 	FCoords bl_n(const FCoords&) const;
388 	void get_brn(const Coords&, Coords*) const;
389 	void get_brn(const FCoords&, FCoords*) const;
390 	Coords br_n(const Coords&) const;
391 	FCoords br_n(const FCoords&) const;
392 
393 	void get_neighbour(const Coords&, Direction dir, Coords*) const;
394 	void get_neighbour(const FCoords&, Direction dir, FCoords*) const;
395 	FCoords get_neighbour(const FCoords&, Direction dir) const;
396 
397 	std::set<Coords> to_set(Area<Coords> area) const;
398 	std::set<TCoords<Coords>> triangles_in_region(std::set<Coords> area) const;
399 
400 	// Pathfinding
401 	int32_t findpath(Coords instart,
402 	                 Coords inend,
403 	                 const int32_t persist,
404 	                 Path&,
405 	                 const CheckStep&,
406 	                 const uint32_t flags = 0,
407 	                 const uint32_t caps_sensitivity = 0,
408 	                 WareWorker type = wwWORKER) const;
409 
410 	/**
411 	 * We can reach a field by water either if it has MOVECAPS_SWIM or if it has
412 	 * MOVECAPS_WALK and at least one of the neighbours has MOVECAPS_SWIM
413 	 */
414 	bool can_reach_by_water(const Coords&) const;
415 
416 	/// Sets the height to a value. Recalculates brightness. Changes the
417 	/// surrounding nodes if necessary. Returns the radius that covers all
418 	/// changes that were made.
419 	///
420 	/// Do not call this to set the height of each node in an area to the same
421 	/// value, because it adjusts the heights of surrounding nodes in each call,
422 	/// so it will be terribly slow. Use set_height for Area for that purpose
423 	/// instead.
424 	uint32_t set_height(const EditorGameBase&, FCoords, Field::Height);
425 
426 	/// Changes the height of the nodes in an Area by a difference.
427 	uint32_t change_height(const EditorGameBase&, Area<FCoords>, int16_t difference);
428 
429 	/// Initializes the 'initial_resources' on 'coords' to the 'resource_type'
430 	/// with the given 'amount'.
431 	void initialize_resources(const FCoords& coords,
432 	                          DescriptionIndex resource_type,
433 	                          ResourceAmount amount);
434 
435 	/// Sets the number of resources of the field to 'amount'. The type of the
436 	/// resource on this field is not changed.
437 	void set_resources(const FCoords& coords, ResourceAmount amount);
438 
439 	/// Clears the resources, i.e. the amount will be set to 0 and the type of
440 	/// resources will be kNoResource.
441 	void clear_resources(const FCoords& coords);
442 
443 	/**
444 	 * Ensures that the height of each node within radius from fc is in
445 	 * height_interval. If the height is < height_interval.min, it is changed to
446 	 * height_interval.min. If the height is > height_interval.max, it is changed
447 	 * to height_interval.max. Otherwise it is left unchanged.
448 	 *
449 	 * Recalculates brightness. Changes the surrounding nodes if necessary.
450 	 * Returns the radius of the area that covers all changes that were made.
451 	 *
452 	 * Calling this is much faster than calling change_height for each node in
453 	 * the area, because this adjusts the surrounding nodes only once, after all
454 	 * nodes in the area had their new height set.
455 	 */
456 	uint32_t set_height(const EditorGameBase&, Area<FCoords>, HeightInterval height_interval);
457 
458 	/***
459 	 * Changes the given triangle's terrain. This happens in the editor and might
460 	 * happen in the game too if some kind of land increasement is implemented (like
461 	 * drying swamps). The nodecaps need to be recalculated. If terrain was changed from
462 	 * or to water, we need to recalculate_allows_seafaring too, depending on the situation.
463 	 *
464 	 * @return the radius of changes.
465 	 */
466 	int32_t change_terrain(const EditorGameBase&, TCoords<FCoords>, DescriptionIndex);
467 
468 	/***
469 	 * Verify if a resource attached to a vertex has enough adjacent matching terrains to be valid.
470 	 *
471 	 * To qualify as valid, resources need to be surrounded by at least two matching terrains.
472 	 */
473 	bool is_resource_valid(const Widelands::World&,
474 	                       const Widelands::FCoords& c,
475 	                       DescriptionIndex curres) const;
476 
477 	// The objectives that are defined in this map if it is a scenario.
objectives()478 	const Objectives& objectives() const {
479 		return objectives_;
480 	}
mutable_objectives()481 	Objectives* mutable_objectives() {
482 		return &objectives_;
483 	}
484 
mutable_valuable_fields()485 	std::set<FCoords>* mutable_valuable_fields() {
486 		return &valuable_fields_;
487 	}
488 
489 	/// Returns the military influence on a location from an area.
490 	MilitaryInfluence calc_influence(Coords, Area<>) const;
491 
492 	/// Translate the whole map so that the given point becomes the new origin.
493 	void set_origin(const Coords&);
494 
495 	// Port space specific functions
496 
497 	/// Checks whether the maximum theoretical possible NodeCap of the field is big,
498 	/// and there is room for a port space
499 	bool is_port_space_allowed(const EditorGameBase&, const FCoords& fc) const;
500 	bool is_port_space(const Coords& c) const;
501 
502 	/// If 'set', set the space at 'c' as port space, otherwise unset.
503 	/// 'force' sets the port space even if it isn't viable, and is to be used for map loading only.
504 	/// Returns whether the port space was set/unset successfully.
505 	bool set_port_space(const EditorGameBase&,
506 	                    const Widelands::Coords& c,
507 	                    bool set,
508 	                    bool force = false,
509 	                    bool recalculate_seafaring = false);
get_port_spaces()510 	const PortSpacesSet& get_port_spaces() const {
511 		return port_spaces_;
512 	}
513 	std::vector<Coords> find_portdock(const Widelands::Coords& c) const;
514 
515 	/// Return true if there are at least 2 port spaces that can be reached from each other by water
516 	bool allows_seafaring() const;
517 	/// Calculate whether there are at least 2 port spaces that can be reached from each other by
518 	/// water and set the allows_seafaring property
519 	void recalculate_allows_seafaring();
520 	/// Remove all port spaces that are not valid (Buildcap < big or not enough space for a
521 	/// portdock).
522 	void cleanup_port_spaces(const EditorGameBase&);
523 
524 	/// Checks whether there are any artifacts on the map
525 	bool has_artifacts();
526 
527 	// Visible for testing.
528 	void set_size(uint32_t w, uint32_t h);
529 
530 	// Change the map size. Must not be used outside the editor.
531 	void resize(EditorGameBase&, Coords, int32_t w, int32_t h);
532 	// Used only to undo a resize() operation.
533 	// Force-resets the entire map's state to the given preserved state.
534 	void set_to(EditorGameBase&, ResizeHistory);
535 	// Creates a ResizeHistory that can be passed to set_to() later.
536 	// This has to save the entire map's state because resize operations
537 	// may affect all fields when resolving height differences etc.
538 	ResizeHistory dump_state(const EditorGameBase&) const;
539 
540 	uint32_t get_waterway_max_length() const;
541 	void set_waterway_max_length(uint32_t max_length);
542 
543 protected:
544 	/// Calculate map compatibility information for the website if it wasn't defined in the map
545 	/// packet. If is_post_one_world is true, this map wasn't created for a specific world (Widelands
546 	/// versions up to Build 18).
547 	void calculate_needs_widelands_version_after(bool is_post_one_world);
548 
549 private:
550 	void recalc_border(const FCoords&);
551 	void recalc_brightness(const FCoords&);
552 	void recalc_nodecaps_pass1(const EditorGameBase&, const FCoords&);
553 	void recalc_nodecaps_pass2(const EditorGameBase&, const FCoords& f);
554 	NodeCaps
555 	calc_nodecaps_pass1(const EditorGameBase&, const FCoords&, bool consider_mobs = true) const;
556 	NodeCaps calc_nodecaps_pass2(const EditorGameBase&,
557 	                             const FCoords&,
558 	                             bool consider_mobs = true,
559 	                             NodeCaps initcaps = CAPS_NONE) const;
560 	void check_neighbour_heights(FCoords, uint32_t& radius);
561 	int calc_buildsize(const EditorGameBase&,
562 	                   const FCoords& f,
563 	                   bool avoidnature,
564 	                   bool* ismine = nullptr,
565 	                   bool consider_mobs = true,
566 	                   NodeCaps initcaps = CAPS_NONE) const;
567 	bool is_cycle_connected(const FCoords& start, uint32_t length, const WalkingDir* dirs) const;
568 	template <typename functorT>
569 	void
570 	find_reachable(const EditorGameBase&, const Area<FCoords>&, const CheckStep&, functorT&) const;
571 	template <typename functorT>
572 	void find(const EditorGameBase&, const Area<FCoords>&, functorT&) const;
573 
574 	/// # of players this map supports (!= Game's number of players!)
575 	PlayerNumber nrplayers_;
576 	ScenarioTypes scenario_types_;  // whether the map is playable as scenario
577 
578 	int16_t width_;
579 	int16_t height_;
580 	std::string filename_;
581 	std::string author_;
582 	std::string name_;
583 	std::string description_;
584 	std::string hint_;
585 	std::string background_;
586 	Tags tags_;
587 	std::vector<SuggestedTeamLineup> suggested_teams_;
588 
589 	std::vector<Coords> starting_pos_;  //  players' starting positions
590 
591 	std::unique_ptr<Field[]> fields_;
592 
593 	std::unique_ptr<PathfieldManager> pathfieldmgr_;
594 	std::vector<std::string> scenario_tribes_;
595 	std::vector<std::string> scenario_names_;
596 	std::vector<std::string> scenario_ais_;
597 	std::vector<bool> scenario_closeables_;
598 
599 	// The map file as a filesystem.
600 	std::unique_ptr<FileSystem> filesystem_;
601 
602 	PortSpacesSet port_spaces_;
603 	bool allows_seafaring_;
604 
605 	uint32_t waterway_max_length_;
606 
607 	Objectives objectives_;
608 
609 	// Fields that are important for the player to own in a win condition
610 	std::set<FCoords> valuable_fields_;
611 
612 	MapVersion map_version_;
613 };
614 
615 /*
616 ==============================================================================
617 
618 Field arithmetics
619 
620 ==============================================================================
621 */
622 
get_index(const Coords & c,int16_t const width)623 inline MapIndex Map::get_index(const Coords& c, int16_t const width) {
624 	assert(0 < width);
625 	assert(0 <= c.x);
626 	assert(c.x < width);
627 	assert(0 <= c.y);
628 	return c.y * width + c.x;
629 }
630 
get_index(const Coords & c)631 inline MapIndex Map::get_index(const Coords& c) const {
632 	return get_index(c, width_);
633 }
634 
635 inline Field& Map::operator[](MapIndex const i) const {
636 	return fields_[i];
637 }
638 inline Field& Map::operator[](const Coords& c) const {
639 	return operator[](get_index(c, width_));
640 }
641 
get_fcoords(const Coords & c)642 inline FCoords Map::get_fcoords(const Coords& c) const {
643 	return FCoords(c, &operator[](c));
644 }
645 
normalize_coords(Coords & c)646 inline void Map::normalize_coords(Coords& c) const {
647 	normalize_coords(c, width_, height_);
648 }
649 
normalize_coords(Coords & c,int16_t w,int16_t h)650 inline void Map::normalize_coords(Coords& c, int16_t w, int16_t h) {
651 	while (c.x < 0) {
652 		c.x += w;
653 	}
654 	while (c.x >= w) {
655 		c.x -= w;
656 	}
657 	while (c.y < 0) {
658 		c.y += h;
659 	}
660 	while (c.y >= h) {
661 		c.y -= h;
662 	}
663 }
664 
665 /**
666  * Calculate the field coordates from the pointer
667  */
get_fcoords(Field & f)668 inline FCoords Map::get_fcoords(Field& f) const {
669 	const int32_t i = &f - fields_.get();
670 	return FCoords(Coords(i % width_, i / width_), &f);
671 }
get_coords(Field & f,Coords & c)672 inline void Map::get_coords(Field& f, Coords& c) const {
673 	c = get_fcoords(f);
674 }
675 
676 /** get_ln, get_rn, get_tln, get_trn, get_bln, get_brn
677  *
678  * Calculate the coordinates and Field pointer of a neighboring field.
679  * Assume input coordinates are valid.
680  *
681  * Note: Input coordinates are passed as value because we have to allow
682  *       usage get_XXn(foo, &foo).
683  */
get_ln(const Coords & f,Coords * const o)684 inline void Map::get_ln(const Coords& f, Coords* const o) const {
685 	assert(0 <= f.x);
686 	assert(f.x < width_);
687 	assert(0 <= f.y);
688 	assert(f.y < height_);
689 	o->y = f.y;
690 	o->x = (f.x ? f.x : width_) - 1;
691 	assert(0 <= o->x);
692 	assert(0 <= o->y);
693 	assert(o->x < width_);
694 	assert(o->y < height_);
695 }
696 
get_ln(const FCoords & f,FCoords * const o)697 inline void Map::get_ln(const FCoords& f, FCoords* const o) const {
698 	assert(0 <= f.x);
699 	assert(f.x < width_);
700 	assert(0 <= f.y);
701 	assert(f.y < height_);
702 	assert(fields_.get() <= f.field);
703 	assert(f.field < fields_.get() + max_index());
704 	o->y = f.y;
705 	o->x = f.x - 1;
706 	o->field = f.field - 1;
707 	if (o->x == -1) {
708 		o->x = width_ - 1;
709 		o->field += width_;
710 	}
711 	assert(0 <= o->x);
712 	assert(o->x < width_);
713 	assert(0 <= o->y);
714 	assert(o->y < height_);
715 	assert(fields_.get() <= o->field);
716 	assert(o->field < fields_.get() + max_index());
717 }
l_n(const Coords & f)718 inline Coords Map::l_n(const Coords& f) const {
719 	assert(0 <= f.x);
720 	assert(f.x < width_);
721 	assert(0 <= f.y);
722 	assert(f.y < height_);
723 	Coords result(f.x - 1, f.y);
724 	if (result.x == -1)
725 		result.x = width_ - 1;
726 	assert(0 <= result.x);
727 	assert(result.x < width_);
728 	assert(0 <= result.y);
729 	assert(result.y < height_);
730 	return result;
731 }
l_n(const FCoords & f)732 inline FCoords Map::l_n(const FCoords& f) const {
733 	assert(0 <= f.x);
734 	assert(f.x < width_);
735 	assert(0 <= f.y);
736 	assert(f.y < height_);
737 	assert(fields_.get() <= f.field);
738 	assert(f.field < fields_.get() + max_index());
739 	FCoords result(Coords(f.x - 1, f.y), f.field - 1);
740 	if (result.x == -1) {
741 		result.x = width_ - 1;
742 		result.field += width_;
743 	}
744 	assert(0 <= result.x);
745 	assert(result.x < width_);
746 	assert(0 <= result.y);
747 	assert(result.y < height_);
748 	assert(fields_.get() <= result.field);
749 	assert(result.field < fields_.get() + max_index());
750 	return result;
751 }
752 
get_rn(const Coords & f,Coords * const o)753 inline void Map::get_rn(const Coords& f, Coords* const o) const {
754 	assert(0 <= f.x);
755 	assert(f.x < width_);
756 	assert(0 <= f.y);
757 	assert(f.y < height_);
758 	o->y = f.y;
759 	o->x = f.x + 1;
760 	if (o->x == width_)
761 		o->x = 0;
762 	assert(0 <= o->x);
763 	assert(o->x < width_);
764 	assert(0 <= o->y);
765 	assert(o->y < height_);
766 }
767 
get_rn(const FCoords & f,FCoords * const o)768 inline void Map::get_rn(const FCoords& f, FCoords* const o) const {
769 	assert(0 <= f.x);
770 	assert(f.x < width_);
771 	assert(0 <= f.y);
772 	assert(f.y < height_);
773 	assert(fields_.get() <= f.field);
774 	assert(f.field < fields_.get() + max_index());
775 	o->y = f.y;
776 	o->x = f.x + 1;
777 	o->field = f.field + 1;
778 	if (o->x == width_) {
779 		o->x = 0;
780 		o->field -= width_;
781 	}
782 	assert(0 <= o->x);
783 	assert(o->x < width_);
784 	assert(0 <= o->y);
785 	assert(o->y < height_);
786 	assert(fields_.get() <= o->field);
787 	assert(o->field < fields_.get() + max_index());
788 }
r_n(const Coords & f)789 inline Coords Map::r_n(const Coords& f) const {
790 	assert(0 <= f.x);
791 	assert(f.x < width_);
792 	assert(0 <= f.y);
793 	assert(f.y < height_);
794 	Coords result(f.x + 1, f.y);
795 	if (result.x == width_)
796 		result.x = 0;
797 	assert(0 <= result.x);
798 	assert(result.x < width_);
799 	assert(0 <= result.y);
800 	assert(result.y < height_);
801 	return result;
802 }
r_n(const FCoords & f)803 inline FCoords Map::r_n(const FCoords& f) const {
804 	assert(0 <= f.x);
805 	assert(f.x < width_);
806 	assert(0 <= f.y);
807 	assert(f.y < height_);
808 	assert(fields_.get() <= f.field);
809 	assert(f.field < fields_.get() + max_index());
810 	FCoords result(Coords(f.x + 1, f.y), f.field + 1);
811 	if (result.x == width_) {
812 		result.x = 0;
813 		result.field -= width_;
814 	}
815 	assert(0 <= result.x);
816 	assert(result.x < width_);
817 	assert(0 <= result.y);
818 	assert(result.y < height_);
819 	assert(fields_.get() <= result.field);
820 	assert(result.field < fields_.get() + max_index());
821 	return result;
822 }
823 
824 // top-left: even: -1/-1  odd: 0/-1
get_tln(const Coords & f,Coords * const o)825 inline void Map::get_tln(const Coords& f, Coords* const o) const {
826 	assert(0 <= f.x);
827 	assert(f.x < width_);
828 	assert(0 <= f.y);
829 	assert(f.y < height_);
830 	o->y = f.y - 1;
831 	o->x = f.x;
832 	if (o->y & 1) {
833 		if (o->y == -1)
834 			o->y = height_ - 1;
835 		o->x = (o->x ? o->x : width_) - 1;
836 	}
837 	assert(0 <= o->x);
838 	assert(o->x < width_);
839 	assert(0 <= o->y);
840 	assert(o->y < height_);
841 }
842 
get_tln(const FCoords & f,FCoords * const o)843 inline void Map::get_tln(const FCoords& f, FCoords* const o) const {
844 	assert(0 <= f.x);
845 	assert(f.x < width_);
846 	assert(0 <= f.y);
847 	assert(f.y < height_);
848 	assert(fields_.get() <= f.field);
849 	assert(f.field < fields_.get() + max_index());
850 	o->y = f.y - 1;
851 	o->x = f.x;
852 	o->field = f.field - width_;
853 	if (o->y & 1) {
854 		if (o->y == -1) {
855 			o->y = height_ - 1;
856 			o->field += max_index();
857 		}
858 		--o->x;
859 		--o->field;
860 		if (o->x == -1) {
861 			o->x = width_ - 1;
862 			o->field += width_;
863 		}
864 	}
865 	assert(0 <= o->x);
866 	assert(o->x < width_);
867 	assert(0 <= o->y);
868 	assert(o->y < height_);
869 	assert(fields_.get() <= o->field);
870 	assert(o->field < fields_.get() + max_index());
871 }
tl_n(const Coords & f)872 inline Coords Map::tl_n(const Coords& f) const {
873 	assert(0 <= f.x);
874 	assert(f.x < width_);
875 	assert(0 <= f.y);
876 	assert(f.y < height_);
877 	Coords result(f.x, f.y - 1);
878 	if (result.y & 1) {
879 		if (result.y == -1)
880 			result.y = height_ - 1;
881 		--result.x;
882 		if (result.x == -1)
883 			result.x = width_ - 1;
884 	}
885 	assert(0 <= result.x);
886 	assert(result.x < width_);
887 	assert(0 <= result.y);
888 	assert(result.y < height_);
889 	return result;
890 }
tl_n(const FCoords & f)891 inline FCoords Map::tl_n(const FCoords& f) const {
892 	assert(0 <= f.x);
893 	assert(f.x < width_);
894 	assert(0 <= f.y);
895 	assert(f.y < height_);
896 	assert(fields_.get() <= f.field);
897 	assert(f.field < fields_.get() + max_index());
898 	FCoords result(Coords(f.x, f.y - 1), f.field - width_);
899 	if (result.y & 1) {
900 		if (result.y == -1) {
901 			result.y = height_ - 1;
902 			result.field += max_index();
903 		}
904 		--result.x;
905 		--result.field;
906 		if (result.x == -1) {
907 			result.x = width_ - 1;
908 			result.field += width_;
909 		}
910 	}
911 	assert(0 <= result.x);
912 	assert(result.x < width_);
913 	assert(0 <= result.y);
914 	assert(result.y < height_);
915 	assert(fields_.get() <= result.field);
916 	assert(result.field < fields_.get() + max_index());
917 	return result;
918 }
919 
920 // top-right: even: 0/-1  odd: +1/-1
get_trn(const Coords & f,Coords * const o)921 inline void Map::get_trn(const Coords& f, Coords* const o) const {
922 	assert(0 <= f.x);
923 	assert(f.x < width_);
924 	assert(0 <= f.y);
925 	assert(f.y < height_);
926 	o->x = f.x;
927 	if (f.y & 1) {
928 		++o->x;
929 		if (o->x == width_)
930 			o->x = 0;
931 	}
932 	o->y = (f.y ? f.y : height_) - 1;
933 	assert(0 <= o->x);
934 	assert(o->x < width_);
935 	assert(0 <= o->y);
936 	assert(o->y < height_);
937 }
938 
get_trn(const FCoords & f,FCoords * const o)939 inline void Map::get_trn(const FCoords& f, FCoords* const o) const {
940 	assert(0 <= f.x);
941 	assert(f.x < width_);
942 	assert(0 <= f.y);
943 	assert(f.y < height_);
944 	assert(fields_.get() <= f.field);
945 	assert(f.field < fields_.get() + max_index());
946 	o->x = f.x;
947 	o->field = f.field - width_;
948 	if (f.y & 1) {
949 		++o->x;
950 		++o->field;
951 		if (o->x == width_) {
952 			o->x = 0;
953 			o->field -= width_;
954 		}
955 	}
956 	o->y = f.y - 1;
957 	if (o->y == -1) {
958 		o->y = height_ - 1;
959 		o->field += max_index();
960 	}
961 	assert(0 <= o->x);
962 	assert(o->x < width_);
963 	assert(0 <= o->y);
964 	assert(o->y < height_);
965 	assert(fields_.get() <= o->field);
966 	assert(o->field < fields_.get() + max_index());
967 }
tr_n(const Coords & f)968 inline Coords Map::tr_n(const Coords& f) const {
969 	assert(0 <= f.x);
970 	assert(f.x < width_);
971 	assert(0 <= f.y);
972 	assert(f.y < height_);
973 	Coords result(f.x, f.y - 1);
974 	if (f.y & 1) {
975 		++result.x;
976 		if (result.x == width_)
977 			result.x = 0;
978 	}
979 	if (result.y == -1)
980 		result.y = height_ - 1;
981 	assert(0 <= result.x);
982 	assert(result.x < width_);
983 	assert(0 <= result.y);
984 	assert(result.y < height_);
985 	return result;
986 }
tr_n(const FCoords & f)987 inline FCoords Map::tr_n(const FCoords& f) const {
988 	assert(0 <= f.x);
989 	assert(f.x < width_);
990 	assert(0 <= f.y);
991 	assert(f.y < height_);
992 	assert(fields_.get() <= f.field);
993 	assert(f.field < fields_.get() + max_index());
994 	FCoords result(Coords(f.x, f.y - 1), f.field - width_);
995 	if (f.y & 1) {
996 		++result.x;
997 		++result.field;
998 		if (result.x == width_) {
999 			result.x = 0;
1000 			result.field -= width_;
1001 		}
1002 	}
1003 	if (result.y == -1) {
1004 		result.y = height_ - 1;
1005 		result.field += max_index();
1006 	}
1007 	assert(0 <= result.x);
1008 	assert(result.x < width_);
1009 	assert(0 <= result.y);
1010 	assert(result.y < height_);
1011 	assert(fields_.get() <= result.field);
1012 	assert(result.field < fields_.get() + max_index());
1013 	return result;
1014 }
1015 
1016 // bottom-left: even: -1/+1  odd: 0/+1
get_bln(const Coords & f,Coords * const o)1017 inline void Map::get_bln(const Coords& f, Coords* const o) const {
1018 	assert(0 <= f.x);
1019 	assert(f.x < width_);
1020 	assert(0 <= f.y);
1021 	assert(f.y < height_);
1022 	o->y = f.y + 1;
1023 	o->x = f.x;
1024 	if (o->y == height_)
1025 		o->y = 0;
1026 	if (o->y & 1)
1027 		o->x = (o->x ? o->x : width_) - 1;
1028 	assert(0 <= o->x);
1029 	assert(o->x < width_);
1030 	assert(0 <= o->y);
1031 	assert(o->y < height_);
1032 }
1033 
get_bln(const FCoords & f,FCoords * const o)1034 inline void Map::get_bln(const FCoords& f, FCoords* const o) const {
1035 	assert(0 <= f.x);
1036 	assert(f.x < width_);
1037 	assert(0 <= f.y);
1038 	assert(f.y < height_);
1039 	assert(fields_.get() <= f.field);
1040 	assert(f.field < fields_.get() + max_index());
1041 	o->y = f.y + 1;
1042 	o->x = f.x;
1043 	o->field = f.field + width_;
1044 	if (o->y == height_) {
1045 		o->y = 0;
1046 		o->field -= max_index();
1047 	}
1048 	if (o->y & 1) {
1049 		--o->x;
1050 		--o->field;
1051 		if (o->x == -1) {
1052 			o->x = width_ - 1;
1053 			o->field += width_;
1054 		}
1055 	}
1056 	assert(0 <= o->x);
1057 	assert(o->x < width_);
1058 	assert(0 <= o->y);
1059 	assert(o->y < height_);
1060 	assert(fields_.get() <= o->field);
1061 	assert(o->field < fields_.get() + max_index());
1062 }
bl_n(const Coords & f)1063 inline Coords Map::bl_n(const Coords& f) const {
1064 	assert(0 <= f.x);
1065 	assert(f.x < width_);
1066 	assert(0 <= f.y);
1067 	assert(f.y < height_);
1068 	Coords result(f.x, f.y + 1);
1069 	if (result.y == height_)
1070 		result.y = 0;
1071 	if (result.y & 1) {
1072 		--result.x;
1073 		if (result.x == -1)
1074 			result.x = width_ - 1;
1075 	}
1076 	assert(0 <= result.x);
1077 	assert(result.x < width_);
1078 	assert(0 <= result.y);
1079 	assert(result.y < height_);
1080 	return result;
1081 }
bl_n(const FCoords & f)1082 inline FCoords Map::bl_n(const FCoords& f) const {
1083 	assert(0 <= f.x);
1084 	assert(f.x < width_);
1085 	assert(0 <= f.y);
1086 	assert(f.y < height_);
1087 	assert(fields_.get() <= f.field);
1088 	assert(f.field < fields_.get() + max_index());
1089 	FCoords result(Coords(f.x, f.y + 1), f.field + width_);
1090 	if (result.y == height_) {
1091 		result.y = 0;
1092 		result.field -= max_index();
1093 	}
1094 	if (result.y & 1) {
1095 		--result.x;
1096 		--result.field;
1097 		if (result.x == -1) {
1098 			result.x = width_ - 1;
1099 			result.field += width_;
1100 		}
1101 	}
1102 	assert(0 <= result.x);
1103 	assert(result.x < width_);
1104 	assert(0 <= result.y);
1105 	assert(result.y < height_);
1106 	assert(fields_.get() <= result.field);
1107 	assert(result.field < fields_.get() + max_index());
1108 	return result;
1109 }
1110 
1111 // bottom-right: even: 0/+1  odd: +1/+1
get_brn(const Coords & f,Coords * const o)1112 inline void Map::get_brn(const Coords& f, Coords* const o) const {
1113 	assert(0 <= f.x);
1114 	assert(f.x < width_);
1115 	assert(0 <= f.y);
1116 	assert(f.y < height_);
1117 	o->x = f.x;
1118 	if (f.y & 1) {
1119 		++o->x;
1120 		if (o->x == width_)
1121 			o->x = 0;
1122 	}
1123 	o->y = f.y + 1;
1124 	if (o->y == height_)
1125 		o->y = 0;
1126 	assert(0 <= o->x);
1127 	assert(o->x < width_);
1128 	assert(0 <= o->y);
1129 	assert(o->y < height_);
1130 }
1131 
get_brn(const FCoords & f,FCoords * const o)1132 inline void Map::get_brn(const FCoords& f, FCoords* const o) const {
1133 	assert(0 <= f.x);
1134 	assert(f.x < width_);
1135 	assert(0 <= f.y);
1136 	assert(f.y < height_);
1137 	assert(fields_.get() <= f.field);
1138 	assert(f.field < fields_.get() + max_index());
1139 	o->x = f.x;
1140 	o->field = f.field + width_;
1141 	if (f.y & 1) {
1142 		++o->x;
1143 		++o->field;
1144 		if (o->x == width_) {
1145 			o->x = 0;
1146 			o->field -= width_;
1147 		}
1148 	}
1149 	o->y = f.y + 1;
1150 	if (o->y == height_) {
1151 		o->y = 0;
1152 		o->field -= max_index();
1153 	}
1154 	assert(0 <= o->x);
1155 	assert(o->x < width_);
1156 	assert(0 <= o->y);
1157 	assert(o->y < height_);
1158 	assert(fields_.get() <= o->field);
1159 	assert(o->field < fields_.get() + max_index());
1160 }
br_n(const Coords & f)1161 inline Coords Map::br_n(const Coords& f) const {
1162 	assert(0 <= f.x);
1163 	assert(f.x < width_);
1164 	assert(0 <= f.y);
1165 	assert(f.y < height_);
1166 	Coords result(f.x, f.y + 1);
1167 	if (f.y & 1) {
1168 		++result.x;
1169 		if (result.x == width_)
1170 			result.x = 0;
1171 	}
1172 	if (result.y == height_)
1173 		result.y = 0;
1174 	assert(0 <= result.x);
1175 	assert(result.x < width_);
1176 	assert(0 <= result.y);
1177 	assert(result.y < height_);
1178 	return result;
1179 }
br_n(const FCoords & f)1180 inline FCoords Map::br_n(const FCoords& f) const {
1181 	assert(0 <= f.x);
1182 	assert(f.x < width_);
1183 	assert(0 <= f.y);
1184 	assert(f.y < height_);
1185 	assert(fields_.get() <= f.field);
1186 	assert(f.field < fields_.get() + max_index());
1187 	FCoords result(Coords(f.x, f.y + 1), f.field + width_);
1188 	if (f.y & 1) {
1189 		++result.x;
1190 		++result.field;
1191 		if (result.x == width_) {
1192 			result.x = 0;
1193 			result.field -= width_;
1194 		}
1195 	}
1196 	if (result.y == height_) {
1197 		result.y = 0;
1198 		result.field -= max_index();
1199 	}
1200 	assert(0 <= result.x);
1201 	assert(result.x < width_);
1202 	assert(0 <= result.y);
1203 	assert(result.y < height_);
1204 	assert(fields_.get() <= result.field);
1205 	assert(result.field < fields_.get() + max_index());
1206 	return result;
1207 }
1208 
get_neighbour(const FCoords & f,const Direction dir)1209 inline FCoords Map::get_neighbour(const FCoords& f, const Direction dir) const {
1210 	switch (dir) {
1211 	case WALK_NW:
1212 		return tl_n(f);
1213 	case WALK_NE:
1214 		return tr_n(f);
1215 	case WALK_E:
1216 		return r_n(f);
1217 	case WALK_SE:
1218 		return br_n(f);
1219 	case WALK_SW:
1220 		return bl_n(f);
1221 	case WALK_W:
1222 		return l_n(f);
1223 	default:
1224 		NEVER_HERE();
1225 	}
1226 }
1227 
move_r(const int16_t mapwidth,FCoords & f)1228 inline void move_r(const int16_t mapwidth, FCoords& f) {
1229 	assert(f.x < mapwidth);
1230 	++f.x;
1231 	++f.field;
1232 	if (f.x == mapwidth) {
1233 		f.x = 0;
1234 		f.field -= mapwidth;
1235 	}
1236 	assert(f.x < mapwidth);
1237 }
1238 
move_r(int16_t const mapwidth,FCoords & f,MapIndex & i)1239 inline void move_r(int16_t const mapwidth, FCoords& f, MapIndex& i) {
1240 	assert(f.x < mapwidth);
1241 	++f.x;
1242 	++f.field;
1243 	++i;
1244 	if (f.x == mapwidth) {
1245 		f.x = 0;
1246 		f.field -= mapwidth;
1247 		i -= mapwidth;
1248 	}
1249 	assert(f.x < mapwidth);
1250 }
1251 
1252 #define iterate_Map_FCoords(map, extent, fc)                                                       \
1253 	for (Widelands::FCoords fc = (map).get_fcoords(Widelands::Coords(0, 0));                        \
1254 	     fc.y < static_cast<int16_t>(extent.h); ++fc.y)                                             \
1255 		for (fc.x = 0; fc.x < static_cast<int16_t>(extent.w); ++fc.x, ++fc.field)
1256 }  // namespace Widelands
1257 
1258 #endif  // end of include guard: WL_LOGIC_MAP_H
1259