openclonk/src/object/C4ObjectInfoList.cpp

261 lines
5.7 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 1998-2000, Matthes Bender
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
/* Dynamic list for crew member info */
#include "C4Include.h"
#include "object/C4ObjectInfoList.h"
#include "object/C4Def.h"
#include "object/C4DefList.h"
#include "object/C4ObjectInfo.h"
#include "c4group/C4Components.h"
#include "game/C4Game.h"
#include "player/C4RankSystem.h"
#include "config/C4Config.h"
#include "object/C4GameObjects.h"
C4ObjectInfoList::C4ObjectInfoList()
{
Default();
}
C4ObjectInfoList::~C4ObjectInfoList()
{
Clear();
}
void C4ObjectInfoList::Default()
{
First=nullptr;
iNumCreated=0;
}
void C4ObjectInfoList::Clear()
{
C4ObjectInfo *next;
while (First)
{
next=First->Next;
delete First;
First=next;
}
}
int32_t C4ObjectInfoList::Load(C4Group &hGroup)
{
C4ObjectInfo *ninf;
int32_t infn=0;
char entryname[256+1];
// Search all oci files
hGroup.ResetSearch();
while (hGroup.FindNextEntry(C4CFN_ObjectInfoFiles,entryname))
if ((ninf=new C4ObjectInfo))
{
if (ninf->Load(hGroup,entryname)) { Add(ninf); infn++; }
else delete ninf;
}
// Search subfolders
hGroup.ResetSearch();
while (hGroup.FindNextEntry("*", entryname))
{
C4Group ItemGroup;
if (ItemGroup.OpenAsChild(&hGroup, entryname))
Load(ItemGroup);
}
return infn;
}
bool C4ObjectInfoList::Add(C4ObjectInfo *pInfo)
{
if (!pInfo) return false;
pInfo->Next=First;
First=pInfo;
return true;
}
void C4ObjectInfoList::MakeValidName(char *sName)
{
char tstr[_MAX_PATH];
int32_t iname;
size_t namelen = SLen(sName);
for (iname=2; NameExists(sName); iname++)
{
sprintf(tstr," %d",iname);
SCopy(tstr, sName + std::min(namelen, C4MaxName - SLen(tstr)));
}
}
bool C4ObjectInfoList::NameExists(const char *szName)
{
C4ObjectInfo *cinf;
for (cinf=First; cinf; cinf=cinf->Next)
if (SEqualNoCase(szName,cinf->Name))
return true;
return false;
}
C4ObjectInfo* C4ObjectInfoList::GetIdle(C4ID c_id, C4DefList &rDefs)
{
C4Def *pDef;
C4ObjectInfo *pInfo;
C4ObjectInfo *pHiExp=nullptr;
// Search list
for (pInfo=First; pInfo; pInfo=pInfo->Next)
// Valid only
if ((pDef = rDefs.ID2Def(pInfo->id)))
// Use standard crew or matching id
if ( (!c_id && !pDef->NativeCrew) || (pInfo->id==c_id) )
// Participating and not in action
if (pInfo->Participation && !pInfo->InAction && !pInfo->HasDied)
// Highest experience
if (!pHiExp || (pInfo->Experience>pHiExp->Experience))
// Set this
pHiExp=pInfo;
// Found
if (pHiExp)
{
pHiExp->Recruit();
return pHiExp;
}
return nullptr;
}
C4ObjectInfo* C4ObjectInfoList::New(C4ID n_id, C4DefList *pDefs)
{
C4ObjectInfo *pInfo;
// Create new info object
if (!(pInfo = new C4ObjectInfo)) return nullptr;
// Default type clonk if none specified
if (n_id == C4ID::None) n_id = C4ID::Clonk;
// Check type valid and def available
C4Def *pDef = nullptr;
if (pDefs)
if (!(pDef = pDefs->ID2Def(n_id)))
{ delete pInfo; return nullptr; }
// Set name source
const char *cpNames = Game.Names.GetData();
if (pDef->pClonkNames) cpNames = pDef->pClonkNames->GetData();
// Default by type
((C4ObjectInfoCore*)pInfo)->Default(n_id, pDefs, cpNames);
// Set birthday
pInfo->Birthday=time(nullptr);
// Make valid names
MakeValidName(pInfo->Name);
// Add
Add(pInfo);
++iNumCreated;
return pInfo;
}
void C4ObjectInfoList::Evaluate()
{
C4ObjectInfo *cinf;
for (cinf=First; cinf; cinf=cinf->Next)
cinf->Evaluate();
}
bool C4ObjectInfoList::Save(C4Group &hGroup, bool fSavegame, bool fStoreTiny, C4DefList *pDefs)
{
// Save in opposite order (for identical crew order on load)
C4ObjectInfo *pInfo;
for (pInfo = GetLast(); pInfo; pInfo = GetPrevious(pInfo))
{
// don't safe TemporaryCrew in regular player files
if (!fSavegame)
{
C4Def *pDef=C4Id2Def(pInfo->id);
if (pDef) if (pDef->TemporaryCrew) continue;
}
// save
if (!pInfo->Save(hGroup, fStoreTiny, pDefs))
return false;
}
return true;
}
C4ObjectInfo* C4ObjectInfoList::GetIdle(const char *szByName)
{
C4ObjectInfo *pInfo;
// Find matching name, participating, alive and not in action
for (pInfo=First; pInfo; pInfo=pInfo->Next)
if (SEqualNoCase(pInfo->Name,szByName))
if (pInfo->Participation && !pInfo->InAction && !pInfo->HasDied)
{
pInfo->Recruit();
return pInfo;
}
return nullptr;
}
void C4ObjectInfoList::DetachFromObjects()
{
C4ObjectInfo *cinf;
for (cinf=First; cinf; cinf=cinf->Next)
::Objects.ClearInfo(cinf);
}
C4ObjectInfo* C4ObjectInfoList::GetLast()
{
C4ObjectInfo *cInfo = First;
while (cInfo && cInfo->Next) cInfo=cInfo->Next;
return cInfo;
}
C4ObjectInfo* C4ObjectInfoList::GetPrevious(C4ObjectInfo *pInfo)
{
for (C4ObjectInfo *cInfo = First; cInfo; cInfo=cInfo->Next)
if (cInfo->Next == pInfo)
return cInfo;
return nullptr;
}
bool C4ObjectInfoList::IsElement(C4ObjectInfo *pInfo)
{
for (C4ObjectInfo *cInfo = First; cInfo; cInfo=cInfo->Next)
if (cInfo == pInfo) return true;
return false;
}
void C4ObjectInfoList::Strip(C4DefList &rDefs)
{
C4ObjectInfo *pInfo, *pPrev;
// Search list
for (pInfo=First, pPrev=nullptr; pInfo; )
{
// Invalid?
if (!rDefs.ID2Def(pInfo->id))
{
C4ObjectInfo *pDelete = pInfo;
if (pPrev) pPrev->Next = pInfo->Next; else First = pInfo->Next;
pInfo = pInfo->Next;
delete pDelete;
}
else
{
pPrev = pInfo;
pInfo = pInfo->Next;
}
}
}