Rev 264 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "XspFile.h"
#include "File_IO.h"
#include "Packages.h"
#include "CatFile.h"
#define ADDSECTIONLIST(T, L) for(CListNode<T> *node = L.Front(); node; node = node->next()) \
_addSection(list, node->Data()->sSection, node->Data()->sData);
#define GENERATESECTION(F, T, L) if ( !L.empty() ) { \
type = F; \
Utils::CList<STypesSection> list; \
ADDSECTIONLIST(T, L); \
data = CXspFile::TypesListToString(list, true); \
}
#define GENERATESTRINGSECTION(F, L, FIRST) if ( !L.empty() ) { \
type = F; \
Utils::CList<STypesSection> list; \
_addDataSection(L, list, FIRST); \
data = CXspFile::TypesListToString(list, true); \
}
CXspFile::CXspFile () : CBaseFile()
{
SetDefaults ();
}
void CXspFile::Delete ()
{
CBaseFile::Delete();
m_pSceneFile = m_pCockpitFile = NULL;
// delete lists
m_lMissileMasks.MemoryClear();
m_lWeaponMasks.MemoryClear();
m_lMissileMasks.destroy();
m_lWeaponMasks.destroy();
for ( CListNode<SCockpit> *n = m_lCockpit.Front(); n; n = n->next() )
n->Data()->lWeaponMask.MemoryClear();
m_lCockpit.MemoryClear();
m_lCockpit.destroy();
_lCutData.clear();
_lBodies.clear();
_lAnimations.clear();
}
void CXspFile::SetDefaults ()
{
CBaseFile::SetDefaults ();
m_pSceneFile = m_pCockpitFile = NULL;
m_bLanguageText = m_bExistingShip = false;
m_iOrgDesc = 0;
ShipyardRace r = ShipyardRace::None;
_iShipyard = static_cast<unsigned long>(ShipyardRace::None);
}
void CXspFile::addText(int id, const Utils::WString &name, const Utils::WString &desc)
{
// first check if theres an existing id
SText *newtext = NULL;
for ( SText *t = m_lText.First(); t; t = m_lText.Next() )
{
if ( t->iId == id )
{
newtext = t;
break;
}
}
if ( !newtext )
{
newtext = new SText;
newtext->iId = id;
m_lText.push_back ( newtext );
}
newtext->sName = name;
newtext->sDesc = desc;
_changed();
}
void CXspFile::RemoveText(int id)
{
for ( SText *t = m_lText.First(); t; t = m_lText.Next() )
{
if ( t->iId == id )
{
_changed();
m_lText.RemoveCurrent();
return;
}
}
}
void CXspFile::addDummy(const Utils::WString §ion, const Utils::WString &data)
{
SDummy *d = new SDummy;
d->sData = data;
d->sSection = section;
if ( d->sData.right(1) != L";" )
d->sData += L";";
m_lDummy.push_back ( d );
_changed();
}
void CXspFile::addComponent(const Utils::WString §ion, const Utils::WString §ion2, const Utils::WString &data)
{
SComponent *c = new SComponent;
c->sData = data;
c->sSection = section;
c->sSection2 = section2;
if ( c->sData.right(1) != L";" )
c->sData += L";";
m_lComponent.push_back ( c );
_changed();
}
void CXspFile::AddWeaponMask ( int game, int mask )
{
// first check if we have one for the game
SWeaponMask *m = NULL;
for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
{
if ( node->Data()->iGame == game )
{
m = node->Data();
break;
}
}
// not found, create one
if ( !m )
{
m = new SWeaponMask;
m_lWeaponMasks.push_back(m);
m->iGame = game;
}
m->iMask = mask;
_changed();
}
void CXspFile::AddMissileMask ( int game, int mask )
{
// first check if we have one for the game
SWeaponMask *m = NULL;
for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
{
if ( node->Data()->iGame == game )
{
m = node->Data();
break;
}
}
// not found, create one
if ( !m )
{
m = new SWeaponMask;
m_lMissileMasks.push_back(m);
m->iGame = game;
}
m->iMask = mask;
_changed();
}
bool CXspFile::IsValid ()
{
if ( this->name().empty() )
return false;
if ( this->author().empty() )
return false;
return true;
}
Utils::WString CXspFile::createValuesLine() const
{
Utils::WString values = CBaseFile::createValuesLine ();
values += L"Data: " + m_sData + L"\n";
values += L"ID: " + m_sID + L"\n";
if ( m_bLanguageText )
values += L"LanguageText\n";
if ( m_bExistingShip )
values += L"ExistingShip\n";
values += Utils::WString(L"OrgDesc: ") + (long)m_iOrgDesc + L"\n";
values += Utils::WString(L"Shipyard: ") + Utils::WString::Number(_iShipyard) + L"\n";
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() ) {
SCockpit *cockpit = node->Data();
values += Utils::WString(L"CockpitNew: ") + (long)cockpit->lWeaponMask.size();
for ( CListNode<SWeaponMask> *wNode = cockpit->lWeaponMask.Front(); wNode; wNode = wNode->next() ) {
values += L":";
values += (long)wNode->Data()->iGame;
values += L":";
values += (long)wNode->Data()->iMask;
}
values += L" ";
values += cockpit->sCockpit + L"\n";
}
for ( CListNode<SText> *tNode = m_lText.Front(); tNode; tNode = tNode->next() )
values += Utils::WString(L"Text: ") + (long)tNode->Data()->iId + L"|" + tNode->Data()->sName.findReplace(L"|", L"<::PiPe::>") + L"|" + tNode->Data()->sDesc + L"\n";
for ( CListNode<SComponent> *cNode = m_lComponent.Front(); cNode; cNode = cNode->next() )
values += L"Component: " + cNode->Data()->sData.findReplace(L"|", L"<::PiPe::>") + L"|" + cNode->Data()->sSection.findReplace(L"|", L"<::PiPe::>") + L"|" + cNode->Data()->sSection2 + L"\n";
for ( CListNode<SDummy> *dNode = m_lDummy.Front(); dNode; dNode = dNode->next() )
values += L"Dummy: " + dNode->Data()->sData.findReplace(L"|", L"<::PiPe::>") + L"|" + dNode->Data()->sSection + L"\n";
for ( CListNode<SWeaponMask> *wNode = m_lWeaponMasks.Front(); wNode; wNode = wNode->next() )
values += Utils::WString(L"WeaponMask: ") + (long)wNode->Data()->iGame + L" " + (long)wNode->Data()->iMask + L"\n";
for ( CListNode<SWeaponMask> *mNode = m_lMissileMasks.Front(); mNode; mNode = mNode->next() )
values += Utils::WString(L"MissileMask: ") + (long)mNode->Data()->iGame + L" " + (long)mNode->Data()->iMask + L"\n";
for (auto itr = _lCutData.begin(); itr != _lCutData.end(); itr++)
values += L"CutData: " + (*itr)->str + L"\n";
for (auto itr = _lBodies.begin(); itr != _lBodies.end(); itr++)
values += L"Bodies: " + (*itr)->str + L"\n";
for (auto itr = _lAnimations.begin(); itr != _lAnimations.end(); itr++)
values += L"Animations: " + (*itr)->str + L"\n";
return values;
}
bool CXspFile::parseValueLine(const Utils::WString &sLine)
{
Utils::WString first = sLine.token(L":", 1);
Utils::WString rest = sLine.tokens(L":", 2).removeFirstSpace();
if ( first.Compare(L"Data") )
m_sData = rest;
else if ( first.Compare(L"ID") )
m_sID = rest;
else if ( sLine.Compare(L"LanguageText") )
m_bLanguageText = true;
else if ( sLine.Compare(L"ExistingShip") )
m_bExistingShip = true;
else if ( first.Compare(L"OrgDesc") || first.Compare(L"OriginalDesc") )
m_iOrgDesc = rest;
else if ( first.Compare(L"Shipyard") )
_iShipyard = rest.toLong();
else if ( first.Compare(L"CutData") )
this->addCutData(rest);
else if ( first.Compare(L"Bodies") )
this->addBodies(rest);
else if ( first.Compare(L"Animations") )
this->addAnimation(rest);
else if ( first.Compare(L"Cockpit") )
this->addCockpit(rest, 0);
else if ( first.Compare(L"CockpitNew") )
{
Utils::WString cockpit = rest.tokens(L" ", 2);
Utils::WString sMasks = rest.token(L" ", 1);
this->addCockpit(cockpit, 0, -1);
int num = sMasks.token(L":", 1);
for ( int i = 0; i < num; i++ )
{
int mask = sMasks.token(L":", ((i + 1) * 2) + 1);
int game = sMasks.token(L":", ((i + 1) * 2));
this->addCockpit(cockpit, game, mask);
}
}
else if ( first == L"Web" ) this->setWebSite(rest);
else if ( first.Compare(L"WeaponMask") )
this->AddWeaponMask(rest.token(L" ", 1), rest.token(L" ", 2));
else if ( first.Compare(L"MissileMask") )
this->AddMissileMask(rest.token(L" ", 1), rest.token(L" ", 2));
else if ( first == L"Text" )
{
SText *text = new SText;
text->iId = rest.token(L"|", 1);
text->sName = rest.token(L"|", 2);
text->sName = text->sName.findReplace(L"<::PiPe::>", L"|");
text->sDesc = rest.tokens(L"|", 3);
m_lText.push_back ( text );
}
else if ( first == L"Component" )
{
SComponent *c = new SComponent;
c->sData = rest.token(L"|", 1);
c->sData = c->sData.findReplace (L"<::PiPe::>", L"|");
c->sSection = rest.token(L"|", 2);
c->sSection = c->sSection.findReplace (L"<::PiPe::>", L"|");
c->sSection2 = rest.tokens(L"|", 3);
m_lComponent.push_back ( c );
}
else if ( first == L"Dummy" )
{
SDummy *d = new SDummy;
d->sData = rest.token(L"|", 1);
d->sData = d->sData.findReplace (L"<::PiPe::>", L"|");
d->sSection = rest.tokens(L"|", 2);
m_lDummy.push_back ( d );
}
else if ( first == L"Comment" ) this->setDescription(rest.findReplace(L"<newline>", L"<br>"));
else
return CBaseFile::parseValueLine(sLine);
return true;
}
Utils::WString CXspFile::shipName(int lang)
{
Utils::WString name;
if ( (m_bLanguageText) && (lang) )
{
for ( SText *text = m_lText.First(); text; text = m_lText.Next() )
{
if ( text->iId == lang )
{
name = text->sName;
break;
}
}
}
if ( name.empty() )
name = this->name(lang);
return name;
}
//TODO: split this up
bool CXspFile::convertOld(const Utils::WString &file)
{
// open the file
FILE *id = _wfopen(file.c_str(), L"rb");
if ( !id )
return false;
// read to memory
fseek(id, 0, SEEK_END);
size_t size = ftell(id);
fseek(id, 0, SEEK_SET);
unsigned char *data = new unsigned char[size + 1];
fread(data, sizeof(unsigned char), size, id);
data[size] = '\0';
fclose(id);
// uncompress the file
size_t len;
unsigned char *compr = LZMADecode_C ( data, size, &len, NULL );
delete[] data;
if ( !compr )
return false;
this->Delete();
this->SetDefaults();
// now read the data line by line
size_t pos = 0;
size_t start = 0;
int packageVersion = 0;
while ( pos < len )
{
while ( compr[pos++] != '\n' && pos < len );
compr[pos - 1] = '\0';
Utils::WString line = Utils::WString::FromString((char *)(compr + start));
start = pos;
if ( line.empty() )
continue;
Utils::WString first = line.token(L":", 1);
Utils::WString rest = line.tokens(L":", 2);
rest = rest.removeFirstSpace();
// now check each line
if ( first.Compare(L"Packager") )
packageVersion = rest;
else if ( first.Compare(L"Shipyard") )
{
std::vector<Utils::WString> strs;
if(rest.tokenise(L";", strs))
{
int cur = 1;
for (size_t i = 0; i < strs.size(); i++, cur *= 2 )
{
if ( strs[i] == L"1" )
this->addShipyard(static_cast<ShipyardRace>(cur));
}
}
}
else if ( first.Compare(L"ScreenShot") )
{
int size = rest.token(L" ", 1);
Utils::WString ext = rest.token(L" ", 2);
C_File *newFile = this->addFile(m_sID + L"_" + (long)(this->countFiles(FILETYPE_SCREEN) + 1) + L"." + ext, L"", FILETYPE_SCREEN);
newFile->ReadFromData((char *)(compr + pos), size);
start += (size + 1);
}
else if ( first.Compare(L"SceneFile") )
{
Utils::WString file = rest.tokens(L" ", 3);
m_pSceneFile = this->addFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_SHIPSCENE);
m_pSceneFile->SetCreationTime((long)rest.token(L" ", 1));
m_pSceneFile->ReadFromData((char *)(compr + pos), rest.token(L" ", 2));
start += m_pSceneFile->GetDataSize();
}
else if ( first.Compare(L"CockpitFile") )
{
Utils::WString file = rest.tokens(L" ", 3);
m_pCockpitFile = this->addFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_COCKPITSCENE);
m_pCockpitFile->SetCreationTime((long)rest.token(L" ", 1));
m_pCockpitFile->ReadFromData((char *)(compr + pos), rest.token(L" ", 2));
start += m_pCockpitFile->GetDataSize();
}
else if ( first.Compare(L"Model") )
{
Utils::WString file = rest.tokens(L" ", 3);
C_File *newFile= this->addFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_SHIPMODEL);
newFile->SetCreationTime((long)rest.token(L" ", 1));
newFile->ReadFromData((char *)(compr + pos), rest.token(L" ", 2));
start += (newFile->GetDataSize() + 1);
}
else if ( first.Compare(L"Files") )
{
Utils::WString file = rest.tokens(L" ", 3);
C_File *newFile = NULL;
int special = 0;
if ( file.Compare(L"types/CutData.txt") || file.Compare(L"types/CutData.pck") )
{
newFile = new C_File(file);
special = 1;
}
else if ( file.Compare(L"types/Bodies.txt") || file.Compare(L"types/Bodies.pck") )
{
newFile = new C_File(file);
special = 2;
}
else if ( file.Compare(L"types/Animations.txt") || file.Compare(L"types/Animations.pck") )
{
newFile = new C_File(file);
special = 3;
}
else
{
newFile = this->addFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_SHIPOTHER);
newFile->SetCreationTime((long)rest.token(L" ", 1));
}
newFile->ReadFromData((char *)(compr + pos), rest.token(L" ", 2));
start += (newFile->GetDataSize() + 1);
if ( special )
{
if (newFile->checkFileExt(L"pck"))
newFile->UnPCKFile();
// read data into lines
Utils::WString data = Utils::WString::FromString((const char *)newFile->GetData());
data.removeChar('\r');
std::vector<Utils::WString> sLines;
if(data.tokenise(L"\n", sLines))
{
// cut data
size_t entries = -1;
if ( special == 1 )
{
Utils::WStringList newLines;
for (size_t i = 0; i < sLines.size(); i++)
{
Utils::WString line = sLines[i];
line.removeChar(' ');
line.removeChar(9);
if ( line.empty() || line[0] == '/' )
continue;
if ( entries == -1 )
{
entries = line.token(L";", 1).toInt() - 36;
if ( entries <= 0 )
break;
}
else
{
int id = line.token(L";", 1).toInt();
if ( id >= 9000 && id <= 9017 )
continue;
switch (id)
{
case 948:
case 4111:
case 4112:
case 4064:
case 4169:
case 4178:
case 4177:
case 4163:
case 4194:
case 4162:
case 4191:
case 4200:
case 4161:
case 4097:
case 4205:
case 4206:
case 4207:
case 4107:
break;
default:
newLines.pushBack(line);
}
if ( newLines.size() == entries )
break;
}
}
for(auto itr = newLines.begin(); itr != newLines.end(); itr++)
this->addCutData((*itr)->str);
}
// bodies
else if ( special == 2 )
{
entries = 0;
Utils::WString section;
for (size_t i = 0; i < sLines.size(); i++ )
{
Utils::WString line = sLines[i];
line.removeChar(' ');
line.removeChar(9);
if ( line.empty() || line[0] == '/' )
continue;
if ( entries <= 0)
{
section = line.token(L";", 1);
entries = line.token(L";", 2).toInt();
}
else
{
if ( !line.isin(L";") )
continue;
if ( line.countToken(L";") <= 2 )
{
this->addBodies(section + ";" + line.token(L";", 1) + L";");
--entries;
}
else
{
bool done = false;
while (!done)
{
std::vector<Utils::WString> strs;
done = true;
line.tokenise(L";", strs);
for (size_t j = 0; j < strs.size(); j++)
{
if ( !entries )
{
line = line.tokens(L";", static_cast<int>(j + 1));
if ( !line.empty() )
done = false;
break;
}
if ( strs[j].empty() )
continue;
this->addBodies(section + L";" + strs[j] + L";");
--entries;
}
//we must be at another section
if ( !done )
{
section = line.token(L";", 1);
entries = line.token(L";", 2).toInt();
line = line.remToken(L";", 1);
line = line.remToken(L";", 1);
if (line.empty())
done = true;
}
}
}
}
}
}
// animations
else if ( special == 3 )
{
Utils::WStringList in;
for (size_t i = 0; i < sLines.size(); i++)
in.pushBack(sLines[i]);
Utils::WStringList out;
if ( CXspFile::ReadAnimations(in, out, 87) )
this->addAnimation(out);
}
}
delete newFile;
}
}
else if ( first.Compare(L"Script") )
{
Utils::WString file = rest.words(3);
C_File *newFile= this->addFile(file, Utils::WString::Null(), FILETYPE_SCRIPT);
newFile->SetCreationTime((long)rest.word(1));
newFile->ReadFromData((char *)(compr + pos), rest.word(2));
start += (newFile->GetDataSize() + 1);
}
else if ( first.Compare(L"Text") )
this->addText(rest.token(L":", 1), rest.token(L":", 2), rest.tokens(L":", 3));
else if ( first.Compare(L"Component") )
this->addComponent(rest.token(L";", 1), rest.token(L";", 2), rest.tokens(L";", 3));
else if ( first.Compare(L"Dummy") )
{
SDummy *d = new SDummy;
d->sData = rest.tokens(L";", 2);
d->sSection = rest.token(L";", 1);
m_lDummy.push_back ( d );
}
else if ( !this->parseValueLine(line) )
{
// printf ( "Command: %s, Rest: %s\n", first.c_str(), rest.c_str());
}
pos = start;
}
// assume all old ones are for X3
if ( !m_sData.empty() )
{
this->AddWeaponMask(GAME_X3 - 1, m_sData.token(L";", 19));
this->AddMissileMask(GAME_X3 - 1, m_sData.token(L";", 25));
}
return true;
}
unsigned long GetMaxShipyards() { return static_cast<unsigned long>(ShipyardRace::Max); }
Utils::WString GetShipyardName (ShipyardRace s)
{
switch (s)
{
case ShipyardRace::Argon:
return L"Argon";
case ShipyardRace::Boron:
return L"Boron";
case ShipyardRace::Paranid:
return L"Paranid";
case ShipyardRace::Split:
return L"Split";
case ShipyardRace::Teladi:
return L"Teladi";
case ShipyardRace::Pirates:
return L"Pirates";
case ShipyardRace::Friend:
return L"Friendly";
case ShipyardRace::Xenon:
return L"Xenon";
case ShipyardRace::Terran:
return L"Terran";
case ShipyardRace::ATF:
return L"ATF";
case ShipyardRace::Goner:
return L"Goner";
case ShipyardRace::Yaki:
return L"Yaki";
case ShipyardRace::None:
return L"";
}
return L"Unknown";
}
bool CXspFile::writeHeader(CFileIO &file, int valueheader, int valueComprLen) const
{
return file.write("XSPCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen);
}
bool CXspFile::_checkHeader(const Utils::WString &header) const
{
if ( header.Compare(L"XSPCycrow") )
return true;
return false;
}
void CXspFile::SetLaserMask(int game, int mask)
{
for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
{
SWeaponMask *m = node->Data();
if ( m->iGame == game )
{
m->iMask = mask;
return;
}
}
// no found, need to add it
this->AddWeaponMask(game, mask);
}
void CXspFile::SetMissileMask(int game, int mask)
{
for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
{
SWeaponMask *m = node->Data();
if ( m->iGame == game )
{
m->iMask = mask;
return;
}
}
// no found, need to add it
this->AddMissileMask(game, mask);
}
int CXspFile::GetLaserMask(int game, bool getOnly)
{
int mask = -1;
for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
{
SWeaponMask *m = node->Data();
if ( m->iGame == game )
return m->iMask;
if ( !mask && !getOnly )
mask = m->iMask;
}
return mask;
}
int CXspFile::GetMissileMask(int game, bool getOnly)
{
int mask = -1;
for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
{
SWeaponMask *m = node->Data();
if ( m->iGame == game )
return m->iMask;
if ( !mask && !getOnly )
mask = m->iMask;
}
return mask;
}
void CXspFile::clearCutData()
{
_lCutData.clear();
}
void CXspFile::clearAnimations()
{
_lAnimations.clear();
}
void CXspFile::clearBodies()
{
_lBodies.clear();
}
Utils::WString CXspFile::shipClass() const
{
if ( !m_sData.empty() )
return m_sData.token(L";", TSHIPPOS_CLASS);
return L"OBJ_SHIP_M5";
}
bool CXspFile::GeneratePackagerScript(bool wildcard, Utils::WStringList *list, int game, const Utils::WStringList &gameAddons, bool datafile)
{
if ( !CBaseFile::GeneratePackagerScript(wildcard, list, game, gameAddons, datafile) )
return false;
list->pushBack(L"# File Type, Script or Ship");
list->pushBack(L"FileType: Ship");
list->pushBack(L"");
if (_iShipyard)
{
list->pushBack(L"# Shipyards, Set which shipyards to add ships for sale to");
for (unsigned long i = 0; i <= GetMaxShipyards(); i *= 2 )
{
if ( this->isShipyard(static_cast<ShipyardRace>(i)) )
list->pushBack(L"Shipyard: " + GetShipyardName(static_cast<ShipyardRace>(i)));
}
list->pushBack(L"");
}
if ( m_iOrgDesc > 0 )
{
list->pushBack(L"# Use Original Description, overrides text entrys to use one of the built in text");
list->pushBack(Utils::WString(L"OriginalDescription: ") + (long)m_iOrgDesc);
list->pushBack(L"");
}
if ( !m_sID.empty() )
{
list->pushBack(L"# Ship ID, the ship id to identify the ship as");
list->pushBack(L"ShipID: " + m_sID);
}
if ( m_bExistingShip )
{
list->pushBack(L"# Existing Ship, replaces an existing ship in the game with ship package instead of creating a new entry");
list->pushBack(L"ExistingShip");
list->pushBack(L"");
}
if ( !m_sData.empty() )
{
list->pushBack(L"# Ship Data, the TShip data entry to add to the game (parts of this are adjusted and auto generated by the installer)");
list->pushBack(L"ShipData: " + m_sData);
list->pushBack(L"");
}
if ( m_lText.size() ) {
list->pushBack(L"# Ship Texts, the name/description of the ship in each language: <LANGID> <NAME>|<DESCRIPTION>");
for(CListNode<SText> *node = m_lText.Front(); node; node = node->next()) {
list->pushBack(Utils::WString(L"ShipText: ") + (long)node->Data()->iId + L" " + node->Data()->sName + L"|" + node->Data()->sDesc);
}
list->pushBack(L"");
}
if ( this->m_lWeaponMasks.size() ) {
list->pushBack(L"# Weapon Masks, the weapons for each game: <GAME> <MASK>");
for(CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next()) {
list->pushBack(Utils::WString(L"WeaponMask: ") + (long)node->Data()->iGame + L" " + (long)node->Data()->iMask);
}
list->pushBack(L"");
}
if ( this->m_lMissileMasks.size() ) {
list->pushBack(L"# Missile Masks, the missiles for each game: <GAME> <MASK>");
for(CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next()) {
list->pushBack(Utils::WString(L"WeaponMask: ") + (long)node->Data()->iGame + L" " + (long)node->Data()->iMask);
}
list->pushBack(L"");
}
if ( this->m_lComponent.size() ) {
list->pushBack(L"# Ship Components, each component used in the ships scene: <SECTION> <MODELENTRY> <VALUES>");
for(CListNode<SComponent> *node = m_lComponent.Front(); node; node = node->next()) {
list->pushBack(Utils::WString(L"Component: ") + node->Data()->sSection + L" " + node->Data()->sSection2 + L" " + node->Data()->sData);
}
list->pushBack(L"");
}
if ( this->m_lDummy.size() ) {
list->pushBack(L"# Ship Dummies, each dummy entry used in the ships scene: <SECTION> <VALUE>");
for(CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next()) {
list->pushBack(L"Dummy: " + node->Data()->sSection + L" " + node->Data()->sData);
}
list->pushBack(L"");
}
if ( this->m_lCockpit.size() ) {
list->pushBack(L"# Cockpit entries, each cockpit value with thier weapons mask");
for(CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next()) {
list->pushBack(L"Cockpit: " + node->Data()->sCockpit.token(L";", 19) + L" " + node->Data()->sCockpit);
for(SWeaponMask *mask = node->Data()->lWeaponMask.First(); mask; mask = node->Data()->lWeaponMask.Next()) {
list->pushBack(L"CockpitWeapon: " + node->Data()->sCockpit.token(L";", 19) + L" " + (long)mask->iGame + L" " + (long)mask->iMask);
}
}
list->pushBack(L"");
}
if (!this->_lCutData.empty())
{
list->pushBack(L"# Ship Cut Data");
for(auto itr = _lCutData.begin(); itr != _lCutData.end(); itr++)
list->pushBack(L"CutData: " + (*itr)->str);
list->pushBack(L"");
}
if (!this->_lBodies.empty())
{
list->pushBack(L"# Ship Bodies");
for(auto itr = _lBodies.begin(); itr != _lBodies.end(); itr++)
list->pushBack(L"Bodies: " + (*itr)->str);
list->pushBack(L"");
}
if (!this->_lAnimations.empty())
{
list->pushBack(L"# Ship Animations");
for (auto itr = _lAnimations.begin(); itr != _lAnimations.end(); itr++)
list->pushBack(L"Animation: " + (*itr)->str);
list->pushBack(L"");
}
if ( !datafile )
{
if ( !CBaseFile::GeneratePackagerScriptFile(wildcard, list, game, gameAddons) )
return false;
}
return true;
}
void CXspFile::_addSection(Utils::CList<STypesSection> &list, const Utils::WString §ion, const Utils::WString &data)
{
STypesSection *currentSubSection = NULL;
for(Utils::CList<STypesSection>::iterator itr = list.begin(); itr != list.end(); itr++) {
if ( (*itr)->sSection.Compare(section) ) {
currentSubSection = *itr;
break;
}
}
if ( !currentSubSection ) {
currentSubSection = new STypesSection;
currentSubSection->sSection = section;
list.push_back(currentSubSection);
}
currentSubSection->lEntries.pushBack(data, L"");
}
void CXspFile::_addDataSection(Utils::WStringList& list, Utils::CList<STypesSection>& sectionList, bool bUseFirst)
{
for(auto itr = list.begin(); itr != list.end(); itr++)
{
if (bUseFirst) {
Utils::WString data = (*itr)->str;
_addSection(sectionList, data.token(L";", 1), data.tokens(L";", 2));
}
else {
_addSection(sectionList, (*itr)->str, (*itr)->data);
}
}
}
void CXspFile::addDummiesToList(Utils::CList<STypesSection> &list)
{
ADDSECTIONLIST(SDummy, m_lDummy);
}
void CXspFile::addComponentsToList(CLinkList<SComponentEntry> &componentList)
{
for(CListNode<SComponent> *node = m_lComponent.Front(); node; node = node->next()) {
SComponentEntry *currentSection = NULL;
for(CListNode<SComponentEntry> *cNode = componentList.Front(); cNode; cNode = cNode->next()) {
if ( cNode->Data()->sSection.Compare(node->Data()->sSection) ) {
currentSection = cNode->Data();
break;
}
}
if ( !currentSection ) {
currentSection = new SComponentEntry();
currentSection->sSection = node->Data()->sSection;
componentList.push_back(currentSection);
}
_addSection(currentSection->lEntries, node->Data()->sSection2, node->Data()->sData);
}
}
void CXspFile::addCutDataToList(Utils::CList<STypesSection> &list)
{
_addDataSection(this->_lCutData, list, false);
}
void CXspFile::addBodiesToList(Utils::CList<STypesSection> &list)
{
_addDataSection(this->_lBodies, list, true);
}
void CXspFile::addAnimationsToList(Utils::CList<STypesSection> &list)
{
_addDataSection(this->_lAnimations, list, false);
}
void CXspFile::addGeneratedFiles(HZIP &hz)
{
CFileIO tmpFile(CPackages::tempDirectory() + L"/temp.tmp");
for(int i = 0; i < 5; i++) {
Utils::WString type;
Utils::WString data;
switch(i) {
case 0:
data = L"50;1\r\n" + this->m_sData;
type = L"TShips";
break;
case 1:
if ( !this->m_lCockpit.empty() ) {
data = Utils::WString("51;") + (long)this->m_lCockpit.size() + L";\r\n";
for(CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next()) {
data += node->Data()->sCockpit + L"\r\n";
}
type = L"TCockpits";
}
break;
case 2:
if ( !this->m_lComponent.empty() ) {
type = L"Components";
CLinkList<SComponentEntry> componentList;
this->addComponentsToList(componentList);
for(CListNode<SComponentEntry> *node = componentList.Front(); node; node = node->next()) {
data += node->Data()->sSection + L"; " + (long)node->Data()->lEntries.size() + L";\r\n";
data += CXspFile::TypesListToString(node->Data()->lEntries, true);
}
}
break;
case 3:
GENERATESECTION(L"Dummies", SDummy, this->m_lDummy);
break;
case 4:
GENERATESTRINGSECTION(L"Bodies", this->_lBodies, true);
break;
}
if ( type.empty() ) continue;
Utils::WString fname = L"GENERATED/types/" + type + L".txt";
Utils::WString fileData = L"// Exported " + type + L" file, Generated by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2) + L"\r\n" + data;
/*
if ( tmpFile.startWrite() ) {
tmpFile.write(fileData.c_str(), fileData.length());
tmpFile.close();
}
// tships files
wsprintf(buf, L"%hs", fname.c_str());
if ( tmpFile.startRead() ) {
*/
ZipAdd(hz, fname.c_str(), (void *)fileData.c_str(), static_cast<unsigned int>(fileData.length() * sizeof(wchar_t)));
//}
}
}
bool CXspFile::loadPackageData(const Utils::WString &sFirst, const Utils::WString &sRest, const Utils::WString &sMainGame, Utils::WStringList &otherGames, Utils::WStringList &gameAddons, CProgressInfo *progress)
{
if ( sFirst.Compare(L"Shipyard") )
{
for (unsigned long i = 0; i <= GetMaxShipyards(); i *= 2)
{
if(sRest.Compare(GetShipyardName(static_cast<ShipyardRace>(i))))
{
this->addShipyard(static_cast<ShipyardRace>(i));
break;
}
}
}
else if ( sFirst.Compare(L"OriginalDescription") )
m_iOrgDesc = sRest;
else if ( sFirst.Compare(L"ShipData") )
m_sData = sRest;
else if ( sFirst.Compare(L"ReadData") ) // read data from a tships file
{
CPackages p;
m_sData = p.readShipData(sRest.tokens(L" ", 2), sRest.token(L" ", 1));
}
else if ( sFirst.Compare(L"ExistingShip") )
m_bExistingShip = true;
else if ( sFirst.Compare(L"ShipID") )
m_sID = sRest;
else if ( sFirst.Compare(L"ShipText") )
this->addText(sRest.token(L" ", 1).toLong(), sRest.tokens(L" ", 2).token(L"|", 1), sRest.tokens(L" ", 2).tokens(L"|", 2));
else if ( sFirst.Compare(L"Component") )
this->addComponent(sRest.token(L" ", 1), sRest.token(L" ", 2), sRest.tokens(L" ", 3));
else if ( sFirst.Compare(L"Cockpit") )
this->addCockpit(sRest.tokens(L" ", 2).replaceToken(L";", 19, sRest.token(L" ", 1)), 0);
else if ( sFirst.Compare(L"CockpitWeapon") )
this->addCockpitWeapon(sRest.token(L" ", 1), sRest.token(L" ", 2), sRest.token(L" ", 3));
else if ( sFirst.Compare(L"WeaponMask") )
this->AddWeaponMask(sRest.token(L" ", 1), sRest.token(L" ", 2));
else if ( sFirst.Compare(L"MissileMask") )
this->AddMissileMask(sRest.token(L" ", 1), sRest.token(L" ", 2));
else if ( sFirst.Compare(L"Dummy") )
this->addDummy(sRest.token(L" ", 1), sRest.token(L" ", 2));
else if ( sFirst.Compare(L"CutData") )
this->addCutData(sRest);
else if ( sFirst.Compare(L"Animation") )
this->addAnimation(sRest);
else if ( sFirst.Compare(L"Bodies") )
this->addBodies(sRest);
else if ( !CBaseFile::loadPackageData(sFirst, sRest, sMainGame, otherGames, gameAddons, progress) )
{
return false;
}
return true;
}
Utils::WString CXspFile::getX3ShipData() const
{
Utils::WString data = m_sData;
// change the ship subtype, Reunion uses number, TC uses a define
Utils::WString sSubType = data.token(L";", 6);
if ( !((long)sSubType) && sSubType != L"0" )
data = data.replaceToken(L";", 6, (long)CShipData::ConvertShipSubType(sSubType));
Utils::WString sClass = data.token(L";", TSHIPPOS_CLASS);
if ( !((long)sClass) && sClass != L"0" )
{
int num = 0;
for ( int i = 0; i < OBJ_SHIP_MAX; i++ )
{
if ( sClass.Compare(CShipData::ConvertShipClass(CShipData::GetShipClassFromNum(i))) )
{
num = i;
break;
}
}
data = data.replaceToken(L";", TSHIPPOS_CLASS, (long)num);
}
return data;
}
Utils::WString CXspFile::getTCShipData() const
{
Utils::WString data = m_sData;
Utils::WString sSubType = data.token(L";", 6);
if ( ((long)sSubType) || sSubType == L"0" )
data = data.replaceToken(L";", 6, CShipData::ConvertShipSubType((long)sSubType));
Utils::WString sClass = data.token(L";", TSHIPPOS_CLASS);
if ( ((long)sClass) || sClass == L"0" )
data = data.replaceToken(L";", TSHIPPOS_CLASS, CShipData::ConvertShipClass((long)sClass));
return data;
}
bool CXspFile::removeCockpit(const Utils::WString &sCockpitId)
{
Utils::WString cockpitid = sCockpitId;
// if its a whole line, just get the end
if ( cockpitid.contains(L";") )
{
cockpitid = cockpitid.tokens(L";", -2);
while ( cockpitid.right(1) == L";" )
cockpitid.truncate(-1);
}
bool ret = false;
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
Utils::WString id = node->Data()->sCockpit.token(L";", 19);
if ( id.Compare(cockpitid) )
{
node->DeleteData();
ret = true;
break;
}
}
m_lCockpit.RemoveEmpty();
return ret;
}
bool CXspFile::removeComponent(const Utils::WString §ion1, const Utils::WString §ion2, const Utils::WString &data)
{
bool ret = false;
for ( CListNode<SComponent> *node = m_lComponent.Front(); node; node = node->next() )
{
if ( node->Data()->sSection.Compare(section1) && node->Data()->sSection2.Compare(section2) && node->Data()->sData.Compare(data) )
{
ret = true;
node->DeleteData();
break;
}
}
m_lComponent.RemoveEmpty();
return ret;
}
bool CXspFile::removeDummy(const Utils::WString §ion, const Utils::WString &data)
{
bool ret = false;
for ( CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next() )
{
if ( node->Data()->sSection.Compare(section) && node->Data()->sData.Compare(data) )
{
ret = true;
node->DeleteData();
break;
}
}
m_lDummy.RemoveEmpty();
return ret;
}
Utils::WString CXspFile::getCockpitData(const Utils::WString &cid)
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
Utils::WString id = node->Data()->sCockpit.token(L";", 19);
if ( id.Compare(cid) )
return node->Data()->sCockpit;
}
return L"";
}
SCockpit *CXspFile::findCockpit(const Utils::WString &cid)
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
Utils::WString id = node->Data()->sCockpit.token(L";", 19);
if ( id.Compare(cid) )
return node->Data();
}
return nullptr;
}
void CXspFile::editCockpit(const Utils::WString &cid, const Utils::WString &cockpit)
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
Utils::WString id = node->Data()->sCockpit.token(L";", 19);
if ( id.Compare(cid) )
{
node->Data()->sCockpit = cockpit;
break;
}
}
}
void CXspFile::editCockpit(const Utils::WString &cid, const Utils::WString &scene, int mask)
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
Utils::WString id = node->Data()->sCockpit.token(L";", 19);
if ( id.Compare(cid) )
{
Utils::WString cockpit = node->Data()->sCockpit;
cockpit = cockpit.replaceToken(L";", 8, scene);
cockpit = cockpit.replaceToken(L";", 9, (long)mask);
node->Data()->sCockpit = cockpit;
break;
}
}
}
void CXspFile::newCockpit(const Utils::WString &id, const Utils::WString &scene, int mask)
{
Utils::WString cockpit = L"0;0;0;0;0;0;0;";
cockpit += scene + L";";
cockpit += (long)mask;
cockpit += L";0;0;0;0;0;0;-100000;0;0;";
cockpit += id + L";";
this->addCockpit(cockpit, -1);
}
bool CXspFile::removeCutData(const Utils::WString &cut)
{
bool ret = false;
for(size_t i = 0; i < _lCutData.size(); i++)
{
Utils::WString str = _lCutData[i]->str;
if (str.token(L";", 1).Compare(cut.token(L";", 1)))
{
ret = true;
_lCutData.remove(str);
break;
}
}
return ret;
}
bool CXspFile::removeBodies(const Utils::WString &cut)
{
bool ret = false;
for (auto itr = _lBodies.begin(); itr != _lBodies.end(); itr++)
{
if ((*itr)->str.remove(' ').Compare(cut.remove(' ')))
{
_lBodies.remove(itr);
return true;
}
}
return false;
}
bool CXspFile::removeAnimation(const Utils::WString &cut)
{
for(auto itr = _lAnimations.begin(); itr != _lAnimations.end(); itr++)
{
if ((*itr)->str.remove(' ').remove('\n').Compare(cut.remove(' ').remove('\n')))
{
_lAnimations.remove(itr);
return true;
}
}
return false;
}
SCockpit *CXspFile::_findCockpit(const Utils::WString &sID)
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() ) {
Utils::WString id = node->Data()->sCockpit.token(L";", 19);
if ( id.Compare(sID) )
return node->Data();
}
return NULL;
}
void CXspFile::addCockpitWeapon(const Utils::WString &cockpit, int game, int mask)
{
SCockpit *pCockpit = _findCockpit(cockpit);
// search if the game mask already exists
SWeaponMask *wm = NULL;
for ( CListNode<SWeaponMask> *node = pCockpit->lWeaponMask.Front(); node; node = node->next() )
{
if ( node->Data()->iGame == game )
{
wm = node->Data();
break;
}
}
if ( !wm )
{
wm = new SWeaponMask;
pCockpit->lWeaponMask.push_back(wm);
}
wm->iGame = game;
if ( mask == -1 )
wm->iMask = pCockpit->sCockpit.token(L";", 9);
else
wm->iMask = mask;
_changed();
}
void CXspFile::addCockpit(const Utils::WString &cockpit, int game, int mask, int index)
{
Utils::WString cid = cockpit.token(L";", 19);
SCockpit *pCockpit = _findCockpit(cid);
if ( !pCockpit )
{
pCockpit = new SCockpit;
pCockpit->sCockpit = cockpit;
pCockpit->iIndex = index;
m_lCockpit.push_back(pCockpit);
}
if ( index != -1 )
pCockpit->iIndex = index;
// now add the game mask
if ( game > 0 )
addCockpitWeapon(cid, game, mask);
_changed();
}
void CXspFile::addBody(const Utils::WString §ion, const Utils::WString &data)
{
this->addBodies(section + L";" + data);
_changed();
}
void CXspFile::addBodies(const Utils::WString &sData)
{
Utils::WString data = sData;
if ( !data.isNumber() )
{
if ( data[(int)(data.length() - 5)] == '.' )
data = data.left(-5);
else if ( data[(int)(data.length() - 4)] == '.' )
data = data.left(-4);
if ( data.right(1) != L";" )
data += L";";
}
if(!_lBodies.contains(data))
_lBodies.pushBack(data);
_changed();
}
void CXspFile::addCutData(const Utils::WString& data)
{
if (!_lCutData.contains(data))
{
_lCutData.pushBack(data);
_changed();
}
}
int CXspFile::GetAnimationType(const Utils::WString &type)
{
if ( type.Compare(L"TAT_TAGSINGLESTEP") )
return TAT_SINGLE;
else if ( type.Compare(L"TAT_TAGONESHOT")
|| type.Compare(L"TAT_TAGONESHOT_REINIT")
|| type.Compare(L"TAT_PINGPONG")
|| type.Compare(L"TAT_TAGLOOP") )
return TAT_3;
return TAT_NONE;
}
Utils::WString CXspFile::TypesListToString(Utils::CList<STypesSection> &list, bool deleteAfter)
{
Utils::WString data;
for(Utils::CList<STypesSection>::iterator itr = list.begin(); itr != list.end(); itr++) {
data += (*itr)->sSection + L"; " + (long)(*itr)->lEntries.size() + L";\r\n";
for(Utils::WStringNode *str = (*itr)->lEntries.first(); str; str = (*itr)->lEntries.next()) {
data += str->str + L"\r\n";
}
if ( deleteAfter ) {
(*itr)->lEntries.clear();
}
}
return data;
}
bool CXspFile::ReadAnimations(const Utils::WStringList &lIn, Utils::WStringList &lOut, int startRecord)
{
Utils::WString lastComment;
Utils::WString addEntry;
int remaining = 0;
Utils::WString lastType;
int newEntries = 0;
int entries = -1;
for(auto itr = lIn.begin(); itr != lIn.end(); itr++)
{
Utils::WString line = (*itr)->str;
line.removeChar('\r');
line.removeChar(9);
if ( line.empty() || line[0] == '/' )
continue;
if ( entries == -1)
{
entries = line.token(L";", 1);
newEntries = entries - startRecord;
}
else
{
// remove comments, endspaces and last ;
Utils::WString sStriped = line;
if ( sStriped.contains(L"//") )
{
if ( entries <= newEntries )
lastComment = L"//" + sStriped.tokens(L"//", 2);
sStriped = sStriped.token(L"//", 1);
}
sStriped.removeEndSpace();
if ( sStriped.right(1) == L";" )
sStriped.truncate(-1);
Utils::WString sRemainingLeft;
if ( remaining > 0 )
sRemainingLeft = sStriped;
else
{
// each line should be a new entry, with some exceptions
// potection for new lines
lastType = sStriped.token(L";", 1);
switch (CXspFile::GetAnimationType(lastType))
{
case TAT_SINGLE:
remaining = (long)sStriped.token(L";", 5) + 1;
sRemainingLeft = sStriped.tokens(L";", 6);
if ( entries <= newEntries )
addEntry = sStriped.tokens(L";", 1, 5) + L";";
break;
case TAT_3:
remaining = (long)sStriped.token(L";", 5) + 1;
sRemainingLeft = sStriped.tokens(L";", 6);
if ( entries <= newEntries )
addEntry = sStriped.tokens(L";", 1, 5) + L";";
break;
default:
remaining = 0;
if ( entries <= newEntries )
addEntry = sStriped;
}
}
if ( !sRemainingLeft.empty() )
{
int tatType = CXspFile::GetAnimationType(lastType);
if ( tatType == TAT_SINGLE )
{
if ( sRemainingLeft.isin(L";") )
remaining -= sRemainingLeft.countToken(L";");
else if ( !sRemainingLeft.empty() )
--remaining;
if ( entries <= newEntries )
addEntry += sRemainingLeft + L";";
}
else if ( tatType == TAT_3 )
{
// last entry
if ( remaining == 1 )
--remaining;
else if ( sRemainingLeft.isin(L";") )
{
if ( !sRemainingLeft.isin(L"TATF_COORDS") )
{
int amt = sRemainingLeft.countToken(L";") / 3;
remaining -= amt;
if ( remaining == 1 && (sRemainingLeft.countToken(L";") - (amt * 3)) == 1 )
--remaining;
}
else
{
int iRem = sRemainingLeft.countToken(L";");
int iPos = 1;
while ( iPos < iRem )
{
Utils::WString first = sRemainingLeft.token(L";", iPos);
if ( first.isin(L"TATF_COORDS") )
iPos += 5;
else
iPos += 3;
--remaining;
}
if ( remaining == 1 && iPos == iRem )
--remaining;
}
}
if ( entries <= newEntries )
addEntry += sRemainingLeft + L";";
}
}
if ( remaining <= 0 )
{
if ( entries <= newEntries && !addEntry.empty())
{
if ( addEntry[(int)addEntry.length() - 1] != ';' )
addEntry += L";";
lOut.pushBack(addEntry + lastComment);
}
--entries;
}
}
}
return !lOut.empty();
}
void CXspFile::addAnimation(const Utils::WStringList &list)
{
for(auto itr = list.begin(); itr != list.end(); itr++)
this->addAnimation((*itr)->str);
_changed();
}
void CXspFile::addAnimation(const Utils::WString& data)
{
if (!_lAnimations.contains(data))
{
_lAnimations.pushBack(data);
_changed();
}
}
SText *CXspFile::FindShipText(int lang)
{
if ( m_lText.empty() )
return NULL;
SText *english = NULL;
SText *german = NULL;
SText *found = NULL;
for ( CListNode<SText> *node = m_lText.Front(); node; node = node->next() )
{
SText *text = node->Data();
// matched language
if ( text->iId == lang )
return text;
else if ( text->iId == 44 )
english = text;
else if ( text->iId == 49 )
german = text;
else if ( !found )
found = text;
}
// if we've found an english version, use that
if ( english )
return english;
// otherwise try a german
if ( german )
return german;
// otherwise use any we've found (usually first one)
return found;
}
Utils::WString CXspFile::textName(int lang)
{
SText *t = FindShipText(lang);
if ( t )
{
// return the correct language text
if ( !t->sName.empty() )
return t->sName;
// we have found a text, but there is no ship name ??
else if ( lang != 44 )
{
// reget the english one
t = FindShipText(44);
if ( t && !t->sName.empty() )
return t->sName;
}
}
// still not found one, return the ships name
return this->shipName(lang);
}
Utils::WString CXspFile::textDescription(int lang)
{
SText *t = FindShipText(lang);
if ( t )
{
// return the correct language text
if ( !t->sDesc.empty() )
return t->sDesc;
// we have found a text, but there is no ship name ??
else if ( lang != 44 )
{
// reget the english one
t = FindShipText(44);
if ( t && !t->sDesc.empty() )
return t->sDesc;
}
}
// still not found one, return the ships name
if ( !this->description().empty() ) return this->description();
return this->shipName(lang);
}
bool CXspFile::startExtractShip(CVirtualFileSystem *pVfs, const Utils::WString &sId, CProgressInfo *pProgress)
{
m_sID = sId.remove('\r');
while ( m_sID.right(1) == L";" )
m_sID.truncate(-1);
m_sData = pVfs->getTShipsEntry(m_sID);
// get scene files
if ( pProgress ) pProgress->UpdateStatus(IMPORTSHIP_SCENE);
if ( !this->extractSceneFiles(pVfs) )
return false;
return true;
}
bool CXspFile::extractShip(CVirtualFileSystem *pVfs, const Utils::WString &sId, CProgressInfo *progress)
{
if ( !this->startExtractShip(pVfs, sId, progress) )
return false;
// read the scene file and get the files list
if ( !this->processSceneFiles(pVfs, progress) )
return false;
// pack all the ship files
this->PackAllFiles();
return true;
}
bool CXspFile::extractSceneFiles(CVirtualFileSystem *pVfs)
{
m_pSceneFile = pVfs->extractGameFileToPackage(this, L"objects\\" + m_sData.token(L";", 17) + L".pbd", FILETYPE_SHIPSCENE, L"objects\\" + m_sData.token(L";", 17) + L".bod");
if ( !m_pSceneFile ) return false;
m_pCockpitFile = pVfs->extractGameFileToPackage(this, L"objects\\" + m_sData.token(L";", 18) + L".pbd", FILETYPE_COCKPITSCENE, L"objects\\" + m_sData.token(L";", 18) + L".bod");
return true;
}
bool CXspFile::readSceneModels(Utils::WStringList& out)
{
// read the scene file
if (!m_pSceneFile)
m_pSceneFile = this->GetFirstFile(FILETYPE_SHIPSCENE);
if (!m_pSceneFile)
return false;
// check if its packed
size_t datasize;
unsigned char* data = m_pSceneFile->UncompressData((long*)&datasize, 0);
// if data wasn't compressed, then copy it itself as we are editing it
bool deleteData = false;
if (data == m_pSceneFile->GetData())
{
data = new unsigned char[m_pSceneFile->GetDataSize()];
memcpy(data, m_pSceneFile->GetData(), m_pSceneFile->GetDataSize());
deleteData = true;
}
if (data && datasize)
{
if (m_pSceneFile->CheckPackedExtension())
data = UnPCKData(data, datasize, &datasize);
}
if (!data || !datasize)
return false;
size_t pos = 0;
bool newline = true;
bool online = false;
while (pos < datasize)
{
char c = data[pos];
++pos;
// skip until next line
if (!newline && !online)
{
if (c == '\n')
newline = true;
continue;
}
if (newline)
{
if (c == ' ' || c == 9 || c == '\n' || c == '\r')
continue;
newline = false;
if (c == 'P' || c == 'p')
{
while (data[pos] == ' ') pos++;
unsigned char* line = (data + pos);
while (data[pos] != ' ' && data[pos] != ';') pos++;
data[pos] = '\0';
if (atoi((const char*)line) == out.size())
online = true;
}
}
// this line is out model
else if (online)
{
if (c == 'B' || c == 'b')
{
while (data[pos] == ' ') pos++;
unsigned char* line = (data + pos);
while (data[pos] != ';') pos++;
data[pos] = '\0';
out.pushBack(Utils::WString::FromString((char*)line));
online = false;
}
}
}
if (deleteData)
delete []data;
return true;
}
void CXspFile::completeFile()
{
C_File* f = GetFirstFile(FILETYPE_SHIPSCENE);
if (f)
m_pSceneFile = f;
f = GetFirstFile(FILETYPE_COCKPITSCENE);
if (f)
m_pCockpitFile = f;
}
void CXspFile::extractCutData(CVirtualFileSystem *pVfs, Utils::WStringList &sceneModels, bool add)
{
std::vector<int> cuts;
for ( CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next() )
{
Utils::WString data = node->Data()->sData;
int states = data.token(L";", 3);
for ( int i = 0; i < states; i++ )
{
int cutid = data.token(L";", (i * 2) + 5);
if ( !cutid ) continue;
cuts.push_back(cutid);
}
}
if ( cuts.empty() ) return;
if ( pVfs->extractGameFile(L"types/CutData.pck", CPackages::tempDirectory() + L"/tmp.dat").empty()) return;
CFileIO File(CPackages::tempDirectory() + L"/tmp.dat");
if ( !File.exists() ) return;
std::vector<Utils::WString> lines;
File.readLines(lines);
int count = -1;
for (auto itr = lines.begin(); itr != lines.end(); itr++)
{
Utils::WString line = *itr;
line.removeChar('\r');
line.removeChar(' ');
line.removeFirstSpace();
if ( line[0] == '/' ) continue;
if ( count == -1 ) count = line.token(L";", 1);
else
{
std::vector<Utils::WString> words;
if(line.tokenise(L";", words))
{
for (size_t i = 0; i < words.size(); i += 2) {
int cutid = words[i];
if ( !cutid ) continue;
for ( std::vector<int>::iterator itr = cuts.begin(); itr != cuts.end(); itr++ )
{
if ( (*itr) == cutid )
{
this->addCutData(words[i] + L";" + words[i + 1] + L";");
if ( add )
sceneModels.pushBack(words[i + 1]);
break;
}
}
}
}
}
}
}
void CXspFile::extractDummies(CVirtualFileSystem *pVfs, Utils::WStringList& sceneModels, bool add)
{
if (sceneModels.empty()) return;
bool extracted = false;
if ( !pVfs->extractGameFile(L"types/dummies.pck", CPackages::tempDirectory() + L"/tmp.dat").empty())
{
CFileIO File(CPackages::tempDirectory() + L"/tmp.dat");
if ( File.exists() )
{
Utils::WString section;
int secCount = 0;
std::vector<Utils::WString> lines;
if (File.readLines(lines))
{
for(auto itr = lines.begin(); itr != lines.end(); itr++)
{
Utils::WString str = itr->remove(9).remove('\r');
str.removeFirstSpace();
if (str.empty())
continue;
if (str[0] == '/')
continue;
// not in a section yet
if (secCount <= 0)
{
section = str.token(L";", 1);
secCount = str.token(L";", 2).toInt();
}
else
{
Utils::WString first = str.token(L";", 1);
if (sceneModels.contains(first))
{
this->addDummy(section, str);
if (add)
{
int pos = 4;
int scene = str.token(L";", 3).toInt();
for (int i = 0; i < scene; i++)
{
sceneModels.pushBack(str.token(L";", 5 + (i * 2)));
pos += 2;
}
int model = str.token(L";", pos).toInt();
for (int i = 0; i < model; i++)
sceneModels.pushBack(str.token(L";", pos + (i * 2) + 1));
}
}
--secCount;
}
}
}
File.remove();
}
}
}
void CXspFile::extractComponants(CVirtualFileSystem *pVfs, const Utils::WStringList& sceneModels)
{
if (sceneModels.empty()) return;
if ( !pVfs->extractGameFile(L"types/components.pck", CPackages::tempDirectory() + L"/tmp.dat").empty())
{
CFileIO File(CPackages::tempDirectory() + L"/tmp.dat");
if ( File.exists() )
{
Utils::WString file;
Utils::WString section;
int secCount = 0;
int secCount2 = 0;
std::vector<Utils::WString> lines;
if (File.readLines(lines))
{
for(auto itr = lines.begin(); itr != lines.end(); itr++)
{
Utils::WString str = itr->remove(9).remove('\r');
str.removeFirstSpace();
if (str.empty())
continue;
if (str[0] == '/')
continue;
// not in a section yet
if (secCount2)
{
if (sceneModels.contains(file))
this->addComponent(section, file, str);
--secCount2;
}
else if (secCount <= 0)
{
section = str.token(L";", 1);
secCount = str.token(L";", 2).toInt();
}
else
{
file = str.token(L";", 1);
secCount2 = str.token(L";", 2).toInt();
--secCount;
}
}
}
File.remove();
}
}
}
bool CXspFile::getTextureList(Utils::WStringList &list, const unsigned char *olddata, size_t size) const
{
if ( !olddata || !size )
return false;
size_t startLine = 0;
Utils::WString line;
size_t pos = 0;
unsigned char *data = new unsigned char[size];
memcpy(data, olddata, size);
while ( (pos++) < size )
{
if ( data[pos] == '\n' )
{
data[pos] = '\0';
line = Utils::WString::FromString((char *)(data + startLine));
line.removeChar(9);
line.removeChar('\r');
line.removeFirstSpace();
if ( !line.empty() && line[0] != '/' )
{
Utils::WString first = line.token(L":", 1);
if ( first.Compare(L"MATERIAL6") )
{
Utils::WString material = line.tokens(L":", 2);
std::vector<Utils::WString> strs;
int num = material.token(L";", 5);
if(material.tokens(L";", 6).tokenise(L"; ", strs))
{
for(size_t i = 0; i < strs.size(); i++) {
Utils::WString type = strs[i].token(L";", 1);
Utils::WString valtype = strs[i].token(L";", 2);
if ( valtype.Compare(L"SPTYPE_STRING") ) {
Utils::WString file = strs[i].token(L";", 3);
if(!list.contains(file))
list.pushBack(file, L"");
}
}
}
}
}
startLine = pos + 1;
}
}
delete [] data;
return true;
}
void CXspFile::extractTextures(CVirtualFileSystem *pVfs)
{
Utils::WStringList lTextures;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( f->GetFileType() != FILETYPE_SHIPMODEL )
continue;
bool deleteData = false;
unsigned char *data = NULL;
size_t size;
// cant do these yet
if (f->checkFileExt(L"pbb") || f->checkFileExt(L"bob"))
{
data = f->BobDecompile(&size);
if ( !data || !size ) {
// search for the pbd or bod files that match and use them instead
Utils::WString file;
file = CFileIO(f->getNameDirectory(NULL)).changeFileExtension(L"pbd");
file = pVfs->extractGameFile(file, CPackages::tempDirectory() + L"tmp.tmp");
if ( file.empty() ) {
file = CFileIO(f->getNameDirectory(NULL)).changeFileExtension(L"bod");
file = pVfs->extractGameFile(file, CPackages::tempDirectory() + L"tmp.tmp");
}
if ( !file.empty() ) {
CFileIO File(file);
if ( File.exists() ) {
data = File.readAll(&size);
File.remove();
}
}
if ( data && size )
this->getTextureList(lTextures, data, size);
continue;
}
deleteData = true;
}
if ( !data || !size ) {
if ( !f->GetData() )
{
if ( !f->ReadFromFile() )
continue;
}
if ( f->checkFileExt(L"pbb") || f->checkFileExt(L"pbd") )
data = f->UnPCKFile(&size);
else
{
data = f->GetData();
size = f->GetDataSize();
}
}
this->getTextureList(lTextures, data, size);
if ( deleteData ) delete data;
}
for(auto itr = lTextures.begin(); itr != lTextures.end(); itr++)
{
CFileIO F((*itr)->str);
if ( F.isFileExtension(L"fx") ) {
/*
if ( !pVfs->extractGameFileToPackage(this, "shader\\1_1\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
pVfs->extractGameFileToPackage(this, "shader\\1_1\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
if ( !pVfs->extractGameFileToPackage(this, "shader\\1_4\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
pVfs->extractGameFileToPackage(this, "shader\\1_4\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
if ( !pVfs->extractGameFileToPackage(this, "shader\\2_0\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
pVfs->extractGameFileToPackage(this, "shader\\2_0\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
if ( !pVfs->extractGameFileToPackage(this, "shader\\2_a\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
pVfs->extractGameFileToPackage(this, "shader\\2_a\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
if ( !pVfs->extractGameFileToPackage(this, "shader\\2_b\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
pVfs->extractGameFileToPackage(this, "shader\\2_b\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
if ( !pVfs->extractGameFileToPackage(this, "shader\\3_0\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
pVfs->extractGameFileToPackage(this, "shader\\3_0\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
*/
}
else {
if ( pVfs->extractGameFileToPackage(this, L"dds\\" + (*itr)->str, FILETYPE_SHIPOTHER) )
continue;
if ( pVfs->extractGameFileToPackage(this, L"dds\\" + (*itr)->str.token(L".", -1), FILETYPE_SHIPOTHER) )
continue;
if ( pVfs->extractGameFileToPackage(this, L"dds\\" + (*itr)->str + L".dds", FILETYPE_SHIPOTHER) )
continue;
if ( pVfs->extractGameFileToPackage(this, L"dds\\" + F.changeFileExtension(L"dds"), FILETYPE_SHIPOTHER) )
continue;
if ( pVfs->extractGameFileToPackage(this, L"textures\\" + (*itr)->str, FILETYPE_SHIPOTHER) )
continue;
if ( pVfs->extractGameFileToPackage(this, L"textures\\" + (*itr)->str.token(L".", -1), FILETYPE_SHIPOTHER) )
continue;
if ( pVfs->extractGameFileToPackage(this, L"textures\\" + (*itr)->str + L".jpg", FILETYPE_SHIPOTHER) )
continue;
if ( pVfs->extractGameFileToPackage(this, L"textures\\" + F.changeFileExtension(L"jpg"), FILETYPE_SHIPOTHER) )
continue;
}
}
}
bool CXspFile::addTextFromFile(const Utils::WString &sFile, int textId)
{
Utils::WString file = sFile;
bool remove = false;
if ( CFileIO(file).isFileExtension(L"pck") )
{
C_File F;
F.setFilename(file);
F.UnPCKFile();
if (F.writeToFile(CPackages::tempDirectory() + L"/tmp.dat"))
{
remove = true;
file = CPackages::tempDirectory() + L"/tmp.dat";
}
}
/*
std::wfstream fileStream(file.c_str());
if ( fileStream.is_open() ) {
while(!fileStream.eof()) {
std::wstring line;
std::getline(fileStream, line);
int i =0;
}
fileStream.close();
}
*/
CFileIO F(file);
if ( F.exists() && F.startRead() ) {
bool ret = this->_addTextFromFile(F, textId);
F.close();
if ( remove ) CFileIO::Remove(file);
_changed();
return ret;
}
return false;
}
bool CXspFile::importBodies(const Utils::WStringList &sceneModels, const Utils::WString &filename)
{
CFileIO File(filename);
if ( File.exists() )
{
Utils::WString sSection;
int section = 0;
std::vector<Utils::WString> lines;
if (File.readLines(lines))
{
for(auto itr = lines.begin(); itr != lines.end(); itr++)
{
Utils::WString l = *itr;
l.removeChar(9);
l.removeChar('\r');
l.removeFirstSpace();
if (l.empty())
continue;
if (l[0] == '/')
continue;
// are we looking for a section
if (section <= 0)
{
sSection = l.token(L";", 1);
section = l.token(L";", 2).toInt();
}
else
{
std::vector<Utils::WString> strs;
if(l.tokenise(L";", strs))
{
for (size_t i = 0; i < strs.size(); i++)
{
strs[i].removeEndSpace();
strs[i].removeFirstSpace();
if (strs[i].empty())
continue;
if (sceneModels.contains(strs[i]))
this->addBody(sSection, strs[i]);
--section;
}
}
}
}
return true;
}
}
return false;
}
bool CXspFile::ImportCockpits(const Utils::WString &filename)
{
CFileIO File(filename);
if ( File.exists() )
{
std::vector<Utils::WString> lines;
if (File.readLines(lines))
{
int entries = 0;
auto itr = lines.begin();
while(itr != lines.end())
{
Utils::WString str = itr->remove(9).remove('\r');
str.removeFirstSpace();
if (str.empty())
itr = lines.erase(itr);
else if (str[0] == '/')
itr = lines.erase(itr);
else if (!entries)
{
entries = str.token(L";", 2).toInt();
itr = lines.erase(itr);
}
else
itr++;
}
// now get all the entries from TShips
for (int i = 0; i < 6; i++)
{
int idx = m_sData.token(L";", 32 + (i * 2));
if (static_cast<size_t>(idx) < lines.size() && idx)
{
Utils::WString turret = lines[idx];
int pos = -1;
Utils::WString id;
while (id.empty() && pos > -100) id = turret.token(L";", pos--);
m_sData = m_sData.replaceToken(L";", 32 + (i * 2), id + L"(" + (long)idx + L")");
this->addCockpit(turret, 0);
}
}
}
return true;
}
return false;
}
bool CXspFile::extractCockpits(CVirtualFileSystem *pVfs)
{
if ( !pVfs->extractGameFile(L"types/TCockpits.pck", CPackages::tempDirectory() + L"/tmp.dat").empty() ) {
bool ret = this->ImportCockpits((CPackages::tempDirectory() + L"/tmp.dat"));
CFileIO::Remove(CPackages::tempDirectory() + L"/tmp.dat");
return ret;
}
return false;
}
bool CXspFile::extractBodies(CVirtualFileSystem *pVfs, const Utils::WStringList &sceneModels)
{
if (sceneModels.empty()) return false;
if ( !pVfs->extractGameFile(L"types/Bodies.pck", CPackages::tempDirectory() + L"/tmp.dat").empty() ) {
bool ret = this->importBodies(sceneModels, (CPackages::tempDirectory() + L"/tmp.dat"));
CFileIO::Remove(CPackages::tempDirectory() + L"/tmp.dat");
return ret;
}
return false;
}
bool CXspFile::_addTextFromFile(CFileIO &F, int textId)
{
if ( textId == -1 && !m_sData.empty() )
textId = m_sData.token(L";", 7);
if ( textId <= 0 )
return false;
if ( !F.isOpened() )
return false;
bool added = false;
Utils::WString shipName;
Utils::WString shipDesc;
int lastAddedGameID = 0;
int currentGameID = 0;
int lang = 0;
bool inpage = false;
while(!F.atEnd()) {
if ( !shipName.empty() && !shipDesc.empty() )
{
added = true;
break;
}
Utils::WString line = F.readEndOfLine();
line.removeChar(9);
line.removeChar('\r');
line.removeFirstSpace();
if ( inpage )
{
if ( line.left(6).Compare(L"</page") ) {
inpage = false;
continue;
}
// find matching id
if ( line.left(6).Compare(L"<t id=") )
{
int pos = line.findPos(L"id=\"", 0);
if ( pos != -1 )
{
pos += 4;
int endpos = line.findPos(L"\"", pos);
if ( endpos != -1 )
{
int id = line.mid(pos, endpos);
if ( id == textId || id == (textId + 1) )
{
pos = line.findPos(L">", endpos);
if ( pos != -1 )
{
endpos = line.findPos(L"</t>", pos);
if ( endpos != -1 )
{
if ( id == textId )
shipName = line.mid(pos + 1, endpos);
else
shipDesc = line.mid(pos + 1, endpos);
lastAddedGameID = currentGameID;
}
}
}
}
}
}
}
else if ( lang ) // search for page 17
{
if ( line.left(8).Compare(L"<page id") )
{
int pos = line.findPos(L"id=\"");
if ( pos != -1 )
{
pos += 4;
int endpos = line.findPos(L"\"", pos);
if ( endpos != -1 )
{
Utils::WString sId = line.mid(pos, endpos);
int id = sId;
if ( sId.length() > 4 ) {
id = sId.right(4);
currentGameID = sId.left(static_cast<long>(sId.length() - 4));
}
if ( currentGameID >= lastAddedGameID && id == 17 )
inpage = true;
}
}
}
}
else if ( line.left(12).Compare(L"<language id") )
{
int pos = line.findPos(L"id=\"");
if ( pos != -1 )
{
// move past the id=
pos += 4;
Utils::WString s = line.right(-pos);
Utils::WString s2 = line.mid(pos, -1);
int endpos = line.findPos(L"\"", pos);
if ( endpos != -1 )
lang = line.mid(pos, endpos);
}
}
}
// incase we only found the shipname
if ( !shipName.empty() )
added = true;
if ( added )
{
if ( lang == 44 || this->name().empty())
{
this->setName(shipName);
this->setDescription(shipDesc.findReplace(L"&", L"&"));
}
this->addText(lang, shipName, shipDesc);
return true;
}
return false;
}
void CXspFile::ExtractTexts(CCatFile *catFile, CCatFile *secondCatFile, int textId)
{
for (auto itr = catFile->GetFiles()->begin(); itr != catFile->GetFiles()->end(); itr++ )
{
SInCatFile *f = *itr;
if ( !f->sFile.left(2).Compare(L"t\\") && !f->sFile.left(2).Compare(L"t/") )
continue;
// extract the text file and read in the data
bool extracted = catFile->extractFile(f->sFile, CPackages::tempDirectory() + L"/tmp.dat");
if ( !extracted && secondCatFile ) extracted = secondCatFile->extractFile(f->sFile, CPackages::tempDirectory() + L"/tmp.dat");
if ( extracted ) {
this->addTextFromFile(CPackages::tempDirectory() + L"/tmp.dat", textId);
CFileIO::Remove(CPackages::tempDirectory() + L"/tmp.dat");
}
}
}
bool CXspFile::processSceneFileSection(int section, CVirtualFileSystem *pVfs, Utils::WStringList &lModels, CProgressInfo *progress)
{
if ( progress ) progress->UpdateStatus(section);
switch ( section )
{
case IMPORTSHIP_COMPONANT:
if (lModels.empty()) return false;
this->extractComponants(pVfs, lModels);
break;
case IMPORTSHIP_MODELS:
{
if (lModels.empty()) return false;
for(auto itr = lModels.begin(); itr != lModels.end(); itr++)
{
if ((*itr)->str.isNumber() ) // count be componants or dummy
continue;
if ( pVfs->extractGameFileToPackage(this, L"objects\\" + (*itr)->str + L".pbb", FILETYPE_SHIPMODEL, L"objects\\" + (*itr)->str + L".bob") )
continue;
if ( pVfs->extractGameFileToPackage(this, L"objects\\" + (*itr)->str + ".pbd", FILETYPE_SHIPMODEL, L"objects\\" + (*itr)->str + L".bod") )
continue;
}
}
break;
case IMPORTSHIP_DUMMIES:
if (lModels.empty()) return false;
this->extractDummies(pVfs, lModels, true);
this->extractCutData(pVfs, lModels, true);
break;
// extract the textures
case IMPORTSHIP_TEXTURES:
this->extractTextures(pVfs);
break;
case IMPORTSHIP_TEXTS:
// extract the text file entries
pVfs->extractTexts(this, m_sData.token(L";", 7));
break;
case IMPORTSHIP_BODIES:
// extract the bodies entries
if (lModels.empty()) return false;
this->extractBodies(pVfs, lModels);
break;
case IMPORTSHIP_COCKPITS:
// extract the cockpit entries
this->extractCockpits(pVfs);
break;
}
return true;
}
bool CXspFile::processSceneFiles(CVirtualFileSystem *pVfs, CProgressInfo *progress)
{
// now lets parse our files
if ( progress ) progress->UpdateStatus(IMPORTSHIP_EXTRACTSCENE);
Utils::WStringList lModels;
if(!readSceneModels(lModels))
return false;
// extract componants, and add extra items to list
if ( !this->processSceneFileSection(IMPORTSHIP_COMPONANT, pVfs, lModels, progress) )
return false;
//lets first find any model files
if ( !this->processSceneFileSection(IMPORTSHIP_MODELS, pVfs, lModels, progress) )
return false;
// extract the dummies
if ( !this->processSceneFileSection(IMPORTSHIP_DUMMIES, pVfs, lModels, progress) )
return false;
// extract the textures
if ( !this->processSceneFileSection(IMPORTSHIP_TEXTURES, pVfs, lModels, progress) )
return false;
// extract the text file entries
if ( !this->processSceneFileSection(IMPORTSHIP_TEXTS, pVfs, lModels, progress) )
return false;
// extract the bodies entries
if ( !this->processSceneFileSection(IMPORTSHIP_BODIES, pVfs, lModels, progress) )
return false;
// extract the cockpit entries
if ( !this->processSceneFileSection(IMPORTSHIP_COCKPITS, pVfs, lModels, progress) )
return false;
return true;
}
void CXspFile::PackAllFiles()
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( f->GetFileType() == FILETYPE_SHIPSCENE || f->GetFileType() == FILETYPE_COCKPITSCENE || f->GetFileType() == FILETYPE_SHIPMODEL || f->GetFileType() == FILETYPE_SHIPOTHER )
{
/*
if ( f->CheckFileExt("bod") )
{
if ( f->PCKFile() )
f->ChangeFileExt("pbd");
}
else */if ( f->checkFileExt(L"bob") )
{
if ( f->PCKFile() )
f->changeFileExt(L"pbb");
}
}
}
}
void CXspFile::AdjustCockpits()
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
SCockpit *c = node->Data();
if ( c->iIndex < 0 )
continue;
Utils::WString id = c->sCockpit.token(L";", 19);
for ( int i = 0; i < 6; i++ )
{
Utils::WString tId = m_sData.token(L";", 32 + (i * 2));
if ( tId.isNumber() && ((int)tId) == c->iIndex )
m_sData = m_sData.replaceToken(L";", 32 + (i * 2), id + L"(" + Utils::WString::Number(c->iIndex) + L")");
}
}
}
Utils::WString CXspFile::formatShipData(const Utils::WStringList &cockpits, int *text, int game)
{
Utils::WString data = (game == GAME_X3) ? this->getX3ShipData() : this->getTCShipData();
// do turrets
for ( int t = 0; t < 6; t++ )
{
int oldPos = 0;
Utils::WString turret = data.token(L";", 32 + (t * 2));
if ( !turret.isNumber() )
{
if ( turret.contains(L"(") )
{
oldPos = turret.tokens(L"(", 2).token(L")", 1);
turret = turret.token(L"(", 1);
}
size_t pos = cockpits.findPos(turret);
if ( pos < 0 ) pos = oldPos;
if (static_cast<size_t>(pos) >= cockpits.size()) pos = 0;
data = data.replaceToken(L";", 32 + (t * 2), (long)pos);
}
}
// adjust the weapons
int mask = this->GetLaserMask(game - 1);
if ( mask != -1 )
data = data.replaceToken(L";", 19, (long)mask);
mask = this->GetMissileMask(game - 1);
if ( mask != -1 )
data = data.replaceToken(L";", 25, (long)mask);
// fix the ship text
if ( m_iOrgDesc > 0 )
(*text) = m_iOrgDesc;
data = data.replaceToken(L";", 7, (long)*text);
// add the ware id
data.removeChar(9);
data.removeEndSpace();
// remove the end ;
while ( data.right(1) == L";" ) data.truncate(-1);
data = data.replaceToken(L";", data.countToken(L";"), this->shipID());
if ( data.right(1) != L";" )
data += L";";
return data;
}