1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 #ifndef C4FINDOBJECT_H
17 #define C4FINDOBJECT_H
18 
19 #include "lib/C4Rect.h"
20 #include "script/C4Value.h"
21 
22 // Condition map
23 enum C4FindObjectCondID
24 {
25 	C4FO_Not           = 1,
26 	C4FO_And           = 2,
27 	C4FO_Or            = 3,
28 	C4FO_Exclude       = 4,
29 	C4FO_InRect        = 5,
30 	C4FO_AtPoint       = 6,
31 	C4FO_AtRect        = 7,
32 	C4FO_OnLine        = 8,
33 	C4FO_Distance      = 9,
34 	C4FO_ID            = 10,
35 	C4FO_OCF           = 11,
36 	C4FO_Category      = 12,
37 	C4FO_Action        = 13,
38 	C4FO_ActionTarget  = 14,
39 	C4FO_Procedure     = 15,
40 	C4FO_Container     = 16,
41 	C4FO_AnyContainer  = 17,
42 	C4FO_Owner         = 18,
43 	C4FO_Controller    = 19,
44 	C4FO_Func          = 20,
45 	C4FO_Layer         = 21,
46 	C4FO_InArray       = 22,
47 	C4FO_Property      = 23,
48 	C4FO_AnyLayer      = 24,
49 	C4FO_Cone          = 25,
50 	// last C4FO must be smaller than C4SO_First.
51 };
52 
53 // Sort map - using same values as C4FindObjectCondID!
54 enum C4SortObjectCondID
55 {
56 	C4SO_First        = 30, // no sort condition smaller than this
57 	C4SO_Reverse      = 31, // reverse sort order
58 	C4SO_Multiple     = 32, // multiple sorts; high priority first; lower priorities if higher prio returned equal
59 	C4SO_Distance     = 33, // nearest first
60 	C4SO_Random       = 34, // random first
61 	C4SO_Speed        = 35, // slowest first
62 	C4SO_Mass         = 36, // lightest first
63 	C4SO_Value        = 37, // cheapest first
64 	C4SO_Func         = 38, // least return values first
65 	C4SO_Last         = 50  // no sort condition larger than this
66 };
67 
68 // Base class
69 class C4FindObject
70 {
71 	friend class C4FindObjectNot;
72 	friend class C4FindObjectAnd;
73 	friend class C4FindObjectOr;
74 
75 	class C4SortObject *pSort{nullptr};
76 public:
77 	C4FindObject() = default;
78 	virtual ~C4FindObject();
79 
80 	static C4FindObject *CreateByValue(const C4Value &Data, C4SortObject **ppSortObj=nullptr, const C4Object *context=nullptr, bool *has_layer_check=nullptr); // createFindObject or SortObject - if ppSortObj==nullptr, SortObject is not allowed
81 
82 	int32_t Count(const C4ObjectList &Objs); // Counts objects for which the condition is true
83 	C4Object *Find(const C4ObjectList &Objs); // Returns first object for which the condition is true
84 	C4ValueArray *FindMany(const C4ObjectList &Objs); // Returns all objects for which the condition is true
85 
86 	int32_t Count(const C4ObjectList &Objs, const C4LSectors &Sct); // Counts objects for which the condition is true
87 	C4Object *Find(const C4ObjectList &Objs, const C4LSectors &Sct);  // Returns first object for which the condition is true
88 	C4ValueArray *FindMany(const C4ObjectList &Objs, const C4LSectors &Sct); // Returns all objects for which the condition is true
89 
90 	void SetSort(C4SortObject *pToSort);
91 
92 protected:
93 	// Overridables
94 	virtual bool Check(C4Object *pObj) = 0;
GetBounds()95 	virtual C4Rect *GetBounds() { return nullptr; }
UseShapes()96 	virtual bool UseShapes() { return false; }
IsImpossible()97 	virtual bool IsImpossible() { return false; }
IsEnsured()98 	virtual bool IsEnsured() { return false; }
99 
100 private:
101 	void CheckObjectStatus(C4ValueArray *pArray);
102 };
103 
104 // Combinators
105 class C4FindObjectNot : public C4FindObject
106 {
107 public:
C4FindObjectNot(C4FindObject * pCond)108 	C4FindObjectNot(C4FindObject *pCond)
109 			: pCond(pCond) { }
110 	~C4FindObjectNot() override;
111 private:
112 	C4FindObject *pCond;
113 protected:
114 	bool Check(C4Object *pObj) override;
IsImpossible()115 	bool IsImpossible() override { return pCond->IsEnsured(); }
IsEnsured()116 	bool IsEnsured() override { return pCond->IsImpossible(); }
117 };
118 
119 class C4FindObjectAnd : public C4FindObject
120 {
121 public:
122 	C4FindObjectAnd(int32_t iCnt, C4FindObject **ppConds, bool fFreeArray = true);
123 	~C4FindObjectAnd() override;
124 private:
125 	int32_t iCnt;
126 	C4FindObject **ppConds; bool fFreeArray; bool fUseShapes;
127 	C4Rect Bounds; bool fHasBounds;
128 protected:
129 	bool Check(C4Object *pObj) override;
GetBounds()130 	C4Rect *GetBounds() override { return fHasBounds ? &Bounds : nullptr; }
UseShapes()131 	bool UseShapes() override { return fUseShapes; }
IsEnsured()132 	bool IsEnsured() override { return !iCnt; }
133 	bool IsImpossible() override;
ForgetConditions()134 	void ForgetConditions() { ppConds=nullptr; iCnt=0; }
135 };
136 
137 // Special variant of C4FindObjectAnd that does not free its conditions
138 class C4FindObjectAndStatic : public C4FindObjectAnd
139 {
140 public:
C4FindObjectAndStatic(int32_t iCnt,C4FindObject ** ppConds)141 	C4FindObjectAndStatic(int32_t iCnt, C4FindObject **ppConds)
142 		: C4FindObjectAnd(iCnt, ppConds, true) {}
~C4FindObjectAndStatic()143 	~C4FindObjectAndStatic() override {ForgetConditions(); }
144 };
145 
146 class C4FindObjectOr : public C4FindObject
147 {
148 public:
149 	C4FindObjectOr(int32_t iCnt, C4FindObject **ppConds);
150 	~C4FindObjectOr() override;
151 private:
152 	int32_t iCnt;
153 	C4FindObject **ppConds; bool fUseShapes;
154 	C4Rect Bounds; bool fHasBounds;
155 protected:
156 	bool Check(C4Object *pObj) override;
GetBounds()157 	C4Rect *GetBounds() override { return fHasBounds ? &Bounds : nullptr; }
UseShapes()158 	bool UseShapes() override { return fUseShapes; }
159 	bool IsEnsured() override;
IsImpossible()160 	bool IsImpossible() override { return !iCnt; }
161 };
162 
163 // Primitive conditions
164 class C4FindObjectExclude : public C4FindObject
165 {
166 public:
C4FindObjectExclude(C4Object * pExclude)167 	C4FindObjectExclude(C4Object *pExclude)
168 			: pExclude(pExclude) { }
169 private:
170 	C4Object *pExclude;
171 protected:
172 	bool Check(C4Object *pObj) override;
173 };
174 
175 class C4FindObjectDef : public C4FindObject
176 {
177 public:
C4FindObjectDef(C4PropList * def)178 	C4FindObjectDef(C4PropList * def)
179 			: def(def) { }
180 private:
181 	C4PropList * def;
182 protected:
183 	bool Check(C4Object *pObj) override;
184 	bool IsImpossible() override;
185 };
186 
187 class C4FindObjectInRect : public C4FindObject
188 {
189 public:
C4FindObjectInRect(const C4Rect & rect)190 	C4FindObjectInRect(const C4Rect &rect)
191 			: rect(rect) { }
192 private:
193 	C4Rect rect;
194 protected:
195 	bool Check(C4Object *pObj) override;
GetBounds()196 	C4Rect *GetBounds() override { return ▭ }
197 	bool IsImpossible() override;
198 };
199 
200 class C4FindObjectAtPoint : public C4FindObject
201 {
202 public:
C4FindObjectAtPoint(int32_t x,int32_t y)203 	C4FindObjectAtPoint(int32_t x, int32_t y)
204 			: bounds(x, y, 1, 1) { }
205 private:
206 	C4Rect bounds;
207 protected:
208 	bool Check(C4Object *pObj) override;
GetBounds()209 	C4Rect *GetBounds() override { return &bounds; }
UseShapes()210 	bool UseShapes() override { return true; }
211 };
212 
213 class C4FindObjectAtRect : public C4FindObject
214 {
215 public:
C4FindObjectAtRect(int32_t x,int32_t y,int32_t wdt,int32_t hgt)216 	C4FindObjectAtRect(int32_t x, int32_t y, int32_t wdt, int32_t hgt)
217 			: bounds(x, y, wdt, hgt) { }
218 private:
219 	C4Rect bounds;
220 protected:
221 	bool Check(C4Object *pObj) override;
GetBounds()222 	C4Rect *GetBounds() override { return &bounds; }
UseShapes()223 	bool UseShapes() override { return true; }
224 };
225 
226 class C4FindObjectOnLine : public C4FindObject
227 {
228 public:
C4FindObjectOnLine(int32_t x,int32_t y,int32_t x2,int32_t y2)229 	C4FindObjectOnLine(int32_t x, int32_t y, int32_t x2, int32_t y2)
230 			: x(x), y(y), x2(x2), y2(y2), bounds(x, y, 1, 1) { bounds.Add(C4Rect(x2, y2, 1,1)); }
231 private:
232 	int32_t x, y, x2, y2;
233 	C4Rect bounds;
234 protected:
235 	bool Check(C4Object *pObj) override;
GetBounds()236 	C4Rect *GetBounds() override { return &bounds; }
UseShapes()237 	bool UseShapes() override { return true; }
238 };
239 
240 class C4FindObjectDistance : public C4FindObject
241 {
242 public:
C4FindObjectDistance(int32_t x,int32_t y,int32_t r)243 	C4FindObjectDistance(int32_t x, int32_t y, int32_t r)
244 			: x(x), y(y), r2(r*r), bounds(x-r, y-r, 2*r+1, 2*r+1) { }
245 private:
246 	int32_t x, y, r2;
247 	C4Rect bounds;
248 protected:
249 	bool Check(C4Object *pObj) override;
GetBounds()250 	C4Rect *GetBounds() override { return &bounds; }
251 };
252 
253 class C4FindObjectCone : public C4FindObject
254 {
255 public:
256 	C4FindObjectCone(int32_t x, int32_t y, int32_t r, int32_t angle, int32_t width, int32_t prec = 1)
x(x)257 			: x(x), y(y), r2(r * r), cone_angle(angle % (360 * prec)), cone_width(width), prec_angle(prec), bounds(x - r, y - r, 2 * r + 1, 2 * r + 1) { }
258 private:
259 	int32_t x, y, r2, cone_angle, cone_width, prec_angle;
260 	C4Rect bounds;
261 protected:
262 	bool Check(C4Object *pObj) override;
GetBounds()263 	C4Rect *GetBounds() override { return &bounds; }
264 };
265 
266 class C4FindObjectOCF : public C4FindObject
267 {
268 public:
C4FindObjectOCF(int32_t ocf)269 	C4FindObjectOCF(int32_t ocf)
270 			: ocf(ocf) { }
271 private:
272 	int32_t ocf;
273 protected:
274 	bool Check(C4Object *pObj) override;
275 	bool IsImpossible() override;
276 };
277 
278 class C4FindObjectCategory : public C4FindObject
279 {
280 public:
C4FindObjectCategory(int32_t iCategory)281 	C4FindObjectCategory(int32_t iCategory)
282 			: iCategory(iCategory) { }
283 private:
284 	int32_t iCategory;
285 protected:
286 	bool Check(C4Object *pObj) override;
287 	bool IsEnsured() override;
288 };
289 
290 class C4FindObjectAction : public C4FindObject
291 {
292 public:
C4FindObjectAction(const char * szAction)293 	C4FindObjectAction(const char *szAction)
294 			: szAction(szAction) { }
295 private:
296 	const char *szAction;
297 protected:
298 	bool Check(C4Object *pObj) override;
299 };
300 
301 class C4FindObjectActionTarget : public C4FindObject
302 {
303 public:
C4FindObjectActionTarget(C4Object * pActionTarget,int index)304 	C4FindObjectActionTarget(C4Object *pActionTarget, int index)
305 			: pActionTarget(pActionTarget), index(index) { }
306 private:
307 	C4Object *pActionTarget;
308 	int index;
309 protected:
310 	bool Check(C4Object *pObj) override;
311 };
312 
313 class C4FindObjectProcedure : public C4FindObject
314 {
315 public:
C4FindObjectProcedure(C4String * procedure)316 	C4FindObjectProcedure(C4String * procedure)
317 			: procedure(procedure) { /* no need to incref, the pointer is never dereferenced */ }
318 private:
319 	C4String * procedure;
320 protected:
321 	bool Check(C4Object *pObj) override;
322 	bool IsImpossible() override;
323 };
324 
325 class C4FindObjectContainer : public C4FindObject
326 {
327 public:
C4FindObjectContainer(C4Object * pContainer)328 	C4FindObjectContainer(C4Object *pContainer)
329 			: pContainer(pContainer) { }
330 private:
331 	C4Object *pContainer;
332 protected:
333 	bool Check(C4Object *pObj) override;
334 };
335 
336 class C4FindObjectAnyContainer : public C4FindObject
337 {
338 public:
339 	C4FindObjectAnyContainer() = default;
340 protected:
341 	bool Check(C4Object *pObj) override;
342 };
343 
344 class C4FindObjectOwner : public C4FindObject
345 {
346 public:
C4FindObjectOwner(int32_t iOwner)347 	C4FindObjectOwner(int32_t iOwner)
348 			: iOwner(iOwner) { }
349 private:
350 	int32_t iOwner;
351 protected:
352 	bool Check(C4Object *pObj) override;
353 	bool IsImpossible() override;
354 };
355 
356 class C4FindObjectController : public C4FindObject
357 {
358 public:
C4FindObjectController(int32_t controller)359 	C4FindObjectController(int32_t controller)
360 			: controller(controller) { }
361 private:
362 	int32_t controller;
363 protected:
364 	bool Check(C4Object *pObj) override;
365 	bool IsImpossible() override;
366 };
367 
368 class C4FindObjectFunc : public C4FindObject
369 {
370 public:
C4FindObjectFunc(C4String * Name)371 	C4FindObjectFunc(C4String * Name): Name(Name) { }
372 	void SetPar(int i, const C4Value &val);
373 private:
374 	C4String * Name;
375 	C4AulParSet Pars;
376 protected:
377 	bool Check(C4Object *pObj) override;
378 	bool IsImpossible() override;
379 };
380 
381 class C4FindObjectProperty : public C4FindObject
382 {
383 public:
C4FindObjectProperty(C4String * Name)384 	C4FindObjectProperty(C4String * Name) : Name(Name) { }
385 private:
386 	C4String * Name;
387 protected:
388 	bool Check(C4Object *pObj) override;
389 	bool IsImpossible() override;
390 };
391 
392 class C4FindObjectLayer : public C4FindObject
393 {
394 public:
C4FindObjectLayer(C4Object * pLayer)395 	C4FindObjectLayer(C4Object *pLayer) : pLayer(pLayer) {}
396 private:
397 	C4Object *pLayer;
398 protected:
399 	bool Check(C4Object *pObj) override;
400 	bool IsImpossible() override;
401 };
402 
403 class C4FindObjectInArray : public C4FindObject
404 {
405 public:
C4FindObjectInArray(C4ValueArray * pArray)406 	C4FindObjectInArray(C4ValueArray *pArray) : pArray(pArray) {}
407 private:
408 	C4ValueArray *pArray;
409 protected:
410 	bool Check(C4Object *pObj) override;
411 	bool IsImpossible() override;
412 };
413 
414 // result sorting
415 class C4SortObject
416 {
417 public:
418 	C4SortObject() = default;
419 	virtual ~C4SortObject() = default;
420 
421 public:
422 	// Overridables
423 	virtual int32_t Compare(C4Object *pObj1, C4Object *pObj2) = 0; // return value <0 if obj1 is to be sorted before obj2
424 
PrepareCache(const C4ValueArray * pObjs)425 	virtual bool PrepareCache(const C4ValueArray *pObjs) { return false; }
CompareCache(int32_t iObj1,int32_t iObj2,C4Object * pObj1,C4Object * pObj2)426 	virtual int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) { return Compare(pObj1, pObj2); }
427 
428 public:
429 	static C4SortObject *CreateByValue(const C4Value &Data, const C4Object *context=nullptr);
430 	static C4SortObject *CreateByValue(int32_t iType, const C4ValueArray &Data, const C4Object *context=nullptr);
431 
432 	void SortObjects(C4ValueArray *pArray);
433 };
434 
435 class C4SortObjectByValue : public C4SortObject
436 {
437 public:
438 	C4SortObjectByValue();
439 	~C4SortObjectByValue() override;
440 
441 private:
442 	int32_t *pVals{nullptr};
443 	int32_t iSize{0};
444 
445 public:
446 	// Overridables
447 	int32_t Compare(C4Object *pObj1, C4Object *pObj2) override;
448 	virtual int32_t CompareGetValue(C4Object *pOf) = 0;
449 
450 	bool PrepareCache(const C4ValueArray *pObjs) override;
451 	int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) override;
452 
453 };
454 
455 class C4SortObjectReverse : public C4SortObject // reverse sort
456 {
457 public:
C4SortObjectReverse(C4SortObject * pSort)458 	C4SortObjectReverse(C4SortObject *pSort)
459 			: C4SortObject(), pSort(pSort) {}
460 	~C4SortObjectReverse() override;
461 private:
462 	C4SortObject *pSort;
463 
464 protected:
465 	int32_t Compare(C4Object *pObj1, C4Object *pObj2) override;
466 
467 	bool PrepareCache(const C4ValueArray *pObjs) override;
468 	int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) override;
469 };
470 
471 class C4SortObjectMultiple : public C4SortObject // apply next sort if previous compares to equality
472 {
473 public:
474 	C4SortObjectMultiple(int32_t iCnt, C4SortObject **ppSorts, bool fFreeArray = true)
C4SortObject()475 			: C4SortObject(), fFreeArray(fFreeArray), iCnt(iCnt), ppSorts(ppSorts) {}
476 	~C4SortObjectMultiple() override;
477 private:
478 	bool fFreeArray;
479 	int32_t iCnt;
480 	C4SortObject **ppSorts;
481 
482 protected:
483 	int32_t Compare(C4Object *pObj1, C4Object *pObj2) override;
484 
485 	bool PrepareCache(const C4ValueArray *pObjs) override;
486 	int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) override;
487 };
488 
489 class C4SortObjectDistance : public C4SortObjectByValue // sort by distance from point x/y
490 {
491 public:
C4SortObjectDistance(int iX,int iY)492 	C4SortObjectDistance(int iX, int iY)
493 			: C4SortObjectByValue(), iX(iX), iY(iY) {}
494 private:
495 	int iX, iY;
496 
497 protected:
498 	int32_t CompareGetValue(C4Object *pFor) override;
499 };
500 
501 class C4SortObjectRandom : public C4SortObjectByValue // randomize order
502 {
503 public:
C4SortObjectRandom()504 	C4SortObjectRandom() : C4SortObjectByValue() {}
505 
506 protected:
507 	int32_t CompareGetValue(C4Object *pFor) override;
508 };
509 
510 class C4SortObjectSpeed : public C4SortObjectByValue // sort by object xdir/ydir
511 {
512 public:
C4SortObjectSpeed()513 	C4SortObjectSpeed() : C4SortObjectByValue() {}
514 
515 protected:
516 	int32_t CompareGetValue(C4Object *pFor) override;
517 };
518 
519 class C4SortObjectMass : public C4SortObjectByValue // sort by mass
520 {
521 public:
C4SortObjectMass()522 	C4SortObjectMass() : C4SortObjectByValue() {}
523 
524 protected:
525 	int32_t CompareGetValue(C4Object *pFor) override;
526 };
527 
528 class C4SortObjectValue : public C4SortObjectByValue // sort by value
529 {
530 public:
C4SortObjectValue()531 	C4SortObjectValue() : C4SortObjectByValue() {}
532 
533 protected:
534 	int32_t CompareGetValue(C4Object *pFor) override;
535 };
536 
537 class C4SortObjectFunc : public C4SortObjectByValue // sort by script function
538 {
539 public:
C4SortObjectFunc(C4String * Name)540 	C4SortObjectFunc(C4String * Name): Name(Name) { }
541 	void SetPar(int i, const C4Value &val);
542 private:
543 	C4String * Name;
544 	C4AulParSet Pars;
545 protected:
546 	int32_t CompareGetValue(C4Object *pFor) override;
547 };
548 
549 #endif
550