Line data Source code
1 : /* Copyright (C) 2022 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #ifndef INCLUDED_ICMPOBSTRUCTIONMANAGER
19 : #define INCLUDED_ICMPOBSTRUCTIONMANAGER
20 :
21 : #include "simulation2/system/Interface.h"
22 :
23 : #include "maths/FixedVector2D.h"
24 : #include "simulation2/helpers/Position.h"
25 :
26 : #include <vector>
27 :
28 : class IObstructionTestFilter;
29 : template<typename T>
30 : class Grid;
31 : struct GridUpdateInformation;
32 : using NavcellData = u16;
33 : class PathfinderPassability;
34 :
35 :
36 : /**
37 : * Obstruction manager: provides efficient spatial queries over objects in the world.
38 : *
39 : * The class deals with two types of shape:
40 : * "static" shapes, typically representing buildings, which are rectangles with a given
41 : * width and height and angle;
42 : * and "unit" shapes, representing units that can move around the world, which have a
43 : * radius and no rotation. (Units sometimes act as axis-aligned squares, sometimes
44 : * as approximately circles, due to the algorithm used by the short pathfinder.)
45 : *
46 : * Other classes (particularly ICmpObstruction) register shapes with this interface
47 : * and keep them updated.
48 : *
49 : * The @c Test functions provide exact collision tests.
50 : * The edge of a shape counts as 'inside' the shape, for the purpose of collisions.
51 : * The functions accept an IObstructionTestFilter argument, which can restrict the
52 : * set of shapes that are counted as collisions.
53 : *
54 : * Units can be marked as either moving or stationary, which simply determines whether
55 : * certain filters include or exclude them.
56 : *
57 : * The @c Rasterize function approximates the current set of shapes onto a 2D grid,
58 : * for use with tile-based pathfinding.
59 : */
60 24 : class ICmpObstructionManager : public IComponent
61 : {
62 : public:
63 : /**
64 : * Standard representation for all types of shapes, for use with geometry processing code.
65 : */
66 67 : struct ObstructionSquare
67 : {
68 : entity_pos_t x, z; // position of center
69 : CFixedVector2D u, v; // 'horizontal' and 'vertical' orthogonal unit vectors, representing orientation
70 : entity_pos_t hw, hh; // half width, half height of square
71 : };
72 :
73 : /**
74 : * External identifiers for shapes.
75 : * (This is a struct rather than a raw u32 for type-safety.)
76 : */
77 : struct tag_t
78 : {
79 3 : tag_t() : n(0) {}
80 130 : explicit tag_t(u32 n) : n(n) {}
81 10 : bool valid() const { return n != 0; }
82 :
83 : u32 n;
84 : };
85 :
86 : /**
87 : * Boolean flags affecting the obstruction behaviour of a shape.
88 : */
89 : enum EFlags
90 : {
91 : FLAG_BLOCK_MOVEMENT = (1 << 0), // prevents units moving through this shape
92 : FLAG_BLOCK_FOUNDATION = (1 << 1), // prevents foundations being placed on this shape
93 : FLAG_BLOCK_CONSTRUCTION = (1 << 2), // prevents buildings being constructed on this shape
94 : FLAG_BLOCK_PATHFINDING = (1 << 3), // prevents the tile pathfinder choosing paths through this shape
95 : FLAG_MOVING = (1 << 4), // reserved for unitMotion - see usage there.
96 : FLAG_DELETE_UPON_CONSTRUCTION = (1 << 5) // this entity is deleted when construction of a building placed on top of this entity starts
97 : };
98 :
99 : /**
100 : * Bitmask of EFlag values.
101 : */
102 : typedef u8 flags_t;
103 :
104 : /**
105 : * Set the bounds of the world.
106 : * Any point outside the bounds is considered obstructed.
107 : * @param x0,z0,x1,z1 Coordinates of the corners of the world
108 : */
109 : virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) = 0;
110 :
111 : /**
112 : * Register a static shape.
113 : *
114 : * @param ent entity ID associated with this shape (or INVALID_ENTITY if none)
115 : * @param x,z coordinates of center, in world space
116 : * @param a angle of rotation (clockwise from +Z direction)
117 : * @param w width (size along X axis)
118 : * @param h height (size along Z axis)
119 : * @param flags a set of EFlags values
120 : * @param group primary control group of the shape. Must be a valid control group ID.
121 : * @param group2 Optional; secondary control group of the shape. Defaults to INVALID_ENTITY.
122 : * @return a valid tag for manipulating the shape
123 : * @see StaticShape
124 : */
125 : virtual tag_t AddStaticShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_angle_t a,
126 : entity_pos_t w, entity_pos_t h, flags_t flags, entity_id_t group, entity_id_t group2 = INVALID_ENTITY) = 0;
127 :
128 : /**
129 : * Register a unit shape.
130 : *
131 : * @param ent entity ID associated with this shape (or INVALID_ENTITY if none)
132 : * @param x,z coordinates of center, in world space
133 : * @param clearance pathfinding clearance of the unit (works as a radius)
134 : * @param flags a set of EFlags values
135 : * @param group control group (typically the owner entity, or a formation controller entity
136 : * - units ignore collisions with others in the same group)
137 : * @return a valid tag for manipulating the shape
138 : * @see UnitShape
139 : */
140 : virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_pos_t clearance,
141 : flags_t flags, entity_id_t group) = 0;
142 :
143 : /**
144 : * Adjust the position and angle of an existing shape.
145 : * @param tag tag of shape (must be valid)
146 : * @param x X coordinate of center, in world space
147 : * @param z Z coordinate of center, in world space
148 : * @param a angle of rotation (clockwise from +Z direction); ignored for unit shapes
149 : */
150 : virtual void MoveShape(tag_t tag, entity_pos_t x, entity_pos_t z, entity_angle_t a) = 0;
151 :
152 : /**
153 : * Set whether a unit shape is moving or stationary.
154 : * @param tag tag of shape (must be valid and a unit shape)
155 : * @param moving whether the unit is currently moving through the world or is stationary
156 : */
157 : virtual void SetUnitMovingFlag(tag_t tag, bool moving) = 0;
158 :
159 : /**
160 : * Set the control group of a unit shape.
161 : * @param tag tag of shape (must be valid and a unit shape)
162 : * @param group control group entity ID
163 : */
164 : virtual void SetUnitControlGroup(tag_t tag, entity_id_t group) = 0;
165 :
166 : /**
167 : * Sets the control group of a static shape.
168 : * @param tag Tag of the shape to set the control group for. Must be a valid and static shape tag.
169 : * @param group Control group entity ID.
170 : */
171 : virtual void SetStaticControlGroup(tag_t tag, entity_id_t group, entity_id_t group2) = 0;
172 :
173 : /**
174 : * Remove an existing shape. The tag will be made invalid and must not be used after this.
175 : * @param tag tag of shape (must be valid)
176 : */
177 : virtual void RemoveShape(tag_t tag) = 0;
178 :
179 : /**
180 : * Returns the distance from the obstruction to the point (px, pz), or -1 if the entity is out of the world.
181 : */
182 : virtual fixed DistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const = 0;
183 :
184 : /**
185 : * Calculate the largest straight line distance between the entity and the point.
186 : */
187 : virtual fixed MaxDistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const = 0;
188 :
189 : /**
190 : * Calculate the shortest distance between the entity and the target.
191 : */
192 : virtual fixed DistanceToTarget(entity_id_t ent, entity_id_t target) const = 0;
193 :
194 : /**
195 : * Calculate the largest straight line distance between the entity and the target.
196 : */
197 : virtual fixed MaxDistanceToTarget(entity_id_t ent, entity_id_t target) const = 0;
198 :
199 : /**
200 : * Calculate the shortest straight line distance between the source and the target
201 : */
202 : virtual fixed DistanceBetweenShapes(const ObstructionSquare& source, const ObstructionSquare& target) const = 0;
203 :
204 : /**
205 : * Calculate the largest straight line distance between the source and the target
206 : */
207 : virtual fixed MaxDistanceBetweenShapes(const ObstructionSquare& source, const ObstructionSquare& target) const = 0;
208 :
209 : /**
210 : * Check if the given entity is in range of the other point given those parameters.
211 : * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE.
212 : */
213 : virtual bool IsInPointRange(entity_id_t ent, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0;
214 :
215 : /**
216 : * Check if the given entity is in range of the target given those parameters.
217 : * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE.
218 : */
219 : virtual bool IsInTargetRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0;
220 :
221 : /**
222 : * Check if the given entity is in parabolic range of the target given those parameters.
223 : * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE.
224 : */
225 : virtual bool IsInTargetParabolicRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t yOrigin, bool opposite) const = 0;
226 :
227 : /**
228 : * Check if the given point is in range of the other point given those parameters.
229 : * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE.
230 : */
231 : virtual bool IsPointInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange) const = 0;
232 :
233 : /**
234 : * Check if the given shape is in range of the target shape given those parameters.
235 : * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE.
236 : */
237 : virtual bool AreShapesInRange(const ObstructionSquare& source, const ObstructionSquare& target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0;
238 :
239 : /**
240 : * Collision test a flat-ended thick line against the current set of shapes.
241 : * The line caps extend by @p r beyond the end points.
242 : * Only intersections going from outside to inside a shape are counted.
243 : * @param filter filter to restrict the shapes that are counted
244 : * @param x0 X coordinate of line's first point
245 : * @param z0 Z coordinate of line's first point
246 : * @param x1 X coordinate of line's second point
247 : * @param z1 Z coordinate of line's second point
248 : * @param r radius (half width) of line
249 : * @param relaxClearanceForUnits whether unit-unit collisions should be more permissive.
250 : * @return true if there is a collision
251 : */
252 : virtual bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, bool relaxClearanceForUnits) const = 0;
253 :
254 : /**
255 : * Collision test a static square shape against the current set of shapes.
256 : * @param filter filter to restrict the shapes that are being tested against
257 : * @param x X coordinate of center
258 : * @param z Z coordinate of center
259 : * @param a angle of rotation (clockwise from +Z direction)
260 : * @param w width (size along X axis)
261 : * @param h height (size along Z axis)
262 : * @param out if non-NULL, all colliding shapes' entities will be added to this list
263 : * @return true if there is a collision
264 : */
265 : virtual bool TestStaticShape(const IObstructionTestFilter& filter,
266 : entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h,
267 : std::vector<entity_id_t>* out) const = 0;
268 :
269 : /**
270 : * Collision test a unit shape against the current set of registered shapes, and optionally writes a list of the colliding
271 : * shapes' entities to an output list.
272 : *
273 : * @param filter filter to restrict the shapes that are being tested against
274 : * @param x X coordinate of shape's center
275 : * @param z Z coordinate of shape's center
276 : * @param clearance clearance of the shape's unit
277 : * @param out if non-NULL, all colliding shapes' entities will be added to this list
278 : *
279 : * @return true if there is a collision
280 : */
281 : virtual bool TestUnitShape(const IObstructionTestFilter& filter,
282 : entity_pos_t x, entity_pos_t z, entity_pos_t clearance,
283 : std::vector<entity_id_t>* out) const = 0;
284 :
285 : /**
286 : * Convert the current set of shapes onto a navcell grid, for all passability classes contained in @p passClasses.
287 : * If @p fullUpdate is false, the function will only go through dirty shapes.
288 : * Shapes are expanded by the @p passClasses clearances, by ORing their masks onto the @p grid.
289 : */
290 : virtual void Rasterize(Grid<NavcellData>& grid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate) = 0;
291 :
292 : /**
293 : * Gets dirtiness information and resets it afterwards. Then it's the role of CCmpPathfinder
294 : * to pass the information to other components if needed. (AIs, etc.)
295 : * The return value is false if an update is unnecessary.
296 : */
297 : virtual void UpdateInformations(GridUpdateInformation& informations) = 0;
298 :
299 : /**
300 : * Find all the obstructions that are inside (or partially inside) the given range.
301 : * @param filter filter to restrict the shapes that are counted
302 : * @param x0 X coordinate of left edge of range
303 : * @param z0 Z coordinate of bottom edge of range
304 : * @param x1 X coordinate of right edge of range
305 : * @param z1 Z coordinate of top edge of range
306 : * @param squares output list of obstructions
307 : */
308 : virtual void GetObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const = 0;
309 : virtual void GetStaticObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const = 0;
310 : virtual void GetUnitObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const = 0;
311 : virtual void GetStaticObstructionsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter) const = 0;
312 :
313 : /**
314 : * Returns the entity IDs of all unit shapes that intersect the given
315 : * obstruction square, filtering out using the given filter.
316 : * @param square the Obstruction squre we want to compare with.
317 : * @param out output list of obstructions
318 : * @param filter filter for the obstructing units
319 : * @param strict whether to be strict in the check or more permissive (ie rasterize more or less). Default false.
320 : */
321 : virtual void GetUnitsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter, bool strict = false) const = 0;
322 :
323 : /**
324 : * Get the obstruction square representing the given shape.
325 : * @param tag tag of shape (must be valid)
326 : */
327 : virtual ObstructionSquare GetObstruction(tag_t tag) const = 0;
328 :
329 : virtual ObstructionSquare GetUnitShapeObstruction(entity_pos_t x, entity_pos_t z, entity_pos_t clearance) const = 0;
330 :
331 : virtual ObstructionSquare GetStaticShapeObstruction(entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h) const = 0;
332 :
333 : /**
334 : * Set the passability to be restricted to a circular map.
335 : */
336 : virtual void SetPassabilityCircular(bool enabled) = 0;
337 :
338 : virtual bool GetPassabilityCircular() const = 0;
339 :
340 : /**
341 : * Toggle the rendering of debug info.
342 : */
343 : virtual void SetDebugOverlay(bool enabled) = 0;
344 :
345 125 : DECLARE_INTERFACE_TYPE(ObstructionManager)
346 : };
347 :
348 : /**
349 : * Interface for ICmpObstructionManager @c Test functions to filter out unwanted shapes.
350 : */
351 13 : class IObstructionTestFilter
352 : {
353 : public:
354 : typedef ICmpObstructionManager::tag_t tag_t;
355 : typedef ICmpObstructionManager::flags_t flags_t;
356 :
357 17 : virtual ~IObstructionTestFilter() {}
358 :
359 : /**
360 : * Return true if the shape with the specified parameters should be tested for collisions.
361 : * This is called for all shapes that would collide, and also for some that wouldn't.
362 : *
363 : * @param tag tag of shape being tested
364 : * @param flags set of EFlags for the shape
365 : * @param group the control group of the shape (typically the shape's unit, or the unit's formation controller, or 0)
366 : * @param group2 an optional secondary control group of the shape, or INVALID_ENTITY if none specified. Currently
367 : * exists only for static shapes.
368 : */
369 : virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const = 0;
370 : };
371 :
372 : /**
373 : * Obstruction test filter that will test against all shapes.
374 : */
375 3 : class NullObstructionFilter : public IObstructionTestFilter
376 : {
377 : public:
378 30 : virtual bool TestShape(tag_t UNUSED(tag), flags_t UNUSED(flags), entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
379 : {
380 30 : return true;
381 : }
382 : };
383 :
384 : /**
385 : * Obstruction test filter that will test only against stationary (i.e. non-moving) shapes.
386 : */
387 1 : class StationaryOnlyObstructionFilter : public IObstructionTestFilter
388 : {
389 : public:
390 6 : virtual bool TestShape(tag_t UNUSED(tag), flags_t flags, entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
391 : {
392 6 : return !(flags & ICmpObstructionManager::FLAG_MOVING);
393 : }
394 : };
395 :
396 : /**
397 : * Obstruction test filter that reject shapes in a given control group,
398 : * and rejects shapes that don't block unit movement, and optionally rejects moving shapes.
399 : */
400 0 : class ControlGroupMovementObstructionFilter : public IObstructionTestFilter
401 : {
402 : bool m_AvoidMoving;
403 : entity_id_t m_Group;
404 :
405 : public:
406 0 : ControlGroupMovementObstructionFilter(bool avoidMoving, entity_id_t group) :
407 0 : m_AvoidMoving(avoidMoving), m_Group(group)
408 0 : {}
409 :
410 0 : virtual bool TestShape(tag_t UNUSED(tag), flags_t flags, entity_id_t group, entity_id_t group2) const
411 : {
412 0 : if (group == m_Group || (group2 != INVALID_ENTITY && group2 == m_Group))
413 0 : return false;
414 :
415 0 : if (!(flags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT))
416 0 : return false;
417 :
418 0 : if ((flags & ICmpObstructionManager::FLAG_MOVING) && !m_AvoidMoving)
419 0 : return false;
420 :
421 0 : return true;
422 : }
423 : };
424 :
425 : /**
426 : * Obstruction test filter that will test only against shapes that:
427 : * - are part of neither one of the specified control groups
428 : * - AND, depending on the value of the 'exclude' argument:
429 : * - have at least one of the specified flags set.
430 : * - OR have none of the specified flags set.
431 : *
432 : * The first (primary) control group to reject shapes from must be specified and valid. The secondary
433 : * control group to reject entities from may be set to INVALID_ENTITY to not use it.
434 : *
435 : * This filter is useful to e.g. allow foundations within the same control group to be placed and
436 : * constructed arbitrarily close together (e.g. for wall pieces that need to link up tightly).
437 : */
438 6 : class SkipControlGroupsRequireFlagObstructionFilter : public IObstructionTestFilter
439 : {
440 : bool m_Exclude;
441 : entity_id_t m_Group;
442 : entity_id_t m_Group2;
443 : flags_t m_Mask;
444 :
445 : public:
446 0 : SkipControlGroupsRequireFlagObstructionFilter(bool exclude, entity_id_t group1, entity_id_t group2, flags_t mask) :
447 0 : m_Exclude(exclude), m_Group(group1), m_Group2(group2), m_Mask(mask)
448 : {
449 0 : Init();
450 0 : }
451 :
452 6 : SkipControlGroupsRequireFlagObstructionFilter(entity_id_t group1, entity_id_t group2, flags_t mask) :
453 6 : m_Exclude(false), m_Group(group1), m_Group2(group2), m_Mask(mask)
454 : {
455 6 : Init();
456 6 : }
457 :
458 40 : virtual bool TestShape(tag_t UNUSED(tag), flags_t flags, entity_id_t group, entity_id_t group2) const
459 : {
460 : // Don't test shapes that share one or more of our control groups.
461 46 : if (group == m_Group || group == m_Group2 || (group2 != INVALID_ENTITY &&
462 8 : (group2 == m_Group || group2 == m_Group2)))
463 22 : return false;
464 :
465 : // If m_Exclude is true, don't test against shapes that have any of the
466 : // obstruction flags specified in m_Mask.
467 18 : if (m_Exclude)
468 0 : return (flags & m_Mask) == 0;
469 :
470 : // Otherwise, only include shapes that match at least one flag in m_Mask.
471 18 : return (flags & m_Mask) != 0;
472 : }
473 : private:
474 6 : void Init()
475 : {
476 : // the primary control group to filter out must be valid
477 6 : ENSURE(m_Group != INVALID_ENTITY);
478 :
479 : // for simplicity, if m_Group2 is INVALID_ENTITY (i.e. not used), then set it equal to m_Group
480 : // so that we have fewer special cases to consider in TestShape().
481 6 : if (m_Group2 == INVALID_ENTITY)
482 3 : m_Group2 = m_Group;
483 6 : }
484 : };
485 :
486 : /**
487 : * Obstruction test filter that will test only against shapes that:
488 : * - are part of both of the specified control groups
489 : * - AND have at least one of the specified flags set.
490 : *
491 : * The first (primary) control group to include shapes from must be specified and valid.
492 : *
493 : * This filter is useful for preventing entities with identical control groups
494 : * from colliding e.g. building a new wall segment on top of an existing wall)
495 : *
496 : * @todo This filter needs test cases.
497 : */
498 0 : class SkipTagRequireControlGroupsAndFlagObstructionFilter : public IObstructionTestFilter
499 : {
500 : tag_t m_Tag;
501 : entity_id_t m_Group;
502 : entity_id_t m_Group2;
503 : flags_t m_Mask;
504 :
505 : public:
506 0 : SkipTagRequireControlGroupsAndFlagObstructionFilter(tag_t tag, entity_id_t group1, entity_id_t group2, flags_t mask) :
507 0 : m_Tag(tag), m_Group(group1), m_Group2(group2), m_Mask(mask)
508 : {
509 0 : ENSURE(m_Group != INVALID_ENTITY);
510 0 : }
511 :
512 0 : virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
513 : {
514 : // To be included in testing, a shape must not have the specified tag, and must
515 : // match at least one of the flags in m_Mask, as well as both control groups.
516 0 : return (tag.n != m_Tag.n && (flags & m_Mask) != 0 && ((group == m_Group
517 0 : && group2 == m_Group2) || (group2 == m_Group && group == m_Group2)));
518 : }
519 : };
520 :
521 : /**
522 : * Obstruction test filter that will test only against shapes that do not have the specified tag set.
523 : */
524 4 : class SkipTagObstructionFilter : public IObstructionTestFilter
525 : {
526 : tag_t m_Tag;
527 : public:
528 4 : SkipTagObstructionFilter(tag_t tag) : m_Tag(tag)
529 : {
530 4 : }
531 :
532 6 : virtual bool TestShape(tag_t tag, flags_t UNUSED(flags), entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
533 : {
534 6 : return tag.n != m_Tag.n;
535 : }
536 : };
537 :
538 : /**
539 : * Similar to ControlGroupMovementObstructionFilter, but also ignoring a specific tag. See D3482 for why this exists.
540 : */
541 0 : class SkipTagAndControlGroupObstructionFilter : public IObstructionTestFilter
542 : {
543 : entity_id_t m_Group;
544 : tag_t m_Tag;
545 : bool m_AvoidMoving;
546 :
547 : public:
548 0 : SkipTagAndControlGroupObstructionFilter(tag_t tag, bool avoidMoving, entity_id_t group) :
549 0 : m_Tag(tag), m_Group(group), m_AvoidMoving(avoidMoving)
550 0 : {}
551 :
552 0 : virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
553 : {
554 0 : if (tag.n == m_Tag.n)
555 0 : return false;
556 :
557 0 : if (group == m_Group || (group2 != INVALID_ENTITY && group2 == m_Group))
558 0 : return false;
559 :
560 0 : if ((flags & ICmpObstructionManager::FLAG_MOVING) && !m_AvoidMoving)
561 0 : return false;
562 :
563 0 : if (!(flags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT))
564 0 : return false;
565 :
566 0 : return true;
567 : }
568 : };
569 :
570 :
571 : /**
572 : * Obstruction test filter that will test only against shapes that:
573 : * - do not have the specified tag
574 : * - AND have at least one of the specified flags set.
575 : */
576 3 : class SkipTagRequireFlagsObstructionFilter : public IObstructionTestFilter
577 : {
578 : tag_t m_Tag;
579 : flags_t m_Mask;
580 : public:
581 3 : SkipTagRequireFlagsObstructionFilter(tag_t tag, flags_t mask) : m_Tag(tag), m_Mask(mask)
582 : {
583 3 : }
584 :
585 18 : virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
586 : {
587 18 : return (tag.n != m_Tag.n && (flags & m_Mask) != 0);
588 : }
589 : };
590 :
591 : #endif // INCLUDED_ICMPOBSTRUCTIONMANAGER
|