forked from Mirrors/openclonk
1184 lines
30 KiB
C++
1184 lines
30 KiB
C++
/*
|
|
* OpenClonk, http://www.openclonk.org
|
|
*
|
|
* Copyright (c) 1998-2000 Matthes Bender
|
|
* Copyright (c) 2001-2006, 2008 Sven Eberhardt
|
|
* Copyright (c) 2004-2006 Peter Wortmann
|
|
* Copyright (c) 2006-2008 Günther Brammer
|
|
* Copyright (c) 2009 Armin Burgmeier
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
|
*
|
|
* Portions might be copyrighted by other authors who have contributed
|
|
* to OpenClonk.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
* See isc_license.txt for full license and disclaimer.
|
|
*
|
|
* "Clonk" is a registered trademark of Matthes Bender.
|
|
* See clonk_trademark_license.txt for full license.
|
|
*/
|
|
|
|
/* Dynamic object list */
|
|
|
|
#include <C4Include.h>
|
|
#include <C4ObjectList.h>
|
|
|
|
#ifndef BIG_C4INCLUDE
|
|
#include <C4Object.h>
|
|
#include <C4Application.h>
|
|
#include <C4Region.h>
|
|
#include <C4GraphicsResource.h>
|
|
#include <C4Game.h>
|
|
#endif
|
|
|
|
C4ObjectList::C4ObjectList(): FirstIter(0)
|
|
{
|
|
Default();
|
|
}
|
|
|
|
C4ObjectList::C4ObjectList(const C4ObjectList &List): FirstIter(0)
|
|
{
|
|
Default();
|
|
Copy(List);
|
|
}
|
|
|
|
C4ObjectList::~C4ObjectList()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
void C4ObjectList::Clear()
|
|
{
|
|
C4ObjectLink *cLnk,*nextLnk;
|
|
for (cLnk=First; cLnk; cLnk=nextLnk)
|
|
{ nextLnk=cLnk->Next; delete cLnk; }
|
|
First=Last=NULL;
|
|
if (pEnumerated) delete pEnumerated; pEnumerated=NULL;
|
|
}
|
|
|
|
const int MaxTempListID = 500;
|
|
C4ID TempListID[MaxTempListID];
|
|
|
|
C4ID C4ObjectList::GetListID(int32_t dwCategory, int Index)
|
|
{
|
|
int clid;
|
|
C4ObjectLink *clnk;
|
|
C4Def *cdef;
|
|
|
|
// Create a temporary list of all id's and counts
|
|
for (clid=0; clid<MaxTempListID; clid++) TempListID[clid]=C4ID_None;
|
|
for (clnk=First; clnk && clnk->Obj; clnk=clnk->Next)
|
|
if (clnk->Obj->Status)
|
|
if ((dwCategory==C4D_All) || ( (cdef=C4Id2Def(clnk->Obj->Def->id)) && (cdef->Category & dwCategory) ))
|
|
for (clid=0; clid<MaxTempListID; clid++)
|
|
{
|
|
// Already there
|
|
if (TempListID[clid]==clnk->Obj->Def->id) break;
|
|
// End of list, add id
|
|
if (TempListID[clid]==C4ID_None) { TempListID[clid]=clnk->Obj->Def->id; break; }
|
|
}
|
|
|
|
// Returns indexed id
|
|
if (Inside(Index,0,MaxTempListID-1)) return TempListID[Index];
|
|
|
|
return C4ID_None;
|
|
}
|
|
|
|
int C4ObjectList::ListIDCount(int32_t dwCategory)
|
|
{
|
|
int clid;
|
|
C4ObjectLink *clnk;
|
|
C4Def *cdef;
|
|
|
|
// Create a temporary list of all id's and counts
|
|
for (clid=0; clid<MaxTempListID; clid++) TempListID[clid]=C4ID_None;
|
|
for (clnk=First; clnk && clnk->Obj; clnk=clnk->Next)
|
|
if (clnk->Obj->Status)
|
|
if ((dwCategory==C4D_All) || ( (cdef=C4Id2Def(clnk->Obj->Def->id)) && (cdef->Category & dwCategory) ))
|
|
for (clid=0; clid<MaxTempListID; clid++)
|
|
{
|
|
// Already there
|
|
if (TempListID[clid]==clnk->Obj->Def->id) break;
|
|
// End of list, add id
|
|
if (TempListID[clid]==C4ID_None) { TempListID[clid]=clnk->Obj->Def->id; break; }
|
|
}
|
|
|
|
// Count different id's
|
|
for (clid=0; clid<MaxTempListID; clid++)
|
|
if (TempListID[clid]==C4ID_None)
|
|
return clid;
|
|
|
|
return MaxTempListID;
|
|
}
|
|
|
|
|
|
|
|
BOOL C4ObjectList::Add(C4Object *nObj, SortType eSort, C4ObjectList *pLstSorted)
|
|
{
|
|
C4ObjectLink *nLnk;
|
|
if (!nObj || !nObj->Def || !nObj->Status) return FALSE;
|
|
|
|
#ifdef _DEBUG
|
|
if (eSort==stMain)
|
|
{
|
|
CheckCategorySort();
|
|
if(pLstSorted)
|
|
assert(CheckSort(pLstSorted));
|
|
}
|
|
#endif
|
|
|
|
// dbg: don't do double links
|
|
assert (!GetLink(nObj));
|
|
|
|
// no self-sort
|
|
assert(pLstSorted != this);
|
|
|
|
// Allocate new link
|
|
if (!(nLnk=new C4ObjectLink)) return FALSE;
|
|
// Set link
|
|
nLnk->Obj=nObj;
|
|
|
|
// Search insert position (default: end of list)
|
|
C4ObjectLink *cLnk = NULL, *cPrev = Last;
|
|
|
|
// Should sort?
|
|
if(eSort == stReverse)
|
|
{
|
|
// reverse sort: Add to beginning of list
|
|
cLnk = First; cPrev = NULL;
|
|
}
|
|
else if (eSort)
|
|
{
|
|
cLnk = NULL; cPrev = Last;
|
|
|
|
// Sort override or line? Leave default as is.
|
|
bool fUnsorted = nObj->Unsorted || nObj->Def->Line;
|
|
if(!fUnsorted)
|
|
{
|
|
|
|
// Find successor by matching category / id
|
|
// Sort by matching category/id is necessary for inventory shifting.
|
|
// It is not done for static back to allow multiobject outside structure.
|
|
// Unsorted objects are ignored in comparison.
|
|
if (!(nObj->Category & C4D_StaticBack))
|
|
for (cPrev=NULL,cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status && !cLnk->Obj->Unsorted)
|
|
{
|
|
if ( (cLnk->Obj->Category & C4D_SortLimit)==(nObj->Category & C4D_SortLimit) )
|
|
if ( cLnk->Obj->id == nObj->id )
|
|
break;
|
|
cPrev=cLnk;
|
|
}
|
|
|
|
// Find successor by relative category
|
|
if (!cLnk)
|
|
for (cPrev=NULL, cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status && !cLnk->Obj->Unsorted)
|
|
{
|
|
if ((cLnk->Obj->Category & C4D_SortLimit)<=(nObj->Category & C4D_SortLimit))
|
|
break;
|
|
cPrev=cLnk;
|
|
}
|
|
|
|
cLnk = cPrev ? cPrev->Next : First;
|
|
}
|
|
|
|
// Sort by master list?
|
|
if(pLstSorted)
|
|
{
|
|
|
|
assert(CheckSort(pLstSorted));
|
|
|
|
// Unsorted: Always search full list (start with first object in list)
|
|
if(fUnsorted) { cLnk = First; cPrev = NULL; }
|
|
|
|
// As cPrev is the last link in front of the first position where the object could be inserted,
|
|
// the object should be after this point in the master list (given it's consistent).
|
|
// If we're about to insert the object at the end of the list, there is obviously nothing to do.
|
|
#ifndef _DEBUG
|
|
if(cLnk)
|
|
{
|
|
#endif
|
|
C4ObjectLink *cLnk2 = cPrev ? pLstSorted->GetLink(cPrev->Obj)->Next : pLstSorted->First;
|
|
for(; cLnk2; cLnk2 = cLnk2->Next)
|
|
if(cLnk2->Obj == nObj)
|
|
// Position found!
|
|
break;
|
|
else if(cLnk && cLnk2->Obj == cLnk->Obj)
|
|
{
|
|
// So cLnk->Obj is actually in front of nObj. Update insert position
|
|
cPrev = cLnk;
|
|
cLnk = cLnk->Next;
|
|
#ifndef _DEBUG
|
|
// At end of list?
|
|
if(!cLnk) break;
|
|
#endif
|
|
}
|
|
|
|
// No position found? This shouldn't happen with a consistent main list.
|
|
assert(cLnk2);
|
|
#ifndef _DEBUG
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(!cPrev || cPrev->Next == cLnk);
|
|
assert(!cLnk || cLnk->Prev == cPrev);
|
|
|
|
// Insert new link after predecessor
|
|
InsertLink(nLnk, cPrev);
|
|
|
|
#ifdef _DEBUG
|
|
// Debug: Check sort
|
|
if(eSort == stMain)
|
|
{
|
|
CheckCategorySort();
|
|
if(pLstSorted)
|
|
assert(CheckSort(pLstSorted));
|
|
}
|
|
#endif
|
|
|
|
// Add mass
|
|
Mass+=nObj->Mass;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL C4ObjectList::Remove(C4Object *pObj)
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
|
|
// Find link
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj==pObj) break;
|
|
if (!cLnk) return FALSE;
|
|
|
|
// Fix iterators
|
|
for (iterator * i = FirstIter; i; i = i->Next)
|
|
{
|
|
if (i->pLink == cLnk) i->pLink = cLnk->Next;
|
|
}
|
|
|
|
// Remove link from list
|
|
RemoveLink(cLnk);
|
|
|
|
// Deallocate link
|
|
delete cLnk;
|
|
|
|
// Remove mass
|
|
Mass-=pObj->Mass; if (Mass<0) Mass=0;
|
|
|
|
#if defined(_DEBUG)
|
|
if (GetLink(pObj)) BREAKPOINT_HERE;
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
C4Object* C4ObjectList::Find(C4ID id, int owner, DWORD dwOCF)
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
// Find link and object
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
if (cLnk->Obj->Def->id==id)
|
|
if ((owner==ANY_OWNER) || (cLnk->Obj->Owner==owner))
|
|
if (dwOCF & cLnk->Obj->OCF)
|
|
return cLnk->Obj;
|
|
return NULL;
|
|
}
|
|
|
|
C4Object* C4ObjectList::FindOther(C4ID id, int owner)
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
// Find link and object
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
if (cLnk->Obj->Def->id!=id)
|
|
if ((owner==ANY_OWNER) || (cLnk->Obj->Owner==owner))
|
|
return cLnk->Obj;
|
|
return NULL;
|
|
}
|
|
|
|
C4Object* C4ObjectList::GetObject(int Index)
|
|
{
|
|
int cIdx;
|
|
C4ObjectLink *cLnk;
|
|
// Find link and object
|
|
for (cLnk=First,cIdx=0; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
{
|
|
if (cIdx==Index) return cLnk->Obj;
|
|
cIdx++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
C4ObjectLink* C4ObjectList::GetLink(C4Object *pObj)
|
|
{
|
|
if (!pObj) return NULL;
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj==pObj)
|
|
return cLnk;
|
|
return NULL;
|
|
}
|
|
|
|
int C4ObjectList::ObjectCount(C4ID id, int32_t dwCategory) const
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
int iCount=0;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
if ( (id==C4ID_None) || (cLnk->Obj->Def->id==id) )
|
|
if ( (dwCategory==C4D_All) || (cLnk->Obj->Category & dwCategory) )
|
|
iCount++;
|
|
return iCount;
|
|
}
|
|
|
|
int C4ObjectList::MassCount()
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
int iMass=0;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
iMass+=cLnk->Obj->Mass;
|
|
Mass=iMass;
|
|
return iMass;
|
|
}
|
|
|
|
void C4ObjectList::DrawIDList(C4Facet &cgo, int iSelection,
|
|
C4DefList &rDefs, int32_t dwCategory,
|
|
C4RegionList *pRegions, int iRegionCom,
|
|
BOOL fDrawOneCounts)
|
|
{
|
|
// Calculations & variables
|
|
/*int iSections = cgo.GetSectionCount();
|
|
int iItems = ListIDCount(dwCategory);*/
|
|
//int iFirstItem = BoundBy(iSelection-iSections/2,0,Max(iItems-iSections,0));
|
|
int32_t cSec = 0;
|
|
int32_t iCount;
|
|
C4Facet cgo2;
|
|
C4Object *pFirstObj;
|
|
char szCount[10];
|
|
// objects are sorted in the list already, so just draw them!
|
|
C4ObjectListIterator iter(*this);
|
|
while (pFirstObj = iter.GetNext(&iCount))
|
|
{
|
|
// Section
|
|
cgo2 = cgo.GetSection(cSec);
|
|
// draw picture
|
|
pFirstObj->DrawPicture(cgo2, cSec==iSelection);
|
|
// Draw count
|
|
sprintf(szCount,"%dx",iCount);
|
|
if ((iCount!=1) || fDrawOneCounts)
|
|
Application.DDraw->TextOut(szCount, ::GraphicsResource.FontRegular, 1.0, cgo2.Surface,cgo2.X+cgo2.Wdt-1,cgo2.Y+cgo2.Hgt-1-::GraphicsResource.FontRegular.iLineHgt,CStdDDraw::DEFAULT_MESSAGE_COLOR,ARight);
|
|
// Region
|
|
if (pRegions) pRegions->Add(cgo2.X,cgo2.Y,cgo2.Wdt,cgo2.Hgt,pFirstObj->GetName(),iRegionCom,pFirstObj,COM_None,COM_None,pFirstObj->Number);
|
|
// Next section
|
|
cSec++;
|
|
}
|
|
// Draw by list sorted ids
|
|
/* for (cPos=0; c_id=GetListID(dwCategory,cPos); cPos++)
|
|
if (Inside(cPos,iFirstItem,iFirstItem+iSections-1))
|
|
{
|
|
// First object of this type
|
|
pFirstObj = Find(c_id);
|
|
// Count
|
|
iCount=ObjectCount(c_id);
|
|
// Section
|
|
cgo2 = cgo.GetSection(cSec);
|
|
// Draw by definition
|
|
rDefs.Draw( c_id, cgo2, (cPos==iSelection), pFirstObj->Color, pFirstObj );
|
|
// Draw count
|
|
sprintf(szCount,"%dx",iCount);
|
|
if ((iCount!=1) || fDrawOneCounts)
|
|
Application.DDraw->TextOut(szCount,cgo2.Surface,cgo2.X+cgo2.Wdt-1,cgo2.Y+cgo2.Hgt-1-Application.DDraw->TextHeight(),FWhite,ARight);
|
|
// Region
|
|
if (pRegions) pRegions->Add(cgo2.X,cgo2.Y,cgo2.Wdt,cgo2.Hgt,pFirstObj->GetName(),iRegionCom,pFirstObj,COM_None,COM_None,pFirstObj->id);
|
|
// Next section
|
|
cSec++;
|
|
} */
|
|
}
|
|
|
|
int C4ObjectList::ClearPointers(C4Object *pObj)
|
|
{
|
|
int rval=0;
|
|
// Clear all primary list pointers
|
|
while (Remove(pObj)) rval++;
|
|
// Clear all sub pointers
|
|
C4Object *cobj; C4ObjectLink *clnk;
|
|
for (clnk=First; clnk && (cobj=clnk->Obj); clnk=clnk->Next)
|
|
cobj->ClearPointers(pObj);
|
|
return rval;
|
|
}
|
|
|
|
void C4ObjectList::DrawAll(C4TargetFacet &cgo, int iPlayer)
|
|
{
|
|
C4ObjectLink *clnk;
|
|
// Draw objects (base)
|
|
for (clnk=Last; clnk; clnk=clnk->Prev)
|
|
clnk->Obj->Draw(cgo, iPlayer);
|
|
// Draw objects (top face)
|
|
for (clnk=Last; clnk; clnk=clnk->Prev)
|
|
clnk->Obj->DrawTopFace(cgo, iPlayer);
|
|
}
|
|
|
|
void C4ObjectList::DrawIfCategory(C4TargetFacet &cgo, int iPlayer, uint32_t dwCat, bool fInvert)
|
|
{
|
|
C4ObjectLink *clnk;
|
|
// Draw objects (base)
|
|
for (clnk=Last; clnk; clnk=clnk->Prev)
|
|
if (!(clnk->Obj->Category & dwCat) == fInvert)
|
|
clnk->Obj->Draw(cgo, iPlayer);
|
|
// Draw objects (top face)
|
|
for (clnk=Last; clnk; clnk=clnk->Prev)
|
|
if (!(clnk->Obj->Category & dwCat) == fInvert)
|
|
clnk->Obj->DrawTopFace(cgo, iPlayer);
|
|
}
|
|
|
|
void C4ObjectList::Draw(C4TargetFacet &cgo, int iPlayer)
|
|
{
|
|
C4ObjectLink *clnk;
|
|
// Draw objects (base)
|
|
for (clnk=Last; clnk; clnk=clnk->Prev)
|
|
if (!(clnk->Obj->Category & C4D_BackgroundOrForeground))
|
|
clnk->Obj->Draw(cgo, iPlayer);
|
|
// Draw objects (top face)
|
|
for (clnk=Last; clnk; clnk=clnk->Prev)
|
|
if (!(clnk->Obj->Category & C4D_BackgroundOrForeground))
|
|
clnk->Obj->DrawTopFace(cgo, iPlayer);
|
|
}
|
|
|
|
void C4ObjectList::Enumerate()
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
// Enumerate object pointers
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
cLnk->Obj->EnumeratePointers();
|
|
}
|
|
|
|
long C4ObjectList::ObjectNumber(C4Object *pObj)
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
if(!pObj) return 0;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj==pObj)
|
|
return cLnk->Obj->Number;
|
|
return 0;
|
|
}
|
|
|
|
bool C4ObjectList::IsContained(C4Object *pObj)
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj==pObj)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
BOOL C4ObjectList::IsClear() const
|
|
{
|
|
return (ObjectCount()==0);
|
|
}
|
|
|
|
BOOL C4ObjectList::ReadEnumerated(const char *szSource)
|
|
{
|
|
assert(false);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL C4ObjectList::DenumerateRead()
|
|
{
|
|
if(!pEnumerated) return FALSE;
|
|
// Denumerate all object pointers
|
|
for(std::list<int32_t>::const_iterator pNum = pEnumerated->begin(); pNum != pEnumerated->end(); ++pNum)
|
|
Add(Game.Objects.ObjectPointer(*pNum), stNone); // Add to tail, unsorted
|
|
// Delete old list
|
|
delete pEnumerated; pEnumerated = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL C4ObjectList::Write(char *szTarget)
|
|
{
|
|
char ostr[25];
|
|
szTarget[0]=0;
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk && cLnk->Obj; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
{
|
|
sprintf(ostr,"%d;",cLnk->Obj->Number);
|
|
SAppend(ostr,szTarget);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void C4ObjectList::Denumerate()
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
cLnk->Obj->DenumeratePointers();
|
|
}
|
|
|
|
void C4ObjectList::CompileFunc(StdCompiler *pComp, bool fSaveRefs, bool fSkipPlayerObjects)
|
|
{
|
|
if(fSaveRefs)
|
|
{
|
|
// this mode not supported
|
|
assert(!fSkipPlayerObjects);
|
|
// (Re)create list
|
|
delete pEnumerated; pEnumerated = new std::list<int32_t>();
|
|
// Decompiling: Build list
|
|
if(!pComp->isCompiler())
|
|
for(C4ObjectLink *pPos = First; pPos; pPos = pPos->Next)
|
|
if(pPos->Obj->Status)
|
|
pEnumerated->push_back(pPos->Obj->Number);
|
|
// Compile list
|
|
pComp->Value(mkSTLContainerAdapt(*pEnumerated, StdCompiler::SEP_SEP2));
|
|
// Decompiling: Delete list
|
|
if(!pComp->isCompiler())
|
|
{ delete pEnumerated; pEnumerated = NULL; }
|
|
// Compiling: Nothing to do - list will e denumerated later
|
|
}
|
|
else
|
|
{
|
|
if(pComp->isDecompiler())
|
|
{
|
|
// skipping player objects would screw object counting in non-naming compilers
|
|
assert(!fSkipPlayerObjects || pComp->hasNaming());
|
|
// Put object count
|
|
int32_t iObjCnt = ObjectCount();
|
|
pComp->Value(mkNamingCountAdapt(iObjCnt, "Object"));
|
|
// Decompile all objects in reverse order
|
|
for(C4ObjectLink *pPos = Last; pPos; pPos = pPos->Prev)
|
|
if(pPos->Obj->Status)
|
|
if (!fSkipPlayerObjects || !pPos->Obj->IsUserPlayerObject())
|
|
pComp->Value(mkNamingAdapt(*pPos->Obj, "Object"));
|
|
}
|
|
else
|
|
{
|
|
// this mode not supported
|
|
assert(!fSkipPlayerObjects);
|
|
// Remove previous data
|
|
Clear();
|
|
// Get "Object" section count
|
|
int32_t iObjCnt;
|
|
pComp->Value(mkNamingCountAdapt(iObjCnt, "Object"));
|
|
// Load objects, add them to the list.
|
|
for(int i = 0; i < iObjCnt; i++)
|
|
{
|
|
C4Object *pObj = NULL;
|
|
try
|
|
{
|
|
pComp->Value(mkNamingAdapt(mkPtrAdaptNoNull(pObj), "Object"));
|
|
Add(pObj, stReverse);
|
|
}
|
|
catch (StdCompiler::Exception *pExc)
|
|
{
|
|
// Failsafe object loading: If an error occurs during object loading, just skip that object and load the next one
|
|
if(!pExc->Pos.getLength())
|
|
LogF("ERROR: Object loading: %s", pExc->Msg.getData());
|
|
else
|
|
LogF("ERROR: Object loading(%s): %s", pExc->Pos.getData(), pExc->Msg.getData());
|
|
delete pExc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
C4Object* C4ObjectList::ObjectPointer(int32_t iNumber)
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Number==iNumber)
|
|
return cLnk->Obj;
|
|
return NULL;
|
|
}
|
|
|
|
C4Object *C4ObjectList::SafeObjectPointer(int32_t iNumber)
|
|
{
|
|
C4Object *pObj = ObjectPointer(iNumber);
|
|
if (pObj) if (!pObj->Status) return NULL;
|
|
return pObj;
|
|
}
|
|
|
|
StdStrBuf C4ObjectList::GetNameList(C4DefList &rDefs, DWORD dwCategory)
|
|
{
|
|
int cpos,idcount;
|
|
C4ID c_id;
|
|
C4Def *cdef;
|
|
StdStrBuf Buf;
|
|
for (cpos=0; c_id=GetListID(dwCategory,cpos); cpos++)
|
|
if (cdef=rDefs.ID2Def(c_id))
|
|
{
|
|
idcount=ObjectCount(c_id);
|
|
if (cpos>0) Buf.Append(", ");
|
|
Buf.AppendFormat("%dx %s",idcount,cdef->GetName());
|
|
}
|
|
return Buf;
|
|
}
|
|
|
|
BOOL C4ObjectList::ValidateOwners()
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
cLnk->Obj->ValidateOwner();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL C4ObjectList::AssignInfo()
|
|
{
|
|
// the list seems to be traced backwards here, to ensure crew objects are added in correct order
|
|
// (or semi-correct, because this will work only if the crew order matches the main object list order)
|
|
// this is obsolete now, because the crew list is stored in the savegame
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=Last; cLnk; cLnk=cLnk->Prev)
|
|
if (cLnk->Obj->Status)
|
|
cLnk->Obj->AssignInfo();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL C4ObjectList::AssignPlrViewRange()
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=Last; cLnk; cLnk=cLnk->Prev)
|
|
if (cLnk->Obj->Status)
|
|
cLnk->Obj->AssignPlrViewRange();
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
void C4ObjectList::ClearInfo(C4ObjectInfo *pInfo)
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
cLnk->Obj->ClearInfo(pInfo);
|
|
}
|
|
|
|
void C4ObjectList::ClearDefPointers(C4Def *pDef)
|
|
{
|
|
// clear all pointers into definition
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Def == pDef)
|
|
{
|
|
cLnk->Obj->Name.Clear();
|
|
}
|
|
}
|
|
|
|
void C4ObjectList::UpdateDefPointers(C4Def *pDef)
|
|
{
|
|
// restore any cleared pointers after def reload
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Def == pDef)
|
|
{
|
|
cLnk->Obj->SetName(NULL);
|
|
}
|
|
}
|
|
|
|
C4Object* C4ObjectList::Enumerated(C4Object *pObj)
|
|
{
|
|
int iPtrNum;
|
|
// If object is enumerated, convert to enumerated pointer
|
|
if (iPtrNum = ObjectNumber(pObj))
|
|
return (C4Object*) (C4EnumPointer1 + iPtrNum);
|
|
// Oops!
|
|
return 0;
|
|
}
|
|
|
|
C4Object* C4ObjectList::Denumerated(C4Object *pObj)
|
|
{
|
|
// If valid enumeration, convert to pointer
|
|
if (Inside( (long) pObj, C4EnumPointer1, C4EnumPointer2 ))
|
|
return ObjectPointer( (long) pObj - C4EnumPointer1 );
|
|
// Oops!
|
|
return NULL;
|
|
}
|
|
|
|
void C4ObjectList::DrawList(C4Facet &cgo, int iSelection, DWORD dwCategory)
|
|
{
|
|
int iSections = cgo.GetSectionCount();
|
|
int iObjects = ObjectCount(C4ID_None,dwCategory);
|
|
int iFirstVisible = BoundBy(iSelection-iSections/2,0,Max(iObjects-iSections,0));
|
|
C4Facet cgo2;
|
|
int iObj=0,iSec=0;
|
|
C4ObjectLink *cLnk; C4Object *cObj;
|
|
for (cLnk=First; cLnk && (cObj=cLnk->Obj); cLnk=cLnk->Next)
|
|
if (cObj->Status && (cObj->Category && dwCategory))
|
|
{
|
|
if (Inside(iObj,iFirstVisible,iFirstVisible+iSections-1))
|
|
{
|
|
cgo2 = cgo.GetSection(iSec++);
|
|
cObj->DrawPicture(cgo2,(iObj==iSelection));
|
|
}
|
|
iObj++;
|
|
}
|
|
}
|
|
|
|
void C4ObjectList::Sort()
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
BOOL fSorted;
|
|
// Sort by id
|
|
do
|
|
{
|
|
fSorted = TRUE;
|
|
for (cLnk=First; cLnk && cLnk->Next; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->id > cLnk->Next->Obj->id)
|
|
{
|
|
RemoveLink(cLnk);
|
|
InsertLink(cLnk,cLnk->Next);
|
|
fSorted = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
while (!fSorted);
|
|
}
|
|
|
|
void C4ObjectList::RemoveLink(C4ObjectLink *pLnk)
|
|
{
|
|
if (pLnk->Prev) pLnk->Prev->Next=pLnk->Next; else First=pLnk->Next;
|
|
if (pLnk->Next) pLnk->Next->Prev=pLnk->Prev; else Last=pLnk->Prev;
|
|
}
|
|
|
|
void C4ObjectList::InsertLink(C4ObjectLink *pLnk, C4ObjectLink *pAfter)
|
|
{
|
|
// Insert after
|
|
if (pAfter)
|
|
{
|
|
pLnk->Prev=pAfter; pLnk->Next=pAfter->Next;
|
|
if (pAfter->Next) pAfter->Next->Prev=pLnk; else Last=pLnk;
|
|
pAfter->Next=pLnk;
|
|
}
|
|
// Insert at head
|
|
else
|
|
{
|
|
pLnk->Prev=NULL; pLnk->Next=First;
|
|
if (First) First->Prev=pLnk; else Last=pLnk;
|
|
First=pLnk;
|
|
}
|
|
}
|
|
|
|
void C4ObjectList::InsertLinkBefore(C4ObjectLink *pLnk, C4ObjectLink *pBefore)
|
|
{
|
|
// Insert before
|
|
if (pBefore)
|
|
{
|
|
pLnk->Prev = pBefore->Prev;
|
|
if (pBefore->Prev) pBefore->Prev->Next = pLnk; else First = pLnk;
|
|
pLnk->Next = pBefore; pBefore->Prev = pLnk;
|
|
}
|
|
// Insert at end
|
|
else
|
|
{
|
|
pLnk->Next = NULL; pLnk->Prev = Last;
|
|
if (Last) Last->Next = pLnk; else First = pLnk;
|
|
Last = pLnk;
|
|
}
|
|
}
|
|
|
|
|
|
void C4NotifyingObjectList::InsertLinkBefore(C4ObjectLink *pLink, C4ObjectLink *pBefore)
|
|
{
|
|
C4ObjectList::InsertLinkBefore(pLink, pBefore);
|
|
ObjectListChangeListener.OnObjectAdded(this, pLink);
|
|
}
|
|
|
|
void C4NotifyingObjectList::InsertLink(C4ObjectLink *pLink, C4ObjectLink *pAfter)
|
|
{
|
|
C4ObjectList::InsertLink(pLink, pAfter);
|
|
ObjectListChangeListener.OnObjectAdded(this, pLink);
|
|
}
|
|
|
|
void C4NotifyingObjectList::RemoveLink(C4ObjectLink *pLnk)
|
|
{
|
|
C4ObjectList::RemoveLink(pLnk);
|
|
ObjectListChangeListener.OnObjectRemove(this, pLnk);
|
|
}
|
|
|
|
void C4ObjectList::SyncClearance()
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj)
|
|
cLnk->Obj->SyncClearance();
|
|
}
|
|
|
|
void C4ObjectList::UpdateGraphics(bool fGraphicsChanged)
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
cLnk->Obj->UpdateGraphics(fGraphicsChanged);
|
|
}
|
|
|
|
void C4ObjectList::UpdateFaces(bool bUpdateShapes)
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
cLnk->Obj->UpdateFace(bUpdateShapes);
|
|
}
|
|
|
|
void C4ObjectList::DrawSelectMark(C4TargetFacet &cgo, float Zoom)
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=Last; cLnk; cLnk=cLnk->Prev)
|
|
cLnk->Obj->DrawSelectMark(cgo, Zoom);
|
|
}
|
|
|
|
void C4ObjectList::GetIDList(C4IDList &rList, int32_t dwCategory)
|
|
{
|
|
C4ObjectLink *clnk;
|
|
C4Def *pDef;
|
|
rList.Clear();
|
|
for (clnk=First; clnk && clnk->Obj; clnk=clnk->Next)
|
|
if (clnk->Obj->Status)
|
|
if ((dwCategory==C4D_All) || ( (pDef=C4Id2Def(clnk->Obj->Def->id)) && (pDef->Category & dwCategory) ))
|
|
rList.IncreaseIDCount(clnk->Obj->Def->id);
|
|
}
|
|
|
|
void C4ObjectList::CloseMenus()
|
|
{
|
|
C4Object *cobj; C4ObjectLink *clnk;
|
|
for (clnk=First; clnk && (cobj=clnk->Obj); clnk=clnk->Next)
|
|
cobj->CloseMenu(true);
|
|
}
|
|
|
|
void C4ObjectList::SetOCF()
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
if (cLnk->Obj->Status)
|
|
cLnk->Obj->SetOCF();
|
|
}
|
|
|
|
void C4ObjectList::Copy(const C4ObjectList &rList)
|
|
{
|
|
Clear(); Default();
|
|
C4ObjectLink *cLnk;
|
|
for (cLnk=rList.First; cLnk; cLnk=cLnk->Next) Add(cLnk->Obj, C4ObjectList::stNone);
|
|
}
|
|
|
|
void C4ObjectList::Default()
|
|
{
|
|
First=Last=NULL;
|
|
Mass=0;
|
|
pEnumerated=NULL;
|
|
}
|
|
|
|
void C4ObjectList::UpdateTransferZones()
|
|
{
|
|
C4Object *cobj; C4ObjectLink *clnk;
|
|
for (clnk=First; clnk && (cobj=clnk->Obj); clnk=clnk->Next)
|
|
cobj->Call(PSF_UpdateTransferZone);
|
|
}
|
|
|
|
void C4ObjectList::ResetAudibility()
|
|
{
|
|
C4Object *cobj; C4ObjectLink *clnk;
|
|
for (clnk=First; clnk && (cobj=clnk->Obj); clnk=clnk->Next)
|
|
cobj->Audible=cobj->AudiblePan=0;
|
|
}
|
|
|
|
void C4ObjectList::SortByCategory()
|
|
{
|
|
C4ObjectLink *cLnk;
|
|
BOOL fSorted;
|
|
// Sort by category
|
|
do
|
|
{
|
|
fSorted = TRUE;
|
|
for (cLnk=First; cLnk && cLnk->Next; cLnk=cLnk->Next)
|
|
if ((cLnk->Obj->Category & C4D_SortLimit) < (cLnk->Next->Obj->Category & C4D_SortLimit))
|
|
{
|
|
RemoveLink(cLnk);
|
|
InsertLink(cLnk,cLnk->Next);
|
|
fSorted = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
while (!fSorted);
|
|
}
|
|
|
|
BOOL C4ObjectList::OrderObjectBefore(C4Object *pObj1, C4Object *pObj2)
|
|
{
|
|
// safety
|
|
if (pObj1->Status != C4OS_NORMAL || pObj2->Status != C4OS_NORMAL) return FALSE;
|
|
// get links (and check whether the objects are part of this list!)
|
|
C4ObjectLink *pLnk1=GetLink(pObj1); if (!pLnk1) return FALSE;
|
|
C4ObjectLink *pLnk2=GetLink(pObj2); if (!pLnk2) return FALSE;
|
|
// check if requirements are already fulfilled
|
|
C4ObjectLink *pLnk=pLnk1;
|
|
while (pLnk=pLnk->Next) if (pLnk==pLnk2) break;
|
|
if (pLnk) return TRUE;
|
|
// if not, reorder pLnk1 directly before pLnk2
|
|
// unlink from current position
|
|
// no need to check pLnk1->Prev here, because pLnk1 cannot be first in the list
|
|
// (at least pLnk2 must lie before it!)
|
|
if (pLnk1->Prev->Next=pLnk1->Next) pLnk1->Next->Prev=pLnk1->Prev; else Last=pLnk1->Prev;
|
|
// relink into new one
|
|
if (pLnk1->Prev=pLnk2->Prev) pLnk2->Prev->Next=pLnk1; else First=pLnk1;
|
|
pLnk1->Next=pLnk2; pLnk2->Prev=pLnk1;
|
|
// done, success
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL C4ObjectList::OrderObjectAfter(C4Object *pObj1, C4Object *pObj2)
|
|
{
|
|
// safety
|
|
if (pObj1->Status != C4OS_NORMAL || pObj2->Status != C4OS_NORMAL) return FALSE;
|
|
// get links (and check whether the objects are part of this list!)
|
|
C4ObjectLink *pLnk1=GetLink(pObj1); if (!pLnk1) return FALSE;
|
|
C4ObjectLink *pLnk2=GetLink(pObj2); if (!pLnk2) return FALSE;
|
|
// check if requirements are already fulfilled
|
|
C4ObjectLink *pLnk=pLnk1;
|
|
while (pLnk=pLnk->Prev) if (pLnk==pLnk2) break;
|
|
if (pLnk) return TRUE;
|
|
// if not, reorder pLnk1 directly after pLnk2
|
|
// unlink from current position
|
|
// no need to check pLnk1->Next here, because pLnk1 cannot be last in the list
|
|
// (at least pLnk2 must lie after it!)
|
|
if (pLnk1->Next->Prev=pLnk1->Prev) pLnk1->Prev->Next=pLnk1->Next; else First=pLnk1->Next;
|
|
// relink into new one
|
|
if (pLnk1->Next=pLnk2->Next) pLnk2->Next->Prev=pLnk1; else Last=pLnk1;
|
|
pLnk1->Prev=pLnk2; pLnk2->Next=pLnk1;
|
|
// done, success
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL C4ObjectList::ShiftContents(C4Object *pNewFirst)
|
|
{
|
|
// get link of new first (this ensures list is not empty)
|
|
C4ObjectLink *pNewFirstLnk = GetLink(pNewFirst);
|
|
if (!pNewFirstLnk) return FALSE;
|
|
// already at front?
|
|
if (pNewFirstLnk == First) return TRUE;
|
|
// sort it there:
|
|
// 1. Make cyclic list
|
|
Last->Next = First; First->Prev = Last;
|
|
// 2. Re-set first and last
|
|
First = pNewFirstLnk;
|
|
Last = pNewFirstLnk->Prev;
|
|
// 3. Uncycle list
|
|
First->Prev = Last->Next = NULL;
|
|
// done, success
|
|
return TRUE;
|
|
}
|
|
|
|
void C4ObjectList::DeleteObjects()
|
|
{
|
|
// delete links and objects
|
|
while (First)
|
|
{
|
|
C4Object *pObj = First->Obj;
|
|
Remove(pObj);
|
|
delete pObj;
|
|
}
|
|
// reset mass
|
|
Mass=0;
|
|
}
|
|
|
|
|
|
// -------------------------------------------------
|
|
// C4ObjectListIterator
|
|
|
|
C4Object *C4ObjectListIterator::GetNext(int32_t *piCount, uint32_t dwCategory)
|
|
{
|
|
// end reached?
|
|
if (pCurrID == rList.end()) return NULL;
|
|
// not yet started?
|
|
if (pCurr == rList.end())
|
|
// then start at first ID list head
|
|
pCurr = pCurrID;
|
|
else
|
|
// next item
|
|
if (++pCurr == rList.end()) return NULL;
|
|
// skip mismatched category
|
|
if (dwCategory)
|
|
while (!((*pCurr)->Category & dwCategory))
|
|
if (++pCurr == rList.end()) return NULL;
|
|
// next ID section reached?
|
|
if ((*pCurr)->id != (*pCurrID)->id)
|
|
pCurrID = pCurr;
|
|
else
|
|
{
|
|
// otherwise, it must be checked, whether this is a duplicate item already iterated
|
|
// if so, advance the list
|
|
for (C4ObjectList::iterator pCheck = pCurrID; pCheck != pCurr; ++pCheck)
|
|
if (!dwCategory || ((*pCheck)->Category & dwCategory))
|
|
if ((*pCheck)->CanConcatPictureWith(*pCurr))
|
|
{
|
|
// next object of matching category
|
|
if (++pCurr == rList.end()) return NULL;
|
|
if (dwCategory)
|
|
while (!((*pCurr)->Category & dwCategory))
|
|
if (++pCurr == rList.end()) return NULL;
|
|
// next ID chunk reached?
|
|
if ((*pCurr)->id != (*pCurrID)->id)
|
|
{
|
|
// then break here
|
|
pCurrID = pCurr;
|
|
break;
|
|
}
|
|
// restart check for next object
|
|
pCheck = pCurrID;
|
|
}
|
|
}
|
|
if (piCount)
|
|
{
|
|
// default count
|
|
*piCount = 1;
|
|
// add additional objects of same ID to the count
|
|
C4ObjectList::iterator pCheck(pCurr);
|
|
for (++pCheck; pCheck != rList.end() && (*pCheck)->id == (*pCurr)->id; ++pCheck)
|
|
if (!dwCategory || ((*pCheck)->Category & dwCategory))
|
|
if ((*pCheck)->CanConcatPictureWith(*pCurr))
|
|
++*piCount;
|
|
}
|
|
// return found object
|
|
return *pCurr;
|
|
}
|
|
|
|
void C4ObjectList::UpdateScriptPointers()
|
|
{
|
|
for (C4ObjectLink *cLnk=First; cLnk; cLnk=cLnk->Next)
|
|
cLnk->Obj->UpdateScriptPointers();
|
|
}
|
|
|
|
struct C4ObjectListDumpHelper
|
|
{
|
|
C4ObjectList *pLst;
|
|
|
|
void CompileFunc(StdCompiler *pComp) { pComp->Value(mkNamingAdapt(*pLst, "Objects")); }
|
|
|
|
C4ObjectListDumpHelper(C4ObjectList *pLst) : pLst(pLst) {}
|
|
ALLOW_TEMP_TO_REF(C4ObjectListDumpHelper)
|
|
};
|
|
|
|
BOOL C4ObjectList::CheckSort(C4ObjectList *pList)
|
|
{
|
|
C4ObjectLink *cLnk = First, *cLnk2 = pList->First;
|
|
while (cLnk && cLnk->Obj->Unsorted) cLnk = cLnk->Next;
|
|
while(cLnk)
|
|
if(!cLnk2)
|
|
{
|
|
Log("CheckSort failure");
|
|
LogSilent(DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(C4ObjectListDumpHelper(this), "SectorList")).getData());
|
|
LogSilent(DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(C4ObjectListDumpHelper(pList), "MainList")).getData());
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if(cLnk->Obj == cLnk2->Obj)
|
|
{
|
|
cLnk = cLnk->Next;
|
|
while (cLnk && cLnk->Obj->Unsorted) cLnk = cLnk->Next;
|
|
}
|
|
cLnk2 = cLnk2->Next;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void C4ObjectList::CheckCategorySort()
|
|
{
|
|
// debug: Check whether object list is sorted correctly
|
|
C4ObjectLink *cLnk, *cPrev=NULL;
|
|
for (cLnk=First; cLnk && cLnk->Next; cLnk=cLnk->Next)
|
|
if (!cLnk->Obj->Unsorted && cLnk->Obj->Status)
|
|
{
|
|
if (cPrev) assert( (cPrev->Obj->Category & C4D_SortLimit) >= (cLnk->Obj->Category & C4D_SortLimit));
|
|
cPrev = cLnk;
|
|
}
|
|
}
|
|
|
|
C4ObjectList::iterator::iterator(C4ObjectList & List):
|
|
List(List), pLink(List.First)
|
|
{
|
|
Next = List.AddIter(this);
|
|
}
|
|
C4ObjectList::iterator::iterator(C4ObjectList & List, C4ObjectLink * pLink):
|
|
List(List), pLink(pLink)
|
|
{
|
|
Next=List.AddIter(this);
|
|
}
|
|
C4ObjectList::iterator::iterator(const C4ObjectList::iterator & iter):
|
|
List(iter.List), pLink(iter.pLink), Next()
|
|
{
|
|
Next=List.AddIter(this);
|
|
}
|
|
C4ObjectList::iterator::~iterator()
|
|
{
|
|
List.RemoveIter(this);
|
|
}
|
|
C4ObjectList::iterator& C4ObjectList::iterator::operator++ ()
|
|
{
|
|
pLink = pLink ? pLink->Next : pLink;
|
|
return *this;
|
|
}
|
|
C4ObjectList::iterator C4ObjectList::iterator::operator++ (int)
|
|
{
|
|
iterator old = *this;
|
|
pLink = pLink ? pLink->Next : pLink;
|
|
return old;
|
|
}
|
|
C4Object * C4ObjectList::iterator::operator* ()
|
|
{
|
|
return pLink ? pLink->Obj : 0;
|
|
}
|
|
bool C4ObjectList::iterator::operator== (const iterator & iter) const
|
|
{
|
|
return &iter.List == &List && iter.pLink == pLink;
|
|
}
|
|
bool C4ObjectList::iterator::operator!= (const iterator & iter) const
|
|
{
|
|
return &iter.List != &List || iter.pLink != pLink;
|
|
}
|
|
|
|
C4ObjectList::iterator& C4ObjectList::iterator::operator=(const iterator & iter)
|
|
{
|
|
// Can only assign iterators into the same list
|
|
assert(&iter.List == &List);
|
|
|
|
pLink = iter.pLink;
|
|
return *this;
|
|
}
|
|
|
|
C4ObjectList::iterator C4ObjectList::begin()
|
|
{
|
|
return iterator(*this);
|
|
}
|
|
const C4ObjectList::iterator C4ObjectList::end()
|
|
{
|
|
return iterator(*this, 0);
|
|
}
|
|
C4ObjectList::iterator * C4ObjectList::AddIter(iterator * iter)
|
|
{
|
|
iterator * r = FirstIter;
|
|
FirstIter = iter;
|
|
return r;
|
|
}
|
|
void C4ObjectList::RemoveIter(iterator * iter)
|
|
{
|
|
if(iter == FirstIter)
|
|
FirstIter = iter->Next;
|
|
else
|
|
{
|
|
iterator * i = FirstIter;
|
|
while(i->Next && i->Next != iter)
|
|
i = i->Next;
|
|
i->Next = iter->Next;
|
|
}
|
|
}
|