Rev 1 | Rev 31 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "XspFile.h"
#include "File_IO.h"
#include "Packages.h"
#include "CatFile.h"
CXspFile::CXspFile () : CBaseFile()
{
SetDefaults ();
m_iType = TYPE_XSP;
}
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();
m_lCutData.Clear();
m_lBodies.Clear();
}
void CXspFile::SetDefaults ()
{
CBaseFile::SetDefaults ();
m_pSceneFile = m_pCockpitFile = NULL;
m_bLanguageText = m_bExistingShip = false;
m_iOrgDesc = 0;
m_iShipyard = SHIPYARD_NONE;
}
void CXspFile::AddText ( int id, CyString name, CyString 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;
m_bChanged = true;
}
void CXspFile::RemoveText(int id)
{
for ( SText *t = m_lText.First(); t; t = m_lText.Next() )
{
if ( t->iId == id )
{
m_bChanged = true;
m_lText.RemoveCurrent();
return;
}
}
}
void CXspFile::AddDummy ( CyString section, CyString data )
{
SDummy *d = new SDummy;
d->sData = data;
d->sSection = section;
if ( d->sData.Right (1) != ";" )
d->sData += ";";
m_lDummy.push_back ( d );
m_bChanged = true;
}
void CXspFile::AddComponent ( CyString section, CyString section2, CyString data )
{
SComponent *c = new SComponent;
c->sData = data;
c->sSection = section;
c->sSection2 = section2;
if ( c->sData.Right (1) != ";" )
c->sData += ";";
m_lComponent.push_back ( c );
m_bChanged = true;
}
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;
m_bChanged = true;
}
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;
m_bChanged = true;
}
bool CXspFile::IsValid ()
{
if ( m_sName.Empty() )
return false;
if ( m_sAuthor.Empty() )
return false;
return true;
}
Utils::String CXspFile::CreateValuesLine() const
{
Utils::String values = CBaseFile::CreateValuesLine ();
values += "Data: " + m_sData + "\n";
values += "ID: " + m_sID + "\n";
if ( m_bLanguageText )
values += "LanguageText\n";
if ( m_bExistingShip )
values += "ExistingShip\n";
values += Utils::String("OrgDesc: ") + (long)m_iOrgDesc + "\n";
values += Utils::String("Shipyard: ") + (long)m_iShipyard + "\n";
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() ) {
SCockpit *cockpit = node->Data();
values += Utils::String("CockpitNew: ") + (long)cockpit->lWeaponMask.size();
for ( CListNode<SWeaponMask> *wNode = cockpit->lWeaponMask.Front(); wNode; wNode = wNode->next() ) {
values += ":";
values += (long)wNode->Data()->iGame;
values += ":";
values += (long)wNode->Data()->iMask;
}
values += " ";
values += cockpit->sCockpit.ToString() + "\n";
}
for ( CListNode<SText> *tNode = m_lText.Front(); tNode; tNode = tNode->next() )
values += Utils::String("Text: ") + (long)tNode->Data()->iId + "|" + tNode->Data()->sName.FindReplace("|", "<::PiPe::>").ToString() + "|" + tNode->Data()->sDesc.ToString() + "\n";
for ( CListNode<SComponent> *cNode = m_lComponent.Front(); cNode; cNode = cNode->next() )
values += Utils::String("Component: ") + cNode->Data()->sData.FindReplace("|", "<::PiPe::>").ToString() + "|" + cNode->Data()->sSection.FindReplace("|", "<::PiPe::>").ToString() + "|" + cNode->Data()->sSection2.ToString() + "\n";
for ( CListNode<SDummy> *dNode = m_lDummy.Front(); dNode; dNode = dNode->next() )
values += Utils::String("Dummy: ") + dNode->Data()->sData.FindReplace("|", "<::PiPe::>").ToString() + "|" + dNode->Data()->sSection.ToString() + "\n";
for ( CListNode<SWeaponMask> *wNode = m_lWeaponMasks.Front(); wNode; wNode = wNode->next() )
values += Utils::String("WeaponMask: ") + (long)wNode->Data()->iGame + " " + (long)wNode->Data()->iMask + "\n";
for ( CListNode<SWeaponMask> *mNode = m_lMissileMasks.Front(); mNode; mNode = mNode->next() )
values += Utils::String("MissileMask: ") + (long)mNode->Data()->iGame + " " + (long)mNode->Data()->iMask + "\n";
for ( SStringList *cut = m_lCutData.Head(); cut; cut = cut->next )
values += Utils::String("CutData: ") + cut->str.ToString() + "\n";
for ( SStringList *body = m_lBodies.Head(); body; body = body->next )
values += Utils::String("Bodies: ") + body->str.ToString() + "\n";
for ( SStringList *ani = m_lAnimations.Head(); ani; ani = ani->next )
values += Utils::String("Animations: ") + ani->str.ToString() + "\n";
return values;
}
bool CXspFile::ParseValueLine(const Utils::String &sLine)
{
Utils::String first = sLine.token(":", 1);
Utils::String rest = sLine.tokens(":", 2).removeFirstSpace();
if ( first.Compare("Data") )
m_sData = rest;
else if ( first.Compare("ID") )
m_sID = rest;
else if ( sLine.Compare("LanguageText") )
m_bLanguageText = true;
else if ( sLine.Compare("ExistingShip") )
m_bExistingShip = true;
else if ( first.Compare("OrgDesc") || first.Compare("OriginalDesc") )
m_iOrgDesc = rest;
else if ( first.Compare("Shipyard") )
m_iShipyard = rest;
else if ( first.Compare("CutData") )
this->AddCutData(rest);
else if ( first.Compare("Bodies") )
this->AddBodies(rest);
else if ( first.Compare("Animations") )
this->AddAnimation(rest);
else if ( first.Compare("Cockpit") )
this->AddCockpit(rest, 0);
else if ( first.Compare("CockpitNew") )
{
Utils::String cockpit = rest.tokens(" ", 2);
Utils::String sMasks = rest.token(" ", 1);
this->AddCockpit(cockpit, 0, -1);
int num = sMasks.token(":", 1);
for ( int i = 0; i < num; i++ )
{
int mask = sMasks.token(":", ((i + 1) * 2) + 1);
int game = sMasks.token(":", ((i + 1) * 2));
this->AddCockpit(cockpit, game, mask);
}
}
else if ( first == "Web" )
m_sWebSite = rest;
else if ( first.Compare("WeaponMask") )
this->AddWeaponMask(rest.token(" ", 1), rest.token(" ", 2));
else if ( first.Compare("MissileMask") )
this->AddMissileMask(rest.token(" ", 1), rest.token(" ", 2));
else if ( first == "Text" )
{
SText *text = new SText;
text->iId = rest.token("|", 1);
text->sName = rest.token("|", 2);
text->sName = text->sName.FindReplace("<::PiPe::>", "|");
text->sDesc = rest.tokens( "|", 3);
m_lText.push_back ( text );
}
else if ( first == "Component" )
{
SComponent *c = new SComponent;
c->sData = rest.token("|", 1);
c->sData = c->sData.FindReplace ("<::PiPe::>", "|");
c->sSection = rest.token("|", 2);
c->sSection = c->sSection.FindReplace ("<::PiPe::>", "|");
c->sSection2 = rest.tokens("|", 3);
m_lComponent.push_back ( c );
}
else if ( first == "Dummy" )
{
SDummy *d = new SDummy;
d->sData = rest.token("|", 1);
d->sData = d->sData.FindReplace ("<::PiPe::>", "|");
d->sSection = rest.tokens( "|", 2);
m_lDummy.push_back ( d );
}
else if ( first == "Comment" )
m_sDescription = rest.findReplace("<newline>", "<br>");
else
return CBaseFile::ParseValueLine(sLine);
return true;
}
CyString CXspFile::GetShipName(int lang)
{
CyString 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 = GetLanguageName(lang);
return name;
}
bool CXspFile::ConvertOld(CyString file)
{
// open the file
FILE *id = fopen(file.c_str(), "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';
CyString line = (char *)(compr + start);
start = pos;
if ( line.Empty() )
continue;
CyString first = line.GetToken(":", 1, 1);
CyString rest = line.GetToken(":", 2);
rest = rest.RemoveFirstSpace();
// now check each line
if ( first.Compare("Packager") )
packageVersion = rest.ToInt();
else if ( first.Compare("Shipyard") )
{
int max;
CyString *strs = rest.SplitToken(";", &max);
if ( strs && max )
{
int cur = 1;
for ( int i = 0; i < max; i++, cur *= 2 )
{
if ( strs[i] == "1" )
this->AddShipyard(cur);
}
}
CLEANSPLIT(strs, max)
}
else if ( first.Compare("ScreenShot") )
{
int size = rest.GetToken(" ", 1, 1).ToInt();
CyString ext = rest.GetToken(" ", 2, 2);
C_File *newFile = this->AddFile(CyString(m_sID) + "_" + CyString::Number(this->CountFiles(FILETYPE_SCREEN) + 1) + "." + ext, "", FILETYPE_SCREEN);
newFile->ReadFromData((char *)(compr + pos), size);
start += (size + 1);
}
else if ( first.Compare("SceneFile") )
{
CyString file = rest.GetToken(" ", 3);
m_pSceneFile = this->AddFile(CFileIO(file).GetFilename(), CFileIO(file).GetDir(), FILETYPE_SHIPSCENE);
m_pSceneFile->SetCreationTime(rest.GetToken(" ", 1, 1).ToLong());
m_pSceneFile->ReadFromData((char *)(compr + pos), rest.GetToken(" ", 2, 2).ToInt());
start += m_pSceneFile->GetDataSize();
}
else if ( first.Compare("CockpitFile") )
{
CyString file = rest.GetToken(" ", 3);
m_pCockpitFile = this->AddFile(CFileIO(file).GetFilename(), CFileIO(file).GetDir(), FILETYPE_COCKPITSCENE);
m_pCockpitFile->SetCreationTime(rest.GetToken(" ", 1, 1).ToLong());
m_pCockpitFile->ReadFromData((char *)(compr + pos), rest.GetToken(" ", 2, 2).ToInt());
start += m_pCockpitFile->GetDataSize();
}
else if ( first.Compare("Model") )
{
CyString file = rest.GetToken(" ", 3);
C_File *newFile= this->AddFile(CFileIO(file).GetFilename(), CFileIO(file).GetDir(), FILETYPE_SHIPMODEL);
newFile->SetCreationTime(rest.GetToken(" ", 1, 1).ToLong());
newFile->ReadFromData((char *)(compr + pos), rest.GetToken(" ", 2, 2).ToInt());
start += (newFile->GetDataSize() + 1);
}
else if ( first.Compare("Files") )
{
CyString file = rest.GetToken(" ", 3);
C_File *newFile = NULL;
int special = 0;
if ( file.Compare("types/CutData.txt") || file.Compare("types/CutData.pck") )
{
newFile = new C_File(file);
special = 1;
}
else if ( file.Compare("types/Bodies.txt") || file.Compare("types/Bodies.pck") )
{
newFile = new C_File(file);
special = 2;
}
else if ( file.Compare("types/Animations.txt") || file.Compare("types/Animations.pck") )
{
newFile = new C_File(file);
special = 3;
}
else
{
newFile = this->AddFile(CFileIO(file).GetFilename(), CFileIO(file).GetDir(), FILETYPE_SHIPOTHER);
newFile->SetCreationTime(rest.GetToken(" ", 1, 1).ToLong());
}
newFile->ReadFromData((char *)(compr + pos), rest.GetToken(" ", 2, 2).ToInt());
start += (newFile->GetDataSize() + 1);
if ( special )
{
if ( newFile->CheckFileExt("pck") )
newFile->UnPCKFile();
// read data into lines
CyString data((const char *)newFile->GetData());
data.RemoveChar('\r');
int iLines;
CyString *sLines = data.SplitToken("\n", &iLines);
if ( sLines && iLines )
{
// cut data
int entries = -1;
if ( special == 1 )
{
CyStringList newLines;
for ( int i = 0; i < iLines; i++ )
{
CyString line = sLines[i];
line.RemoveChar(' ');
line.RemoveChar(9);
if ( line.Empty() || line[0] == '/' )
continue;
if ( entries == -1 )
{
entries = line.GetToken(";", 1, 1).ToInt() - 36;
if ( entries <= 0 )
break;
}
else
{
int id = line.GetToken(";", 1, 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.Count() == entries )
break;
}
}
for ( SStringList *strNode = newLines.Head(); strNode; strNode = strNode->next )
this->AddCutData(strNode->str);
}
// bodies
else if ( special == 2 )
{
entries = 0;
CyString section;
for ( int i = 0; i < iLines; i++ )
{
CyString line = sLines[i];
line.RemoveChar(' ');
line.RemoveChar(9);
if ( line.Empty() || line[0] == '/' )
continue;
if ( entries <= 0)
{
section = line.GetToken(";", 1, 1);
entries = line.GetToken(";", 2, 2).ToInt();
}
else
{
if ( !line.IsIn(";") )
continue;
if ( line.NumToken(";") <= 2 )
{
this->AddBodies(section + ";" + line.GetToken(";", 1, 1) + ";");
--entries;
}
else
{
bool done = false;
while (!done)
{
int num;
CyString *strs = line.SplitToken(";", &num);
done = true;
for ( int j = 0; j < num; j++ )
{
if ( !entries )
{
line = line.GetToken(";", j + 1);
if ( !line.Empty() )
done = false;
break;
}
if ( strs[j].Empty() )
continue;
this->AddBodies(section + ";" + strs[j] + ";");
--entries;
}
//we must be at another section
if ( !done )
{
section = line.GetToken(";", 1, 1);
entries = line.GetToken(";", 2, 2).ToInt();
line = line.RemToken(";", 1);
line = line.RemToken(";", 1);
if (line.Empty())
done = true;
}
CLEANSPLIT(strs, num)
}
}
}
}
}
// animations
else if ( special == 3 )
{
CyStringList in;
for ( int i = 0; i < iLines; i++ )
{
CyString line = sLines[i];
in.PushBack(line);
}
CyStringList out;
if ( CXspFile::ReadAnimations(&in, &out, 87) )
this->AddAnimation(&out);
}
}
CLEANSPLIT(sLines, iLines)
delete newFile;
}
}
else if ( first.Compare("Script") )
{
CyString file = rest.GetToken(" ", 3);
C_File *newFile= this->AddFile(file, NullString, FILETYPE_SCRIPT);
newFile->SetCreationTime(rest.GetToken(" ", 1, 1).ToLong());
newFile->ReadFromData((char *)(compr + pos), rest.GetToken(" ", 2, 2).ToInt());
start += (newFile->GetDataSize() + 1);
}
else if ( first.Compare("Text") )
this->AddText(rest.GetToken ( ":", 1, 1 ).ToInt(), rest.GetToken ( ":", 2, 2 ), rest.GetToken ( ":", 3 ));
else if ( first.Compare("Component") )
this->AddComponent(rest.GetToken ( ";", 1, 1 ), rest.GetToken ( ";", 2, 2 ), rest.GetToken ( ";", 3 ));
else if ( first.Compare("Dummy") )
{
SDummy *d = new SDummy;
d->sData = rest.GetToken ( ";", 2 );
d->sSection = rest.GetToken ( ";", 1, 1 );
m_lDummy.push_back ( d );
}
else if ( !this->ParseValueLine(line.ToString()) )
{
// 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(";", 19));
this->AddMissileMask(GAME_X3 - 1, m_sData.token(";", 25));
}
return true;
}
int GetMaxShipyards() { return (int)SHIPYARD_MAX; }
CyString GetShipyardName (int s)
{
switch (s)
{
case SHIPYARD_ARGON:
return "Argon";
case SHIPYARD_BORON:
return "Boron";
case SHIPYARD_PARANID:
return "Paranid";
case SHIPYARD_SPLIT:
return "Split";
case SHIPYARD_TELADI:
return "Teladi";
case SHIPYARD_PIRATES:
return "Pirates";
case SHIPYARD_FRIEND:
return "Friendly";
case SHIPYARD_XENON:
return "Xenon";
case SHIPYARD_TERRAN:
return "Terran";
}
return "Unknown";
}
bool CXspFile::WriteHeader(FILE *id, int valueheader, int valueComprLen)
{
fprintf ( id, "XSPCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen );
if ( ferror(id) )
return false;
return true;
}
bool CXspFile::CheckHeader(const Utils::String header) const
{
if ( header.Compare("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;
}
CyString CXspFile::GetShipClass()
{
if ( !m_sData.empty() )
return m_sData.token(";", TSHIPPOS_CLASS);
return "OBJ_SHIP_M5";
}
bool CXspFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile)
{
if ( !CBaseFile::GeneratePackagerScript(wildcard, list, datafile) )
return false;
if ( m_iShipyard )
{
list->PushBack("# Shipyards, Set which shipyards to add ships for sale to");
for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 )
{
if ( this->IsShipyard(i) )
list->PushBack(CyString("Shipyard: ") + GetShipyardName(i));
}
list->PushBack("");
}
if ( m_iOrgDesc > 0 )
{
list->PushBack("# Use Original Description, overrides text entrys to use one of the built in text");
list->PushBack(CyString("OriginalDescription: ") + (long)m_iOrgDesc);
list->PushBack("");
}
if ( !m_sID.empty() )
{
list->PushBack("# Ship ID, the ship id to identify the ship as");
list->PushBack(CyString("ShipID: ") + m_sID);
}
if ( !m_sData.empty() )
{
list->PushBack("# Ship Data, the TShip data entry to add to the game (parts of this are adjusted and auto generated by the installer)");
list->PushBack(CyString("ShipData: ") + m_sData);
list->PushBack("");
}
if ( m_bExistingShip )
{
list->PushBack("# Existing Ship, replaces an existing ship in the game with ship package instead of creating a new entry");
list->PushBack("ExistingShip");
list->PushBack("");
}
if ( !datafile )
{
if ( !CBaseFile::GeneratePackagerScriptFile(wildcard, list) )
return false;
}
return true;
}
bool CXspFile::LoadPackageData(const Utils::String &sFirst, const Utils::String &sRest)
{
if ( sFirst.Compare("Shipyard") )
{
for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 )
{
if ( sRest.Compare(GetShipyardName(i).ToString()) )
{
this->AddShipyard(i);
break;
}
}
}
else if ( sFirst.Compare("OriginalDescription") )
m_iOrgDesc = sRest;
else if ( sFirst.Compare("ShipData") )
m_sData = sRest;
else if ( sFirst.Compare("ReadData") ) // read data from a tships file
{
CPackages p;
m_sData = p.ReadShipData(sRest.tokens(" ", 2), sRest.token(" ", 1)).ToString();
}
else if ( sFirst.Compare("ExistingShip") )
m_bExistingShip = true;
else if ( sFirst.Compare("ShipID") )
m_sID = sRest;
else if ( !CBaseFile::LoadPackageData(sFirst, sRest) )
{
return false;
}
return true;
}
CyString CXspFile::GetX3ShipData()
{
CyString data = m_sData;
// change the ship subtype, Reunion uses number, TC uses a define
CyString sSubType = data.GetToken(";", 6, 6);
if ( !sSubType.ToInt() && sSubType != "0" )
data = data.RepToken(";", 6, CyString::Number(CShipData::ConvertShipSubType(sSubType)));
CyString sClass = data.GetToken(";", TSHIPPOS_CLASS, TSHIPPOS_CLASS);
if ( !sClass.ToInt() && sClass != "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.RepToken(";", TSHIPPOS_CLASS, CyString::Number(num));
}
return data;
}
CyString CXspFile::GetTCShipData()
{
CyString data = m_sData;
CyString sSubType = data.GetToken(";", 6, 6);
if ( sSubType.ToInt() || sSubType == "0" )
data = data.RepToken(";", 6, CShipData::ConvertShipSubType(sSubType.ToInt()));
CyString sClass = data.GetToken(";", TSHIPPOS_CLASS, TSHIPPOS_CLASS);
if ( sClass.ToInt() || sClass == "0" )
data = data.RepToken(";", TSHIPPOS_CLASS, CShipData::ConvertShipClass(sClass.ToInt()));
return data;
}
bool CXspFile::RemoveCockpit(CyString cockpitid)
{
// if its a whole line, just get the end
if ( cockpitid.IsIn(";") )
{
cockpitid = cockpitid.GetToken(";", -2);
while ( cockpitid.Right(1) == ";" )
cockpitid.Truncate((int)cockpitid.Length() - 1);
}
bool ret = false;
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
CyString id = node->Data()->sCockpit.GetToken(";", 19, 19);
if ( id.Compare(cockpitid) )
{
node->DeleteData();
ret = true;
break;
}
}
m_lCockpit.RemoveEmpty();
return ret;
}
bool CXspFile::RemoveComponent(CyString section1, CyString section2, CyString 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(CyString section, CyString 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;
}
CyString CXspFile::GetCockpitData(CyString cid)
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
CyString id = node->Data()->sCockpit.GetToken(";", 19, 19);
if ( id.Compare(cid) )
return node->Data()->sCockpit;
}
return NullString;
}
SCockpit *CXspFile::FindCockpit(CyString cid)
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
CyString id = node->Data()->sCockpit.GetToken(";", 19, 19);
if ( id.Compare(cid) )
return node->Data();
}
return NULL;
}
void CXspFile::EditCockpit(CyString cid, CyString cockpit)
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
CyString id = node->Data()->sCockpit.GetToken(";", 19, 19);
if ( id.Compare(cid) )
{
node->Data()->sCockpit = cockpit;
break;
}
}
}
void CXspFile::EditCockpit(CyString cid, CyString scene, int mask)
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
CyString id = node->Data()->sCockpit.GetToken(";", 19, 19);
if ( id.Compare(cid) )
{
CyString cockpit = node->Data()->sCockpit;
cockpit = cockpit.RepToken(";", 8, scene);
cockpit = cockpit.RepToken(";", 9, CyString::Number(mask));
node->Data()->sCockpit = cockpit;
break;
}
}
}
void CXspFile::NewCockpit(CyString id, CyString scene, int mask)
{
CyString cockpit = "0;0;0;0;0;0;0;";
cockpit += scene + ";";
cockpit += CyString::Number(mask);
cockpit += ";0;0;0;0;0;0;-100000;0;0;";
cockpit += id + ";";
this->AddCockpit(cockpit, -1);
}
bool CXspFile::RemoveCutData(CyString cut)
{
bool ret = false;
for ( SStringList *str = m_lCutData.Head(); str; str = str->next )
{
if ( str->str.GetToken(";", 1, 1).Compare(cut.GetToken(";", 1, 1)) )
{
ret = true;
str->remove = true;
break;
}
}
m_lCutData.RemoveMarked();
return ret;
}
bool CXspFile::RemoveBodies(CyString cut)
{
bool ret = false;
for ( SStringList *str = m_lBodies.Head(); str; str = str->next )
{
if ( str->str.Remove(' ').Compare(cut.Remove(' ')) )
{
ret = true;
str->remove = true;
break;
}
}
m_lBodies.RemoveMarked();
return ret;
}
bool CXspFile::RemoveAnimation(CyString cut)
{
bool ret = false;
for ( SStringList *str = m_lAnimations.Head(); str; str = str->next )
{
if ( str->str.Remove(' ').Remove('\n').Compare(cut.Remove(' ').Remove('\n')) )
{
ret = true;
str->remove = true;
break;
}
}
m_lAnimations.RemoveMarked();
return ret;
}
void CXspFile::AddCockpit(CyString cockpit, int game, int mask, int index)
{
SCockpit *pCockpit = NULL;
// first search for the cockpit entry
CyString cid = cockpit.GetToken(";", 19, 19);
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
CyString id = node->Data()->sCockpit.GetToken(";", 19, 19);
if ( id.Compare(cid) )
{
pCockpit = node->Data();
break;
}
}
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 )
{
// 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 = cockpit.GetToken(";", 9, 9).ToInt();
else
wm->iMask = mask;
}
m_bChanged = true;
}
void CXspFile::AddBody(CyString section, CyString data)
{
this->AddBodies(section + ";" + data);
m_bChanged = true;
}
void CXspFile::AddBodies(CyString data)
{
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) != ";" )
data += ";";
}
m_lBodies.PushBack(data, true);
m_bChanged = true;
}
int CXspFile::GetAnimationType(CyString type)
{
if ( type.Compare("TAT_TAGSINGLESTEP") )
return TAT_SINGLE;
else if ( type.Compare("TAT_TAGONESHOT")
|| type.Compare("TAT_TAGONESHOT_REINIT")
|| type.Compare("TAT_PINGPONG")
|| type.Compare("TAT_TAGLOOP") )
return TAT_3;
return TAT_NONE;
}
bool CXspFile::ReadAnimations(CyStringList *lIn, CyStringList *lOut, int startRecord)
{
CyString lastComment;
CyString addEntry;
int remaining = 0;
CyString lastType;
int newEntries = 0;
int entries = -1;
for ( SStringList *strNode = lIn->Head(); strNode; strNode = strNode->next )
{
CyString line = strNode->str;
line.RemoveChar('\r');
line.RemoveChar(9);
if ( line.Empty() || line[0] == '/' )
continue;
if ( entries == -1)
{
entries = line.GetToken(";", 1, 1).ToInt();
newEntries = entries - startRecord;
}
else
{
// remove comments, endspaces and last ;
CyString sStriped = line;
if ( sStriped.IsIn("//") )
{
if ( entries <= newEntries )
lastComment = CyString("//") + sStriped.GetToken("//", 2);
sStriped = sStriped.GetToken("//", 1, 1);
}
sStriped.RemoveEndSpace();
if ( sStriped.Right(1) == ";" )
sStriped.Truncate(-1);
CyString sRemainingLeft;
if ( remaining > 0 )
sRemainingLeft = sStriped;
else
{
// each line should be a new entry, with some exceptions
// potection for new lines
lastType = sStriped.GetToken(";", 1, 1);
switch (CXspFile::GetAnimationType(lastType))
{
case TAT_SINGLE:
remaining = sStriped.GetToken(";", 5, 5).ToInt() + 1;
sRemainingLeft = sStriped.GetToken(";", 6);
if ( entries <= newEntries )
addEntry = sStriped.GetToken(";", 1, 5) + ";";
break;
case TAT_3:
remaining = sStriped.GetToken(";", 5, 5).ToInt() + 1;
sRemainingLeft = sStriped.GetToken(";", 6);
if ( entries <= newEntries )
addEntry = sStriped.GetToken(";", 1, 5) + ";";
break;
default:
remaining = 0;
if ( entries <= newEntries )
addEntry = sStriped;
}
}
if ( !sRemainingLeft.Empty() )
{
int tatType = CXspFile::GetAnimationType(lastType);
if ( tatType == TAT_SINGLE )
{
if ( sRemainingLeft.IsIn(";") )
remaining -= sRemainingLeft.NumToken(";");
else if ( !sRemainingLeft.Empty() )
--remaining;
if ( entries <= newEntries )
addEntry += sRemainingLeft + ";";
}
else if ( tatType == TAT_3 )
{
// last entry
if ( remaining == 1 )
--remaining;
else if ( sRemainingLeft.IsIn(";") )
{
if ( !sRemainingLeft.IsIn("TATF_COORDS") )
{
int amt = sRemainingLeft.NumToken(";") / 3;
remaining -= amt;
if ( remaining == 1 && (sRemainingLeft.NumToken(";") - (amt * 3)) == 1 )
--remaining;
}
else
{
int iRem = sRemainingLeft.NumToken(";");
int iPos = 1;
while ( iPos < iRem )
{
CyString first = sRemainingLeft.GetToken(";", iPos, iPos);
if ( first.IsIn("TATF_COORDS") )
iPos += 5;
else
iPos += 3;
--remaining;
}
if ( remaining == 1 && iPos == iRem )
--remaining;
}
}
if ( entries <= newEntries )
addEntry += sRemainingLeft + ";";
}
}
if ( remaining <= 0 )
{
if ( entries <= newEntries && !addEntry.Empty())
{
if ( addEntry[(int)addEntry.Length() - 1] != ';' )
addEntry += ";";
lOut->PushBack(addEntry + lastComment);
}
--entries;
}
}
}
return !lOut->Empty();
}
void CXspFile::AddAnimation(CyStringList *list)
{
for ( SStringList *strNode = list->Head(); strNode; strNode = strNode->next )
this->AddAnimation(strNode->str);
m_bChanged = true;
}
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;
}
CyString CXspFile::GetTextName(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->GetShipName(lang);
}
CyString CXspFile::GetTextDescription(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 ( !m_sDescription.Empty() )
return m_sDescription;
return this->GetShipName(lang);
}
bool CXspFile::StartExtractShip(CCatFile *catFile, CyString id, CProgressInfo *progress)
{
id.RemoveChar('\r');
while ( id.Right(1) == ";" )
id.Truncate((int)id.Length() - 1);
m_sID = id.ToString();
m_sData = catFile->GetTShipsEntry(id).ToString();
// get scene files
if ( progress ) progress->UpdateStatus(IMPORTSHIP_SCENE);
if ( !this->ExtractSceneFiles(catFile) )
return false;
return true;
}
bool CXspFile::StartExtractShip(CyString catFile, CyString id, CProgressInfo *progress)
{
CCatFile cat;
if ( cat.Open(catFile, "", CATREAD_CATDECRYPT, false) != CATERR_NONE )
return this->StartExtractShip(&cat, id, progress);
return false;
}
bool CXspFile::ExtractShip(CCatFile *catFile, CyString id, CProgressInfo *progress)
{
if ( !this->StartExtractShip(catFile, id, progress) )
return false;
// read the scene file and get the files list
if ( !this->ProcessSceneFiles(catFile, progress) )
return false;
// pack all the ship files
this->PackAllFiles();
return true;
}
bool CXspFile::ExtractShip(CyString catFile, CyString id, CProgressInfo *progress)
{
CCatFile cat;
if ( cat.Open(catFile, "", CATREAD_CATDECRYPT, false) == CATERR_NONE )
return ExtractShip(&cat, id, progress);
return false;
}
C_File *CXspFile::ExtractFileToPackage(CCatFile *catFile, CyString file, int type, CyString addAs)
{
if ( catFile->ExtractFile(file, "tmp") )
{
CFileIO File("tmp");
C_File *f = this->AddFile(CFileIO(addAs.Empty() ? file : addAs).GetFilename(), CFileIO(addAs.Empty() ? file : addAs).GetDir(), type);
if ( f )
{
if ( f->ReadFromFile("tmp") )
{
File.Remove();
return f;
}
}
File.Remove();
}
return NULL;
}
bool CXspFile::ExtractSceneFiles(CCatFile *catFile)
{
m_pSceneFile = this->ExtractFileToPackage(catFile, CyString("objects\\") + m_sData.token(";", 17) + ".pbd", FILETYPE_SHIPSCENE, CyString("objects\\") + m_sData.token(";", 17) + ".bod");
if ( !m_pSceneFile )
{
m_pSceneFile = this->ExtractFileToPackage(catFile, CyString("objects\\") + m_sData.token(";", 17) + ".bod", FILETYPE_SHIPSCENE);
if ( !m_pSceneFile )
return false;
}
m_pCockpitFile = this->ExtractFileToPackage(catFile, CyString("objects\\") + m_sData.token(";", 18) + ".pbd", FILETYPE_COCKPITSCENE, CyString("objects\\") + m_sData.token(";", 18) + ".bod");
if ( !m_pCockpitFile )
m_pCockpitFile = this->ExtractFileToPackage(catFile, CyString("objects\\") + m_sData.token(";", 18) + ".bod", FILETYPE_COCKPITSCENE);
return true;
}
bool CXspFile::ExtractSceneFiles(CyString catFile)
{
CCatFile cat;
if ( cat.Open(catFile, "", CATREAD_CATDECRYPT, false) == CATERR_NONE )
return ExtractSceneFiles(&cat);
return false;
}
CyStringList *CXspFile::ReadSceneModels()
{
// read the scene file
if ( !m_pSceneFile )
m_pSceneFile = this->GetFirstFile(FILETYPE_SHIPSCENE);
if ( !m_pSceneFile )
return NULL;
// 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 NULL;
CyStringList *lModels = new CyStringList;
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) == lModels->Count() )
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';
lModels->PushBack((char *)line);
online = false;
}
}
}
if ( deleteData )
delete data;
return lModels;
}
void CXspFile::ExtractDummies(CCatFile *catFile, CyStringList *sceneModels, bool add)
{
if ( !sceneModels ) return;
if ( catFile->ExtractFile("types/dummies.pck", "tmp") )
{
CFileIO File("tmp");
if ( File.Exists() )
{
CyString section;
int secCount = 0;
CyStringList *lines = File.ReadLinesStr();
for ( SStringList *node = lines->Head(); node; node = node->next )
{
node->str.RemoveFirstSpace();
node->str.RemoveChar(9);
node->str.RemoveChar('\r');
if ( node->str.Empty() )
continue;
if ( node->str[0] == '/' )
continue;
// not in a section yet
if ( secCount <= 0 )
{
section = node->str.GetToken(";", 1, 1);
secCount = node->str.GetToken(";", 2, 2).ToInt();
}
else
{
CyString first = node->str.GetToken(";", 1, 1);
if ( sceneModels->FindString(first) )
{
this->AddDummy(section, node->str);
if ( add )
{
int pos = 4;
int scene = node->str.GetToken(";", 3, 3).ToInt();
for ( int i = 0; i < scene; i++ )
{
sceneModels->PushBack(node->str.GetToken(";", 5 + (i * 2), 5 + (i * 2)));
pos += 2;
}
int model = node->str.GetToken(";", pos, pos).ToInt();
for ( int i = 0; i < model; i++ )
sceneModels->PushBack(node->str.GetToken(";", pos + (i * 2) + 1, pos + (i * 2) + 1));
}
}
--secCount;
}
}
delete lines;
File.Remove();
}
}
}
void CXspFile::ExtractComponants(CCatFile *catFile, CyStringList *sceneModels)
{
if ( !sceneModels ) return;
if ( catFile->ExtractFile("types/components.pck", "tmp") )
{
CFileIO File("tmp");
if ( File.Exists() )
{
CyString file;
CyString section;
int secCount = 0;
int secCount2 = 0;
CyStringList *lines = File.ReadLinesStr();
for ( SStringList *node = lines->Head(); node; node = node->next )
{
node->str.RemoveFirstSpace();
node->str.RemoveChar(9);
node->str.RemoveChar('\r');
if ( node->str.Empty() )
continue;
if ( node->str[0] == '/' )
continue;
// not in a section yet
if ( secCount2 )
{
if ( sceneModels->FindString(file) )
this->AddComponent(section, file, node->str);
--secCount2;
}
else if ( secCount <= 0 )
{
section = node->str.GetToken(";", 1, 1);
secCount = node->str.GetToken(";", 2, 2).ToInt();
}
else
{
file = node->str.GetToken(";", 1, 1);
secCount2 = node->str.GetToken(";", 2, 2).ToInt();
--secCount;
}
}
delete lines;
File.Remove();
}
}
}
bool CXspFile::GetTextureList(CyStringList *list, const unsigned char *olddata, size_t size)
{
if ( !olddata || !size )
return false;
size_t startLine = 0;
CyString 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 = (char *)(data + startLine);
line.RemoveChar(9);
line.RemoveChar('\r');
line.RemoveFirstSpace();
if ( !line.Empty() && line[0] != '/' )
{
CyString first = line.GetToken(":", 1, 1);
if ( first.Compare("MATERIAL6") )
{
int max;
CyString *strs = line.GetToken(":", 2).SplitToken("; ", &max);
if ( strs && max >= 2)
{
for ( int i = 2; i < max; i++ )
{
CyString s = strs[i];
if ( s.IsIn(";") )
s = s.GetToken(";", 1, 1);
if ( !s.IsNumber() && !s.Compare("NULL") && s.IsIn(".") )
list->PushBack(s, "", true);
}
}
CLEANSPLIT(strs, max)
}
}
startLine = pos + 1;
}
}
delete [] data;
return true;
}
void CXspFile::ExtractTextures(CCatFile *catFile)
{
CyStringList lTextures;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( f->GetFileType() != FILETYPE_SHIPMODEL )
continue;
// cant do these yet
if ( f->CheckFileExt("pbb") || f->CheckFileExt("bob") )
{
if ( !f->BobDecompile() )
continue;
}
if ( !f->GetData() )
{
if ( !f->ReadFromFile() )
continue;
}
unsigned char *data = NULL;
size_t size;
if ( f->CheckFileExt("pbb") || f->CheckFileExt("pbd") )
data = f->UnPCKFile(&size);
else
{
data = f->GetData();
size = f->GetDataSize();
}
this->GetTextureList(&lTextures, data, size);
}
for ( SStringList *node = lTextures.Head(); node; node = node->next )
{
if ( CFileIO(node->str).CheckFileExtension("dds") )
this->ExtractFileToPackage(catFile, CyString("dds\\") + node->str, FILETYPE_SHIPOTHER);
else
this->ExtractFileToPackage(catFile, CyString("textures\\") + node->str, FILETYPE_SHIPOTHER);
}
}
bool CXspFile::AddTextFromFile(CyString file, int textId)
{
bool remove = false;
if ( CFileIO(file).CheckFileExtension("pck") )
{
C_File F(file);
F.UnPCKFile();
if ( F.WriteToFile("tmp") )
{
remove = true;
file = "tmp";
}
}
FILE *fid = fopen(file.c_str(), "r");
if ( fid )
{
bool ret = this->AddTextFromFile(fid, textId);
fclose(fid);
if ( remove )
CFileIO(file).Remove();
m_bChanged = true;
return ret;
}
return false;
}
bool CXspFile::ImportBodies(CyStringList *sceneModels, CyString filename)
{
CFileIO File(filename);
if ( File.Exists() )
{
CyString sSection;
int section = 0;
CyStringList *lines = File.ReadLinesStr();
for ( SStringList *node = lines->Head(); node; node = node->next )
{
node->str.RemoveChar(9);
node->str.RemoveChar('\r');
node->str.RemoveFirstSpace();
if ( node->str.Empty() )
continue;
if ( node->str[0] == '/' )
continue;
// are we looking for a section
if ( section <= 0 )
{
sSection = node->str.GetToken(";", 1, 1);
section = node->str.GetToken(";", 2, 2).ToInt();
}
else
{
int max;
CyString *strs = node->str.SplitToken(";", &max);
if ( strs && max )
{
for ( int i = 0; i < max; i++ )
{
strs[i].RemoveSpaces();
if (strs[i].Empty() )
continue;
if ( sceneModels->FindString(strs[i]) )
this->AddBody(sSection, strs[i]);
--section;
}
}
CLEANSPLIT(strs, max)
}
}
delete lines;
return true;
}
return false;
}
bool CXspFile::ImportCockpits(CyString filename)
{
CFileIO File(filename);
if ( File.Exists() )
{
CyStringList *lines = File.ReadLinesStr();
int entries = 0;
for ( SStringList *node = lines->Head(); node; node = node->next )
{
node->str.RemoveChar(9);
node->str.RemoveChar('\r');
node->str.RemoveFirstSpace();
if ( node->str.Empty() )
node->remove = true;
else if ( node->str[0] == '/' )
node->remove = true;
else if ( !entries )
{
entries = node->str.GetToken(";", 2, 2).ToInt();
node->remove = true;
}
}
lines->RemoveMarked();
// now get all the entries from TShips
for ( int i = 0; i < 6; i++ )
{
int idx = m_sData.token(";", 32 + (i * 2));
if ( idx < lines->Count() && idx )
{
CyString turret = lines->GetAt(idx)->str;
int pos = -1;
Utils::String id;
while ( id.empty() && pos > -100 ) id = turret.GetToken(";", pos, pos--).ToString();
m_sData = m_sData.replaceToken(";", 32 + (i * 2), id + "(" + (long)idx + ")");
this->AddCockpit(turret, 0);
}
}
delete lines;
return true;
}
return false;
}
bool CXspFile::ExtractCockpits(CCatFile *catFile)
{
if ( catFile->ExtractFile("types/TCockpits.pck", "tmp") )
{
bool ret = this->ImportCockpits("tmp");
CFileIO("tmp").Remove();
return ret;
}
return false;
}
bool CXspFile::ExtractBodies(CCatFile *catFile, CyStringList *sceneModels)
{
if ( !sceneModels ) return false;
if ( catFile->ExtractFile("types/Bodies.pck", "tmp") )
{
bool ret = this->ImportBodies(sceneModels, "tmp");
CFileIO("tmp").Remove();
return ret;
}
return false;
}
bool CXspFile::AddTextFromFile(FILE *id, int textId)
{
if ( textId == -1 && !m_sData.empty() )
textId = m_sData.token(";", 7);
if ( textId <= 0 )
return false;
CyString line;
if ( !id )
return false;
bool added = false;
CyString shipName;
CyString shipDesc;
int lang = 0;
bool inpage = false;
while ( !feof(id) )
{
if ( !shipName.Empty() && !shipDesc.Empty() )
{
added = true;
break;
}
line.GetEndOfLine(id, 0, false);
line.RemoveChar(9);
line.RemoveChar('\r');
line.RemoveFirstSpace();
if ( inpage )
{
if ( line.Left(6).Compare("</page") )
break;
// find matching id
if ( line.Left(6).Compare("<t id=") )
{
int pos = line.FindPos("id=\"");
if ( pos != -1 )
{
int endpos = line.FindPos("\"", pos + 5);
if ( endpos != -1 )
{
int id = line.Mid(pos + 5, endpos).ToInt();
if ( id == textId || id == (textId + 1) )
{
pos = line.FindPos(">", endpos);
if ( pos != -1 )
{
endpos = line.FindPos("</t>", pos);
if ( endpos != -1 )
{
if ( id == textId )
shipName = line.Mid(pos + 2, endpos - (pos + 1));
else
shipDesc = line.Mid(pos + 2, endpos - (pos + 1));
}
}
}
}
}
}
}
else if ( lang ) // search for page 17
{
if ( line.Left(8).Compare("<page id") )
{
int pos = line.FindPos("id=\"");
if ( pos != -1 )
{
int endpos = line.FindPos("\"", pos + 5);
if ( endpos != -1 )
{
CyString sId = line.Mid(pos + 5, endpos - (pos + 4));
int id = sId.ToInt();
if ( id == 17 || sId.Right(4).ToInt() == 17 )
inpage = true;
}
}
}
}
else if ( line.Left(12).Compare("<language id") )
{
int pos = line.FindPos("id=\"");
if ( pos != -1 )
{
int endpos = line.FindPos("\"", pos + 5);
if ( endpos != -1 )
lang = line.Mid(pos + 5, endpos - (pos + 4)).ToInt();
}
}
}
// incase we only found the shipname
if ( !shipName.Empty() )
added = true;
if ( added )
{
if ( lang == 44 || m_sName.Empty())
{
m_sName = shipName;
m_sDescription= shipDesc;
m_sDescription = m_sDescription.FindReplace("&", "&");
}
this->AddText(lang, shipName, shipDesc);
return true;
}
return false;
}
void CXspFile::ExtractTexts(CCatFile *catFile, int textId)
{
for ( CListNode<SInCatFile> *node = catFile->GetFiles()->Front(); node; node = node->next() )
{
SInCatFile *f = node->Data();
if ( !f->sFile.Left(2).Compare("t\\") && !f->sFile.Left(2).Compare("t/") )
continue;
// extract the text file and read in the data
if ( catFile->ExtractFile(f->sFile, "tmp") )
{
this->AddTextFromFile("tmp", textId);
CFileIO("tmp").Remove();
}
}
}
bool CXspFile::ProcessSceneFileSection(int section, CCatFile *catFile, CyStringList *lModels, CProgressInfo *progress)
{
if ( progress ) progress->UpdateStatus(section);
switch ( section )
{
case IMPORTSHIP_COMPONANT:
if ( !lModels ) return false;
this->ExtractComponants(catFile, lModels);
break;
case IMPORTSHIP_MODELS:
{
if ( !lModels ) return false;
for ( SStringList *node = lModels->Head(); node; node = node->next )
{
if ( node->str.IsNumber() ) // count be componants or dummy
continue;
if ( this->ExtractFileToPackage(catFile, CyString("objects\\") + node->str + ".pbb", FILETYPE_SHIPMODEL, CyString("objects\\") + node->str + ".bob") )
continue;
if ( this->ExtractFileToPackage(catFile, CyString("objects\\") + node->str + ".pbd", FILETYPE_SHIPMODEL, CyString("objects\\") + node->str + ".bod") )
continue;
if ( this->ExtractFileToPackage(catFile, CyString("objects\\") + node->str + ".bob", FILETYPE_SHIPMODEL) )
continue;
if ( this->ExtractFileToPackage(catFile, CyString("objects\\") + node->str + ".bod", FILETYPE_SHIPMODEL) )
continue;
}
}
break;
case IMPORTSHIP_DUMMIES:
if ( !lModels ) return false;
this->ExtractDummies(catFile, lModels, true);
break;
// extract the textures
case IMPORTSHIP_TEXTURES:
this->ExtractTextures(catFile);
break;
case IMPORTSHIP_TEXTS:
// extract the text file entries
this->ExtractTexts(catFile, m_sData.token(";", 7));
break;
case IMPORTSHIP_BODIES:
// extract the bodies entries
if ( !lModels ) return false;
this->ExtractBodies(catFile, lModels);
break;
case IMPORTSHIP_COCKPITS:
// extract the cockpit entries
this->ExtractCockpits(catFile);
break;
}
return true;
}
bool CXspFile::ProcessSceneFiles(CCatFile *catFile, CProgressInfo *progress)
{
// now lets parse our files
if ( progress ) progress->UpdateStatus(IMPORTSHIP_EXTRACTSCENE);
CyStringList *lModels = this->ReadSceneModels();
if ( !lModels )
return false;
// extract componants, and add extra items to list
if ( !this->ProcessSceneFileSection(IMPORTSHIP_COMPONANT, catFile, lModels, progress) )
return false;
//lets first find any model files
if ( !this->ProcessSceneFileSection(IMPORTSHIP_MODELS, catFile, lModels, progress) )
return false;
// extract the dummies
if ( !this->ProcessSceneFileSection(IMPORTSHIP_DUMMIES, catFile, lModels, progress) )
return false;
// extract the textures
if ( !this->ProcessSceneFileSection(IMPORTSHIP_TEXTURES, catFile, lModels, progress) )
return false;
// extract the text file entries
if ( !this->ProcessSceneFileSection(IMPORTSHIP_TEXTS, catFile, lModels, progress) )
return false;
// extract the bodies entries
if ( !this->ProcessSceneFileSection(IMPORTSHIP_BODIES, catFile, lModels, progress) )
return false;
// extract the cockpit entries
if ( !this->ProcessSceneFileSection(IMPORTSHIP_COCKPITS, catFile, lModels, progress) )
return false;
delete lModels;
return true;
}
bool CXspFile::ProcessSceneFiles(CyString catFile, CProgressInfo *progress)
{
CCatFile cat;
if ( cat.Open(catFile, "", CATREAD_CATDECRYPT, false) == CATERR_NONE )
return ProcessSceneFiles(&cat, progress);
return false;
}
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("bob") )
{
if ( f->PCKFile() )
f->ChangeFileExt("pbb");
}
}
}
}
void CXspFile::AdjustCockpits()
{
for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
{
SCockpit *c = node->Data();
if ( c->iIndex < 0 )
continue;
CyString id = c->sCockpit.GetToken(";", 19, 19);
for ( int i = 0; i < 6; i++ )
{
CyString tId = m_sData.token(";", 32 + (i * 2));
if ( tId.IsNumber() && tId.ToInt() == c->iIndex )
m_sData = m_sData.replaceToken(";", 32 + (i * 2), (id + "(" + CyString::Number(c->iIndex) + ")").c_str());
}
}
}
CyString CXspFile::FormatShipData(CyStringList *cockpits, int *text, int game)
{
CyString data = (game == GAME_X3) ? this->GetX3ShipData() : this->GetTCShipData();
// do turrets
for ( int t = 0; t < 6; t++ )
{
int oldPos = 0;
CyString turret = data.GetToken(";", 32 + (t * 2), 32 + (t * 2));
if ( !turret.IsNumber() )
{
if ( turret.IsIn("(") )
{
oldPos = turret.GetToken("(", 2).GetToken(")", 1, 1).ToInt();
turret = turret.GetToken("(", 1, 1);
}
int pos = cockpits->FindStringPos(turret);
if ( pos < 0 ) pos = oldPos;
data = data.RepToken(";", 32 + (t * 2), CyString::Number(pos));
}
}
// adjust the weapons
int mask = this->GetLaserMask(game - 1);
if ( mask != -1 )
data = data.RepToken(";", 19, CyString::Number(mask));
mask = this->GetMissileMask(game - 1);
if ( mask != -1 )
data = data.RepToken(";", 25, CyString::Number(mask));
// fix the ship text
if ( m_iOrgDesc > 0 )
(*text) = m_iOrgDesc;
data = data.RepToken(";", 7, CyString::Number(*text));
// add the ware id
data.RemoveChar(9);
data.RemoveEndSpace();
// remove the end ;
while ( data.Right(1) == ";" ) data.Truncate((int)data.Length() - 1);
data = data.RepToken(";", data.NumToken(";"), this->GetShipID());
if ( data.Right(1) != ";" )
data += ";";
return data;
}