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