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