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_OCF:
163  return new C4FindObjectOCF(Data[1].getInt());
164 
165  case C4FO_Category:
166  return new C4FindObjectCategory(Data[1].getInt());
167 
168  case C4FO_Action:
169  {
170  C4String *pStr = Data[1].getStr();
171  if (!pStr) return nullptr;
172  // Don't copy, it should be safe
173  return new C4FindObjectAction(pStr->GetCStr());
174  }
175 
176  case C4FO_Func:
177  {
178  // Get function name
179  C4String *pStr = Data[1].getStr();
180  if (!pStr) return nullptr;
181  // Construct
182  C4FindObjectFunc *pFO = new C4FindObjectFunc(pStr);
183  // Add parameters
184  for (int i = 2; i < Data.GetSize(); i++)
185  pFO->SetPar(i - 2, Data[i]);
186  // Done
187  return pFO;
188  }
189 
190  case C4FO_ActionTarget:
191  {
192  int index = 0;
193  if (Data.GetSize() >= 3)
194  index = Clamp(Data[2].getInt(), 0, 1);
195  return new C4FindObjectActionTarget(Data[1].getObj(), index);
196  }
197 
198  case C4FO_Procedure:
199  return new C4FindObjectProcedure(Data[1].getStr());
200 
201  case C4FO_Container:
202  return new C4FindObjectContainer(Data[1].getObj());
203 
204  case C4FO_AnyContainer:
205  return new C4FindObjectAnyContainer();
206 
207  case C4FO_Owner:
208  return new C4FindObjectOwner(Data[1].getInt());
209 
210  case C4FO_Controller:
211  return new C4FindObjectController(Data[1].getInt());
212 
213  case C4FO_Layer:
214  // explicit layer check given. do not add implicit layer check
215  if (has_layer_check) *has_layer_check = true;
216  return new C4FindObjectLayer(Data[1].getObj());
217 
218  case C4FO_InArray:
219  return new C4FindObjectInArray(Data[1].getArray());
220 
221  case C4FO_Property:
222  {
223  // Get property name
224  C4String *pStr = Data[1].getStr();
225  if (!pStr) return nullptr;
226  // Construct
228  // Done
229  return pFO;
230  }
231 
232  case C4FO_AnyLayer:
233  // do not add implicit layer check
234  if (has_layer_check) *has_layer_check = true;
235  return nullptr;
236 
237  }
238  return nullptr;
239 }
240 
241 int32_t C4FindObject::Count(const C4ObjectList &Objs)
242 {
243  // Trivial cases
244  if (IsImpossible())
245  return 0;
246  if (IsEnsured())
247  return Objs.ObjectCount();
248  // Count
249  int32_t iCount = 0;
250  for (C4Object *obj : Objs)
251  if (obj->Status && Check(obj))
252  iCount++;
253  return iCount;
254 }
255 
257 {
258  // Trivial case
259  if (IsImpossible())
260  return nullptr;
261  // Search
262  // Double-check object status, as object might be deleted after Check()!
263  C4Object *pBestResult = nullptr;
264  for (C4Object *obj : Objs)
265  if (obj->Status)
266  if (Check(obj))
267  if (obj->Status)
268  {
269  // no sorting: Use first object found
270  if (!pSort) return obj;
271  // Sorting: Check if found object is better
272  if (!pBestResult || pSort->Compare(obj, pBestResult) > 0)
273  if (obj->Status)
274  pBestResult = obj;
275  }
276  return pBestResult;
277 }
278 
279 // return is to be freed by the caller
281 {
282  // Trivial case
283  if (IsImpossible())
284  return new C4ValueArray();
285  // Set up array
286  C4ValueArray *pArray = new C4ValueArray(32);
287  int32_t iSize = 0;
288  // Search
289  for (C4Object *obj : Objs)
290  if (obj->Status)
291  if (Check(obj))
292  {
293  // Grow the array, if neccessary
294  if (iSize >= pArray->GetSize())
295  pArray->SetSize(iSize * 2);
296  // Add object
297  (*pArray)[iSize++] = C4VObj(obj);
298  }
299  // Shrink array
300  pArray->SetSize(iSize);
301  // Recheck object status (may shrink array again)
302  CheckObjectStatus(pArray);
303  // Apply sorting
304  if (pSort) pSort->SortObjects(pArray);
305  return pArray;
306 }
307 
308 int32_t C4FindObject::Count(const C4ObjectList &Objs, const C4LSectors &Sct)
309 {
310  // Trivial cases
311  if (IsImpossible())
312  return 0;
313  if (IsEnsured())
314  return Objs.ObjectCount();
315  // Check bounds
316  C4Rect *pBounds = GetBounds();
317  if (!pBounds)
318  return Count(Objs);
319  else if (UseShapes())
320  {
321  // Get area
322  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
323  C4ObjectList *pLst = Area.FirstObjectShapes(&pSct);
324  // Check if a single-sector check is enough
325  if (!Area.Next(pSct))
326  return Count(pSct->ObjectShapes);
327  // Create marker, count over all areas
328  uint32_t iMarker = ::Objects.GetNextMarker();
329  int32_t iCount = 0;
330  for (; pLst; pLst=Area.NextObjectShapes(pLst, &pSct))
331  for (C4Object *obj : Objs)
332  if (obj->Status)
333  if (obj->Marker != iMarker)
334  {
335  obj->Marker = iMarker;
336  if (Check(obj))
337  iCount++;
338  }
339  return iCount;
340  }
341  else
342  {
343  // Count objects per area
344  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
345  int32_t iCount = 0;
346  for (C4ObjectList *pLst=Area.FirstObjects(&pSct); pLst; pLst=Area.NextObjects(pLst, &pSct))
347  iCount += Count(*pLst);
348  return iCount;
349  }
350 }
351 
353 {
354  // Trivial case
355  if (IsImpossible())
356  return nullptr;
357  C4Object *pBestResult = nullptr;
358  // Check bounds
359  C4Rect *pBounds = GetBounds();
360  if (!pBounds)
361  return Find(Objs);
362  // Traverse areas, return first matching object w/o sort or best with sort
363  else if (UseShapes())
364  {
365  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
366  C4Object *pObj;
367  for (C4ObjectList *pLst=Area.FirstObjectShapes(&pSct); pLst; pLst=Area.NextObjectShapes(pLst, &pSct))
368  if ((pObj = Find(*pLst)))
369  {
370  if (!pSort)
371  return pObj;
372  else if (!pBestResult || pSort->Compare(pObj, pBestResult) > 0)
373  if (pObj->Status)
374  pBestResult = pObj;
375  }
376  }
377  else
378  {
379  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
380  C4Object *pObj;
381  for (C4ObjectList *pLst=Area.FirstObjects(&pSct); pLst; pLst=Area.NextObjects(pLst, &pSct))
382  {
383  if ((pObj = Find(*pLst)))
384  {
385  if (!pSort)
386  return pObj;
387  else if (!pBestResult || pSort->Compare(pObj, pBestResult) > 0)
388  if (pObj->Status)
389  pBestResult = pObj;
390  }
391  }
392  }
393  return pBestResult;
394 }
395 
396 // return is to be freed by the caller
398 {
399  // Trivial case
400  if (IsImpossible())
401  return new C4ValueArray();
402  C4Rect *pBounds = GetBounds();
403  if (!pBounds)
404  return FindMany(Objs);
405  // Prepare for array that may be generated
406  C4ValueArray *pArray; int32_t iSize;
407  // Check shape lists?
408  if (UseShapes())
409  {
410  // Get area
411  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
412  C4ObjectList *pLst = Area.FirstObjectShapes(&pSct);
413  // Check if a single-sector check is enough
414  if (!Area.Next(pSct))
415  return FindMany(pSct->ObjectShapes);
416  // Set up array
417  pArray = new C4ValueArray(32); iSize = 0;
418  // Create marker, search all areas
419  uint32_t iMarker = ::Objects.GetNextMarker();
420  for (; pLst; pLst=Area.NextObjectShapes(pLst, &pSct))
421  for (C4Object *obj : *pLst)
422  if (obj->Status)
423  if (obj->Marker != iMarker)
424  {
425  obj->Marker = iMarker;
426  if (Check(obj))
427  {
428  // Grow the array, if neccessary
429  if (iSize >= pArray->GetSize())
430  pArray->SetSize(iSize * 2);
431  // Add object
432  (*pArray)[iSize++] = C4VObj(obj);
433  }
434  }
435  }
436  else
437  {
438  // Set up array
439  pArray = new C4ValueArray(32); iSize = 0;
440  // Search
441  C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct;
442  for (C4ObjectList *pLst=Area.FirstObjects(&pSct); pLst; pLst=Area.NextObjects(pLst, &pSct))
443  for (C4Object *obj : *pLst)
444  if (obj->Status)
445  if (Check(obj))
446  {
447  // Grow the array, if neccessary
448  if (iSize >= pArray->GetSize())
449  pArray->SetSize(iSize * 2);
450  // Add object
451  (*pArray)[iSize++] = C4VObj(obj);
452  }
453  }
454  // Shrink array
455  pArray->SetSize(iSize);
456  // Recheck object status (may shrink array again)
457  CheckObjectStatus(pArray);
458  // Apply sorting
459  if (pSort) pSort->SortObjects(pArray);
460  return pArray;
461 }
462 
463 void C4FindObject::CheckObjectStatus(C4ValueArray *pArray)
464 {
465  // Recheck object status
466  for (int32_t i = 0; i < pArray->GetSize(); i++)
467  if (!pArray->GetItem(i).getObj()->Status)
468  {
469  // This shouldn't happen really, so this is done as a separate loop.
470  int32_t j = i; i++;
471  for (; i < pArray->GetSize(); i++)
472  if (pArray->GetItem(i).getObj()->Status)
473  (*pArray)[j++] = pArray->GetItem(i);
474  // Set new size
475  pArray->SetSize(j);
476  break;
477  }
478 }
479 
481 {
482  delete pSort;
483  pSort = pToSort;
484 }
485 
486 
487 // *** C4FindObjectNot
488 
490 {
491  delete pCond;
492 }
493 
495 {
496  return !pCond->Check(pObj);
497 }
498 
499 // *** C4FindObjectAnd
500 
501 C4FindObjectAnd::C4FindObjectAnd(int32_t inCnt, C4FindObject **ppConds, bool fFreeArray)
502  : iCnt(inCnt), ppConds(ppConds), fFreeArray(fFreeArray), fUseShapes(false), fHasBounds(false)
503 {
504  // Filter ensured entries
505  int32_t i;
506  for (i = 0; i < iCnt; )
507  if (ppConds[i]->IsEnsured())
508  {
509  delete ppConds[i];
510  iCnt--;
511  for (int32_t j = i; j < iCnt; j++)
512  ppConds[j] = ppConds[j + 1];
513  }
514  else
515  i++;
516  // Intersect all child bounds
517  for (i = 0; i < iCnt; i++)
518  {
519  C4Rect *pChildBounds = ppConds[i]->GetBounds();
520  if (pChildBounds)
521  {
522  if (!fHasBounds)
523  {
524  fUseShapes = ppConds[i]->UseShapes();
525  Bounds = *pChildBounds;
526  fHasBounds = true;
527  }
528  // some objects might be in an rect and at a point not in that rect
529  // so do not intersect shapes bounds with rects bound
530  else if (fUseShapes == ppConds[i]->UseShapes())
531  Bounds.Intersect(*pChildBounds);
532  // simply use a larger rect than strictly necessary,
533  // the objects will be filtered out later
534  }
535  }
536 }
537 
539 {
540  for (int32_t i = 0; i < iCnt; i++)
541  delete ppConds[i];
542  if (fFreeArray)
543  delete [] ppConds;
544 }
545 
547 {
548  for (int32_t i = 0; i < iCnt; i++)
549  if (!ppConds[i]->Check(pObj))
550  return false;
551  return true;
552 }
553 
555 {
556  for (int32_t i = 0; i < iCnt; i++)
557  if (ppConds[i]->IsImpossible())
558  return true;
559  return false;
560 }
561 
562 // *** C4FindObjectOr
563 
565  : iCnt(inCnt), ppConds(ppConds), fHasBounds(false)
566 {
567  // Filter impossible entries
568  int32_t i;
569  for (i = 0; i < iCnt; )
570  if (ppConds[i]->IsImpossible())
571  {
572  delete ppConds[i];
573  iCnt--;
574  for (int32_t j = i; j < iCnt; j++)
575  ppConds[j] = ppConds[j + 1];
576  }
577  else
578  i++;
579  // Sum up all child bounds
580  for (i = 0; i < iCnt; i++)
581  {
582  C4Rect *pChildBounds = ppConds[i]->GetBounds();
583  if (!pChildBounds) { fHasBounds = false; break; }
584  // With objects that have a position outside their shape, mixing
585  // shape bounds with rect bounds results in no bounds
586  if (fHasBounds && fUseShapes != ppConds[i]->UseShapes())
587  { fHasBounds = false; break; }
588  if (fHasBounds)
589  Bounds.Add(*pChildBounds);
590  else
591  {
592  fUseShapes = ppConds[i]->UseShapes();
593  Bounds = *pChildBounds;
594  fHasBounds = true;
595  }
596  }
597 }
598 
600 {
601  for (int32_t i = 0; i < iCnt; i++)
602  delete ppConds[i];
603  delete [] ppConds;
604 }
605 
607 {
608  for (int32_t i = 0; i < iCnt; i++)
609  if (ppConds[i]->Check(pObj))
610  return true;
611  return false;
612 }
613 
615 {
616  for (int32_t i = 0; i < iCnt; i++)
617  if (ppConds[i]->IsEnsured())
618  return true;
619  return false;
620 }
621 
622 // *** C4FindObject* (primitive conditions)
623 
625 {
626  return pObj != pExclude;
627 }
628 
630 {
631  return pObj->GetPrototype() == def;
632 }
633 
635 {
636  return !def || !def->GetDef() || !def->GetDef()->Count;
637 }
638 
640 {
641  return rect.Contains(pObj->GetX(), pObj->GetY());
642 }
643 
645 {
646  return !rect.Wdt || !rect.Hgt;
647 }
648 
650 {
651  return pObj->Shape.Contains(bounds.x - pObj->GetX(), bounds.y - pObj->GetY());
652 }
653 
655 {
656  C4Rect rcShapeBounds = pObj->Shape;
657  rcShapeBounds.x += pObj->GetX(); rcShapeBounds.y += pObj->GetY();
658  return !!rcShapeBounds.Overlap(bounds);
659 }
660 
662 {
663  return pObj->Shape.IntersectsLine(x - pObj->GetX(), y - pObj->GetY(), x2 - pObj->GetX(), y2 - pObj->GetY());
664 }
665 
667 {
668  return (pObj->GetX() - x) * (pObj->GetX() - x) + (pObj->GetY() - y) * (pObj->GetY() - y) <= r2;
669 }
670 
672 {
673  return !! (pObj->OCF & ocf);
674 }
675 
677 {
678  return !ocf;
679 }
680 
682 {
683  return !! (pObj->Category & iCategory);
684 }
685 
687 {
688  return !iCategory;
689 }
690 
692 {
693  assert(pObj);
694  if (!pObj->GetAction()) return false;
695  return SEqual(pObj->GetAction()->GetName(), szAction);
696 }
697 
699 {
700  assert(index >= 0 && index <= 1);
701  assert(pObj);
702  if (!pObj->GetAction()) return false;
703  if (index == 0)
704  return pObj->Action.Target == pActionTarget;
705  else if (index == 1)
706  return pObj->Action.Target2 == pActionTarget;
707  else
708  return false;
709 }
710 
712 {
713  assert(pObj);
714  if (!pObj->GetAction()) return false;
715  C4Value v;
716  pObj->GetAction()->GetProperty(P_Procedure, &v);
717  return v != C4VNull && v.getStr() == procedure;
718 }
719 
721 {
722  return false;
723 }
724 
726 {
727  return pObj->Contained == pContainer;
728 }
729 
731 {
732  return !! pObj->Contained;
733 }
734 
736 {
737  return pObj->Owner == iOwner;
738 }
739 
741 {
742  return iOwner != NO_OWNER && !ValidPlr(iOwner);
743 }
744 
746 {
747  return pObj->Controller == controller;
748 }
749 
751 {
752  return controller != NO_OWNER && !ValidPlr(controller);
753 }
754 
755 // *** C4FindObjectFunc
756 
757 void C4FindObjectFunc::SetPar(int i, const C4Value &Par)
758 {
759  // Over limit?
760  if (i >= C4AUL_MAX_Par) return;
761  // Set parameter
762  Pars[i] = Par;
763 }
764 
766 {
767  assert(Name); // checked in constructor
768  // Function not found?
769  return pObj->Call(Name, &Pars).getBool();
770 }
771 
773 {
774  return false;
775 }
776 
777 // *** C4FindObjectLayer
778 
780 {
781  return pObj->Layer == pLayer;
782 }
783 
785 {
786  return false;
787 }
788 
789 // *** C4FindObjectInArray
790 
792 {
793  // O(n) array look-up
794  if (!pArray) return false;
795  int32_t sz = pArray->GetSize();
796  for (int i=0; i<sz; ++i)
797  if (pArray->_GetItem(i).getObj() == pObj)
798  return true;
799  return false;
800 }
801 
803 {
804  return !pArray || !pArray->GetSize();
805 }
806 
807 // *** C4FindObjectProperty
808 
810 {
811  assert(Name); // checked in constructor
812  C4Value value;
813  return pObj->GetPropertyByS(Name, &value) && value.getBool();
814 }
815 
817 {
818  return false;
819 }
820 
821 
822 // *** C4SortObject
823 
825 {
826  // Must be an array
827  const C4ValueArray *pArray = C4Value(DataVal).getArray();
828  if (!pArray) return nullptr;
829  const C4ValueArray &Data = *pArray;
830  int32_t iType = Data[0].getInt();
831  return CreateByValue(iType, Data, context);
832 }
833 
834 C4SortObject *C4SortObject::CreateByValue(int32_t iType, const C4ValueArray &Data, const C4Object *context)
835 {
836  switch (iType)
837  {
838  case C4SO_Reverse:
839  {
840  // create child sort
841  C4SortObject *pChildSort = C4SortObject::CreateByValue(Data[1], context);
842  if (!pChildSort) return nullptr;
843  // wrap
844  return new C4SortObjectReverse(pChildSort);
845  }
846 
847  case C4SO_Multiple:
848  {
849  // Trivial case (one sort)
850  if (Data.GetSize() == 2)
851  {
852  return C4SortObject::CreateByValue(Data[1], context);
853  }
854  // Create all children
855  int32_t i;
856  C4SortObject **ppSorts = new C4SortObject *[Data.GetSize() - 1];
857  for (i = 0; i < Data.GetSize() - 1; i++)
858  {
859  ppSorts[i] = C4SortObject::CreateByValue(Data[i+1], context);
860  }
861  // Count real entries, move them to start of list
862  int32_t iSize = 0;
863  for (i = 0; i < Data.GetSize() - 1; i++)
864  if (ppSorts[i])
865  if (iSize++ != i)
866  ppSorts[iSize-1] = ppSorts[i];
867  // Create
868  return new C4SortObjectMultiple(iSize, ppSorts);
869  }
870 
871  case C4SO_Distance:
872  {
873  int32_t x = Data[1].getInt();
874  int32_t y = Data[2].getInt();
875  if (context)
876  {
877  x += context->GetX();
878  y += context->GetY();
879  }
880  return new C4SortObjectDistance(x, y);
881  }
882 
883  case C4SO_Random:
884  return new C4SortObjectRandom();
885 
886  case C4SO_Speed:
887  return new C4SortObjectSpeed();
888 
889  case C4SO_Mass:
890  return new C4SortObjectMass();
891 
892  case C4SO_Value:
893  return new C4SortObjectValue();
894 
895  case C4SO_Func:
896  {
897  // Get function name
898  C4String *pStr = Data[1].getStr();
899  if (!pStr) return nullptr;
900  // Construct
901  C4SortObjectFunc *pSO = new C4SortObjectFunc(pStr);
902  // Add parameters
903  for (int i = 2; i < Data.GetSize(); i++)
904  pSO->SetPar(i - 2, Data[i]);
905  // Done
906  return pSO;
907  }
908 
909  }
910  return nullptr;
911 }
912 
914 {
915  pArray->Sort(*this);
916 }
917 
918 // *** C4SortObjectByValue
919 
921  : C4SortObject()
922 {
923 }
924 
926 {
927  delete [] pVals; pVals = nullptr;
928 }
929 
931 {
932  // Clear old cache
933  delete [] pVals; pVals = nullptr; iSize = 0;
934  // Create new cache
935  iSize = pObjs->GetSize(); pVals = new int32_t [iSize];
936  for (int32_t i = 0; i < iSize; i++)
937  pVals[i] = CompareGetValue(pObjs->GetItem(i)._getObj());
938  // Okay
939  return true;
940 }
941 
943 {
944  // this is rather slow, should only be called in special cases
945 
946  // make sure to hardcode the call order, as it might lead to desyncs otherwise [Icewing]
947  int32_t iValue1 = CompareGetValue(pObj1);
948  int32_t iValue2 = CompareGetValue(pObj2);
949  return iValue2 - iValue1;
950 }
951 
952 int32_t C4SortObjectByValue::CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2)
953 {
954  assert(pVals); assert(iObj1 >= 0 && iObj1 < iSize); assert(iObj2 >= 0 && iObj2 < iSize);
955  // Might overflow for large values...!
956  return pVals[iObj2] - pVals[iObj1];
957 }
958 
960 {
961  delete pSort;
962 }
963 
965 {
966  return pSort->Compare(pObj2, pObj1);
967 }
968 
970 {
971  return pSort->PrepareCache(pObjs);
972 }
973 
974 int32_t C4SortObjectReverse::CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2)
975 {
976  return pSort->CompareCache(iObj2, iObj1, pObj2, pObj1);
977 }
978 
980 {
981  for (int32_t i=0; i<iCnt; ++i) delete ppSorts[i];
982  if (fFreeArray) delete [] ppSorts;
983 }
984 
986 {
987  // return first comparison that's nonzero
988  int32_t iCmp;
989  for (int32_t i=0; i<iCnt; ++i)
990  if ((iCmp = ppSorts[i]->Compare(pObj1, pObj2)))
991  return iCmp;
992  // all comparisons equal
993  return 0;
994 }
995 
997 {
998  bool fCaches = false;
999  for (int32_t i=0; i<iCnt; ++i)
1000  fCaches |= ppSorts[i]->PrepareCache(pObjs);
1001  // return wether a sort citerion uses a cache
1002  return fCaches;
1003 }
1004 
1005 int32_t C4SortObjectMultiple::CompareCache(int32_t iObj1, int32_t iObj2, C4Object *pObj1, C4Object *pObj2)
1006 {
1007  // return first comparison that's nonzero
1008  int32_t iCmp;
1009  for (int32_t i=0; i<iCnt; ++i)
1010  if ((iCmp = ppSorts[i]->CompareCache(iObj1, iObj2, pObj1, pObj2)))
1011  return iCmp;
1012  // all comparisons equal
1013  return 0;
1014 }
1015 
1017 {
1018  int32_t dx=pFor->GetX()-iX, dy=pFor->GetY()-iY;
1019  return dx*dx+dy*dy;
1020 }
1021 
1023 {
1024  return Random(1 << 16);
1025 }
1026 
1028 {
1029  return fixtoi(pFor->xdir*pFor->xdir + pFor->ydir*pFor->ydir);
1030 }
1031 
1033 {
1034  return pFor->Mass;
1035 }
1036 
1038 {
1039  return pFor->GetValue(nullptr, NO_OWNER);
1040 }
1041 
1042 void C4SortObjectFunc::SetPar(int i, const C4Value &Par)
1043 {
1044  // Over limit?
1045  if (i >= C4AUL_MAX_Par) return;
1046  // Set parameter
1047  Pars[i] = Par;
1048 }
1049 
1051 {
1052  if (!Name) return false;
1053  return pObj->Call(Name, &Pars).getInt();
1054 }
int32_t GetY() const
Definition: C4Object.h:287
virtual bool UseShapes()
Definition: C4FindObject.h:95
friend class C4FindObjectNot
Definition: C4FindObject.h:70
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:97
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:130
int32_t GetValue(C4Object *pInBase, int32_t iForPlayer)
Definition: C4Object.cpp:1691
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:2678
const char * GetCStr() const
Definition: C4StringTable.h:49
bool GetPropertyByS(const C4String *k, C4Value *pResult) const override
Definition: C4Object.cpp:4877
Definition: C4Rect.h:27
virtual C4Rect * GetBounds()
Definition: C4FindObject.h:94
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
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:681
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:71
#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:180
bool Check(C4Object *pObj) override
virtual const char * GetName() const
Definition: C4PropList.cpp:645
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:131
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:138
bool Check(C4Object *pObj) override
void SetSize(int32_t inSize)
virtual bool IsImpossible()
Definition: C4FindObject.h:96
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:157
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:411
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:72
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:412
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:159
bool Check(C4Object *pObj) override
C4Value Call(C4PropertyName k, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4PropList.h:110
bool Check(C4Object *pObj) override