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