1 /*
2  * Copyright (C) 2008-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_CHECKSTEP_H
21 #define WL_LOGIC_MAP_OBJECTS_CHECKSTEP_H
22 
23 #include <memory>
24 #include <set>
25 #include <vector>
26 
27 #include "logic/widelands_geometry.h"
28 
29 namespace Widelands {
30 
31 class EditorGameBase;
32 class Map;
33 class Player;
34 
35 struct CheckStep {
36 	enum StepId {
37 		stepNormal,  //  normal step treatment
38 		stepFirst,   //  first step of a path
39 		stepLast,    //  last step of a path
40 	};
41 
42 private:
43 	struct BaseCapsule {
~BaseCapsuleCheckStep::BaseCapsule44 		virtual ~BaseCapsule() {
45 		}
46 		virtual bool allowed(
47 		   const Map&, const FCoords& start, const FCoords& end, int32_t dir, StepId id) const = 0;
48 		virtual bool reachable_dest(const Map&, const FCoords& dest) const = 0;
49 	};
50 	template <typename T> struct Capsule : public BaseCapsule {
CapsuleCheckStep::Capsule51 		Capsule(const T& init_op) : op(init_op) {
52 		}
53 
allowedCheckStep::Capsule54 		bool allowed(const Map& map,
55 		             const FCoords& start,
56 		             const FCoords& end,
57 		             int32_t const dir,
58 		             StepId const id) const override {
59 			return op.allowed(map, start, end, dir, id);
60 		}
reachable_destCheckStep::Capsule61 		bool reachable_dest(const Map& map, const FCoords& dest) const override {
62 			return op.reachable_dest(map, dest);
63 		}
64 
65 		const T op;
66 	};
67 
68 	std::shared_ptr<BaseCapsule> capsule;
69 
70 	static const CheckStep& always_false();
71 
72 public:
73 	CheckStep();
74 
CheckStepCheckStep75 	template <typename T> CheckStep(const T& op) : capsule(new Capsule<T>(op)) {
76 	}
77 
78 	/**
79 	 * \return \c true true if moving from start to end (single step in the given
80 	 * direction) is allowed.
81 	 */
allowedCheckStep82 	bool allowed(const Map& map,
83 	             const FCoords& start,
84 	             const FCoords& end,
85 	             int32_t const dir,
86 	             StepId const id) const {
87 		return capsule->allowed(map, start, end, dir, id);
88 	}
89 
90 	/**
91 	 * \return \c true if the destination field can be reached at all
92 	 * (e.g. return false for land-based bobs when dest is in water).
93 	 */
reachable_destCheckStep94 	bool reachable_dest(const Map& map, const FCoords& dest) const {
95 		return capsule->reachable_dest(map, dest);
96 	}
97 };
98 
99 /**
100  * CheckStep implementation that returns the logic and of all
101  * sub-implementations that have been added via \ref add().
102  */
103 struct CheckStepAnd {
104 	void add(const CheckStep& sub);
105 
106 	bool allowed(const Map&,
107 	             const FCoords& start,
108 	             const FCoords& end,
109 	             int32_t dir,
110 	             CheckStep::StepId id) const;
111 	bool reachable_dest(const Map&, const FCoords& dest) const;
112 
113 private:
114 	std::vector<CheckStep> subs;
115 };
116 
117 /**
118  * Implements the default step checking behaviours that should be used for all
119  * normal bobs.
120  *
121  * Simply check whether the movecaps are matching (basic exceptions for water
122  * bobs moving onto the shore).
123  */
124 struct CheckStepDefault {
CheckStepDefaultCheckStepDefault125 	CheckStepDefault(uint8_t const movecaps) : movecaps_(movecaps) {
126 	}
127 
128 	bool allowed(
129 	   const Map&, const FCoords& start, const FCoords& end, int32_t dir, CheckStep::StepId) const;
130 	bool reachable_dest(const Map&, const FCoords& dest) const;
131 
132 private:
133 	uint8_t movecaps_;
134 };
135 
136 /**
137  * Implements the step checking behaviour for ferries.
138  *
139  * A ferry can travel on an edge if and only if both adjacent triangles are water.
140  */
141 struct CheckStepFerry {
CheckStepFerryCheckStepFerry142 	CheckStepFerry(const EditorGameBase& egbase) : egbase_(egbase) {
143 	}
144 
145 	bool allowed(
146 	   const Map&, const FCoords& start, const FCoords& end, int32_t dir, CheckStep::StepId) const;
147 	bool reachable_dest(const Map&, const FCoords& dest) const;
148 
149 private:
150 	const EditorGameBase& egbase_;
151 };
152 
153 /**
154  * Implements the default step checking behaviours with one exception: we can
155  * move from a walkable field onto an unwalkable one.
156  * If onlyend is true, we can only do this on the final step.
157  */
158 struct CheckStepWalkOn {
CheckStepWalkOnCheckStepWalkOn159 	CheckStepWalkOn(uint8_t const movecaps, bool const onlyend)
160 	   : movecaps_(movecaps), onlyend_(onlyend) {
161 	}
162 
163 	bool allowed(
164 	   const Map&, const FCoords& start, const FCoords& end, int32_t dir, CheckStep::StepId) const;
165 	bool reachable_dest(const Map&, FCoords dest) const;
166 
167 private:
168 	uint8_t movecaps_;
169 	bool onlyend_;
170 };
171 
172 /**
173  * Implements the step checking behaviour for road building.
174  *
175  * player is the player who is building the road.
176  * movecaps are the capabilities with which the road is to be built (swimming
177  * for boats, walking for normal roads).
178  */
179 struct CheckStepRoad {
CheckStepRoadCheckStepRoad180 	CheckStepRoad(const Player& player, uint8_t const movecaps)
181 	   : player_(player), movecaps_(movecaps) {
182 	}
183 
184 	bool allowed(
185 	   const Map&, const FCoords& start, const FCoords& end, int32_t dir, CheckStep::StepId) const;
186 	bool reachable_dest(const Map&, const FCoords& dest) const;
187 
188 private:
189 	const Player& player_;
190 	uint8_t movecaps_;
191 };
192 
193 /**
194  * A version of CheckStep that is limited to a set of allowed locations. It
195  * only checks whether the target is an allowed location.
196  */
197 struct CheckStepLimited {
add_allowed_locationCheckStepLimited198 	void add_allowed_location(const Coords& c) {
199 		allowed_locations_.insert(c);
200 	}
201 	bool allowed(
202 	   const Map&, const FCoords& start, const FCoords& end, int32_t dir, CheckStep::StepId) const;
203 	bool reachable_dest(const Map&, FCoords dest) const;
204 
205 private:
206 	// The ordering of the set does not matter, as long as it is system
207 	// independent (for parallel simulation).
208 	// The only thing that matters is whether a location is in the set.
209 	std::set<Coords> allowed_locations_;
210 };
211 }  // namespace Widelands
212 
213 #endif  // end of include guard: WL_LOGIC_MAP_OBJECTS_CHECKSTEP_H
214