OpenClonk
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 *link;
51  C4ObjectLink *next_link;
52  for (link = First; link; link = next_link)
53  {
54  next_link = link->Next;
55  delete link;
56  }
57  First = Last = nullptr;
58  if (pEnumerated)
59  {
60  delete pEnumerated;
61  pEnumerated = nullptr;
62  }
63 
64  for (iterator* it = FirstIter; it; it = it->Next)
65  {
66  it->link = NULL_LINK;
67  }
68 }
69 
70 const int MaxTempListID = 500;
72 
73 C4ID C4ObjectList::GetListID(int32_t dwCategory, int index) const
74 {
75  C4ObjectLink *link;
76 
77  // Create a temporary list of all id's and counts
78  for (int i = 0; i < MaxTempListID; i++)
79  {
81  }
82  for (link = First; link && link->Obj; link = link->Next)
83  {
84  if (link->Obj->Status)
85  {
86  C4Def *def;
87  if ((dwCategory==C4D_All) || ( (def = C4Id2Def(link->Obj->Def->id)) && (def->Category & dwCategory) ))
88  {
89  for (int i = 0; i < MaxTempListID; i++)
90  {
91  // Already there
92  if (TempListID[i] == link->Obj->Def->id)
93  {
94  break;
95  }
96  // End of list, add id
97  if (TempListID[i] == C4ID::None)
98  {
99  TempListID[i] = link->Obj->Def->id;
100  break;
101  }
102  }
103  }
104  }
105  }
106 
107  // Returns indexed id
108  if (Inside(index, 0, MaxTempListID - 1))
109  {
110  return TempListID[index];
111  }
112 
113  return C4ID::None;
114 }
115 
116 int C4ObjectList::ListIDCount(int32_t dwCategory) const
117 {
118  C4ObjectLink *link;
119 
120  // Create a temporary list of all id's and counts
121  for (int clid = 0; clid < MaxTempListID; clid++)
122  {
123  TempListID[clid] = C4ID::None;
124  }
125  for (link = First; link && link->Obj; link = link->Next)
126  {
127  if (link->Obj->Status)
128  {
129  C4Def *def;
130  if ((dwCategory == C4D_All) || ( (def = C4Id2Def(link->Obj->Def->id)) && (def->Category & dwCategory) ))
131  {
132  for (int clid = 0; clid < MaxTempListID; clid++)
133  {
134  // Already there
135  if (TempListID[clid] == link->Obj->Def->id)
136  {
137  break;
138  }
139  // End of list, add id
140  if (TempListID[clid] == C4ID::None)
141  {
142  TempListID[clid] = link->Obj->Def->id;
143  break;
144  }
145  }
146  }
147  }
148  }
149 
150  // Count different id's
151  for (int i = 0; i < MaxTempListID; i++)
152  {
153  if (TempListID[i] == C4ID::None)
154  {
155  return i;
156  }
157  }
158 
159  return MaxTempListID;
160 }
161 
162 
163 
164 bool C4ObjectList::Add(C4Object *new_obj, SortType sort_type, C4ObjectList *sorted_list)
165 {
166  if (!new_obj || !new_obj->Def || !new_obj->Status)
167  {
168  return false;
169  }
170 
171 #ifdef _DEBUG
172  if (sort_type == stMain)
173  {
175  if (sorted_list)
176  {
177  assert(CheckSort(sorted_list));
178  }
179  }
180 #endif
181 
182  // Debug: don't do double links
183  assert(!GetLink(new_obj));
184 
185  // No self-sort
186  assert(sorted_list != this);
187 
188  // Allocate new link
189  C4ObjectLink *new_link = new C4ObjectLink;
190  if (!new_link)
191  {
192  return false;
193  }
194  // Set link
195  new_link->Obj = new_obj;
196 
197  // Search insert position (default: end of list)
198  C4ObjectLink *current = nullptr;
199  C4ObjectLink *previous = Last;
200 
201  // Should sort?
202  if (sort_type == stReverse)
203  {
204  // Reverse sort: Add to beginning of list
205  current = First;
206  previous = nullptr;
207  }
208  else if (sort_type)
209  {
210  // Sort override? Leave default as is.
211  bool is_sorted = !(new_obj->Unsorted);
212  if (is_sorted)
213  {
214  // Sort by master list?
215  if (sorted_list)
216  {
217  previous = nullptr;
218  current = First;
219  while (current && (!current->Obj->Status || current->Obj->Unsorted))
220  {
221  current = current->Next;
222  }
223 
224 #ifndef _DEBUG
225  if (current)
226 #endif
227  {
228  C4ObjectLink* link2;
229  for (link2 = sorted_list->First; link2; link2 = link2->Next)
230  {
231  if (link2->Obj->Status && !link2->Obj->Unsorted)
232  {
233  if (link2->Obj == new_obj)
234  {
235  assert(!current || current->Obj != new_obj);
236  break;
237  }
238 
239  if (current && link2->Obj == current->Obj)
240  {
241  previous = current;
242  current = current->Next;
243  while (current && (!current->Obj->Status || current->Obj->Unsorted))
244  {
245  current = current->Next;
246  }
247 
248 #ifndef _DEBUG
249  if (!current)
250  {
251  break;
252  }
253 #endif
254  }
255  }
256  }
257 
258  assert(link2 != nullptr);
259  }
260  }
261  else
262  {
263  // No master list: Find successor by matching Plane / id
264  // Sort by matching Plane/id is necessary for inventory shifting.
265  // It is not done for static back to allow multiobject outside structure.
266  // Unsorted objects are ignored in comparison.
267  if (!(new_obj->Category & C4D_StaticBack))
268  {
269  for (previous = nullptr, current = First; current; current = current->Next)
270  {
271  if (current->Obj->Status && !current->Obj->Unsorted)
272  {
273  if ((current->Obj->GetPlane() == new_obj->GetPlane())
274  && (current->Obj->id == new_obj->id))
275  {
276  break;
277  }
278  previous = current;
279  }
280  }
281  }
282 
283  // Find successor by relative category
284  if (!current)
285  {
286  for (previous = nullptr, current = First; current; current = current->Next)
287  {
288  if (current->Obj->Status && !current->Obj->Unsorted)
289  {
290  if (current->Obj->GetPlane() <= new_obj->GetPlane())
291  {
292  break;
293  }
294  previous = current;
295  }
296  }
297  }
298  }
299 
300  current = previous ? previous->Next : First;
301  }
302  }
303 
304  assert(!previous || previous->Next == current);
305  assert(!current || current->Prev == previous);
306 
307  // Insert new link after predecessor
308  InsertLink(new_link, previous);
309 
310 #ifdef _DEBUG
311  // Debug: Check sort
312  if (sort_type == stMain)
313  {
315  if (sorted_list)
316  {
317  assert(CheckSort(sorted_list));
318  }
319  }
320 #endif
321 
322  // Add mass
323  Mass += new_obj->Mass;
324 
325  return true;
326 }
327 
329 {
330  C4ObjectLink *link;
331 
332  // Find link
333  for (link = First; link; link = link->Next)
334  {
335  if (link->Obj == obj)
336  {
337  break;
338  }
339  }
340  if (!link)
341  {
342  return false;
343  }
344 
345  // Fix iterators
346  for (iterator * it = FirstIter; it; it = it->Next)
347  {
348  // Adjust pointers of internal link field
349  if (it->link.Prev == link)
350  {
351  it->link.Prev = link->Prev;
352  }
353  else if (it->link.Next == link)
354  {
355  it->link.Next = link->Next;
356  }
357  else if (it->link.Obj == link->Obj)
358  {
359  it->link.Obj = nullptr;
360  }
361  }
362 
363  // Remove link from list
364  RemoveLink(link);
365 
366  // Deallocate link
367  delete link;
368 
369  // Remove mass
370  Mass -= obj->Mass;
371  if (Mass < 0)
372  {
373  Mass = 0;
374  }
375 
376 #if defined(_DEBUG)
377  assert(!GetLink(obj));
378 #endif
379 
380  return true;
381 }
382 
383 C4Object* C4ObjectList::Find(C4Def * def, int owner, DWORD dwOCF)
384 {
385  C4ObjectLink *link;
386  // Find link and object
387  for (link = First; link; link = link->Next)
388  {
389  if ((link->Obj->Status)
390  && (link->Obj->Def == def)
391  && ((owner == ANY_OWNER) || (link->Obj->Owner == owner))
392  && (dwOCF & link->Obj->OCF))
393  {
394  return link->Obj;
395  }
396  }
397  return nullptr;
398 }
399 
401 {
402  C4ObjectLink *link;
403  // Find link and object
404  for (link = First; link; link = link->Next)
405  {
406  if ((link->Obj->Status)
407  && (link->Obj->Def->id!=id)
408  && ((owner==ANY_OWNER) || (link->Obj->Owner == owner)))
409  {
410  return link->Obj;
411  }
412  }
413  return nullptr;
414 }
415 
417 {
418  int cIdx;
419  C4ObjectLink *link;
420  // Find link and object
421  for (link = First, cIdx = 0; link; link = link->Next)
422  {
423  if (link->Obj->Status)
424  {
425  if (cIdx == index)
426  {
427  return link->Obj;
428  }
429  cIdx++;
430  }
431  }
432  return nullptr;
433 }
434 
436 {
437  if (!obj)
438  {
439  return nullptr;
440  }
441  C4ObjectLink *link;
442  for (link = First; link; link = link->Next)
443  {
444  if (link->Obj == obj)
445  {
446  return link;
447  }
448  }
449  return nullptr;
450 }
451 
453 {
454  C4ObjectLink *link;
455  int count = 0;
456  for (link = First; link; link = link->Next)
457  {
458  if (link->Obj->Status && (id == C4ID::None || link->Obj->Def->id == id))
459  {
460  count++;
461  }
462  }
463  return count;
464 }
465 
467 {
468  C4ObjectLink *link;
469  int mass = 0;
470  for (link = First; link; link = link->Next)
471  {
472  if (link->Obj->Status)
473  {
474  mass += link->Obj->Mass;
475  }
476  }
477  Mass = mass;
478  return mass;
479 }
480 
482 {
483  int removed_amount = 0;
484  // Clear all primary list pointers
485  while (Remove(obj))
486  {
487  removed_amount++;
488  }
489  // Clear all sub pointers
490  C4Object *current_obj;
491  C4ObjectLink *link;
492  for (link = First; link && (current_obj = link->Obj); link = link->Next)
493  {
494  current_obj->ClearPointers(obj);
495  }
496  return removed_amount;
497 }
498 
499 void C4ObjectList::Draw(C4TargetFacet &cgo, int player, int MinPlane, int MaxPlane)
500 {
501  C4ObjectLink *link;
502  C4ObjectLink *first;
503  for (first = Last; first; first = first->Prev)
504  {
505  if (first->Obj->GetPlane() >= MinPlane)
506  {
507  break;
508  }
509  }
510  // Draw objects (base)
511  for (link = first; link; link = link->Prev)
512  {
513  if (link->Obj->GetPlane() > MaxPlane)
514  {
515  break;
516  }
517  if (link->Obj->Category & C4D_Foreground)
518  {
519  continue;
520  }
521  link->Obj->Draw(cgo, player);
522  }
523  // Draw objects (top face)
524  for (link = first; link; link = link->Prev)
525  {
526  if (link->Obj->GetPlane() > MaxPlane)
527  {
528  break;
529  }
530  if (link->Obj->Category & C4D_Foreground)
531  {
532  continue;
533  }
534  link->Obj->DrawTopFace(cgo, player);
535  }
536 }
537 
538 void C4ObjectList::DrawIfCategory(C4TargetFacet &cgo, int player, uint32_t dwCategory, bool invert)
539 {
540  C4ObjectLink *link;
541  // Draw objects (base)
542  for (link = Last; link; link = link->Prev)
543  {
544  if (!(link->Obj->Category & dwCategory) == invert)
545  {
546  link->Obj->Draw(cgo, player);
547  }
548  }
549  // Draw objects (top face)
550  for (link = Last; link; link = link->Prev)
551  {
552  if (!(link->Obj->Category & dwCategory) == invert)
553  {
554  link->Obj->DrawTopFace(cgo, player);
555  }
556  }
557 }
558 
559 bool C4ObjectList::IsContained(const C4Object *obj) const
560 {
561  C4ObjectLink *link;
562  for (link = First; link; link = link->Next)
563  {
564  if (link->Obj == obj)
565  {
566  return true;
567  }
568  }
569  return false;
570 }
571 
573 {
574  return ObjectCount() == 0;
575 }
576 
578 {
579  if (!pEnumerated)
580  {
581  return false;
582  }
583  // Denumerate all object pointers
584  for (std::list<int32_t>::const_iterator pNum = pEnumerated->begin(); pNum != pEnumerated->end(); ++pNum)
585  {
586  Add(::Objects.ObjectPointer(*pNum), stNone); // Add to tail, unsorted
587  }
588  // Delete old list
589  delete pEnumerated;
590  pEnumerated = nullptr;
591  return true;
592 }
593 
594 bool C4ObjectList::Write(char *szTarget)
595 {
596  char ostr[25];
597  szTarget[0] = 0;
598  C4ObjectLink *link;
599  for (link = First; link && link->Obj; link = link->Next)
600  {
601  if (link->Obj->Status)
602  {
603  sprintf(ostr, "%d;", link->Obj->Number);
604  SAppend(ostr, szTarget);
605  }
606  }
607  return true;
608 }
609 
611 {
612  C4ObjectLink *link;
613  for (link = First; link; link = link->Next)
614  {
615  if (link->Obj->Status)
616  {
617  link->Obj->Denumerate(numbers);
618  }
619  }
620 }
621 
622 void C4ObjectList::CompileFunc(StdCompiler *pComp, bool skip_player_objects, C4ValueNumbers * numbers)
623 {
624  // "Object" section count
625  int32_t object_count = ObjectCount();
626  pComp->Value(mkNamingCountAdapt(object_count, "Object"));
627  if (pComp->isSerializer())
628  {
629  // skipping player objects would screw object counting in non-naming compilers
630  assert(!skip_player_objects || pComp->hasNaming());
631  // Decompile all objects in reverse order
632  for (C4ObjectLink *link = Last; link; link = link->Prev)
633  {
634  if (link->Obj->Status && (!skip_player_objects || !link->Obj->IsUserPlayerObject()))
635  {
636  pComp->Value(mkNamingAdapt(mkParAdapt(*link->Obj, numbers), "Object"));
637  }
638  }
639  }
640  else
641  {
642  // FIXME: Check that no PlayerObjects are loaded when skip_player_objects is true
643  // i.e. that loading and saving was done with the same flag.
644  // Remove previous data
645  Clear();
646  // Load objects, add them to the list.
647  for (int i = 0; i < object_count; i++)
648  {
649  C4Object *obj = nullptr;
650  try
651  {
652  pComp->Value(mkNamingAdapt(mkParAdapt(mkPtrAdaptNoNull(obj), numbers), "Object"));
653  Add(obj, stReverse);
654  }
655  catch (StdCompiler::Exception *exception)
656  {
657  // Failsafe object loading: If an error occurs during object loading, just skip that object and load the next one
658  if (!exception->Pos.getLength())
659  {
660  LogF("ERROR: Object loading: %s", exception->Msg.getData());
661  }
662  else
663  {
664  LogF("ERROR: Object loading(%s): %s", exception->Pos.getData(), exception->Msg.getData());
665  }
666  delete exception;
667  }
668  }
669  }
670 }
671 
673 {
674  // (Re)create list
675  delete pEnumerated;
676  pEnumerated = new std::list<int32_t>();
677  // Decompiling: Build list
678  if (!pComp->isDeserializer())
679  {
680  for (C4ObjectLink *link = First; link; link = link->Next)
681  {
682  if (link->Obj->Status)
683  {
684  pEnumerated->push_back(link->Obj->Number);
685  }
686  }
687  }
688  // Compile list
690  // Decompiling: Delete list
691  if (!pComp->isDeserializer())
692  {
693  delete pEnumerated;
694  pEnumerated = nullptr;
695  }
696  // Compiling: Nothing to do - list will be denumerated later
697 }
698 
700 {
701  C4ID id;
702  StdStrBuf Buf;
703  for (int i = 0; (id = GetListID(C4D_All, i)); i++)
704  {
705  C4Def *current_def = defs.ID2Def(id);
706  if (current_def)
707  {
708  int idcount = ObjectCount(id);
709  if (i > 0)
710  {
711  Buf.Append(", ");
712  }
713  Buf.AppendFormat("%dx %s", idcount, current_def->GetName());
714  }
715  }
716  return Buf;
717 }
718 
720 {
721  C4ObjectLink *link;
722  for (link = First; link; link = link->Next)
723  {
724  if (link->Obj->Status)
725  {
726  link->Obj->ValidateOwner();
727  }
728  }
729  return true;
730 }
731 
733 {
734  // the list seems to be traced backwards here, to ensure crew objects are added in correct order
735  // (or semi-correct, because this will work only if the crew order matches the main object list order)
736  // this is obsolete now, because the crew list is stored in the savegame
737  C4ObjectLink *link;
738  for (link = Last; link; link = link->Prev)
739  {
740  if (link->Obj->Status)
741  {
742  link->Obj->AssignInfo();
743  }
744  }
745  return true;
746 }
747 
749 {
750  C4ObjectLink *link;
751  for (link = First; link; link = link->Next)
752  {
753  if (link->Obj->Status)
754  {
755  link->Obj->ClearInfo(pInfo);
756  }
757  }
758 }
759 
761 {
762  C4ObjectLink *link;
763  bool is_sorted;
764  // Sort by id
765  do
766  {
767  is_sorted = true;
768  for (link = First; link && link->Next; link = link->Next)
769  {
770  if (link->Obj->id > link->Next->Obj->id)
771  {
772  RemoveLink(link);
773  InsertLink(link, link->Next);
774  is_sorted = false;
775  break;
776  }
777  }
778  }
779  while (!is_sorted);
780 }
781 
783 {
784  // Table format is OK here
785  if (link->Prev) { link->Prev->Next = link->Next; } else { First = link->Next; }
786  if (link->Next) { link->Next->Prev = link->Prev; } else { Last = link->Prev; }
787 }
788 
790 {
791  // Insert after
792  if (after_link)
793  {
794  link->Prev = after_link;
795  link->Next = after_link->Next;
796  if (after_link->Next)
797  {
798  after_link->Next->Prev = link;
799  }
800  else
801  {
802  Last = link;
803  }
804  after_link->Next = link;
805  }
806  // Insert at head
807  else
808  {
809  link->Prev = nullptr;
810  link->Next = First;
811  if (First)
812  {
813  First->Prev = link;
814  }
815  else
816  {
817  Last = link;
818  }
819  First = link;
820  }
821 
822  // Adjust iterators
823  if (after_link)
824  {
825  for (iterator* it = FirstIter; it; it = it->Next)
826  {
827  if (it->link.Obj == after_link->Obj)
828  {
829  it->link.Next = link;
830  }
831  }
832  }
833 }
834 
836 {
837  // Insert before
838  if (before_link)
839  {
840  link->Prev = before_link->Prev;
841  if (before_link->Prev)
842  {
843  before_link->Prev->Next = link;
844  }
845  else
846  {
847  First = link;
848  }
849  link->Next = before_link;
850  before_link->Prev = link;
851  }
852  // Insert at end
853  else
854  {
855  link->Next = nullptr;
856  link->Prev = Last;
857  if (Last)
858  {
859  Last->Next = link;
860  }
861  else
862  {
863  First = link;
864  }
865  Last = link;
866  }
867 
868  // Adjust iterators
869  if (before_link)
870  {
871  for (iterator* it = FirstIter; it; it = it->Next)
872  {
873  if (it->link.Obj == before_link->Obj)
874  {
875  it->link.Prev = link;
876  }
877  }
878  }
879 }
880 
881 
883 {
884  C4ObjectList::InsertLinkBefore(link, before_link);
886 }
887 
889 {
890  C4ObjectList::InsertLink(link, after_link);
892 }
893 
895 {
898 }
899 
900 void C4ObjectList::UpdateGraphics(bool graphics_changed)
901 {
902  C4ObjectLink *link;
903  for (link = First; link; link = link->Next)
904  {
905  if (link->Obj->Status)
906  {
907  link->Obj->UpdateGraphics(graphics_changed);
908  }
909  }
910 }
911 
912 void C4ObjectList::UpdateFaces(bool update_shapes)
913 {
914  C4ObjectLink *link;
915  for (link = First; link; link = link->Next)
916  {
917  if (link->Obj->Status)
918  {
919  link->Obj->UpdateFace(update_shapes);
920  }
921  }
922 }
923 
925 {
926  C4ObjectLink *link;
927  for (link = Last; link; link = link->Prev)
928  {
929  link->Obj->DrawSelectMark(cgo);
930  }
931 }
932 
934 {
935  C4Object *obj;
936  C4ObjectLink *link;
937  for (link = First; link && (obj = link->Obj); link = link->Next)
938  {
939  obj->CloseMenu(true);
940  }
941 }
942 
944 {
945  Clear(); Default();
946  C4ObjectLink *link;
947  for (link = list.First; link; link = link->Next)
948  {
949  Add(link->Obj, C4ObjectList::stNone);
950  }
951 }
952 
954 {
955  First = Last = nullptr;
956  Mass = 0;
957  pEnumerated = nullptr;
958 }
959 
961 {
962  // Get link of new first (this ensures list is not empty)
963  C4ObjectLink *new_first_link = GetLink(new_first_obj);
964  if (!new_first_link)
965  {
966  return false;
967  }
968  // Already at front?
969  if (new_first_link == First)
970  {
971  return true;
972  }
973  // Sort it there:
974  // 1. Make cyclic list
975  Last->Next = First;
976  First->Prev = Last;
977  // 2. Re-set first and last
978  First = new_first_link;
979  Last = new_first_link->Prev;
980  // 3. Uncycle list
981  First->Prev = Last->Next = nullptr;
982  // Done, success
983  return true;
984 }
985 
987 {
988  // Delete links and objects
989  while (First)
990  {
991  C4Object *obj = First->Obj;
992  if (obj->Status)
993  {
994  Game.ClearPointers(obj); // Clear pointers to removed objects that weren't deleted (game end or section change)
995  }
996  obj->Status = C4OS_DELETED;
997  Remove(obj);
998  delete obj;
999  }
1000  // Reset mass
1001  Mass = 0;
1002 }
1003 
1004 
1005 // -------------------------------------------------
1006 // C4ObjectListIterator
1007 
1009 {
1010  // End reached?
1011  if (pCurrID == rList.end())
1012  {
1013  return nullptr;
1014  }
1015  // Not yet started?
1016  if (pCurr == rList.end())
1017  {
1018  // Then start at first ID list head
1019  pCurr = pCurrID;
1020  }
1021  else if (++pCurr == rList.end()) // Next item
1022  {
1023  return nullptr;
1024  }
1025  // Next ID section reached?
1026  if ((*pCurr)->id != (*pCurrID)->id)
1027  {
1028  pCurrID = pCurr;
1029  }
1030  else
1031  {
1032  // Otherwise, it must be checked, whether this is a duplicate item already iterated
1033  // if so, advance the list
1034  for (C4ObjectList::iterator pCheck = pCurrID; pCheck != pCurr; ++pCheck)
1035  {
1036  if ((*pCheck)->CanConcatPictureWith(*pCurr))
1037  {
1038  // Next object of matching category
1039  if (++pCurr == rList.end())
1040  {
1041  return nullptr;
1042  }
1043  // Next ID chunk reached?
1044  if ((*pCurr)->id != (*pCurrID)->id)
1045  {
1046  // then break here
1047  pCurrID = pCurr;
1048  break;
1049  }
1050  // restart check for next object
1051  pCheck = pCurrID;
1052  }
1053  }
1054  }
1055  if (piCount)
1056  {
1057  // Default count
1058  *piCount = 1;
1059  // Add additional objects of same ID to the count
1060  C4ObjectList::iterator pCheck(pCurr);
1061  for (++pCheck; pCheck != rList.end() && (*pCheck)->id == (*pCurr)->id; ++pCheck)
1062  {
1063  if ((*pCheck)->CanConcatPictureWith(*pCurr))
1064  {
1065  ++*piCount;
1066  }
1067  }
1068  }
1069  // return found object
1070  return *pCurr;
1071 }
1072 
1074 {
1075  for (C4ObjectLink *link = First; link; link = link->Next)
1076  {
1077  link->Obj->UpdateScriptPointers();
1078  }
1079 }
1080 
1082 {
1085 
1086  void CompileFunc(StdCompiler *pComp) { pComp->Value(mkNamingAdapt(mkParAdapt(*list, numbers), "Objects")); }
1087 
1089 };
1090 
1092 {
1093  C4ObjectLink *link = First;
1094  C4ObjectLink *compare_link = list->First;
1095  while (link && (!link->Obj->Status || link->Obj->Unsorted))
1096  {
1097  link = link->Next;
1098  }
1099 
1100  while (link)
1101  {
1102  if (!compare_link)
1103  {
1104  Log("CheckSort failure");
1105  C4ValueNumbers numbers;
1106  LogSilent(DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(C4ObjectListDumpHelper(this, &numbers), "SectorList")).getData());
1107  LogSilent(DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(C4ObjectListDumpHelper(list, &numbers), "MainList")).getData());
1108  return false;
1109  }
1110  else
1111  {
1112  if (link->Obj == compare_link->Obj)
1113  {
1114  link = link->Next;
1115  while (link && (!link->Obj->Status || link->Obj->Unsorted))
1116  {
1117  link = link->Next;
1118  }
1119  }
1120  compare_link = compare_link->Next;
1121  }
1122 }
1123  return true;
1124 }
1125 
1127 {
1128  // debug: Check whether object list is sorted correctly
1129  C4ObjectLink *link;
1130  C4ObjectLink *previous = nullptr;
1131  for (link = First; link; link = link->Next)
1132  {
1133  if (!link->Obj->Unsorted && link->Obj->Status)
1134  {
1135  if (previous)
1136  {
1137  assert(previous->Obj->GetPlane() >= link->Obj->GetPlane());
1138  }
1139  previous = link;
1140  }
1141  }
1142 }
1143 
1144 C4ObjectList::iterator::iterator(const C4ObjectList & list, const C4ObjectLink * link, bool reverse):
1145  List(list), link(link ? *link : NULL_LINK), reverse(reverse)
1146 {
1147  Next=list.AddIter(this);
1148 }
1150  List(iter.List), link(iter.link), Next(), reverse(iter.reverse)
1151 {
1152  Next=List.AddIter(this);
1153 }
1155 {
1156  List.RemoveIter(this);
1157 }
1159 {
1160  C4ObjectLink* advance = reverse ? link.Prev : link.Next;
1161  link = advance ? *advance : NULL_LINK;
1162  return *this;
1163 }
1165 {
1166  iterator old = *this;
1168  return old;
1169 }
1171 {
1172  return link.Obj;
1173 }
1175 {
1176  return
1177  &iter.List == &List &&
1178  iter.link.Obj == link.Obj /* checking for same object should be enough */ &&
1179  iter.reverse == reverse;
1180 }
1182 {
1183  return !(*this == iter);
1184 }
1185 
1187 {
1188  while (link.Obj)
1189  {
1190  if (link.Obj == target)
1191  {
1192  return true;
1193  }
1194  else
1195  {
1196  (*this)++;
1197  }
1198  }
1199  return false;
1200 }
1201 
1203 {
1204  return link.Obj == nullptr;
1205 }
1206 
1208 {
1209  C4ObjectLink* l = reverse ? List.Last : List.First;
1210  link = l ? *l : NULL_LINK;
1211  return !atEnd();
1212 }
1213 
1215 {
1216  (*this)++;
1217  return !atEnd();
1218 }
1219 
1221 {
1222  // Can only assign iterators into the same list
1223  assert(&iter.List == &List);
1224 
1225  link = iter.link;
1226  reverse = iter.reverse;
1227  return *this;
1228 }
1229 
1231 {
1232  return iterator(*this, First, false);
1233 }
1235 {
1236  return iterator(*this, nullptr, false);
1237 }
1239 {
1240  iterator * r = FirstIter;
1241  FirstIter = iter;
1242  return r;
1243 }
1245 {
1246  if (iter == FirstIter)
1247  {
1248  FirstIter = iter->Next;
1249  }
1250  else
1251  {
1252  iterator * i = FirstIter;
1253  while (i->Next && i->Next != iter)
1254  {
1255  i = i->Next;
1256  }
1257  i->Next = iter->Next;
1258  }
1259 }
1260 
1262 {
1263  return iterator(list, list.Last, true);
1264 }
1265 
1267 {
1268  return iterator(list, nullptr, true);
1269 }
const int ANY_OWNER
Definition: C4Constants.h:138
const int32_t C4D_Foreground
Definition: C4Def.h:53
const int32_t C4D_All
Definition: C4Def.h:39
const int32_t C4D_StaticBack
Definition: C4Def.h:40
C4Def * C4Id2Def(C4ID id)
Definition: C4DefList.h:84
C4Game Game
Definition: C4Globals.cpp:52
C4GameObjects Objects
Definition: C4Globals.cpp:48
bool LogSilent(const char *szMessage, bool fConsole)
Definition: C4Log.cpp:126
bool Log(const char *szMessage)
Definition: C4Log.cpp:204
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:262
#define C4OS_DELETED
Definition: C4Object.h:34
const int MaxTempListID
C4ID TempListID[MaxTempListID]
C4ObjectLink * Prev
Definition: C4ObjectList.h:29
C4ObjectLink * Next
Definition: C4ObjectList.h:29
C4Object * Obj
Definition: C4ObjectList.h:28
C4ObjectListChangeListener & ObjectListChangeListener
uint32_t DWORD
void SAppend(const char *szSource, char *szTarget, int iMaxL)
Definition: Standard.cpp:263
#define sprintf
Definition: Standard.h:162
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:43
StdSTLContainerAdapt< C > mkSTLContainerAdapt(C &rTarget, StdCompiler::Sep eSep=StdCompiler::SEP_SEP)
Definition: StdAdaptors.h:713
StdPtrAdapt< T > mkPtrAdaptNoNull(T *&rpObj)
Definition: StdAdaptors.h:638
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:490
StdNamingCountAdapt< int_t > mkNamingCountAdapt(int_t &iCount, const char *szName)
Definition: StdAdaptors.h:1008
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:92
Definition: C4Def.h:99
C4ID id
Definition: C4Def.h:101
int32_t Category
Definition: C4Def.h:117
C4Def * ID2Def(C4ID id)
void ClearPointers(C4Object *obj)
Definition: C4Game.cpp:1125
C4Object * ObjectPointer(int32_t object_number)
Definition: C4Id.h:26
static const C4ID None
Definition: C4Id.h:39
void InsertLink(C4ObjectLink *link, C4ObjectLink *after_link) override
void InsertLinkBefore(C4ObjectLink *link, C4ObjectLink *before_link) override
void RemoveLink(C4ObjectLink *link) override
void UpdateScriptPointers()
Definition: C4Object.cpp:1272
void UpdateFace(bool bUpdateShape, bool fTemp=false)
void DrawTopFace(C4TargetFacet &cgo, int32_t iByPlayer=-1, DrawMode eDrawMode=ODM_Normal, float offX=0, float offY=0)
int32_t Owner
Definition: C4Object.h:108
int32_t Category
Definition: C4Object.h:111
void ClearPointers(C4Object *ptr)
Definition: C4Object.cpp:816
uint32_t OCF
Definition: C4Object.h:132
bool ValidateOwner()
Definition: C4Object.cpp:1035
C4ID id
Definition: C4Object.h:106
bool CloseMenu(bool fForce)
bool Unsorted
Definition: C4Object.h:127
void ClearInfo(C4ObjectInfo *pInfo)
Definition: C4Object.cpp:1075
void Draw(C4TargetFacet &cgo, int32_t iByPlayer=-1, DrawMode eDrawMode=ODM_Normal, float offX=0, float offY=0)
void DrawSelectMark(C4TargetFacet &cgo) const
void Denumerate(C4ValueNumbers *) override
Definition: C4Object.cpp:1007
int32_t GetPlane() const
Definition: C4Object.h:179
int32_t Mass
Definition: C4Object.h:113
bool IsUserPlayerObject()
Definition: C4Object.cpp:1302
C4Def * Def
Definition: C4Object.h:141
bool AssignInfo()
Definition: C4Object.cpp:1045
void UpdateGraphics(bool fGraphicsChanged, bool fTemp=false)
iterator & operator=(const iterator &iter)
iterator(const iterator &iter)
bool find(C4Object *target)
bool operator!=(const iterator &iter) const
bool operator==(const iterator &iter) const
virtual void OnObjectRemove(C4ObjectList *list, C4ObjectLink *link)
Definition: C4ObjectList.h:35
virtual void OnObjectAdded(C4ObjectList *list, C4ObjectLink *link)
Definition: C4ObjectList.h:36
bool DenumeratePointers()
virtual void Clear()
void UpdateFaces(bool update_shape)
void UpdateGraphics(bool graphics_changed)
void UpdateScriptPointers()
bool ShiftContents(C4Object *new_first)
virtual void Default()
C4ObjectLink * First
Definition: C4ObjectList.h:51
virtual bool AssignInfo()
int ListIDCount(int32_t dwCategory) const
void Copy(const C4ObjectList &list)
virtual void InsertLinkBefore(C4ObjectLink *link, C4ObjectLink *before_link)
iterator begin() const
void Draw(C4TargetFacet &cgo, int player, int MinPlane, int MaxPlane)
iterator * AddIter(iterator *iter) const
bool Write(char *szTarget)
bool IsClear() const
void DrawSelectMark(C4TargetFacet &cgo) const
const C4ObjectLink * GetLink(const C4Object *obj) const
virtual bool Add(C4Object *new_obj, SortType sort_type, C4ObjectList *sorted_list=nullptr)
friend class iterator
Definition: C4ObjectList.h:169
virtual bool ValidateOwners()
C4ObjectLink * Last
Definition: C4ObjectList.h:51
virtual void RemoveLink(C4ObjectLink *link)
iterator * FirstIter
Definition: C4ObjectList.h:165
C4ID GetListID(int32_t dwCategory, int index) const
const ReverseView reverse() const
Definition: C4ObjectList.h:104
C4Object * Find(C4Def *def, int owner=ANY_OWNER, DWORD dwOCF=OCF_All)
virtual bool Remove(C4Object *obj)
virtual void InsertLink(C4ObjectLink *link, C4ObjectLink *after_link)
void CheckCategorySort()
int ObjectCount(C4ID id=C4ID::None) const
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *=nullptr)
void ClearInfo(C4ObjectInfo *info)
StdStrBuf GetNameList(C4DefList &defs) const
std::list< int32_t > * pEnumerated
Definition: C4ObjectList.h:53
int ClearPointers(C4Object *obj)
bool IsContained(const C4Object *obj) const
void DeleteObjects()
C4Object * FindOther(C4ID id, int owner=ANY_OWNER)
bool CheckSort(C4ObjectList *list)
void DrawIfCategory(C4TargetFacet &cgo, int player, uint32_t dwCategory, bool invert)
void Denumerate(C4ValueNumbers *)
const iterator end() const
virtual ~C4ObjectList()
C4Object * GetObject(int index=0) const
void RemoveIter(iterator *iter) const
C4Object * GetNext(int32_t *piCount)
int32_t Status
Definition: C4PropList.h:173
const char * GetName() const override
Definition: C4PropList.cpp:243
void Value(const T &rStruct)
Definition: StdCompiler.h:161
bool isSerializer()
Definition: StdCompiler.h:54
virtual bool isDeserializer()
Definition: StdCompiler.h:53
virtual bool hasNaming()
Definition: StdCompiler.h:58
void AppendFormat(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:190
const char * getData() const
Definition: StdBuf.h:442
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
size_t getLength() const
Definition: StdBuf.h:445
C4ObjectListDumpHelper(C4ObjectList *pLst, C4ValueNumbers *numbers)
void CompileFunc(StdCompiler *pComp)
C4ValueNumbers * numbers