OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4ObjectList.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Dynamic object list */
19 
20 #include "C4Include.h"
21 #include "object/C4ObjectList.h"
22 
23 #include "object/C4Def.h"
24 #include "object/C4DefList.h"
25 #include "object/C4Object.h"
26 #include "game/C4Application.h"
28 #include "game/C4Game.h"
29 #include "object/C4GameObjects.h"
30 
31 static const C4ObjectLink NULL_LINK = { nullptr, nullptr, nullptr };
32 
34 {
35  Default();
36 }
37 
38 C4ObjectList::C4ObjectList(const C4ObjectList &List): FirstIter(0)
39 {
40  Default();
41  Copy(List);
42 }
43 
45 {
46  Clear();
47 }
48 
50 {
51  C4ObjectLink *cLnk,*nextLnk;
52  for (cLnk=First; cLnk; cLnk=nextLnk)
53  { nextLnk=cLnk->Next; delete cLnk; }
54  First=Last=nullptr;
55  if (pEnumerated)
56  {
57  delete pEnumerated;
58  pEnumerated=nullptr;
59  }
60 
61  for (iterator* it = FirstIter; it; it = it->Next)
62  {
63  it->link = NULL_LINK;
64  }
65 }
66 
67 const int MaxTempListID = 500;
69 
70 C4ID C4ObjectList::GetListID(int32_t dwCategory, int Index) const
71 {
72  int clid;
73  C4ObjectLink *clnk;
74  C4Def *cdef;
75 
76  // Create a temporary list of all id's and counts
77  for (clid=0; clid<MaxTempListID; clid++) TempListID[clid]=C4ID::None;
78  for (clnk=First; clnk && clnk->Obj; clnk=clnk->Next)
79  if (clnk->Obj->Status)
80  if ((dwCategory==C4D_All) || ( (cdef=C4Id2Def(clnk->Obj->Def->id)) && (cdef->Category & dwCategory) ))
81  for (clid=0; clid<MaxTempListID; clid++)
82  {
83  // Already there
84  if (TempListID[clid]==clnk->Obj->Def->id) break;
85  // End of list, add id
86  if (TempListID[clid]==C4ID::None) { TempListID[clid]=clnk->Obj->Def->id; break; }
87  }
88 
89  // Returns indexed id
90  if (Inside(Index,0,MaxTempListID-1)) return TempListID[Index];
91 
92  return C4ID::None;
93 }
94 
95 int C4ObjectList::ListIDCount(int32_t dwCategory) const
96 {
97  int clid;
98  C4ObjectLink *clnk;
99  C4Def *cdef;
100 
101  // Create a temporary list of all id's and counts
102  for (clid=0; clid<MaxTempListID; clid++) TempListID[clid]=C4ID::None;
103  for (clnk=First; clnk && clnk->Obj; clnk=clnk->Next)
104  if (clnk->Obj->Status)
105  if ((dwCategory==C4D_All) || ( (cdef=C4Id2Def(clnk->Obj->Def->id)) && (cdef->Category & dwCategory) ))
106  for (clid=0; clid<MaxTempListID; clid++)
107  {
108  // Already there
109  if (TempListID[clid]==clnk->Obj->Def->id) break;
110  // End of list, add id
111  if (TempListID[clid]==C4ID::None) { TempListID[clid]=clnk->Obj->Def->id; break; }
112  }
113 
114  // Count different id's
115  for (clid=0; clid<MaxTempListID; clid++)
116  if (TempListID[clid]==C4ID::None)
117  return clid;
118 
119  return MaxTempListID;
120 }
121 
122 
123 
124 bool C4ObjectList::Add(C4Object *nObj, SortType eSort, C4ObjectList *pLstSorted)
125 {
126  C4ObjectLink *nLnk;
127  if (!nObj || !nObj->Def || !nObj->Status) return false;
128 
129 #ifdef _DEBUG
130  if (eSort==stMain)
131  {
133  if (pLstSorted)
134  assert(CheckSort(pLstSorted));
135  }
136 #endif
137 
138  // dbg: don't do double links
139  assert (!GetLink(nObj));
140 
141  // no self-sort
142  assert(pLstSorted != this);
143 
144  // Allocate new link
145  if (!(nLnk=new C4ObjectLink)) return false;
146  // Set link
147  nLnk->Obj=nObj;
148 
149  // Search insert position (default: end of list)
150  C4ObjectLink *cLnk = nullptr, *cPrev = Last;
151 
152  // Should sort?
153  if (eSort == stReverse)
154  {
155  // reverse sort: Add to beginning of list
156  cLnk = First; cPrev = nullptr;
157  }
158  else if (eSort)
159  {
160  // Sort override? Leave default as is.
161  bool fUnsorted = nObj->Unsorted;
162  if (!fUnsorted)
163  {
164  // Sort by master list?
165  if (pLstSorted)
166  {
167  cPrev = nullptr; cLnk = First;
168  while(cLnk && (!cLnk->Obj->Status || cLnk->Obj->Unsorted)) cLnk = cLnk->Next;
169 
170 #ifndef _DEBUG
171  if(cLnk)
172 #endif
173  {
174  C4ObjectLink* cLnk2;
175  for(cLnk2 = pLstSorted->First; cLnk2; cLnk2 = cLnk2->Next)
176  {
177  if(cLnk2->Obj->Status && !cLnk2->Obj->Unsorted)
178  {
179  if(cLnk2->Obj == nObj)
180  {
181  assert(!cLnk || cLnk->Obj != nObj);
182  break;
183  }
184 
185  if(cLnk && cLnk2->Obj == cLnk->Obj)
186  {
187  cPrev = cLnk;
188  cLnk = cLnk->Next;
189  while(cLnk && (!cLnk->Obj->Status || cLnk->Obj->Unsorted)) cLnk = cLnk->Next;
190 
191 #ifndef _DEBUG
192  if(!cLnk) break;
193 #endif
194  }
195  }
196  }
197 
198  assert(cLnk2 != nullptr);
199  }
200  }
201  else
202  {
203  // No master list: Find successor by matching Plane / id
204  // Sort by matching Plane/id is necessary for inventory shifting.
205  // It is not done for static back to allow multiobject outside structure.
206  // Unsorted objects are ignored in comparison.
207  if (!(nObj->Category & C4D_StaticBack))
208  for (cPrev=nullptr,cLnk=First; cLnk; cLnk=cLnk->Next)
209  if (cLnk->Obj->Status && !cLnk->Obj->Unsorted)
210  {
211  if (cLnk->Obj->GetPlane() == nObj->GetPlane())
212  if (cLnk->Obj->id == nObj->id)
213  break;
214  cPrev=cLnk;
215  }
216 
217  // Find successor by relative category
218  if(!cLnk)
219  for (cPrev=nullptr, cLnk=First; cLnk; cLnk=cLnk->Next)
220  if (cLnk->Obj->Status && !cLnk->Obj->Unsorted)
221  {
222  if (cLnk->Obj->GetPlane() <= nObj->GetPlane())
223  break;
224  cPrev=cLnk;
225  }
226  }
227 
228  cLnk = cPrev ? cPrev->Next : First;
229  }
230  }
231 
232  assert(!cPrev || cPrev->Next == cLnk);
233  assert(!cLnk || cLnk->Prev == cPrev);
234 
235  // Insert new link after predecessor
236  InsertLink(nLnk, cPrev);
237 
238 #ifdef _DEBUG
239  // Debug: Check sort
240  if (eSort == stMain)
241  {
243  if (pLstSorted)
244  assert(CheckSort(pLstSorted));
245  }
246 #endif
247 
248  // Add mass
249  Mass+=nObj->Mass;
250 
251  return true;
252 }
253 
255 {
256  C4ObjectLink *cLnk;
257 
258  // Find link
259  for (cLnk=First; cLnk; cLnk=cLnk->Next)
260  if (cLnk->Obj==pObj) break;
261  if (!cLnk) return false;
262 
263  // Fix iterators
264  for (iterator * i = FirstIter; i; i = i->Next)
265  {
266  // adjust pointers of internal link field
267  if (i->link.Prev == cLnk)
268  {
269  i->link.Prev = cLnk->Prev;
270  }
271  else if (i->link.Next == cLnk)
272  {
273  i->link.Next = cLnk->Next;
274  }
275  else if (i->link.Obj == cLnk->Obj)
276  {
277  i->link.Obj = nullptr;
278  }
279  }
280 
281  // Remove link from list
282  RemoveLink(cLnk);
283 
284  // Deallocate link
285  delete cLnk;
286 
287  // Remove mass
288  Mass-=pObj->Mass; if (Mass<0) Mass=0;
289 
290 #if defined(_DEBUG)
291  if (GetLink(pObj)) BREAKPOINT_HERE;
292 #endif
293 
294  return true;
295 }
296 
297 C4Object* C4ObjectList::Find(C4Def * def, int owner, DWORD dwOCF)
298 {
299  C4ObjectLink *cLnk;
300  // Find link and object
301  for (cLnk=First; cLnk; cLnk=cLnk->Next)
302  if (cLnk->Obj->Status)
303  if (cLnk->Obj->Def==def)
304  if ((owner==ANY_OWNER) || (cLnk->Obj->Owner==owner))
305  if (dwOCF & cLnk->Obj->OCF)
306  return cLnk->Obj;
307  return nullptr;
308 }
309 
311 {
312  C4ObjectLink *cLnk;
313  // Find link and object
314  for (cLnk=First; cLnk; cLnk=cLnk->Next)
315  if (cLnk->Obj->Status)
316  if (cLnk->Obj->Def->id!=id)
317  if ((owner==ANY_OWNER) || (cLnk->Obj->Owner==owner))
318  return cLnk->Obj;
319  return nullptr;
320 }
321 
323 {
324  int cIdx;
325  C4ObjectLink *cLnk;
326  // Find link and object
327  for (cLnk=First,cIdx=0; cLnk; cLnk=cLnk->Next)
328  if (cLnk->Obj->Status)
329  {
330  if (cIdx==Index) return cLnk->Obj;
331  cIdx++;
332  }
333  return nullptr;
334 }
335 
336 const C4ObjectLink* C4ObjectList::GetLink(const C4Object *pObj) const
337 {
338  if (!pObj) return nullptr;
339  C4ObjectLink *cLnk;
340  for (cLnk=First; cLnk; cLnk=cLnk->Next)
341  if (cLnk->Obj==pObj)
342  return cLnk;
343  return nullptr;
344 }
345 
347 {
348  C4ObjectLink *cLnk;
349  int iCount=0;
350  for (cLnk=First; cLnk; cLnk=cLnk->Next)
351  if (cLnk->Obj->Status && (id==C4ID::None || cLnk->Obj->Def->id==id))
352  iCount++;
353  return iCount;
354 }
355 
357 {
358  C4ObjectLink *cLnk;
359  int iMass=0;
360  for (cLnk=First; cLnk; cLnk=cLnk->Next)
361  if (cLnk->Obj->Status)
362  iMass+=cLnk->Obj->Mass;
363  Mass=iMass;
364  return iMass;
365 }
366 
368 {
369  int rval=0;
370  // Clear all primary list pointers
371  while (Remove(pObj)) rval++;
372  // Clear all sub pointers
373  C4Object *cobj; C4ObjectLink *clnk;
374  for (clnk=First; clnk && (cobj=clnk->Obj); clnk=clnk->Next)
375  cobj->ClearPointers(pObj);
376  return rval;
377 }
378 
379 void C4ObjectList::Draw(C4TargetFacet &cgo, int iPlayer, int MinPlane, int MaxPlane)
380 {
381  C4ObjectLink * clnk, * first;
382  for (first=Last; first; first=first->Prev)
383  if (first->Obj->GetPlane() >= MinPlane)
384  break;
385  // Draw objects (base)
386  for (clnk=first; clnk; clnk=clnk->Prev)
387  {
388  if (clnk->Obj->GetPlane() > MaxPlane)
389  break;
390  if (clnk->Obj->Category & C4D_Foreground)
391  continue;
392  clnk->Obj->Draw(cgo, iPlayer);
393  }
394  // Draw objects (top face)
395  for (clnk=first; clnk; clnk=clnk->Prev)
396  {
397  if (clnk->Obj->GetPlane() > MaxPlane)
398  break;
399  if (clnk->Obj->Category & C4D_Foreground)
400  continue;
401  clnk->Obj->DrawTopFace(cgo, iPlayer);
402  }
403 }
404 
405 void C4ObjectList::DrawIfCategory(C4TargetFacet &cgo, int iPlayer, uint32_t dwCat, bool fInvert)
406 {
407  C4ObjectLink *clnk;
408  // Draw objects (base)
409  for (clnk=Last; clnk; clnk=clnk->Prev)
410  if (!(clnk->Obj->Category & dwCat) == fInvert)
411  clnk->Obj->Draw(cgo, iPlayer);
412  // Draw objects (top face)
413  for (clnk=Last; clnk; clnk=clnk->Prev)
414  if (!(clnk->Obj->Category & dwCat) == fInvert)
415  clnk->Obj->DrawTopFace(cgo, iPlayer);
416 }
417 
418 bool C4ObjectList::IsContained(const C4Object *pObj) const
419 {
420  C4ObjectLink *cLnk;
421  for (cLnk=First; cLnk; cLnk=cLnk->Next)
422  if (cLnk->Obj==pObj)
423  return true;
424  return false;
425 }
426 
428 {
429  return (ObjectCount()==0);
430 }
431 
433 {
434  if (!pEnumerated) return false;
435  // Denumerate all object pointers
436  for (std::list<int32_t>::const_iterator pNum = pEnumerated->begin(); pNum != pEnumerated->end(); ++pNum)
437  Add(::Objects.ObjectPointer(*pNum), stNone); // Add to tail, unsorted
438  // Delete old list
439  delete pEnumerated; pEnumerated = nullptr;
440  return true;
441 }
442 
443 bool C4ObjectList::Write(char *szTarget)
444 {
445  char ostr[25];
446  szTarget[0]=0;
447  C4ObjectLink *cLnk;
448  for (cLnk=First; cLnk && cLnk->Obj; cLnk=cLnk->Next)
449  if (cLnk->Obj->Status)
450  {
451  sprintf(ostr,"%d;",cLnk->Obj->Number);
452  SAppend(ostr,szTarget);
453  }
454  return true;
455 }
456 
458 {
459  C4ObjectLink *cLnk;
460  for (cLnk=First; cLnk; cLnk=cLnk->Next)
461  if (cLnk->Obj->Status)
462  cLnk->Obj->Denumerate(numbers);
463 }
464 
465 void C4ObjectList::CompileFunc(StdCompiler *pComp, bool fSkipPlayerObjects, C4ValueNumbers * numbers)
466 {
467  // "Object" section count
468  int32_t iObjCnt = ObjectCount();
469  pComp->Value(mkNamingCountAdapt(iObjCnt, "Object"));
470  if (pComp->isSerializer())
471  {
472  // skipping player objects would screw object counting in non-naming compilers
473  assert(!fSkipPlayerObjects || pComp->hasNaming());
474  // Decompile all objects in reverse order
475  for (C4ObjectLink *pPos = Last; pPos; pPos = pPos->Prev)
476  if (pPos->Obj->Status)
477  if (!fSkipPlayerObjects || !pPos->Obj->IsUserPlayerObject())
478  pComp->Value(mkNamingAdapt(mkParAdapt(*pPos->Obj, numbers), "Object"));
479  }
480  else
481  {
482  // FIXME: Check that no PlayerObjects are loaded when fSkipPlayerObjects is true
483  // i.e. that loading and saving was done with the same flag.
484  // Remove previous data
485  Clear();
486  // Load objects, add them to the list.
487  for (int i = 0; i < iObjCnt; i++)
488  {
489  C4Object *pObj = nullptr;
490  try
491  {
492  pComp->Value(mkNamingAdapt(mkParAdapt(mkPtrAdaptNoNull(pObj), numbers), "Object"));
493  Add(pObj, stReverse);
494  }
495  catch (StdCompiler::Exception *pExc)
496  {
497  // Failsafe object loading: If an error occurs during object loading, just skip that object and load the next one
498  if (!pExc->Pos.getLength())
499  LogF("ERROR: Object loading: %s", pExc->Msg.getData());
500  else
501  LogF("ERROR: Object loading(%s): %s", pExc->Pos.getData(), pExc->Msg.getData());
502  delete pExc;
503  }
504  }
505  }
506 }
507 
509 {
510  // (Re)create list
511  delete pEnumerated; pEnumerated = new std::list<int32_t>();
512  // Decompiling: Build list
513  if (!pComp->isDeserializer())
514  for (C4ObjectLink *pPos = First; pPos; pPos = pPos->Next)
515  if (pPos->Obj->Status)
516  pEnumerated->push_back(pPos->Obj->Number);
517  // Compile list
519  // Decompiling: Delete list
520  if (!pComp->isDeserializer())
521  { delete pEnumerated; pEnumerated = nullptr; }
522  // Compiling: Nothing to do - list will be denumerated later
523 }
524 
526 {
527  int cpos,idcount;
528  C4ID c_id;
529  C4Def *cdef;
530  StdStrBuf Buf;
531  for (cpos=0; (c_id=GetListID(C4D_All,cpos)); cpos++)
532  if ((cdef=rDefs.ID2Def(c_id)))
533  {
534  idcount=ObjectCount(c_id);
535  if (cpos>0) Buf.Append(", ");
536  Buf.AppendFormat("%dx %s",idcount,cdef->GetName());
537  }
538  return Buf;
539 }
540 
542 {
543  C4ObjectLink *cLnk;
544  for (cLnk=First; cLnk; cLnk=cLnk->Next)
545  if (cLnk->Obj->Status)
546  cLnk->Obj->ValidateOwner();
547  return true;
548 }
549 
551 {
552  // the list seems to be traced backwards here, to ensure crew objects are added in correct order
553  // (or semi-correct, because this will work only if the crew order matches the main object list order)
554  // this is obsolete now, because the crew list is stored in the savegame
555  C4ObjectLink *cLnk;
556  for (cLnk=Last; cLnk; cLnk=cLnk->Prev)
557  if (cLnk->Obj->Status)
558  cLnk->Obj->AssignInfo();
559  return true;
560 }
561 
563 {
564  C4ObjectLink *cLnk;
565  for (cLnk=First; cLnk; cLnk=cLnk->Next)
566  if (cLnk->Obj->Status)
567  cLnk->Obj->ClearInfo(pInfo);
568 }
569 
571 {
572  C4ObjectLink *cLnk;
573  bool fSorted;
574  // Sort by id
575  do
576  {
577  fSorted = true;
578  for (cLnk=First; cLnk && cLnk->Next; cLnk=cLnk->Next)
579  if (cLnk->Obj->id > cLnk->Next->Obj->id)
580  {
581  RemoveLink(cLnk);
582  InsertLink(cLnk,cLnk->Next);
583  fSorted = false;
584  break;
585  }
586  }
587  while (!fSorted);
588 }
589 
591 {
592  if (pLnk->Prev) pLnk->Prev->Next=pLnk->Next; else First=pLnk->Next;
593  if (pLnk->Next) pLnk->Next->Prev=pLnk->Prev; else Last=pLnk->Prev;
594 }
595 
597 {
598  // Insert after
599  if (pAfter)
600  {
601  pLnk->Prev=pAfter; pLnk->Next=pAfter->Next;
602  if (pAfter->Next) pAfter->Next->Prev=pLnk; else Last=pLnk;
603  pAfter->Next=pLnk;
604  }
605  // Insert at head
606  else
607  {
608  pLnk->Prev=nullptr; pLnk->Next=First;
609  if (First) First->Prev=pLnk; else Last=pLnk;
610  First=pLnk;
611  }
612 
613  // adjust iterators
614  if (pAfter)
615  {
616  for (iterator* it = FirstIter; it; it = it->Next)
617  {
618  if (it->link.Obj == pAfter->Obj)
619  {
620  it->link.Next = pLnk;
621  }
622  }
623  }
624 }
625 
627 {
628  // Insert before
629  if (pBefore)
630  {
631  pLnk->Prev = pBefore->Prev;
632  if (pBefore->Prev) pBefore->Prev->Next = pLnk; else First = pLnk;
633  pLnk->Next = pBefore; pBefore->Prev = pLnk;
634  }
635  // Insert at end
636  else
637  {
638  pLnk->Next = nullptr; pLnk->Prev = Last;
639  if (Last) Last->Next = pLnk; else First = pLnk;
640  Last = pLnk;
641  }
642 
643  // adjust iterators
644  if (pBefore)
645  {
646  for (iterator* it = FirstIter; it; it = it->Next)
647  {
648  if (it->link.Obj == pBefore->Obj)
649  {
650  it->link.Prev = pLnk;
651  }
652  }
653  }
654 }
655 
656 
658 {
659  C4ObjectList::InsertLinkBefore(pLink, pBefore);
661 }
662 
664 {
665  C4ObjectList::InsertLink(pLink, pAfter);
667 }
668 
670 {
673 }
674 
675 void C4ObjectList::UpdateGraphics(bool fGraphicsChanged)
676 {
677  C4ObjectLink *cLnk;
678  for (cLnk=First; cLnk; cLnk=cLnk->Next)
679  if (cLnk->Obj->Status)
680  cLnk->Obj->UpdateGraphics(fGraphicsChanged);
681 }
682 
683 void C4ObjectList::UpdateFaces(bool bUpdateShapes)
684 {
685  C4ObjectLink *cLnk;
686  for (cLnk=First; cLnk; cLnk=cLnk->Next)
687  if (cLnk->Obj->Status)
688  cLnk->Obj->UpdateFace(bUpdateShapes);
689 }
690 
692 {
693  C4ObjectLink *cLnk;
694  for (cLnk=Last; cLnk; cLnk=cLnk->Prev)
695  cLnk->Obj->DrawSelectMark(cgo);
696 }
697 
699 {
700  C4Object *cobj; C4ObjectLink *clnk;
701  for (clnk=First; clnk && (cobj=clnk->Obj); clnk=clnk->Next)
702  cobj->CloseMenu(true);
703 }
704 
706 {
707  Clear(); Default();
708  C4ObjectLink *cLnk;
709  for (cLnk=rList.First; cLnk; cLnk=cLnk->Next) Add(cLnk->Obj, C4ObjectList::stNone);
710 }
711 
713 {
714  First=Last=nullptr;
715  Mass=0;
716  pEnumerated=nullptr;
717 }
718 
720 {
721  // get link of new first (this ensures list is not empty)
722  C4ObjectLink *pNewFirstLnk = GetLink(pNewFirst);
723  if (!pNewFirstLnk) return false;
724  // already at front?
725  if (pNewFirstLnk == First) return true;
726  // sort it there:
727  // 1. Make cyclic list
728  Last->Next = First; First->Prev = Last;
729  // 2. Re-set first and last
730  First = pNewFirstLnk;
731  Last = pNewFirstLnk->Prev;
732  // 3. Uncycle list
733  First->Prev = Last->Next = nullptr;
734  // done, success
735  return true;
736 }
737 
739 {
740  // delete links and objects
741  while (First)
742  {
743  C4Object *pObj = First->Obj;
744  if (pObj->Status) Game.ClearPointers(pObj); // clear pointers to removed objects that weren't deleted (game end or section change)
745  pObj->Status = C4OS_DELETED;
746  Remove(pObj);
747  delete pObj;
748  }
749  // reset mass
750  Mass=0;
751 }
752 
753 
754 // -------------------------------------------------
755 // C4ObjectListIterator
756 
758 {
759  // end reached?
760  if (pCurrID == rList.end()) return nullptr;
761  // not yet started?
762  if (pCurr == rList.end())
763  // then start at first ID list head
764  pCurr = pCurrID;
765  else
766  // next item
767  if (++pCurr == rList.end()) return nullptr;
768  // next ID section reached?
769  if ((*pCurr)->id != (*pCurrID)->id)
770  pCurrID = pCurr;
771  else
772  {
773  // otherwise, it must be checked, whether this is a duplicate item already iterated
774  // if so, advance the list
775  for (C4ObjectList::iterator pCheck = pCurrID; pCheck != pCurr; ++pCheck)
776  if ((*pCheck)->CanConcatPictureWith(*pCurr))
777  {
778  // next object of matching category
779  if (++pCurr == rList.end()) return nullptr;
780  // next ID chunk reached?
781  if ((*pCurr)->id != (*pCurrID)->id)
782  {
783  // then break here
784  pCurrID = pCurr;
785  break;
786  }
787  // restart check for next object
788  pCheck = pCurrID;
789  }
790  }
791  if (piCount)
792  {
793  // default count
794  *piCount = 1;
795  // add additional objects of same ID to the count
796  C4ObjectList::iterator pCheck(pCurr);
797  for (++pCheck; pCheck != rList.end() && (*pCheck)->id == (*pCurr)->id; ++pCheck)
798  if ((*pCheck)->CanConcatPictureWith(*pCurr))
799  ++*piCount;
800  }
801  // return found object
802  return *pCurr;
803 }
804 
806 {
807  for (C4ObjectLink *cLnk=First; cLnk; cLnk=cLnk->Next)
808  cLnk->Obj->UpdateScriptPointers();
809 }
810 
812 {
815 
816  void CompileFunc(StdCompiler *pComp) { pComp->Value(mkNamingAdapt(mkParAdapt(*pLst, numbers), "Objects")); }
817 
818  C4ObjectListDumpHelper(C4ObjectList *pLst, C4ValueNumbers * numbers) : pLst(pLst), numbers(numbers) {}
819 };
820 
822 {
823  C4ObjectLink *cLnk = First, *cLnk2 = pList->First;
824  while (cLnk && (!cLnk->Obj->Status || cLnk->Obj->Unsorted)) cLnk = cLnk->Next;
825 
826  while (cLnk)
827  if (!cLnk2)
828  {
829  Log("CheckSort failure");
830  C4ValueNumbers numbers;
831  LogSilent(DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(C4ObjectListDumpHelper(this, &numbers), "SectorList")).getData());
832  LogSilent(DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(C4ObjectListDumpHelper(pList, &numbers), "MainList")).getData());
833  return false;
834  }
835  else
836  {
837  if (cLnk->Obj == cLnk2->Obj)
838  {
839  cLnk = cLnk->Next;
840  while (cLnk && (!cLnk->Obj->Status || cLnk->Obj->Unsorted)) cLnk = cLnk->Next;
841  }
842  cLnk2 = cLnk2->Next;
843  }
844  return true;
845 }
846 
848 {
849  // debug: Check whether object list is sorted correctly
850  C4ObjectLink *cLnk, *cPrev=nullptr;
851  for (cLnk=First; cLnk; cLnk=cLnk->Next)
852  if (!cLnk->Obj->Unsorted && cLnk->Obj->Status)
853  {
854  if (cPrev) assert(cPrev->Obj->GetPlane() >= cLnk->Obj->GetPlane());
855  cPrev = cLnk;
856  }
857 }
858 
859 C4ObjectList::iterator::iterator(const C4ObjectList & List, const C4ObjectLink * pLink, bool reverse):
860  List(List), link(pLink ? *pLink : NULL_LINK), reverse(reverse)
861 {
862  Next=List.AddIter(this);
863 }
865  List(iter.List), link(iter.link), Next(), reverse(iter.reverse)
866 {
867  Next=List.AddIter(this);
868 }
870 {
871  List.RemoveIter(this);
872 }
874 {
875  C4ObjectLink* advance = reverse ? link.Prev : link.Next;
876  link = advance ? *advance : NULL_LINK;
877  return *this;
878 }
880 {
881  iterator old = *this;
883  return old;
884 }
886 {
887  return link.Obj;
888 }
890 {
891  return
892  &iter.List == &List &&
893  iter.link.Obj == link.Obj /* checking for same object should be enough */ &&
894  iter.reverse == reverse;
895 }
897 {
898  return !(*this == iter);
899 }
900 
902 {
903  while (link.Obj)
904  {
905  if (link.Obj == target)
906  {
907  return true;
908  }
909  else
910  {
911  (*this)++;
912  }
913  }
914  return false;
915 }
916 
918 {
919  return link.Obj == nullptr;
920 }
921 
923 {
924  C4ObjectLink* l = reverse ? List.Last : List.First;
925  link = l ? *l : NULL_LINK;
926  return !atEnd();
927 }
928 
930 {
931  (*this)++;
932  return !atEnd();
933 }
934 
936 {
937  // Can only assign iterators into the same list
938  assert(&iter.List == &List);
939 
940  link = iter.link;
941  reverse = iter.reverse;
942  return *this;
943 }
944 
946 {
947  return iterator(*this, First, false);
948 }
950 {
951  return iterator(*this, nullptr, false);
952 }
954 {
955  iterator * r = FirstIter;
956  FirstIter = iter;
957  return r;
958 }
960 {
961  if (iter == FirstIter)
962  FirstIter = iter->Next;
963  else
964  {
965  iterator * i = FirstIter;
966  while (i->Next && i->Next != iter)
967  i = i->Next;
968  i->Next = iter->Next;
969  }
970 }
971 
973 {
974  return iterator(list, list.Last, true);
975 }
976 
978 {
979  return iterator(list, nullptr, true);
980 }
const char * getData() const
Definition: StdBuf.h:450
C4Def * ID2Def(C4ID id)
C4ID id
Definition: C4Def.h:103
virtual void InsertLinkBefore(C4ObjectLink *pLink, C4ObjectLink *pBefore)
C4Object * GetNext(int32_t *piCount)
virtual bool hasNaming()
Definition: StdCompiler.h:68
C4ID id
Definition: C4Object.h:108
virtual const char * GetName() const
Definition: C4PropList.cpp:267
bool LogSilent(const char *szMessage, bool fConsole)
Definition: C4Log.cpp:117
virtual bool Add(C4Object *nObj, SortType eSort, C4ObjectList *pLstSorted=nullptr)
void UpdateFaces(bool bUpdateShape)
StdNamingCountAdapt< int_t > mkNamingCountAdapt(int_t &iCount, const char *szName)
Definition: StdAdaptors.h:977
virtual void Denumerate(C4ValueNumbers *)
Definition: C4Object.cpp:2315
void SAppend(const char *szSource, char *szTarget, int iMaxL)
Definition: Standard.cpp:234
C4Game Game
Definition: C4Globals.cpp:52
bool DenumeratePointers()
bool ShiftContents(C4Object *pNewFirst)
virtual void InsertLinkBefore(C4ObjectLink *pLink, C4ObjectLink *pBefore)
#define sprintf
Definition: Standard.h:171
int32_t Mass
Definition: C4Object.h:115
void Draw(C4TargetFacet &cgo, int32_t iByPlayer=-1, DrawMode eDrawMode=ODM_Normal, float offX=0, float offY=0)
Definition: C4Object.cpp:1792
void DrawSelectMark(C4TargetFacet &cgo) const
Definition: C4Object.cpp:2517
void ClearInfo(C4ObjectInfo *pInfo)
virtual void RemoveLink(C4ObjectLink *pLnk)
iterator * FirstIter
Definition: C4ObjectList.h:165
C4ObjectLink * First
Definition: C4ObjectList.h:51
int32_t GetPlane() const
Definition: C4Object.h:180
bool operator==(const iterator &iter) const
const int ANY_OWNER
Definition: C4Constants.h:139
void Copy(const C4ObjectList &rList)
StdStrBuf GetNameList(C4DefList &rDefs) const
void RemoveIter(iterator *iter) const
void Draw(C4TargetFacet &cgo, int iPlayer, int MinPlane, int MaxPlane)
void DrawTopFace(C4TargetFacet &cgo, int32_t iByPlayer=-1, DrawMode eDrawMode=ODM_Normal, float offX=0, float offY=0)
Definition: C4Object.cpp:2052
void DeleteObjects()
virtual bool ValidateOwners()
bool ValidateOwner()
Definition: C4Object.cpp:2383
iterator begin() const
void UpdateGraphics(bool fGraphicsChanged, bool fTemp=false)
Definition: C4Object.cpp:407
virtual ~C4ObjectList()
#define C4OS_DELETED
Definition: C4Object.h:34
void AppendFormat(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:197
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:93
const C4ObjectLink * GetLink(const C4Object *pObj) const
iterator(const iterator &iter)
bool isSerializer()
Definition: StdCompiler.h:64
iterator & operator=(const iterator &iter)
void DrawIfCategory(C4TargetFacet &cgo, int iPlayer, uint32_t dwCat, bool fInvert)
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *=0)
C4ObjectLink * Next
Definition: C4ObjectList.h:29
C4Def * Def
Definition: C4Object.h:143
void UpdateScriptPointers()
void UpdateGraphics(bool fGraphicsChanged)
static const C4ID None
Definition: C4Id.h:42
const int MaxTempListID
virtual void OnObjectAdded(C4ObjectList *pList, C4ObjectLink *pLnk)
Definition: C4ObjectList.h:36
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:527
int32_t Owner
Definition: C4Object.h:110
StdPtrAdapt< T > mkPtrAdaptNoNull(T *&rpObj)
Definition: StdAdaptors.h:607
void CheckCategorySort()
virtual void InsertLink(C4ObjectLink *pLink, C4ObjectLink *pAfter)
const int32_t C4D_All
Definition: C4Def.h:41
Definition: C4Def.h:100
int ListIDCount(int32_t dwCategory) const
virtual void InsertLink(C4ObjectLink *pLink, C4ObjectLink *pAfter)
#define BREAKPOINT_HERE
C4Object * GetObject(int Index=0) const
int32_t Status
Definition: C4PropList.h:170
const int32_t C4D_StaticBack
Definition: C4Def.h:42
void Value(const T &rStruct)
Definition: StdCompiler.h:171
Definition: C4Id.h:28
C4ValueNumbers * numbers
C4ObjectLink * Prev
Definition: C4ObjectList.h:29
void UpdateFace(bool bUpdateShape, bool fTemp=false)
Definition: C4Object.cpp:381
bool Unsorted
Definition: C4Object.h:129
iterator * AddIter(iterator *iter) const
virtual bool AssignInfo()
bool operator!=(const iterator &iter) const
int32_t Category
Definition: C4Object.h:113
const ReverseView reverse() const
Definition: C4ObjectList.h:104
virtual bool isDeserializer()
Definition: StdCompiler.h:63
C4Object * FindOther(C4ID id, int iOwner=ANY_OWNER)
int ObjectCount(C4ID id=C4ID::None) const
const iterator end() const
bool find(C4Object *target)
C4ID GetListID(int32_t dwCategory, int Index) const
C4ID TempListID[MaxTempListID]
void ClearPointers(C4Object *cobj)
Definition: C4Game.cpp:925
C4Def * C4Id2Def(C4ID id)
Definition: C4DefList.h:80
iterator begin() const
C4Object * Find(C4Def *def, int iOwner=ANY_OWNER, DWORD dwOCF=OCF_All)
StdSTLContainerAdapt< C > mkSTLContainerAdapt(C &rTarget, StdCompiler::Sep eSep=StdCompiler::SEP_SEP)
Definition: StdAdaptors.h:682
friend class iterator
Definition: C4ObjectList.h:169
void Denumerate(C4ValueNumbers *)
bool Log(const char *szMessage)
Definition: C4Log.cpp:195
C4ObjectListChangeListener & ObjectListChangeListener
int32_t Category
Definition: C4Def.h:119
C4ObjectLink * Last
Definition: C4ObjectList.h:51
bool AssignInfo()
Definition: C4Object.cpp:2393
int ClearPointers(C4Object *pObj)
virtual void Default()
void DrawSelectMark(C4TargetFacet &cgo) const
bool IsContained(const C4Object *pObj) const
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:459
size_t getLength() const
Definition: StdBuf.h:453
virtual void OnObjectRemove(C4ObjectList *pList, C4ObjectLink *pLnk)
Definition: C4ObjectList.h:35
C4ObjectListDumpHelper(C4ObjectList *pLst, C4ValueNumbers *numbers)
virtual void Clear()
bool IsClear() const
std::list< int32_t > * pEnumerated
Definition: C4ObjectList.h:53
uint32_t OCF
Definition: C4Object.h:134
uint32_t DWORD
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:253
bool CheckSort(C4ObjectList *pList)
C4Object * Obj
Definition: C4ObjectList.h:28
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:45
C4Object * ObjectPointer(int32_t iNumber)
bool Write(char *szTarget)
virtual void RemoveLink(C4ObjectLink *pLnk)
const int32_t C4D_Foreground
Definition: C4Def.h:55
void ClearInfo(C4ObjectInfo *pInfo)
Definition: C4Object.cpp:2431
virtual bool Remove(C4Object *pObj)
C4GameObjects Objects
Definition: C4Globals.cpp:48
void CompileFunc(StdCompiler *pComp)