OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4FindObject.cpp
Go to the documentation of this file.
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 #include "C4Include.h"
17 #include "object/C4FindObject.h"
18 
19 #include "lib/C4Random.h"
20 #include "object/C4Def.h"
21 #include "object/C4DefList.h"
22 #include "object/C4GameObjects.h"
23 #include "object/C4Object.h"
24 #include "player/C4PlayerList.h"
25 
26 // *** C4FindObject
27 
29 {
30  delete pSort;
31 }
32 
33 C4FindObject *C4FindObject::CreateByValue(const C4Value &DataVal, C4SortObject **ppSortObj, const C4Object *context, bool *has_layer_check)
34 {
35  // Must be an array
36  C4ValueArray *pArray = C4Value(DataVal).getArray();
37  if (!pArray) return nullptr;
38 
39  const C4ValueArray &Data = *pArray;
40  int32_t iType = Data[0].getInt();
41  if (Inside<int32_t>(iType, C4SO_First, C4SO_Last))
42  {
43  // this is not a FindObject but a sort condition!
44  // sort condition not desired here?
45  if (!ppSortObj) return nullptr;
46  // otherwise, create it!
47  *ppSortObj = C4SortObject::CreateByValue(iType, Data, context);
48  // done
49  return nullptr;
50  }
51 
52  switch (iType)
53  {
54  case C4FO_Not:
55  {
56  // Create child condition
57  C4FindObject *pCond = C4FindObject::CreateByValue(Data[1], nullptr, context, has_layer_check);
58  if (!pCond) return nullptr;
59  // wrap
60  return new C4FindObjectNot(pCond);
61  }
62 
63  case C4FO_And: case C4FO_Or:
64  {
65  // Trivial case (one condition)
66  if (Data.GetSize() == 2)
67  return C4FindObject::CreateByValue(Data[1], nullptr, context, has_layer_check);
68  // Create all childs
69  int32_t i;
70  C4FindObject **ppConds = new C4FindObject *[Data.GetSize() - 1];
71  for (i = 0; i < Data.GetSize() - 1; i++)
72  ppConds[i] = C4FindObject::CreateByValue(Data[i + 1], nullptr, context, has_layer_check);
73  // Count real entries, move them to start of list
74  int32_t iSize = 0;
75  for (i = 0; i < Data.GetSize() - 1; i++)
76  if (ppConds[i])
77  if (iSize++ != i)
78  ppConds[iSize-1] = ppConds[i];
79  // Create
80  if (iType == C4FO_And)
81  return new C4FindObjectAnd(iSize, ppConds);
82  else
83  return new C4FindObjectOr(iSize, ppConds);
84  }
85 
86  case C4FO_Exclude:
87  return new C4FindObjectExclude(Data[1].getObj());
88 
89  case C4FO_ID:
90  return new C4FindObjectDef(Data[1].getPropList());
91 
92 
93  // #973: For all criteria using coordinates: If FindObject et al. are called in object context, offset by object center
94  case C4FO_InRect:
95  {
96  int32_t x = Data[1].getInt();
97  int32_t y = Data[2].getInt();
98  int32_t w = Data[3].getInt();
99  int32_t h = Data[4].getInt();
100  if (context)
101  {
102  x += context->GetX();
103  y += context->GetY();
104  }
105  return new C4FindObjectInRect(C4Rect(x, y, w, h));
106  }
107 
108  case C4FO_AtPoint:
109  {
110  int32_t x = Data[1].getInt();
111  int32_t y = Data[2].getInt();
112  if (context)
113  {
114  x += context->GetX();
115  y += context->GetY();
116  }
117  return new C4FindObjectAtPoint(x, y);
118  }
119 
120  case C4FO_AtRect:
121  {
122  int32_t x = Data[1].getInt();
123  int32_t y = Data[2].getInt();
124  int32_t w = Data[3].getInt();
125  int32_t h = Data[4].getInt();
126  if (context)
127  {
128  x += context->GetX();
129  y += context->GetY();
130  }
131  return new C4FindObjectAtRect(x, y, w, h);
132  }
133 
134  case C4FO_OnLine:
135  {
136  int32_t x1 = Data[1].getInt();
137  int32_t y1 = Data[2].getInt();
138  int32_t x2 = Data[3].getInt();
139  int32_t y2 = Data[4].getInt();
140  if (context)
141  {
142  x1 += context->GetX();
143  x2 += context->GetX();
144  y1 += context->GetY();
145  y2 += context->GetY();
146  }
147  return new C4FindObjectOnLine(x1, y1, x2, y2);
148  }
149 
150  case C4FO_Distance:
151  {
152  int32_t x = Data[1].getInt();
153  int32_t y = Data[2].getInt();
154  if (context)
155  {
156  x += context->GetX();
157  y += context->GetY();
158  }
159  return new C4FindObjectDistance(x, y, Data[3].getInt());
160  }
161 
162  case C4FO_Cone:
163  {
164  int32_t x = Data[1].getInt();
165  int32_t y = Data[2].getInt();
166  if (context)
167  {
168  x += context->GetX();
169  y += context->GetY();
170  }
171  return new C4FindObjectCone(x, y, Data[3].getInt(), Data[4].getInt(), Data[5].getInt(), Data[6].getInt());
172  }
173 
174  case C4FO_OCF:
175  return new C4FindObjectOCF(Data[1].getInt());
176 
177  case C4FO_Category:
178  return new C4FindObjectCategory(Data[1].getInt());
179 
180  case C4FO_Action:
181  {
182  C4String *pStr = Data[1].getStr();
183  if (!pStr) return nullptr;
184  // Don't copy, it should be safe
185  return new C4FindObjectAction(pStr->GetCStr());
186  }
187 
188  case C4FO_Func:
189  {
190  // Get function name
191  C4String *pStr = Data[1].getStr();
192  if (!pStr) return nullptr;
193  // Construct
194  C4FindObjectFunc *pFO = new C4FindObjectFunc(pStr);
195  // Add parameters
196  for (int i = 2; i < Data.GetSize(); i++)
197  pFO->SetPar(i - 2, Data[i]);
198  // Done
199  return pFO;
200  }
201 
202  case C4FO_ActionTarget:
203  {
204  int index = 0;
205  if (Data.GetSize() >= 3)
206  index = Clamp(Data[2].getInt(), 0, 1);
207  return new C4FindObjectActionTarget(Data[1].getObj(), index);
208  }
209 
210  case C4FO_Procedure:
211  return new C4FindObjectProcedure(Data[1].getStr());
212 
213  case C4FO_Container:
214  return new C4FindObjectContainer(Data[1].getObj());
215 
216  case C4FO_AnyContainer:
217  return new C4FindObjectAnyContainer();
218 
219  case C4FO_Owner:
220  return new C4FindObjectOwner(Data[1].getInt());
221 
222  case C4FO_Controller:
223  return new C4FindObjectController(Data[1].getInt());
224 
225  case C4FO_Layer:
226  // explicit layer check given. do not add implicit layer check
227  if (has_layer_check) *has_layer_check = true;
228  return new C4FindObjectLayer(Data[1].getObj());
229 
230  case C4FO_InArray:
231  return new C4FindObjectInArray(Data[1].getArray());
232 
233  case C4FO_Property:
234  {
235  // Get property name
236  C4String *pStr = Data[1].getStr();
237  if (!pStr) return nullptr;
238  // Construct
240  // Done
241  return pFO;
242  }
243 
244  case C4FO_AnyLayer:
245  // do not add implicit layer check
246  if (has_layer_check) *has_layer_check = true;
247  return nullptr;
248 
249  }
250  return nullptr;
251 }
252 
253 int32_t C4FindObject::Count(const C4ObjectList &Objs)
254 {
255  // Trivial cases
256  if (IsImpossible())
257  return 0;
258  if (IsEnsured())
259  return Objs.ObjectCount();
260  // Count
261  int32_t iCount = 0;
262  for (C4Object *obj : Objs)
263  if (obj->Status && Check(obj))
264  iCount++;
265  return iCount;
266 }
267 
269 {
270  // Trivial case
271  if (IsImpossible())
272  return nullptr;
273  // Search
274  // Double-check object status, as object might be deleted after Check()!
275  C4Object *pBestResult = nullptr;
276  for (C4Object *obj : Objs)
277  if (obj->Status)
278  if (Check(obj))
279  if (obj->Status)
280  {
281  // no sorting: Use first object found
282  if (!pSort) return obj;
283  // Sorting: Check if found object is better
284  if (!pBestResult || pSort->Compare(obj, pBestResult) > 0)
285  if (obj->Status)
286  pBestResult = obj;
287  }
288  return pBestResult;
289 }
290 
291 // return is to be freed by the caller
293 {
294  // Trivial case
295  if (IsImpossible())
296  return new C4ValueArray();
297  // Set up array
298  C4ValueArray *pArray = new C4ValueArray(32);
299  int32_t iSize = 0;
300  // Search
301  for (C4Object *obj : Objs)
302  if (obj->Status)
303  if (Check(obj))
304  {
305  // Grow the array, if neccessary
306  if (iSize >= pArray->GetSize())
307  pArray->SetSize(iSize * 2);
308  // Add object
309  (*pArray)[iSize++] = C4VObj(obj);
310  }
311  // Shrink array
312  pArray->SetSize(iSize);
313  // Recheck object status (may shrink array again)
314  CheckObjectStatus(pArray);
315  // Apply sorting
316  if (pSort) pSort->SortObjects(pArray);
317  return pArray;
318 }
319 
320 int32_t C4FindObject::Count(const C4ObjectList &Objs, const C4LSectors &Sct)
321 {
322  // Trivial cases
323  if (IsImpossible())
324  return 0;
325  if (IsEnsured())
326  return Objs.ObjectCount();
327  // Check bounds
328  C4Rect *pBounds = GetBounds();
329  if (!pBounds)
330  return Count(Objs);
331  else if (UseShapes())
332  {
333  // Get area
334  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
335  C4ObjectList *pLst = Area.FirstObjectShapes(&pSct);
336  // Check if a single-sector check is enough
337  if (!Area.Next(pSct))
338  return Count(pSct->ObjectShapes);
339  // Create marker, count over all areas
340  uint32_t iMarker = ::Objects.GetNextMarker();
341  int32_t iCount = 0;
342  for (; pLst; pLst=Area.NextObjectShapes(pLst, &pSct))
343  for (C4Object *obj : Objs)
344  if (obj->Status)
345  if (obj->Marker != iMarker)
346  {
347  obj->Marker = iMarker;
348  if (Check(obj))
349  iCount++;
350  }
351  return iCount;
352  }
353  else
354  {
355  // Count objects per area
356  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
357  int32_t iCount = 0;
358  for (C4ObjectList *pLst=Area.FirstObjects(&pSct); pLst; pLst=Area.NextObjects(pLst, &pSct))
359  iCount += Count(*pLst);
360  return iCount;
361  }
362 }
363 
365 {
366  // Trivial case
367  if (IsImpossible())
368  return nullptr;
369  C4Object *pBestResult = nullptr;
370  // Check bounds
371  C4Rect *pBounds = GetBounds();
372  if (!pBounds)
373  return Find(Objs);
374  // Traverse areas, return first matching object w/o sort or best with sort
375  else if (UseShapes())
376  {
377  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
378  C4Object *pObj;
379  for (C4ObjectList *pLst=Area.FirstObjectShapes(&pSct); pLst; pLst=Area.NextObjectShapes(pLst, &pSct))
380  if ((pObj = Find(*pLst)))
381  {
382  if (!pSort)
383  return pObj;
384  else if (!pBestResult || pSort->Compare(pObj, pBestResult) > 0)
385  if (pObj->Status)
386  pBestResult = pObj;
387  }
388  }
389  else
390  {
391  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
392  C4Object *pObj;
393  for (C4ObjectList *pLst=Area.FirstObjects(&pSct); pLst; pLst=Area.NextObjects(pLst, &pSct))
394  {
395  if ((pObj = Find(*pLst)))
396  {
397  if (!pSort)
398  return pObj;
399  else if (!pBestResult || pSort->Compare(pObj, pBestResult) > 0)
400  if (pObj->Status)
401  pBestResult = pObj;
402  }
403  }
404  }
405  return pBestResult;
406 }
407 
408 // return is to be freed by the caller
410 {
411  // Trivial case
412  if (IsImpossible())
413  return new C4ValueArray();
414  C4Rect *pBounds = GetBounds();
415  if (!pBounds)
416  return FindMany(Objs);
417  // Prepare for array that may be generated
418  C4ValueArray *pArray; int32_t iSize;
419  // Check shape lists?
420  if (UseShapes())
421  {
422  // Get area
423  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
424  C4ObjectList *pLst = Area.FirstObjectShapes(&pSct);
425  // Check if a single-sector check is enough
426  if (!Area.Next(pSct))
427  return FindMany(pSct->ObjectShapes);
428  // Set up array
429  pArray = new C4ValueArray(32); iSize = 0;
430  // Create marker, search all areas
431  uint32_t iMarker = ::Objects.GetNextMarker();
432  for (; pLst; pLst=Area.NextObjectShapes(pLst, &pSct))
433  for (C4Object *obj : *pLst)
434  if (obj->Status)
435  if (obj->Marker != iMarker)
436  {
437  obj->Marker = iMarker;
438  if (Check(obj))
439  {
440  // Grow the array, if neccessary
441  if (iSize >= pArray->GetSize())
442  pArray->SetSize(iSize * 2);
443  // Add object
444  (*pArray)[iSize++] = C4VObj(obj);
445  }
446  }
447  }
448  else
449  {
450  // Set up array
451  pArray = new C4ValueArray(32); iSize = 0;
452  // Search
453  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
454  for (C4ObjectList *pLst=Area.FirstObjects(&pSct); pLst; pLst=Area.NextObjects(pLst, &pSct))
455  for (C4Object *obj : *pLst)
456  if (obj->Status)
457  if (Check(obj))
458  {
459  // Grow the array, if neccessary
460  if (iSize >= pArray->GetSize())
461  pArray->SetSize(iSize * 2);
462  // Add object
463  (*pArray)[iSize++] = C4VObj(obj);
464  }
465  }
466  // Shrink array
467  pArray->SetSize(iSize);
468  // Recheck object status (may shrink array again)
469  CheckObjectStatus(pArray);
470  // Apply sorting
471  if (pSort) pSort->SortObjects(pArray);
472  return pArray;
473 }
474 
475 void C4FindObject::CheckObjectStatus(C4ValueArray *pArray)
476 {
477  // Recheck object status
478  for (int32_t i = 0; i < pArray->GetSize(); i++)
479  if (!pArray->GetItem(i).getObj()->Status)
480  {
481  // This shouldn't happen really, so this is done as a separate loop.
482  int32_t j = i; i++;
483  for (; i < pArray->GetSize(); i++)
484  if (pArray->GetItem(i).getObj()->Status)
485  (*pArray)[j++] = pArray->GetItem(i);
486  // Set new size
487  pArray->SetSize(j);
488  break;
489  }
490 }
491 
493 {
494  delete pSort;
495  pSort = pToSort;
496 }
497 
498 
499 // *** C4FindObjectNot
500 
502 {
503  delete pCond;
504 }
505 
507 {
508  return !pCond->Check(pObj);
509 }
510 
511 // *** C4FindObjectAnd
512 
513 C4FindObjectAnd::C4FindObjectAnd(int32_t inCnt, C4FindObject **ppConds, bool fFreeArray)
514  : iCnt(inCnt), ppConds(ppConds), fFreeArray(fFreeArray), fUseShapes(false), fHasBounds(false)
515 {
516  // Filter ensured entries
517  int32_t i;
518  for (i = 0; i < iCnt; )
519  if (ppConds[i]->IsEnsured())
520  {
521  delete ppConds[i];
522  iCnt--;
523  for (int32_t j = i; j < iCnt; j++)
524  ppConds[j] = ppConds[j + 1];
525  }
526  else
527  i++;
528  // Intersect all child bounds
529  for (i = 0; i < iCnt; i++)
530  {
531  C4Rect *pChildBounds = ppConds[i]->GetBounds();
532  if (pChildBounds)
533  {
534  if (!fHasBounds)
535  {
536  fUseShapes = ppConds[i]->UseShapes();
537  Bounds = *pChildBounds;
538  fHasBounds = true;
539  }
540  // some objects might be in an rect and at a point not in that rect
541  // so do not intersect shapes bounds with rects bound
542  else if (fUseShapes == ppConds[i]->UseShapes())
543  Bounds.Intersect(*pChildBounds);
544  // simply use a larger rect than strictly necessary,
545  // the objects will be filtered out later
546  }
547  }
548 }
549 
551 {
552  for (int32_t i = 0; i < iCnt; i++)
553  delete ppConds[i];
554  if (fFreeArray)
555  delete [] ppConds;
556 }
557 
559 {
560  for (int32_t i = 0; i < iCnt; i++)
561  if (!ppConds[i]->Check(pObj))
562  return false;
563  return true;
564 }
565 
567 {
568  for (int32_t i = 0; i < iCnt; i++)
569  if (ppConds[i]->IsImpossible())
570  return true;
571  return false;
572 }
573 
574 // *** C4FindObjectOr
575 
577  : iCnt(inCnt), ppConds(ppConds), fHasBounds(false)
578 {
579  // Filter impossible entries
580  int32_t i;
581  for (i = 0; i < iCnt; )
582  if (ppConds[i]->IsImpossible())
583  {
584  delete ppConds[i];
585  iCnt--;
586  for (int32_t j = i; j < iCnt; j++)
587  ppConds[j] = ppConds[j + 1];
588  }
589  else
590  i++;
591  // Sum up all child bounds
592  for (i = 0; i < iCnt; i++)
593  {
594  C4Rect *pChildBounds = ppConds[i]->GetBounds();
595  if (!pChildBounds) { fHasBounds = false; break; }
596  // With objects that have a position outside their shape, mixing
597  // shape bounds with rect bounds results in no bounds
598  if (fHasBounds && fUseShapes != ppConds[i]->UseShapes())
599  { fHasBounds = false; break; }
600  if (fHasBounds)
601  Bounds.Add(*pChildBounds);
602  else
603  {
604  fUseShapes = ppConds[i]->UseShapes();
605  Bounds = *pChildBounds;
606  fHasBounds = true;
607  }
608  }
609 }
610 
612 {
613  for (int32_t i = 0; i < iCnt; i++)
614  delete ppConds[i];
615  delete [] ppConds;
616 }
617 
619 {
620  for (int32_t i = 0; i < iCnt; i++)
621  if (ppConds[i]->Check(pObj))
622  return true;
623  return false;
624 }
625 
627 {
628  for (int32_t i = 0; i < iCnt; i++)
629  if (ppConds[i]->IsEnsured())
630  return true;
631  return false;
632 }
633 
634 // *** C4FindObject* (primitive conditions)
635 
637 {
638  return pObj != pExclude;
639 }
640 
642 {
643  return pObj->GetPrototype() == def;
644 }
645 
647 {
648  return !def || !def->GetDef() || !def->GetDef()->Count;
649 }
650 
652 {
653  return rect.Contains(pObj->GetX(), pObj->GetY());
654 }
655 
657 {
658  return !rect.Wdt || !rect.Hgt;
659 }
660 
662 {
663  return pObj->Shape.Contains(bounds.x - pObj->GetX(), bounds.y - pObj->GetY());
664 }
665 
667 {
668  C4Rect rcShapeBounds = pObj->Shape;
669  rcShapeBounds.x += pObj->GetX(); rcShapeBounds.y += pObj->GetY();
670  return !!rcShapeBounds.Overlap(bounds);
671 }
672 
674 {
675  return pObj->Shape.IntersectsLine(x - pObj->GetX(), y - pObj->GetY(), x2 - pObj->GetX(), y2 - pObj->GetY());
676 }
677 
679 {
680  return (pObj->GetX() - x) * (pObj->GetX() - x) + (pObj->GetY() - y) * (pObj->GetY() - y) <= r2;
681 }
682 
684 {
685  bool in_circle = (pObj->GetX() - x) * (pObj->GetX() - x) + (pObj->GetY() - y) * (pObj->GetY() - y) <= r2;
686  int32_t obj_angle = Angle(x, y, pObj->GetX(), pObj->GetY(), prec_angle);
687  bool in_cone = Inside(obj_angle, cone_angle - cone_width, cone_angle + cone_width) ||
688  Inside(obj_angle - 360 * prec_angle, cone_angle - cone_width, cone_angle + cone_width) ||
689  Inside(obj_angle + 360 * prec_angle, cone_angle - cone_width, cone_angle + cone_width);
690  return in_circle && in_cone;
691 }
692 
694 {
695  return !! (pObj->OCF & ocf);
696 }
697 
699 {
700  return !ocf;
701 }
702 
704 {
705  return !! (pObj->Category & iCategory);
706 }
707 
709 {
710  return !iCategory;
711 }
712 
714 {
715  assert(pObj);
716  if (!pObj->GetAction()) return false;
717  return SEqual(pObj->GetAction()->GetName(), szAction);
718 }
719 
721 {
722  assert(index >= 0 && index <= 1);
723  assert(pObj);
724  if (!pObj->GetAction()) return false;
725  if (index == 0)
726  return pObj->Action.Target == pActionTarget;
727  else if (index == 1)
728  return pObj->Action.Target2 == pActionTarget;
729  else
730  return false;
731 }
732 
734 {
735  assert(pObj);
736  if (!pObj->GetAction()) return false;
737  C4Value v;
738  pObj->GetAction()->GetProperty(P_Procedure, &v);
739  return v != C4VNull && v.getStr() == procedure;
740 }
741 
743 {
744  return false;
745 }
746 
748 {
749  return pObj->Contained == pContainer;
750 }
751 
753 {
754  return !! pObj->Contained;
755 }
756 
758 {
759  return pObj->Owner == iOwner;
760 }
761 
763 {
764  return iOwner != NO_OWNER && !ValidPlr(iOwner);
765 }
766 
768 {
769  return pObj->Controller == controller;
770 }
771 
773 {
774  return controller != NO_OWNER && !ValidPlr(controller);
775 }
776 
777 // *** C4FindObjectFunc
778 
779 void C4FindObjectFunc::SetPar(int i, const C4Value &Par)
780 {
781  // Over limit?
782  if (i >= C4AUL_MAX_Par) return;
783  // Set parameter
784  Pars[i] = Par;
785 }
786 
788 {
789  assert(Name); // checked in constructor
790  // Function not found?
791  return pObj->Call(Name, &Pars).getBool();
792 }
793 
795 {
796  return false;
797 }
798 
799 // *** C4FindObjectLayer
800 
802 {
803  return pObj->Layer == pLayer;
804 }
805 
807 {
808  return false;
809 }
810 
811 // *** C4FindObjectInArray
812 
814 {
815  // O(n) array look-up
816  if (!pArray) return false;
817  int32_t sz = pArray->GetSize();
818  for (int i=0; i<sz; ++i)
819  if (pArray->_GetItem(i).getObj() == pObj)
820  return true;
821  return false;
822 }
823 
825 {
826  return !pArray || !pArray->GetSize();
827 }
828 
829 // *** C4FindObjectProperty
830 
832 {
833  assert(Name); // checked in constructor
834  C4Value value;
835  return pObj->GetPropertyByS(Name, &value) && value.getBool();
836 }
837 
839 {
840  return false;
841 }
842 
843 
844 // *** C4SortObject
845 
847 {
848  // Must be an array
849  const C4ValueArray *pArray = C4Value(DataVal).getArray();
850  if (!pArray) return nullptr;
851  const C4ValueArray &Data = *pArray;
852  int32_t iType = Data[0].getInt();
853  return CreateByValue(iType, Data, context);
854 }
855 
856 C4SortObject *C4SortObject::CreateByValue(int32_t iType, const C4ValueArray &Data, const C4Object *context)
857 {
858  switch (iType)
859  {
860  case C4SO_Reverse:
861  {
862  // create child sort
863  C4SortObject *pChildSort = C4SortObject::CreateByValue(Data[1], context);
864  if (!pChildSort) return nullptr;
865  // wrap
866  return new C4SortObjectReverse(pChildSort);
867  }
868 
869  case C4SO_Multiple:
870  {
871  // Trivial case (one sort)
872  if (Data.GetSize() == 2)
873  {
874  return C4SortObject::CreateByValue(Data[1], context);
875  }
876  // Create all children
877  int32_t i;
878  C4SortObject **ppSorts = new C4SortObject *[Data.GetSize() - 1];
879  for (i = 0; i < Data.GetSize() - 1; i++)
880  {
881  ppSorts[i] = C4SortObject::CreateByValue(Data[i+1], context);
882  }
883  // Count real entries, move them to start of list
884  int32_t iSize = 0;
885  for (i = 0; i < Data.GetSize() - 1; i++)
886  if (ppSorts[i])
887  if (iSize++ != i)
888  ppSorts[iSize-1] = ppSorts[i];
889  // Create
890  return new C4SortObjectMultiple(iSize, ppSorts);
891  }
892 
893  case C4SO_Distance:
894  {
895  int32_t x = Data[1].getInt();
896  int32_t y = Data[2].getInt();
897  if (context)
898  {
899  x += context->GetX();
900  y += context->GetY();
901  }
902  return new C4SortObjectDistance(x, y);
903  }
904 
905  case C4SO_Random:
906  return new C4SortObjectRandom();
907 
908  case C4SO_Speed:
909  return new C4SortObjectSpeed();
910 
911  case C4SO_Mass:
912  return new C4SortObjectMass();
913 
914  case C4SO_Value:
915  return new C4SortObjectValue();
916 
917  case C4SO_Func:
918  {
919  // Get function name
920  C4String *pStr = Data[1].getStr();
921  if (!pStr) return nullptr;
922  // Construct
923  C4SortObjectFunc *pSO = new C4SortObjectFunc(pStr);
924  // Add parameters
925  for (int i = 2; i < Data.GetSize(); i++)
926  pSO->SetPar(i - 2, Data[i]);
927  // Done
928  return pSO;
929  }
930 
931  }
932  return nullptr;
933 }
934 
936 {
937  pArray->Sort(*this);
938 }
939 
940 // *** C4SortObjectByValue
941 
943  : C4SortObject()
944 {
945 }
946 
948 {
949  delete [] pVals; pVals = nullptr;
950 }
951 
953 {
954  // Clear old cache
955  delete [] pVals; pVals = nullptr; iSize = 0;
956  // Create new cache
957  iSize = pObjs->GetSize(); pVals = new int32_t [iSize];
958  for (int32_t i = 0; i < iSize; i++)
959  pVals[i] = CompareGetValue(pObjs->GetItem(i)._getObj());
960  // Okay
961  return true;
962 }
963 
965 {
966  // this is rather slow, should only be called in special cases
967 
968  // make sure to hardcode the call order, as it might lead to desyncs otherwise [Icewing]
969  int32_t iValue1 = CompareGetValue(pObj1);
970  int32_t iValue2 = CompareGetValue(pObj2);
971  return iValue2 - iValue1;
972 }
973 
974 int32_t C4SortObjectByValue::CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2)
975 {
976  assert(pVals); assert(iObj1 >= 0 && iObj1 < iSize); assert(iObj2 >= 0 && iObj2 < iSize);
977  // Might overflow for large values...!
978  return pVals[iObj2] - pVals[iObj1];
979 }
980 
982 {
983  delete pSort;
984 }
985 
987 {
988  return pSort->Compare(pObj2, pObj1);
989 }
990 
992 {
993  return pSort->PrepareCache(pObjs);
994 }
995 
996 int32_t C4SortObjectReverse::CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2)
997 {
998  return pSort->CompareCache(iObj2, iObj1, pObj2, pObj1);
999 }
1000 
1002 {
1003  for (int32_t i=0; i<iCnt; ++i) delete ppSorts[i];
1004  if (fFreeArray) delete [] ppSorts;
1005 }
1006 
1008 {
1009  // return first comparison that's nonzero
1010  int32_t iCmp;
1011  for (int32_t i=0; i<iCnt; ++i)
1012  if ((iCmp = ppSorts[i]->Compare(pObj1, pObj2)))
1013  return iCmp;
1014  // all comparisons equal
1015  return 0;
1016 }
1017 
1019 {
1020  bool fCaches = false;
1021  for (int32_t i=0; i<iCnt; ++i)
1022  fCaches |= ppSorts[i]->PrepareCache(pObjs);
1023  // return wether a sort citerion uses a cache
1024  return fCaches;
1025 }
1026 
1027 int32_t C4SortObjectMultiple::CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2)
1028 {
1029  // return first comparison that's nonzero
1030  int32_t iCmp;
1031  for (int32_t i=0; i<iCnt; ++i)
1032  if ((iCmp = ppSorts[i]->CompareCache(iObj1, iObj2, pObj1, pObj2)))
1033  return iCmp;
1034  // all comparisons equal
1035  return 0;
1036 }
1037 
1039 {
1040  int32_t dx=pFor->GetX()-iX, dy=pFor->GetY()-iY;
1041  return dx*dx+dy*dy;
1042 }
1043 
1045 {
1046  return Random(1 << 16);
1047 }
1048 
1050 {
1051  return fixtoi(pFor->xdir*pFor->xdir + pFor->ydir*pFor->ydir);
1052 }
1053 
1055 {
1056  return pFor->Mass;
1057 }
1058 
1060 {
1061  return pFor->GetValue(nullptr, NO_OWNER);
1062 }
1063 
1064 void C4SortObjectFunc::SetPar(int i, const C4Value &Par)
1065 {
1066  // Over limit?
1067  if (i >= C4AUL_MAX_Par) return;
1068  // Set parameter
1069  Pars[i] = Par;
1070 }
1071 
1073 {
1074  if (!Name) return false;
1075  return pObj->Call(Name, &Pars).getInt();
1076 }
int32_t GetY() const
Definition: C4Object.h:287
virtual bool UseShapes()
Definition: C4FindObject.h:96
friend class C4FindObjectNot
Definition: C4FindObject.h:71
static C4FindObject * CreateByValue(const C4Value &Data, C4SortObject **ppSortObj=nullptr, const C4Object *context=nullptr, bool *has_layer_check=nullptr)
bool Contains(int32_t iX, int32_t iY) const
Definition: C4Rect.h:40
void SortObjects(C4ValueArray *pArray)
bool Check(C4Object *pObj) override
virtual bool IsEnsured()
Definition: C4FindObject.h:98
uint32_t Random()
Definition: C4Random.cpp:43
bool IsImpossible() override
bool IsImpossible() override
C4String * getStr() const
Definition: C4Value.h:117
bool GetProperty(C4PropertyName k, C4Value *pResult) const
Definition: C4PropList.h:101
bool UseShapes() override
Definition: C4FindObject.h:131
int32_t GetValue(C4Object *pInBase, int32_t iForPlayer)
Definition: C4Object.cpp:1688
bool IsImpossible() override
bool Check(C4Object *pObj) override
int32_t Mass
Definition: C4Object.h:115
int32_t CompareGetValue(C4Object *pFor) override
bool Check(C4Object *pObj) override
C4PropList * GetAction() const
Definition: C4Object.cpp:2675
const char * GetCStr() const
Definition: C4StringTable.h:49
bool GetPropertyByS(const C4String *k, C4Value *pResult) const override
Definition: C4Object.cpp:4874
Definition: C4Rect.h:27
virtual C4Rect * GetBounds()
Definition: C4FindObject.h:95
int32_t Compare(C4Object *pObj1, C4Object *pObj2) override
bool Check(C4Object *pObj) override
bool getBool() const
Definition: C4Value.h:113
C4FindObjectOr(int32_t iCnt, C4FindObject **ppConds)
C4ObjectList * NextObjectShapes(C4ObjectList *pPrev, C4LSector **ppSct)
Definition: C4Sector.cpp:317
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
C4ObjectPtr Target2
Definition: C4Object.h:87
bool Check(C4Object *pObj) override
C4ObjectPtr Layer
Definition: C4Object.h:136
C4Value C4VObj(C4Object *pObj)
Definition: C4Value.cpp:88
virtual int32_t Compare(C4Object *pObj1, C4Object *pObj2)=0
void Intersect(const C4Rect &r2)
Definition: C4Rect.cpp:100
int32_t Angle(int32_t iX1, int32_t iY1, int32_t iX2, int32_t iY2, int32_t iPrec)
Definition: Standard.cpp:37
bool IsImpossible() override
C4LSector * Next(C4LSector *pPrev) const
Definition: C4Sector.cpp:276
virtual ~C4FindObject()
T Clamp(T bval, T lbound, T rbound)
Definition: Standard.h:44
bool Check(C4Object *pObj) override
const C4Value & GetItem(int32_t iElem) const
Definition: C4ValueArray.h:38
virtual C4Def const * GetDef() const
Definition: C4PropList.cpp:685
void SetSort(C4SortObject *pToSort)
int32_t Wdt
Definition: C4Rect.h:30
int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) override
C4ValueArray * FindMany(const C4ObjectList &Objs)
friend class C4FindObjectAnd
Definition: C4FindObject.h:72
#define C4AUL_MAX_Par
Definition: C4AulFunc.h:26
bool IsImpossible() override
int32_t y
Definition: C4Rect.h:30
virtual int32_t CompareGetValue(C4Object *pOf)=0
bool Check(C4Object *pObj) override
int iCnt
Definition: TstC4NetIO.cpp:32
C4Object * _getObj() const
Definition: C4Value.cpp:73
~C4FindObjectOr() override
int32_t Count
Definition: C4Def.h:179
bool Check(C4Object *pObj) override
virtual const char * GetName() const
Definition: C4PropList.cpp:649
bool IsImpossible() override
bool Check(C4Object *pObj) override
C4PropList * GetPrototype() const
Definition: C4PropList.h:81
~C4SortObjectByValue() override
int32_t Owner
Definition: C4Object.h:110
bool IsEnsured() override
Definition: C4FindObject.h:132
bool Check(C4Object *pObj) override
bool IsImpossible() override
bool Check(C4Object *pObj) override
void Add(const C4Rect &r2)
Definition: C4Rect.cpp:144
int32_t GetX() const
Definition: C4Object.h:286
uint32_t GetNextMarker()
C4ObjectList * FirstObjects(C4LSector **ppSct)
Definition: C4Sector.h:118
bool PrepareCache(const C4ValueArray *pObjs) override
const int NO_OWNER
Definition: C4Constants.h:137
bool Check(C4Object *pObj) override
void SetSize(int32_t inSize)
bool Check(C4Object *pObj) override
virtual bool IsImpossible()
Definition: C4FindObject.h:97
int32_t Status
Definition: C4PropList.h:168
C4ValueArray * getArray() const
Definition: C4Value.h:118
C4ObjectList ObjectShapes
Definition: C4Sector.h:49
int32_t Compare(C4Object *pObj1, C4Object *pObj2) override
int32_t CompareGetValue(C4Object *pFor) override
int32_t GetSize() const
Definition: C4ValueArray.h:36
C4ObjectList * FirstObjectShapes(C4LSector **ppSct)
Definition: C4Sector.h:122
bool IsEnsured() override
int32_t Category
Definition: C4Object.h:113
int32_t Count(const C4ObjectList &Objs)
C4LSectors Sectors
Definition: C4GameObjects.h:42
void Sort(class C4SortObject &rSort)
int32_t getInt() const
Definition: C4Value.h:112
int32_t x
Definition: C4Rect.h:30
bool Check(C4Object *pObj) override
bool Check(C4Object *pObj) override
~C4SortObjectMultiple() override
int ObjectCount(C4ID id=C4ID::None) const
const C4Value C4VNull
Definition: C4Value.cpp:30
C4ObjectPtr Target
Definition: C4Object.h:87
bool IsEnsured() override
const C4Value & _GetItem(int32_t iElem) const
Definition: C4ValueArray.h:48
bool Check(C4Object *pObj) override
int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) override
bool IsImpossible() override
bool Check(C4Object *pObj) override
int32_t CompareGetValue(C4Object *pFor) override
C4FindObjectAnd(int32_t iCnt, C4FindObject **ppConds, bool fFreeArray=true)
bool UseShapes() override
Definition: C4FindObject.h:158
bool Check(C4Object *pObj) override
int32_t ValidPlr(int32_t plr)
bool PrepareCache(const C4ValueArray *pObjs) override
void SetPar(int i, const C4Value &val)
bool IsImpossible() override
bool Check(C4Object *pObj) override
bool Check(C4Object *pObj) override
virtual bool PrepareCache(const C4ValueArray *pObjs)
Definition: C4FindObject.h:425
int32_t CompareGetValue(C4Object *pFor) override
int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2) override
bool PrepareCache(const C4ValueArray *pObjs) override
bool Overlap(C4Rect &rTarget)
Definition: C4Rect.cpp:91
bool IntersectsLine(int32_t iX, int32_t iY, int32_t iX2, int32_t iY2)
Definition: C4Rect.cpp:122
~C4FindObjectAnd() override
int32_t Compare(C4Object *pObj1, C4Object *pObj2) override
friend class C4FindObjectOr
Definition: C4FindObject.h:73
C4ObjectPtr Contained
Definition: C4Object.h:144
virtual bool Check(C4Object *pObj)=0
int32_t Hgt
Definition: C4Rect.h:30
C4Action Action
Definition: C4Object.h:147
C4Shape Shape
Definition: C4Object.h:148
uint32_t OCF
Definition: C4Object.h:134
bool Check(C4Object *pObj) override
~C4FindObjectNot() override
int32_t CompareGetValue(C4Object *pFor) override
static C4SortObject * CreateByValue(const C4Value &Data, const C4Object *context=nullptr)
int fixtoi(const C4Fixed &x)
Definition: C4Real.h:259
C4Real xdir
Definition: C4Object.h:126
int32_t Controller
Definition: C4Object.h:111
C4Object * Find(const C4ObjectList &Objs)
bool IsImpossible() override
virtual int32_t CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2)
Definition: C4FindObject.h:426
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:43
bool Check(C4Object *pObj) override
C4ObjectList * NextObjects(C4ObjectList *pPrev, C4LSector **ppSct)
Definition: C4Sector.cpp:303
~C4SortObjectReverse() override
bool IsImpossible() override
C4Object * getObj() const
Definition: C4Value.cpp:68
C4Real ydir
Definition: C4Object.h:126
int32_t CompareGetValue(C4Object *pFor) override
void SetPar(int i, const C4Value &val)
C4GameObjects Objects
Definition: C4Globals.cpp:48
int iSize
Definition: TstC4NetIO.cpp:32
bool IsImpossible() override
Definition: C4FindObject.h:160
bool Check(C4Object *pObj) override
C4Value Call(C4PropertyName k, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4PropList.h:110
bool Check(C4Object *pObj) override