Subversion Repositories spk

Rev

Rev 98 | Rev 108 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 cycrow 1
#include "XspFile.h"
2
#include "File_IO.h"
3
#include "Packages.h"
4
#include "CatFile.h"
5
 
6
CXspFile::CXspFile () : CBaseFile()
7
{
8
	SetDefaults ();
9
}
10
 
11
void CXspFile::Delete ()
12
{
13
	CBaseFile::Delete();
14
	m_pSceneFile = m_pCockpitFile = NULL;
15
 
16
	// delete lists
17
	m_lMissileMasks.MemoryClear();
18
	m_lWeaponMasks.MemoryClear();
19
 
20
	m_lMissileMasks.destroy();
21
	m_lWeaponMasks.destroy();
22
 
23
	for ( CListNode<SCockpit> *n = m_lCockpit.Front(); n; n = n->next() )
24
		n->Data()->lWeaponMask.MemoryClear();
25
	m_lCockpit.MemoryClear();
26
	m_lCockpit.destroy();
27
	m_lCutData.Clear();
28
	m_lBodies.Clear();
29
}
30
 
31
void CXspFile::SetDefaults ()
32
{
33
	CBaseFile::SetDefaults ();
34
 
35
	m_pSceneFile = m_pCockpitFile = NULL;
36
	m_bLanguageText = m_bExistingShip = false;
37
	m_iOrgDesc = 0;
38
 
39
	m_iShipyard = SHIPYARD_NONE;
40
}
41
 
39 cycrow 42
void CXspFile::AddText ( int id, const Utils::String &name, const Utils::String &desc )
1 cycrow 43
{
44
	// first check if theres an existing id
45
	SText *newtext = NULL;
46
	for ( SText *t = m_lText.First(); t; t = m_lText.Next() )
47
	{
48
		if ( t->iId == id )
49
		{
50
			newtext = t;
51
			break;
52
		}
53
	}
54
 
55
	if ( !newtext )
56
	{
57
		newtext = new SText;
58
		newtext->iId = id;
59
		m_lText.push_back ( newtext );
60
	}
61
 
62
	newtext->sName = name;
63
	newtext->sDesc = desc;
64
 
50 cycrow 65
	_changed();
1 cycrow 66
}
67
 
68
void CXspFile::RemoveText(int id)
69
{
70
	for ( SText *t = m_lText.First(); t; t = m_lText.Next() )
71
	{
72
		if ( t->iId == id )
73
		{
50 cycrow 74
			_changed();
1 cycrow 75
			m_lText.RemoveCurrent();
76
			return;
77
		}
78
	}
79
}
80
 
39 cycrow 81
void CXspFile::AddDummy ( const Utils::String &section, const Utils::String &data )
1 cycrow 82
{
83
	SDummy *d = new SDummy;
84
	d->sData = data;
85
	d->sSection = section;
86
 
39 cycrow 87
	if ( d->sData.right(1) != ";" )
1 cycrow 88
		d->sData += ";";
89
 
90
	m_lDummy.push_back ( d );
91
 
50 cycrow 92
	_changed();
1 cycrow 93
}
94
 
39 cycrow 95
void CXspFile::AddComponent ( const Utils::String &section, const Utils::String &section2, const Utils::String &data )
1 cycrow 96
{
97
	SComponent *c = new SComponent;
98
	c->sData = data;
99
	c->sSection = section;
100
	c->sSection2 = section2;
101
 
39 cycrow 102
	if ( c->sData.right(1) != ";" )
1 cycrow 103
		c->sData += ";";
104
 
105
	m_lComponent.push_back ( c );
106
 
50 cycrow 107
	_changed();
1 cycrow 108
}
109
 
110
void CXspFile::AddWeaponMask ( int game, int mask )
111
{
112
	// first check if we have one for the game
113
	SWeaponMask *m = NULL;
114
	for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
115
	{
116
		if ( node->Data()->iGame == game )
117
		{
118
			m = node->Data();
119
			break;
120
		}
121
	}
122
 
123
	// not found, create one
124
	if ( !m )
125
	{
126
		m = new SWeaponMask;
127
		m_lWeaponMasks.push_back(m);
128
		m->iGame = game;
129
	}
130
 
131
	m->iMask = mask;
50 cycrow 132
	_changed();
1 cycrow 133
}
134
void CXspFile::AddMissileMask ( int game, int mask )
135
{
136
	// first check if we have one for the game
137
	SWeaponMask *m = NULL;
138
	for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
139
	{
140
		if ( node->Data()->iGame == game )
141
		{
142
			m = node->Data();
143
			break;
144
		}
145
	}
146
 
147
	// not found, create one
148
	if ( !m )
149
	{
150
		m = new SWeaponMask;
151
		m_lMissileMasks.push_back(m);
152
		m->iGame = game;
153
	}
154
 
155
	m->iMask = mask;
50 cycrow 156
	_changed();
1 cycrow 157
}
158
 
159
bool CXspFile::IsValid ()
160
{
50 cycrow 161
	if ( this->name().empty() )
1 cycrow 162
		return false;
50 cycrow 163
	if ( this->author().empty() )
1 cycrow 164
		return false;
165
 
166
	return true;
167
}
168
 
14 cycrow 169
Utils::String CXspFile::CreateValuesLine() const
1 cycrow 170
{
14 cycrow 171
	Utils::String values = CBaseFile::CreateValuesLine ();
1 cycrow 172
 
14 cycrow 173
	values += "Data: " + m_sData + "\n";
174
	values += "ID: " + m_sID + "\n";
1 cycrow 175
 
176
	if ( m_bLanguageText )
177
		values += "LanguageText\n";
178
	if ( m_bExistingShip )
179
		values += "ExistingShip\n";
14 cycrow 180
	values += Utils::String("OrgDesc: ") + (long)m_iOrgDesc + "\n";
181
	values += Utils::String("Shipyard: ") + (long)m_iShipyard + "\n";
1 cycrow 182
 
14 cycrow 183
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() ) {
184
		SCockpit *cockpit = node->Data();
185
		values += Utils::String("CockpitNew: ") + (long)cockpit->lWeaponMask.size();
186
		for ( CListNode<SWeaponMask> *wNode = cockpit->lWeaponMask.Front(); wNode; wNode = wNode->next() ) {
1 cycrow 187
			values += ":";
14 cycrow 188
			values += (long)wNode->Data()->iGame;
1 cycrow 189
			values += ":";
14 cycrow 190
			values += (long)wNode->Data()->iMask;
1 cycrow 191
		}
192
		values += " ";
39 cycrow 193
		values += cockpit->sCockpit + "\n";
1 cycrow 194
	}
195
 
14 cycrow 196
	for ( CListNode<SText> *tNode = m_lText.Front(); tNode; tNode = tNode->next() )
39 cycrow 197
		values += Utils::String("Text: ") + (long)tNode->Data()->iId + "|" + tNode->Data()->sName.findReplace("|", "<::PiPe::>") + "|" + tNode->Data()->sDesc + "\n";
1 cycrow 198
 
14 cycrow 199
	for ( CListNode<SComponent> *cNode = m_lComponent.Front(); cNode; cNode = cNode->next() )
39 cycrow 200
		values += "Component: " + cNode->Data()->sData.findReplace("|", "<::PiPe::>") + "|" + cNode->Data()->sSection.findReplace("|", "<::PiPe::>") + "|" + cNode->Data()->sSection2 + "\n";
1 cycrow 201
 
14 cycrow 202
	for ( CListNode<SDummy> *dNode = m_lDummy.Front(); dNode; dNode = dNode->next() )
39 cycrow 203
		values += "Dummy: " + dNode->Data()->sData.findReplace("|", "<::PiPe::>") + "|" + dNode->Data()->sSection + "\n";
1 cycrow 204
 
14 cycrow 205
	for ( CListNode<SWeaponMask> *wNode = m_lWeaponMasks.Front(); wNode; wNode = wNode->next() )
206
		values += Utils::String("WeaponMask: ") + (long)wNode->Data()->iGame + " " + (long)wNode->Data()->iMask + "\n";
207
	for ( CListNode<SWeaponMask> *mNode = m_lMissileMasks.Front(); mNode; mNode = mNode->next() )
208
		values += Utils::String("MissileMask: ") + (long)mNode->Data()->iGame + " " + (long)mNode->Data()->iMask + "\n";
1 cycrow 209
	for ( SStringList *cut = m_lCutData.Head(); cut; cut = cut->next )
14 cycrow 210
		values += Utils::String("CutData: ") + cut->str.ToString() + "\n";
1 cycrow 211
	for ( SStringList *body = m_lBodies.Head(); body; body = body->next )
14 cycrow 212
		values += Utils::String("Bodies: ") + body->str.ToString() + "\n";
1 cycrow 213
	for ( SStringList *ani = m_lAnimations.Head(); ani; ani = ani->next )
14 cycrow 214
		values += Utils::String("Animations: ") + ani->str.ToString() + "\n";
1 cycrow 215
 
216
	return values;
217
}
218
 
14 cycrow 219
bool CXspFile::ParseValueLine(const Utils::String &sLine)
1 cycrow 220
{
14 cycrow 221
	Utils::String first = sLine.token(":", 1);
222
	Utils::String rest  = sLine.tokens(":", 2).removeFirstSpace();
1 cycrow 223
 
14 cycrow 224
	if ( first.Compare("Data") )
1 cycrow 225
		m_sData = rest;
14 cycrow 226
	else if ( first.Compare("ID") )
1 cycrow 227
		m_sID = rest;
14 cycrow 228
	else if ( sLine.Compare("LanguageText") )
1 cycrow 229
		m_bLanguageText = true;
14 cycrow 230
	else if ( sLine.Compare("ExistingShip") )
1 cycrow 231
		m_bExistingShip = true;
14 cycrow 232
	else if ( first.Compare("OrgDesc") || first.Compare("OriginalDesc") )
233
		m_iOrgDesc = rest;
234
	else if ( first.Compare("Shipyard") )
235
		m_iShipyard = rest;
236
	else if ( first.Compare("CutData") )
1 cycrow 237
		this->AddCutData(rest);
14 cycrow 238
	else if ( first.Compare("Bodies") )
1 cycrow 239
		this->AddBodies(rest);
14 cycrow 240
	else if ( first.Compare("Animations") )
1 cycrow 241
		this->AddAnimation(rest);
14 cycrow 242
	else if ( first.Compare("Cockpit") )
1 cycrow 243
		this->AddCockpit(rest, 0);
14 cycrow 244
	else if ( first.Compare("CockpitNew") )
1 cycrow 245
	{
14 cycrow 246
		Utils::String cockpit = rest.tokens(" ", 2);
247
		Utils::String sMasks = rest.token(" ", 1);
1 cycrow 248
		this->AddCockpit(cockpit, 0, -1);
14 cycrow 249
		int num = sMasks.token(":", 1);
1 cycrow 250
		for ( int i = 0; i < num; i++ )
251
		{
14 cycrow 252
			int mask = sMasks.token(":", ((i + 1) * 2) + 1);
253
			int game = sMasks.token(":", ((i + 1) * 2));
1 cycrow 254
			this->AddCockpit(cockpit, game, mask);
255
		}
256
	}
49 cycrow 257
	else if ( first == "Web" )	this->setWebSite(rest);
1 cycrow 258
	else if ( first.Compare("WeaponMask") )
14 cycrow 259
		this->AddWeaponMask(rest.token(" ", 1), rest.token(" ", 2));
1 cycrow 260
	else if ( first.Compare("MissileMask") )
14 cycrow 261
		this->AddMissileMask(rest.token(" ", 1), rest.token(" ", 2));
1 cycrow 262
	else if ( first == "Text" )
263
	{
264
		SText *text = new SText;
14 cycrow 265
		text->iId = rest.token("|", 1);
266
		text->sName = rest.token("|", 2);
39 cycrow 267
		text->sName = text->sName.findReplace("<::PiPe::>", "|");
14 cycrow 268
		text->sDesc = rest.tokens( "|", 3);
1 cycrow 269
		m_lText.push_back ( text );
270
	}
271
	else if ( first == "Component" )
272
	{
273
		SComponent *c = new SComponent;
14 cycrow 274
		c->sData = rest.token("|", 1);
39 cycrow 275
		c->sData = c->sData.findReplace ("<::PiPe::>", "|");
14 cycrow 276
		c->sSection = rest.token("|", 2);
39 cycrow 277
		c->sSection = c->sSection.findReplace ("<::PiPe::>", "|");
14 cycrow 278
		c->sSection2 = rest.tokens("|", 3);
1 cycrow 279
		m_lComponent.push_back ( c );
280
	}
281
	else if ( first == "Dummy" )
282
	{
283
		SDummy *d = new SDummy;
14 cycrow 284
		d->sData = rest.token("|", 1);
39 cycrow 285
		d->sData = d->sData.findReplace ("<::PiPe::>", "|");
14 cycrow 286
		d->sSection = rest.tokens( "|", 2);
1 cycrow 287
		m_lDummy.push_back ( d );
288
	}
48 cycrow 289
	else if ( first == "Comment" )	this->setDescription(rest.findReplace("<newline>", "<br>"));
1 cycrow 290
	else
14 cycrow 291
		return CBaseFile::ParseValueLine(sLine);
1 cycrow 292
 
293
	return true;
294
}
295
 
39 cycrow 296
Utils::String CXspFile::GetShipName(int lang)
1 cycrow 297
{
39 cycrow 298
	Utils::String name;
1 cycrow 299
	if ( (m_bLanguageText) && (lang) )
300
	{
301
		for ( SText *text = m_lText.First(); text; text = m_lText.Next() )
302
		{
303
			if ( text->iId == lang )
304
			{
305
				name = text->sName;
306
				break;
307
			}
308
		}
309
	}
310
 
39 cycrow 311
	if ( name.empty() )
312
		name = GetLanguageName(lang).ToString();
1 cycrow 313
 
314
	return name;
315
}
316
 
39 cycrow 317
//TODO: split this up
318
bool CXspFile::ConvertOld(const Utils::String &file)
1 cycrow 319
{
320
	// open the file
321
	FILE *id = fopen(file.c_str(), "rb");
322
	if ( !id )
323
		return false;
324
 
325
	// read to memory
326
	fseek(id, 0, SEEK_END);
327
	size_t size = ftell(id);
328
	fseek(id, 0, SEEK_SET);
329
	unsigned char *data = new unsigned char[size + 1];
330
	fread(data, sizeof(unsigned char), size, id);
331
	data[size] = '\0';
332
	fclose(id);
333
 
334
	// uncompress the file
335
	size_t len;
336
	unsigned char *compr = LZMADecode_C ( data, size, &len, NULL );
337
 
338
	delete data;
339
 
340
	if ( !compr )
341
		return false;
342
 
343
	this->Delete();
344
	this->SetDefaults();
345
 
346
	// now read the data line by line
347
	size_t pos = 0;
348
	size_t start = 0;
349
	int packageVersion = 0;
350
	while ( pos < len )
351
	{
352
		while ( compr[pos++] != '\n' && pos < len );
353
 
354
		compr[pos - 1] = '\0';
39 cycrow 355
		Utils::String line = (char *)(compr + start);
1 cycrow 356
		start = pos;
39 cycrow 357
		if ( line.empty() )
1 cycrow 358
			continue;
39 cycrow 359
		Utils::String first = line.token(":", 1);
360
		Utils::String rest = line.tokens(":", 2);
361
		rest = rest.removeFirstSpace();
1 cycrow 362
 
363
		// now check each line
364
		if ( first.Compare("Packager") )
39 cycrow 365
			packageVersion = rest;
1 cycrow 366
		else if ( first.Compare("Shipyard") )
367
		{
368
			int max;
39 cycrow 369
			Utils::String *strs = rest.tokenise(";", &max);
1 cycrow 370
			if ( strs && max )
371
			{
372
				int cur = 1;
373
				for ( int i = 0; i < max; i++, cur *= 2 )
374
				{
375
					if ( strs[i] == "1" )
376
						this->AddShipyard(cur);
377
				}
378
			}
379
			CLEANSPLIT(strs, max)
380
		}
381
		else if ( first.Compare("ScreenShot") )
382
		{
39 cycrow 383
			int size = rest.token(" ", 1);
384
			Utils::String ext = rest.token(" ", 2);
1 cycrow 385
 
39 cycrow 386
			C_File *newFile = this->AddFile(m_sID + "_" + (long)(this->CountFiles(FILETYPE_SCREEN) + 1) + "." + ext, "", FILETYPE_SCREEN);
1 cycrow 387
			newFile->ReadFromData((char *)(compr + pos), size); 
388
 
389
			start += (size + 1);
390
		}
391
		else if ( first.Compare("SceneFile") )
392
		{
39 cycrow 393
			Utils::String file = rest.tokens(" ", 3);
102 cycrow 394
			m_pSceneFile = this->AddFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_SHIPSCENE);
39 cycrow 395
			m_pSceneFile->SetCreationTime((long)rest.token(" ", 1));
396
			m_pSceneFile->ReadFromData((char *)(compr + pos), rest.token(" ", 2));
1 cycrow 397
 
398
			start += m_pSceneFile->GetDataSize();
399
		}
400
		else if ( first.Compare("CockpitFile") )
401
		{
39 cycrow 402
			Utils::String file = rest.tokens(" ", 3);
102 cycrow 403
			m_pCockpitFile = this->AddFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_COCKPITSCENE);
39 cycrow 404
			m_pCockpitFile->SetCreationTime((long)rest.token(" ", 1));
405
			m_pCockpitFile->ReadFromData((char *)(compr + pos), rest.token(" ", 2));
1 cycrow 406
 
407
			start += m_pCockpitFile->GetDataSize();
408
		}
409
		else if ( first.Compare("Model") )
410
		{
39 cycrow 411
			Utils::String file = rest.tokens(" ", 3);
102 cycrow 412
			C_File *newFile= this->AddFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_SHIPMODEL);
39 cycrow 413
			newFile->SetCreationTime((long)rest.token(" ", 1));
414
			newFile->ReadFromData((char *)(compr + pos), rest.token(" ", 2));
1 cycrow 415
 
416
			start += (newFile->GetDataSize() + 1);
417
		}
418
		else if ( first.Compare("Files") )
419
		{
39 cycrow 420
			Utils::String file = rest.tokens(" ", 3);
1 cycrow 421
 
422
			C_File *newFile = NULL;
423
			int special = 0;
424
			if ( file.Compare("types/CutData.txt") || file.Compare("types/CutData.pck") )
425
			{
39 cycrow 426
				newFile = new C_File(CyString(file));
1 cycrow 427
				special = 1;
428
			}
429
			else if ( file.Compare("types/Bodies.txt") || file.Compare("types/Bodies.pck") )
430
			{
39 cycrow 431
				newFile = new C_File(CyString(file));
1 cycrow 432
				special = 2;
433
			}
434
			else if ( file.Compare("types/Animations.txt") || file.Compare("types/Animations.pck") )
435
			{
39 cycrow 436
				newFile = new C_File(CyString(file));
1 cycrow 437
				special = 3;
438
			}
439
			else
440
			{
102 cycrow 441
				newFile = this->AddFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_SHIPOTHER);
39 cycrow 442
				newFile->SetCreationTime((long)rest.token(" ", 1));
1 cycrow 443
			}
39 cycrow 444
			newFile->ReadFromData((char *)(compr + pos), rest.token(" ", 2));
1 cycrow 445
			start += (newFile->GetDataSize() + 1);
446
 
447
			if ( special )
448
			{
449
				if ( newFile->CheckFileExt("pck") )
450
					newFile->UnPCKFile();
451
 
452
				// read data into lines
453
				CyString data((const char *)newFile->GetData());
454
				data.RemoveChar('\r');
455
				int iLines;
456
				CyString *sLines = data.SplitToken("\n", &iLines);
457
 
458
				if ( sLines && iLines )
459
				{
460
					// cut data
461
					int entries = -1;
462
					if ( special == 1 )
463
					{
464
						CyStringList newLines;
465
						for ( int i = 0; i < iLines; i++ )
466
						{
467
							CyString line = sLines[i];
468
							line.RemoveChar(' ');
469
							line.RemoveChar(9);
470
							if ( line.Empty() || line[0] == '/' )
471
								continue;
472
							if ( entries == -1 )
473
							{
474
								entries	= line.GetToken(";", 1, 1).ToInt() - 36;
475
								if ( entries <= 0 )
476
									break;
477
							}
478
							else
479
							{
480
								int id = line.GetToken(";", 1, 1).ToInt();
481
								if ( id >= 9000 && id <= 9017 )
482
									continue;
483
 
484
								switch (id)
485
								{
486
									case 948:
487
									case 4111:
488
									case 4112:
489
									case 4064:
490
									case 4169:
491
									case 4178:
492
									case 4177:
493
									case 4163:
494
									case 4194:
495
									case 4162:
496
									case 4191:
497
									case 4200:
498
									case 4161:
499
									case 4097:
500
									case 4205:
501
									case 4206:
502
									case 4207:
503
									case 4107:
504
										break;
505
 
506
									default:
507
										newLines.PushBack(line);
508
								}
509
								if ( newLines.Count() == entries )
510
									break;
511
							}
512
						}
513
 
514
						for ( SStringList *strNode = newLines.Head(); strNode; strNode = strNode->next )
39 cycrow 515
							this->AddCutData(strNode->str.ToString());
1 cycrow 516
					}
517
					// bodies
518
					else if ( special == 2 )
519
					{
520
						entries = 0;
39 cycrow 521
						Utils::String section;
1 cycrow 522
						for ( int i = 0; i < iLines; i++ )
523
						{
39 cycrow 524
							Utils::String line = sLines[i].ToString();
525
							line.removeChar(' ');
526
							line.removeChar(9);
527
							if ( line.empty() || line[0] == '/' )
1 cycrow 528
								continue;
529
							if ( entries <= 0)
530
							{
39 cycrow 531
								section = line.token(";", 1);
532
								entries	= line.token(";", 2);
1 cycrow 533
							}
534
							else
535
							{
39 cycrow 536
								if ( !line.isin(";") )
1 cycrow 537
									continue;
39 cycrow 538
								if ( line.countToken(";") <= 2 )
1 cycrow 539
								{
39 cycrow 540
									this->AddBodies(section + ";" + line.token(";", 1) + ";");
1 cycrow 541
									--entries;
542
								}
543
								else
544
								{
545
									bool done = false;
546
									while (!done)
547
									{
548
										int num;
39 cycrow 549
										Utils::String *strs = line.tokenise(";", &num);
1 cycrow 550
										done = true;
551
										for ( int j = 0; j < num; j++ )
552
										{
553
											if ( !entries )
554
											{
39 cycrow 555
												line = line.tokens(";", j + 1);
556
												if ( !line.empty() )
1 cycrow 557
													done = false;
558
												break;
559
											}
560
 
39 cycrow 561
											if ( strs[j].empty() )
1 cycrow 562
												continue;
563
 
564
											this->AddBodies(section + ";" + strs[j] + ";");
565
											--entries;
566
										}
567
										//we must be at another section
568
										if ( !done )
569
										{
39 cycrow 570
											section = line.token(";", 1);
571
											entries	= line.token(";", 2);
572
											line = line.remToken(";", 1);
573
											line = line.remToken(";", 1);
1 cycrow 574
 
39 cycrow 575
											if (line.empty())
1 cycrow 576
												done = true;
577
										}
578
 
579
										CLEANSPLIT(strs, num)
580
									}									
581
								}
582
							}
583
						}
584
					}
585
					// animations
586
					else if ( special == 3 )
587
					{
588
						CyStringList in;
589
						for ( int i = 0; i < iLines; i++ )
590
						{
591
							CyString line = sLines[i];
592
							in.PushBack(line);
593
						}
594
 
595
						CyStringList out;
596
						if ( CXspFile::ReadAnimations(&in, &out, 87) )
597
							this->AddAnimation(&out);
598
					}
599
				}
600
				CLEANSPLIT(sLines, iLines)
601
				delete newFile;
602
			}
603
		}
604
		else if ( first.Compare("Script") )
605
		{
39 cycrow 606
			Utils::String file = rest.words(3);
1 cycrow 607
			C_File *newFile= this->AddFile(file, NullString, FILETYPE_SCRIPT);
39 cycrow 608
			newFile->SetCreationTime((long)rest.word(1));
609
			newFile->ReadFromData((char *)(compr + pos), rest.word(2));
1 cycrow 610
 
611
			start += (newFile->GetDataSize() + 1);
612
		}
613
		else if ( first.Compare("Text") )
39 cycrow 614
			this->AddText(rest.token(":", 1), rest.token(":", 2), rest.tokens(":", 3));
1 cycrow 615
		else if ( first.Compare("Component") )
39 cycrow 616
			this->AddComponent(rest.token(";", 1), rest.token(";", 2), rest.tokens(";", 3));
1 cycrow 617
		else if ( first.Compare("Dummy") )
618
		{
619
			SDummy *d = new SDummy;
39 cycrow 620
			d->sData = rest.tokens(";", 2);
621
			d->sSection = rest.token(";", 1);
1 cycrow 622
			m_lDummy.push_back ( d );
623
		}
39 cycrow 624
		else if ( !this->ParseValueLine(line) )
1 cycrow 625
		{
626
		//	printf ( "Command: %s, Rest: %s\n", first.c_str(), rest.c_str());
627
		}
628
 
629
		pos = start;
630
	}
631
 
632
	// assume all old ones are for X3
14 cycrow 633
	if ( !m_sData.empty() )
1 cycrow 634
	{
14 cycrow 635
		this->AddWeaponMask(GAME_X3 - 1, m_sData.token(";", 19));
636
		this->AddMissileMask(GAME_X3 - 1, m_sData.token(";", 25));
1 cycrow 637
	}
638
 
639
	return true;
640
}
641
 
642
 
643
int GetMaxShipyards() { return (int)SHIPYARD_MAX; }
644
 
39 cycrow 645
Utils::String GetShipyardName (int s)
1 cycrow 646
{
647
	switch (s)
648
	{
649
		case SHIPYARD_ARGON:
650
			return "Argon";
651
		case SHIPYARD_BORON:
652
			return "Boron";
653
		case SHIPYARD_PARANID:
654
			return "Paranid";
655
		case SHIPYARD_SPLIT:
656
			return "Split";
657
		case SHIPYARD_TELADI:
658
			return "Teladi";
659
		case SHIPYARD_PIRATES:
660
			return "Pirates";
661
		case SHIPYARD_FRIEND:
662
			return "Friendly";
663
		case SHIPYARD_XENON:
664
			return "Xenon";
665
		case SHIPYARD_TERRAN:
666
			return "Terran";
667
	}
668
 
669
	return "Unknown";
670
}
671
 
52 cycrow 672
bool CXspFile::WriteHeader(CFileIO &file, int valueheader, int valueComprLen)
1 cycrow 673
{
52 cycrow 674
	return file.write("XSPCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen);
1 cycrow 675
}
676
 
14 cycrow 677
bool CXspFile::CheckHeader(const Utils::String header) const
1 cycrow 678
{
679
	if ( header.Compare("XSPCycrow") )
680
		return true;
681
	return false;
682
}
683
 
684
void CXspFile::SetLaserMask(int game, int mask)
685
{
686
	for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
687
	{
688
		SWeaponMask *m = node->Data();
689
		if ( m->iGame == game )
690
		{
691
			m->iMask = mask;
692
			return;
693
		}
694
	}
695
 
696
	// no found, need to add it
697
	this->AddWeaponMask(game, mask);
698
}
699
 
700
void CXspFile::SetMissileMask(int game, int mask)
701
{
702
	for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
703
	{
704
		SWeaponMask *m = node->Data();
705
		if ( m->iGame == game )
706
		{
707
			m->iMask = mask;
708
			return;
709
		}
710
	}
711
 
712
	// no found, need to add it
713
	this->AddMissileMask(game, mask);
714
}
715
int CXspFile::GetLaserMask(int game, bool getOnly)
716
{
717
	int mask = -1;
718
	for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
719
	{
720
		SWeaponMask *m = node->Data();
721
		if ( m->iGame == game )
722
			return m->iMask;
723
 
724
		if ( !mask && !getOnly )
725
			mask = m->iMask;
726
	}
727
 
728
	return mask;
729
}
730
 
731
int CXspFile::GetMissileMask(int game, bool getOnly)
732
{
733
	int mask = -1;
734
	for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
735
	{
736
		SWeaponMask *m = node->Data();
737
		if ( m->iGame == game )
738
			return m->iMask;
739
 
740
		if ( !mask && !getOnly )
741
			mask = m->iMask;
742
	}
743
 
744
	return mask;
745
}
746
 
39 cycrow 747
Utils::String CXspFile::GetShipClass()
1 cycrow 748
{
14 cycrow 749
	if ( !m_sData.empty() )
750
		return m_sData.token(";", TSHIPPOS_CLASS);
1 cycrow 751
	return "OBJ_SHIP_M5";
752
}
753
 
754
bool CXspFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile)
755
{
756
	if ( !CBaseFile::GeneratePackagerScript(wildcard, list, datafile) )
757
		return false;
758
 
98 cycrow 759
	list->PushBack("# File Type, Script or Ship");
760
	list->PushBack("FileType: Ship");
761
	list->PushBack("");
762
 
1 cycrow 763
	if ( m_iShipyard )
764
	{
765
		list->PushBack("# Shipyards, Set which shipyards to add ships for sale to");
766
		for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 )
767
		{
768
			if ( this->IsShipyard(i) )
769
				list->PushBack(CyString("Shipyard: ") + GetShipyardName(i));
770
		}
771
		list->PushBack("");
772
	}
773
 
774
	if ( m_iOrgDesc > 0 )
775
	{
776
		list->PushBack("# Use Original Description, overrides text entrys to use one of the built in text");
777
		list->PushBack(CyString("OriginalDescription: ") + (long)m_iOrgDesc);
778
		list->PushBack("");
779
	}
780
 
14 cycrow 781
	if ( !m_sID.empty() )
1 cycrow 782
	{
783
		list->PushBack("# Ship ID, the ship id to identify the ship as");
784
		list->PushBack(CyString("ShipID: ") + m_sID);
785
	}
786
 
14 cycrow 787
	if ( !m_sData.empty() )
1 cycrow 788
	{
789
		list->PushBack("# Ship Data, the TShip data entry to add to the game (parts of this are adjusted and auto generated by the installer)");
790
		list->PushBack(CyString("ShipData: ") + m_sData);
791
		list->PushBack("");
792
	}
793
 
794
	if ( m_bExistingShip )
795
	{
796
		list->PushBack("# Existing Ship, replaces an existing ship in the game with ship package instead of creating a new entry");
797
		list->PushBack("ExistingShip");
798
		list->PushBack("");
799
	}
800
 
801
	if ( !datafile )
802
	{
803
		if ( !CBaseFile::GeneratePackagerScriptFile(wildcard, list) )
804
			return false;
805
	}
806
 
807
	return true;
808
}
809
 
98 cycrow 810
bool CXspFile::LoadPackageData(const Utils::String &sFirst, const Utils::String &sRest, const Utils::String &sMainGame, Utils::CStringList &otherGames)
1 cycrow 811
{
14 cycrow 812
	if ( sFirst.Compare("Shipyard") )
1 cycrow 813
	{
814
		for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 )
815
		{
39 cycrow 816
			if ( sRest.Compare(GetShipyardName(i)) )
1 cycrow 817
			{
818
				this->AddShipyard(i);
819
				break;
820
			}
821
		}
822
	}
14 cycrow 823
	else if ( sFirst.Compare("OriginalDescription") )
824
		m_iOrgDesc = sRest;
825
	else if ( sFirst.Compare("ShipData") )
826
		m_sData = sRest;
827
	else if ( sFirst.Compare("ReadData") ) // read data from a tships file
1 cycrow 828
	{
829
		CPackages p;
14 cycrow 830
		m_sData = p.ReadShipData(sRest.tokens(" ", 2), sRest.token(" ", 1)).ToString();
1 cycrow 831
	}
14 cycrow 832
	else if ( sFirst.Compare("ExistingShip") )
1 cycrow 833
		m_bExistingShip = true;
14 cycrow 834
	else if ( sFirst.Compare("ShipID") )
835
		m_sID = sRest;
98 cycrow 836
	else if ( !CBaseFile::LoadPackageData(sFirst, sRest, sMainGame, otherGames) )
1 cycrow 837
	{
838
		return false;
839
	}
840
 
841
	return true;
842
}
843
 
844
 
39 cycrow 845
Utils::String CXspFile::GetX3ShipData()
1 cycrow 846
{
39 cycrow 847
	Utils::String data = m_sData;
1 cycrow 848
 
849
	// change the ship subtype, Reunion uses number, TC uses a define
39 cycrow 850
	Utils::String sSubType = data.token(";", 6);
851
	if ( !((long)sSubType) && sSubType != "0" )
852
		data = data.replaceToken(";", 6, (long)CShipData::ConvertShipSubType(CyString(sSubType)));
1 cycrow 853
 
39 cycrow 854
	Utils::String sClass = data.token(";", TSHIPPOS_CLASS);
855
	if ( !((long)sClass) && sClass != "0" )
1 cycrow 856
	{
857
		int num = 0;
858
		for ( int i = 0; i < OBJ_SHIP_MAX; i++ )
859
		{
94 cycrow 860
			if ( sClass.Compare(CShipData::ConvertShipClass(CShipData::GetShipClassFromNum(i))) )
1 cycrow 861
			{
862
				num = i;
863
				break;
864
			}
865
		}
866
 
39 cycrow 867
		data = data.replaceToken(";", TSHIPPOS_CLASS, (long)num);
1 cycrow 868
	}
869
 
870
	return data;
871
}
872
 
39 cycrow 873
Utils::String CXspFile::GetTCShipData()
1 cycrow 874
{
39 cycrow 875
	Utils::String data = m_sData;
1 cycrow 876
 
39 cycrow 877
	Utils::String sSubType = data.token(";", 6);
878
	if ( ((long)sSubType) || sSubType == "0" )
879
		data = data.replaceToken(";", 6, CShipData::ConvertShipSubType((long)sSubType).ToString());
1 cycrow 880
 
39 cycrow 881
	Utils::String sClass = data.token(";", TSHIPPOS_CLASS);
882
	if ( ((long)sClass) || sClass == "0" )
94 cycrow 883
		data = data.replaceToken(";", TSHIPPOS_CLASS, CShipData::ConvertShipClass((long)sClass));
1 cycrow 884
 
885
	return data;
886
}
887
 
39 cycrow 888
bool CXspFile::RemoveCockpit(const Utils::String &sCockpitId)
1 cycrow 889
{
39 cycrow 890
	Utils::String cockpitid = sCockpitId;
1 cycrow 891
	// if its a whole line, just get the end
39 cycrow 892
	if ( cockpitid.isin(";") )
1 cycrow 893
	{
39 cycrow 894
		cockpitid = cockpitid.tokens(";", -2);
895
		while ( cockpitid.right(1) == ";" )
896
			cockpitid.truncate(-1);
1 cycrow 897
	}
898
 
899
	bool ret = false;
900
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
901
	{
39 cycrow 902
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 903
		if ( id.Compare(cockpitid) )
904
		{
905
			node->DeleteData();
906
			ret = true;
907
			break;
908
		}
909
	}
910
 
911
	m_lCockpit.RemoveEmpty();
912
 
913
	return ret;
914
}
915
 
39 cycrow 916
bool CXspFile::RemoveComponent(const Utils::String &section1, const Utils::String &section2, const Utils::String &data)
1 cycrow 917
{
918
	bool ret = false;
919
	for ( CListNode<SComponent> *node = m_lComponent.Front(); node; node = node->next() )
920
	{
921
		if ( node->Data()->sSection.Compare(section1) && node->Data()->sSection2.Compare(section2) && node->Data()->sData.Compare(data) )
922
		{
923
			ret = true;
924
			node->DeleteData();
925
			break;
926
		}
927
	}
928
	m_lComponent.RemoveEmpty();
929
	return ret;
930
}
931
 
39 cycrow 932
bool CXspFile::RemoveDummy(const Utils::String &section, const Utils::String &data)
1 cycrow 933
{
934
	bool ret = false;
935
	for ( CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next() )
936
	{
937
		if ( node->Data()->sSection.Compare(section) && node->Data()->sData.Compare(data) )
938
		{
939
			ret = true;
940
			node->DeleteData();
941
			break;
942
		}
943
	}
944
	m_lDummy.RemoveEmpty();
945
 
946
	return ret;
947
}
948
 
39 cycrow 949
Utils::String CXspFile::GetCockpitData(const Utils::String &cid)
1 cycrow 950
{
951
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
952
	{
39 cycrow 953
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 954
		if ( id.Compare(cid) )
955
			return node->Data()->sCockpit;
956
	}
957
 
39 cycrow 958
	return "";
1 cycrow 959
}
960
 
39 cycrow 961
SCockpit *CXspFile::FindCockpit(const Utils::String &cid)
1 cycrow 962
{
963
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
964
	{
39 cycrow 965
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 966
		if ( id.Compare(cid) )
967
			return node->Data();
968
	}
969
 
970
	return NULL;
971
}
972
 
39 cycrow 973
void CXspFile::EditCockpit(const Utils::String &cid, const Utils::String &cockpit)
1 cycrow 974
{
975
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
976
	{
39 cycrow 977
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 978
		if ( id.Compare(cid) )
979
		{
980
			node->Data()->sCockpit = cockpit;
981
			break;
982
		}
983
	}
984
}
985
 
39 cycrow 986
void CXspFile::EditCockpit(const Utils::String &cid, const Utils::String &scene, int mask)
1 cycrow 987
{
988
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
989
	{
39 cycrow 990
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 991
		if ( id.Compare(cid) )
992
		{
39 cycrow 993
			Utils::String cockpit = node->Data()->sCockpit;
994
			cockpit = cockpit.replaceToken(";", 8, scene);
995
			cockpit = cockpit.replaceToken(";", 9, (long)mask);
1 cycrow 996
			node->Data()->sCockpit = cockpit;
997
			break;
998
		}
999
	}
1000
}
39 cycrow 1001
void CXspFile::NewCockpit(const Utils::String &id, const Utils::String &scene, int mask)
1 cycrow 1002
{
39 cycrow 1003
	Utils::String cockpit = "0;0;0;0;0;0;0;";
1 cycrow 1004
	cockpit += scene + ";";
39 cycrow 1005
	cockpit += (long)mask;
1 cycrow 1006
	cockpit += ";0;0;0;0;0;0;-100000;0;0;";
1007
	cockpit += id + ";";
1008
	this->AddCockpit(cockpit, -1);
1009
}
1010
 
39 cycrow 1011
bool CXspFile::RemoveCutData(const Utils::String &cut)
1 cycrow 1012
{
1013
	bool ret = false;
1014
	for ( SStringList *str = m_lCutData.Head(); str; str = str->next )
1015
	{
39 cycrow 1016
		if ( str->str.GetToken(";", 1, 1).Compare(CyString(cut.token(";", 1))) )
1 cycrow 1017
		{
1018
			ret = true;
1019
			str->remove = true;
1020
			break;
1021
		}
1022
	}
1023
 
1024
	m_lCutData.RemoveMarked();
1025
 
1026
	return ret;
1027
}
1028
 
39 cycrow 1029
bool CXspFile::RemoveBodies(const Utils::String &cut)
1 cycrow 1030
{
1031
	bool ret = false;
1032
	for ( SStringList *str = m_lBodies.Head(); str; str = str->next )
1033
	{
39 cycrow 1034
		if ( str->str.Remove(' ').Compare(CyString(cut.remove(' '))) )
1 cycrow 1035
		{
1036
			ret = true;
1037
			str->remove = true;
1038
			break;
1039
		}
1040
	}
1041
 
1042
	m_lBodies.RemoveMarked();
1043
 
1044
	return ret;
1045
}
1046
 
39 cycrow 1047
bool CXspFile::RemoveAnimation(const Utils::String &cut)
1 cycrow 1048
{
1049
	bool ret = false;
1050
	for ( SStringList *str = m_lAnimations.Head(); str; str = str->next )
1051
	{
39 cycrow 1052
		if ( str->str.Remove(' ').Remove('\n').Compare(CyString(cut.remove(' ').remove('\n'))) )
1 cycrow 1053
		{
1054
			ret = true;
1055
			str->remove = true;
1056
			break;
1057
		}
1058
	}
1059
 
1060
	m_lAnimations.RemoveMarked();
1061
 
1062
	return ret;
1063
}
1064
 
39 cycrow 1065
void CXspFile::AddCockpit(const Utils::String &cockpit, int game, int mask, int index)
1 cycrow 1066
{
1067
	SCockpit *pCockpit = NULL;
1068
 
1069
	// first search for the cockpit entry
39 cycrow 1070
	Utils::String cid = cockpit.token(";", 19);
1 cycrow 1071
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1072
	{
39 cycrow 1073
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 1074
		if ( id.Compare(cid) )
1075
		{
1076
			pCockpit = node->Data();
1077
			break;
1078
		}
1079
	}
1080
 
1081
	if ( !pCockpit )
1082
	{
1083
		pCockpit = new SCockpit;
1084
		pCockpit->sCockpit = cockpit;
1085
		pCockpit->iIndex = index;
1086
		m_lCockpit.push_back(pCockpit);
1087
	}
1088
	if ( index != -1 )
1089
		pCockpit->iIndex = index;
1090
 
1091
	// now add the game mask
1092
	if ( game > 0 )
1093
	{
1094
		// search if the game mask already exists
1095
		SWeaponMask *wm = NULL;
1096
		for ( CListNode<SWeaponMask> *node = pCockpit->lWeaponMask.Front(); node; node = node->next() )
1097
		{
1098
			if ( node->Data()->iGame == game )
1099
			{
1100
				wm = node->Data();
1101
				break;
1102
			}
1103
		}
1104
 
1105
		if ( !wm )
1106
		{
1107
			wm = new SWeaponMask;
1108
			pCockpit->lWeaponMask.push_back(wm);
1109
		}
1110
 
1111
		wm->iGame = game;
1112
		if ( mask == -1 )
39 cycrow 1113
			wm->iMask = cockpit.token(";", 9);
1 cycrow 1114
		else
1115
			wm->iMask = mask;
1116
	}
50 cycrow 1117
	_changed();
1 cycrow 1118
}
1119
 
39 cycrow 1120
void CXspFile::AddBody(const Utils::String &section, const Utils::String &data)
1 cycrow 1121
{
1122
	this->AddBodies(section + ";" + data);
50 cycrow 1123
	_changed();
1 cycrow 1124
}
39 cycrow 1125
void CXspFile::AddBodies(const Utils::String &sData)
1 cycrow 1126
{
39 cycrow 1127
	Utils::String data = sData;
1128
	if ( !data.isNumber() )
1 cycrow 1129
	{
39 cycrow 1130
		if ( data[(int)(data.length() - 5)] == '.' )
1131
			data = data.left(-5);
1132
		else if ( data[(int)(data.length() - 4)] == '.' )
1133
			data = data.left(-4);
1134
		if ( data.right(1) != ";" )
1 cycrow 1135
			data += ";";
1136
	}
39 cycrow 1137
	m_lBodies.PushBack(CyString(data), true);
50 cycrow 1138
	_changed();
1 cycrow 1139
}
1140
 
39 cycrow 1141
int CXspFile::GetAnimationType(const Utils::String &type)
1 cycrow 1142
{
1143
	if ( type.Compare("TAT_TAGSINGLESTEP") )
1144
		return TAT_SINGLE;
1145
	else if ( type.Compare("TAT_TAGONESHOT") 
1146
				|| type.Compare("TAT_TAGONESHOT_REINIT") 
1147
				|| type.Compare("TAT_PINGPONG")
1148
				|| type.Compare("TAT_TAGLOOP") )
1149
		return TAT_3;
1150
 
1151
	return TAT_NONE;
1152
}
1153
 
1154
bool CXspFile::ReadAnimations(CyStringList *lIn, CyStringList *lOut, int startRecord)
1155
{
39 cycrow 1156
	Utils::String lastComment;
1157
	Utils::String addEntry;
1 cycrow 1158
	int remaining = 0;
39 cycrow 1159
	Utils::String lastType;
1 cycrow 1160
	int newEntries = 0;
1161
	int entries = -1;
1162
	for ( SStringList *strNode = lIn->Head(); strNode; strNode = strNode->next )
1163
	{
39 cycrow 1164
		Utils::String line = strNode->str.ToString();
1165
		line.removeChar('\r');
1166
		line.removeChar(9);
1167
		if ( line.empty() || line[0] == '/' )
1 cycrow 1168
			continue;
1169
		if ( entries == -1)
1170
		{
39 cycrow 1171
			entries	= line.token(";", 1);
1 cycrow 1172
			newEntries = entries - startRecord;
1173
		}
1174
		else
1175
		{
1176
			// remove comments, endspaces and last ;
39 cycrow 1177
			Utils::String sStriped = line;
1178
			if ( sStriped.isin("//") )
1 cycrow 1179
			{
1180
				if ( entries <= newEntries )
39 cycrow 1181
					lastComment = "//" + sStriped.tokens("//", 2);
1182
				sStriped = sStriped.token("//", 1);
1 cycrow 1183
			}
39 cycrow 1184
			sStriped.removeEndSpace();
1185
			if ( sStriped.right(1) == ";" )
1186
				sStriped.truncate(-1);
1 cycrow 1187
 
39 cycrow 1188
			Utils::String sRemainingLeft;
1 cycrow 1189
			if ( remaining > 0 )
1190
				sRemainingLeft = sStriped;
1191
			else
1192
			{
1193
				// each line should be a new entry, with some exceptions
1194
				// potection for new lines
39 cycrow 1195
				lastType = sStriped.token(";", 1);
1 cycrow 1196
 
1197
				switch (CXspFile::GetAnimationType(lastType))
1198
				{
1199
					case TAT_SINGLE:
39 cycrow 1200
						remaining = (long)sStriped.token(";", 5) + 1;
1201
						sRemainingLeft = sStriped.tokens(";", 6);
1 cycrow 1202
						if ( entries <= newEntries )
39 cycrow 1203
							addEntry = sStriped.tokens(";", 1, 5) + ";";
1 cycrow 1204
						break;
1205
					case TAT_3:
39 cycrow 1206
						remaining = (long)sStriped.token(";", 5) + 1;
1207
						sRemainingLeft = sStriped.tokens(";", 6);
1 cycrow 1208
						if ( entries <= newEntries )
39 cycrow 1209
							addEntry = sStriped.tokens(";", 1, 5) + ";";
1 cycrow 1210
						break;
1211
 
1212
					default:
1213
						remaining = 0;
1214
						if ( entries <= newEntries )
1215
							addEntry = sStriped;
1216
 
1217
				}
1218
			}
1219
 
39 cycrow 1220
			if ( !sRemainingLeft.empty() )
1 cycrow 1221
			{
1222
				int tatType = CXspFile::GetAnimationType(lastType);
1223
				if ( tatType == TAT_SINGLE )
1224
				{
39 cycrow 1225
					if ( sRemainingLeft.isin(";") )
1226
						remaining -= sRemainingLeft.countToken(";");
1227
					else if ( !sRemainingLeft.empty() )
1 cycrow 1228
						--remaining;
1229
 
1230
					if ( entries <= newEntries )
1231
						addEntry += sRemainingLeft + ";";
1232
				}
1233
				else if ( tatType == TAT_3 )
1234
				{
1235
					// last entry
1236
					if ( remaining == 1 )
1237
						--remaining;
39 cycrow 1238
					else if ( sRemainingLeft.isin(";") )
1 cycrow 1239
					{
39 cycrow 1240
						if ( !sRemainingLeft.isin("TATF_COORDS") )
1 cycrow 1241
						{
39 cycrow 1242
							int amt = sRemainingLeft.countToken(";") / 3;
1 cycrow 1243
							remaining -= amt;
39 cycrow 1244
							if ( remaining == 1 && (sRemainingLeft.countToken(";") - (amt * 3)) == 1 )
1 cycrow 1245
								--remaining;
1246
						}
1247
						else
1248
						{
39 cycrow 1249
							int iRem = sRemainingLeft.countToken(";");
1 cycrow 1250
							int iPos = 1;
1251
							while ( iPos < iRem )
1252
							{
39 cycrow 1253
								Utils::String first = sRemainingLeft.token(";", iPos);
1254
								if ( first.isin("TATF_COORDS") )
1 cycrow 1255
									iPos += 5;
1256
								else
1257
									iPos += 3;
1258
								--remaining;
1259
							}
1260
 
1261
							if ( remaining == 1 && iPos == iRem )
1262
								--remaining;
1263
						}
1264
					}
1265
 
1266
					if ( entries <= newEntries )
1267
						addEntry += sRemainingLeft + ";";
1268
				}
1269
			}
1270
 
1271
			if ( remaining <= 0 )
1272
			{
39 cycrow 1273
				if ( entries <= newEntries && !addEntry.empty())
1 cycrow 1274
				{
39 cycrow 1275
					if ( addEntry[(int)addEntry.length() - 1] != ';' )
1 cycrow 1276
						addEntry += ";";
39 cycrow 1277
					lOut->PushBack(CyString(addEntry + lastComment));
1 cycrow 1278
				}
1279
				--entries;
1280
			}
1281
		}
1282
	}
1283
 
1284
	return !lOut->Empty();
1285
}
1286
 
1287
void CXspFile::AddAnimation(CyStringList *list)
1288
{
1289
	for ( SStringList *strNode = list->Head(); strNode; strNode = strNode->next )
39 cycrow 1290
		this->AddAnimation(strNode->str.ToString());
50 cycrow 1291
	_changed();
1 cycrow 1292
}
1293
 
1294
SText *CXspFile::FindShipText(int lang)
1295
{
1296
	if ( m_lText.empty() )
1297
		return NULL;
1298
 
1299
	SText *english = NULL;
1300
	SText *german = NULL;
1301
	SText *found = NULL;
1302
	for ( CListNode<SText> *node = m_lText.Front(); node; node = node->next() )
1303
	{
1304
		SText *text = node->Data();
1305
		// matched language
1306
		if ( text->iId == lang )
1307
			return text;
1308
		else if ( text->iId == 44 )
1309
			english = text;
1310
		else if ( text->iId == 49 )
1311
			german = text;
1312
		else if ( !found )
1313
			found = text;
1314
	}
1315
 
1316
	// if we've found an english version, use that
1317
	if ( english )
1318
		return english;
1319
	// otherwise try a german
1320
	if ( german )
1321
		return german;
1322
	// otherwise use any we've found (usually first one)
1323
	return found;
1324
}
1325
 
39 cycrow 1326
Utils::String CXspFile::GetTextName(int lang)
1 cycrow 1327
{
1328
	SText *t = FindShipText(lang);
1329
	if ( t )
1330
	{
1331
		// return the correct language text
39 cycrow 1332
		if ( !t->sName.empty() )
1 cycrow 1333
			return t->sName;
1334
		// we have found a text, but there is no ship name ??
1335
		else if ( lang != 44 )
1336
		{
1337
			// reget the english one
1338
			t = FindShipText(44);
39 cycrow 1339
			if ( t && !t->sName.empty() )
1 cycrow 1340
				return t->sName;
1341
		}
1342
	}
1343
 
1344
	// still not found one, return the ships name
1345
	return this->GetShipName(lang);
1346
}
1347
 
39 cycrow 1348
Utils::String CXspFile::GetTextDescription(int lang)
1 cycrow 1349
{
1350
	SText *t = FindShipText(lang);
1351
	if ( t )
1352
	{
1353
		// return the correct language text
39 cycrow 1354
		if ( !t->sDesc.empty() )
1 cycrow 1355
			return t->sDesc;
1356
		// we have found a text, but there is no ship name ??
1357
		else if ( lang != 44 )
1358
		{
1359
			// reget the english one
1360
			t = FindShipText(44);
39 cycrow 1361
			if ( t && !t->sDesc.empty() )
1 cycrow 1362
				return t->sDesc;
1363
		}
1364
	}
1365
 
1366
	// still not found one, return the ships name
48 cycrow 1367
	if ( !this->description().empty() ) return this->description();
1 cycrow 1368
	return this->GetShipName(lang);
1369
}
1370
 
35 cycrow 1371
bool CXspFile::startExtractShip(CVirtualFileSystem *pVfs, const Utils::String &sId, CProgressInfo *pProgress)
1 cycrow 1372
{
39 cycrow 1373
	m_sID = sId.remove('\r');
35 cycrow 1374
	while ( m_sID.right(1) == ";" )
1375
		m_sID.truncate(-1);
1 cycrow 1376
 
35 cycrow 1377
	m_sData = pVfs->getTShipsEntry(m_sID);
1378
 
1 cycrow 1379
	// get scene files
35 cycrow 1380
	if ( pProgress ) pProgress->UpdateStatus(IMPORTSHIP_SCENE);
1381
	if ( !this->extractSceneFiles(pVfs) )
1 cycrow 1382
		return false;
1383
 
1384
	return true;
1385
}
1386
 
35 cycrow 1387
bool CXspFile::extractShip(CVirtualFileSystem *pVfs, const Utils::String &sId, CProgressInfo *progress)
1 cycrow 1388
{
35 cycrow 1389
	if ( !this->startExtractShip(pVfs, sId, progress) )
1 cycrow 1390
		return false;
1391
 
1392
	// read the scene file and get the files list
35 cycrow 1393
	if ( !this->processSceneFiles(pVfs, progress) )
1 cycrow 1394
		return false;
1395
 
1396
	// pack all the ship files
1397
	this->PackAllFiles();
1398
 
1399
	return true;
1400
}
1401
 
35 cycrow 1402
bool CXspFile::extractSceneFiles(CVirtualFileSystem *pVfs)
1 cycrow 1403
{
35 cycrow 1404
	m_pSceneFile = pVfs->extractGameFileToPackage(this, "objects\\" + m_sData.token(";", 17) + ".pbd", FILETYPE_SHIPSCENE, "objects\\" + m_sData.token(";", 17) + ".bod");
1405
	if ( !m_pSceneFile ) return false;
1406
	m_pCockpitFile = pVfs->extractGameFileToPackage(this, "objects\\" + m_sData.token(";", 18) + ".pbd", FILETYPE_COCKPITSCENE, "objects\\" + m_sData.token(";", 18) + ".bod");
1 cycrow 1407
 
1408
	return true;
1409
}
1410
 
1411
CyStringList *CXspFile::ReadSceneModels()
1412
{
1413
	// read the scene file
1414
	if ( !m_pSceneFile )
1415
		m_pSceneFile = this->GetFirstFile(FILETYPE_SHIPSCENE);
1416
 
1417
	if ( !m_pSceneFile )
1418
		return NULL;
1419
 
1420
	// check if its packed
1421
	size_t datasize;
1422
	unsigned char *data = m_pSceneFile->UncompressData((long *)&datasize, 0);
1423
 
1424
	// if data wasn't compressed, then copy it itself as we are editing it
1425
	bool deleteData = false;
1426
	if ( data == m_pSceneFile->GetData() )
1427
	{
1428
		data = new unsigned char[m_pSceneFile->GetDataSize()];
1429
		memcpy(data, m_pSceneFile->GetData(), m_pSceneFile->GetDataSize());
1430
		deleteData = true;
1431
	}
1432
 
1433
	if ( data && datasize )
1434
	{
1435
		if ( m_pSceneFile->CheckPackedExtension() )
1436
			data = UnPCKData(data, datasize, &datasize);
1437
	}
1438
 
1439
	if ( !data || !datasize )
1440
		return NULL;
1441
 
1442
	CyStringList *lModels = new CyStringList;
1443
 
1444
	size_t pos = 0;
1445
	bool newline = true;
1446
	bool online = false;
1447
	while ( pos < datasize )
1448
	{
1449
		char c = data[pos];
1450
		++pos;
1451
 
1452
		// skip until next line
1453
		if ( !newline && !online )
1454
		{
1455
			if ( c == '\n' )
1456
				newline = true;
1457
			continue;
1458
		}
1459
 
1460
		if ( newline )
1461
		{
1462
			if ( c == ' ' || c == 9 || c == '\n' || c == '\r' )
1463
				continue;
1464
 
1465
			newline = false;
1466
 
1467
			if ( c == 'P' || c == 'p' )
1468
			{
1469
				while ( data[pos] == ' ' ) pos++;
1470
				unsigned char *line = (data + pos);
1471
				while ( data[pos] != ' ' && data[pos] != ';' ) pos++;
1472
				data[pos] = '\0';
1473
				if ( atoi((const char *)line) == lModels->Count() )
1474
					online = true;
1475
			}
1476
		}
1477
		// this line is out model
1478
		else if ( online )
1479
		{
1480
			if ( c == 'B' || c == 'b' )
1481
			{
1482
				while(data[pos] == ' ') pos++;
1483
				unsigned char *line = (data + pos);
1484
				while(data[pos] != ';') pos++;
1485
				data[pos] = '\0';
1486
 
1487
				lModels->PushBack((char *)line);
1488
				online = false;
1489
			}
1490
		}
1491
	}
1492
 
1493
	if ( deleteData )
1494
		delete data;
1495
 
1496
	return lModels;
1497
}
1498
 
42 cycrow 1499
void CXspFile::extractCutData(CVirtualFileSystem *pVfs, CyStringList *sceneModels, bool add)
1500
{
1501
	std::vector<int> cuts;
1502
	for ( CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next() ) {
1503
		Utils::String data = node->Data()->sData;
1504
		int states = data.token(";", 3);
1505
		for ( int i = 0; i < states; i++ ) {
1506
			int cutid = data.token(";", (i * 2) + 5);
1507
			if ( !cutid ) continue;
1508
			cuts.push_back(cutid);
1509
		}
1510
	}
1511
 
1512
	if ( cuts.empty() ) return;
1513
 
79 cycrow 1514
	if ( pVfs->ExtractGameFile("types/CutData.pck", CPackages::tempDirectory() + "tmp.dat").empty() ) return;
42 cycrow 1515
 
79 cycrow 1516
	CFileIO File(CPackages::tempDirectory() + "tmp.dat");
52 cycrow 1517
	if ( !File.exists() ) return;
42 cycrow 1518
 
1519
	CyStringList *lines = File.ReadLinesStr();
1520
	int count = -1;
1521
	for ( SStringList *node = lines->Head(); node; node = node->next ) {
1522
		Utils::String line = node->str.ToString();
1523
		line.removeChar('\r');
1524
		line.removeChar(' ');
1525
		line.removeFirstSpace();
1526
		if ( line[0] == '/' ) continue;
1527
		if ( count == -1 ) count = line.token(";", 1);
1528
		else {
1529
			int max;
1530
			Utils::String *words = line.tokenise(";", &max);
1531
			if ( words && max ) {
1532
				for ( int i = 0; i < max; i += 2 ) {
1533
					int cutid = words[i];
1534
					if ( !cutid ) continue;
1535
					for ( std::vector<int>::iterator itr = cuts.begin(); itr != cuts.end(); itr++ ) {
1536
						if ( (*itr) == cutid ) {
1537
							this->AddCutData(words[i] + ";" + words[i + 1] + ";");
1538
							if ( add ) {
1539
								sceneModels->PushBack(CyString(words[i + 1]));
1540
							}
1541
							break;
1542
						}
1543
					}
1544
				}
1545
				CLEANSPLIT(words, max);
1546
			}
1547
		}
1548
	}
1549
}
1550
 
35 cycrow 1551
void CXspFile::extractDummies(CVirtualFileSystem *pVfs, CyStringList *sceneModels, bool add)
1 cycrow 1552
{
1553
	if ( !sceneModels ) return;
31 cycrow 1554
 
1555
	bool extracted = false;
79 cycrow 1556
	if ( !pVfs->ExtractGameFile("types/dummies.pck", CPackages::tempDirectory() + "tmp.dat").empty() ) {
1557
		CFileIO File(CPackages::tempDirectory() + "tmp.dat");
52 cycrow 1558
		if ( File.exists() )
1 cycrow 1559
		{
39 cycrow 1560
			Utils::String section;
1 cycrow 1561
			int secCount = 0;
1562
			CyStringList *lines = File.ReadLinesStr();
1563
			for ( SStringList *node = lines->Head(); node; node = node->next )
1564
			{
1565
				node->str.RemoveFirstSpace();
1566
				node->str.RemoveChar(9);
1567
				node->str.RemoveChar('\r');
1568
				if ( node->str.Empty() )
1569
					continue;
1570
				if ( node->str[0] == '/' )
1571
					continue;
1572
 
1573
				// not in a section yet
1574
				if ( secCount <= 0 )
1575
				{
39 cycrow 1576
					section = node->str.GetToken(";", 1, 1).ToString();
1 cycrow 1577
					secCount = node->str.GetToken(";", 2, 2).ToInt();
1578
				}
1579
				else
1580
				{
39 cycrow 1581
					Utils::String first = node->str.GetToken(";", 1, 1).ToString();
1 cycrow 1582
					if ( sceneModels->FindString(first) )
1583
					{
39 cycrow 1584
						this->AddDummy(section, node->str.ToString());
1 cycrow 1585
 
1586
						if ( add )
1587
						{
1588
							int pos = 4;
1589
							int scene = node->str.GetToken(";", 3, 3).ToInt();
1590
							for ( int i = 0; i < scene; i++ )
1591
							{
1592
								sceneModels->PushBack(node->str.GetToken(";", 5 + (i * 2), 5 + (i * 2)));
1593
								pos += 2;
1594
							}
1595
 
1596
							int model = node->str.GetToken(";", pos, pos).ToInt();
1597
							for ( int i = 0; i < model; i++ )
1598
								sceneModels->PushBack(node->str.GetToken(";", pos + (i * 2) + 1, pos + (i * 2) + 1));
1599
						}
1600
					}
1601
					--secCount;
1602
 
1603
				}
1604
			}
1605
 
1606
			delete lines;
52 cycrow 1607
			File.remove();
1 cycrow 1608
		}
1609
	}
1610
}
1611
 
35 cycrow 1612
void CXspFile::extractComponants(CVirtualFileSystem *pVfs, CyStringList *sceneModels)
1 cycrow 1613
{
1614
	if ( !sceneModels ) return;
79 cycrow 1615
	if ( !pVfs->ExtractGameFile("types/components.pck", CPackages::tempDirectory() + "tmp.dat").empty() )
1 cycrow 1616
	{
79 cycrow 1617
		CFileIO File(CPackages::tempDirectory() + "tmp.dat");
52 cycrow 1618
		if ( File.exists() )
1 cycrow 1619
		{
39 cycrow 1620
			Utils::String file;
1621
			Utils::String section;
1 cycrow 1622
			int secCount = 0;
1623
			int secCount2 = 0;
1624
			CyStringList *lines = File.ReadLinesStr();
1625
			for ( SStringList *node = lines->Head(); node; node = node->next )
1626
			{
1627
				node->str.RemoveFirstSpace();
1628
				node->str.RemoveChar(9);
1629
				node->str.RemoveChar('\r');
1630
				if ( node->str.Empty() )
1631
					continue;
1632
				if ( node->str[0] == '/' )
1633
					continue;
1634
 
1635
				// not in a section yet
1636
				if ( secCount2 )
1637
				{
1638
					if ( sceneModels->FindString(file) )
39 cycrow 1639
						this->AddComponent(section, file, node->str.ToString());
1 cycrow 1640
					--secCount2;
1641
				}
1642
				else if ( secCount <= 0 )
1643
				{
39 cycrow 1644
					section = node->str.GetToken(";", 1, 1).ToString();
1 cycrow 1645
					secCount = node->str.GetToken(";", 2, 2).ToInt();
1646
				}
1647
				else
1648
				{
39 cycrow 1649
					file = node->str.GetToken(";", 1, 1).ToString();
1 cycrow 1650
					secCount2 = node->str.GetToken(";", 2, 2).ToInt();
1651
					--secCount;
1652
				}
1653
			}
1654
 
1655
			delete lines;
52 cycrow 1656
			File.remove();
1 cycrow 1657
		}
1658
	}
1659
}
1660
 
1661
bool CXspFile::GetTextureList(CyStringList *list, const unsigned char *olddata, size_t size)
1662
{
1663
	if ( !olddata || !size )
1664
		return false;
1665
 
1666
	size_t startLine = 0;
1667
	CyString line;
1668
	size_t pos = 0;
1669
 
1670
	unsigned char *data = new unsigned char[size];
1671
	memcpy(data, olddata, size);
1672
 
1673
	while ( (pos++) < size )
1674
	{
1675
		if ( data[pos] == '\n' )
1676
		{
1677
			data[pos] = '\0';
1678
			line = (char *)(data + startLine);
1679
			line.RemoveChar(9);
1680
			line.RemoveChar('\r');
1681
			line.RemoveFirstSpace();
1682
 
1683
			if ( !line.Empty() && line[0] != '/' )
1684
			{
1685
				CyString first = line.GetToken(":", 1, 1);
1686
				if ( first.Compare("MATERIAL6") )
1687
				{
1688
					int max;
1689
					CyString *strs = line.GetToken(":", 2).SplitToken("; ", &max);
1690
 
1691
					if ( strs && max >= 2)
1692
					{
1693
						for ( int i = 2; i < max; i++ )
1694
						{
1695
							CyString s = strs[i];
1696
							if ( s.IsIn(";") )
1697
								s = s.GetToken(";", 1, 1);
1698
							if ( !s.IsNumber() && !s.Compare("NULL") && s.IsIn(".") )
1699
								list->PushBack(s, "", true);
1700
						}
1701
					}
1702
 
1703
					CLEANSPLIT(strs, max)
1704
				}
1705
			}
1706
 
1707
			startLine = pos + 1;
1708
		}
1709
	}
1710
 
1711
	delete [] data;
1712
 
1713
	return true;
1714
}
1715
 
35 cycrow 1716
void CXspFile::extractTextures(CVirtualFileSystem *pVfs)
1 cycrow 1717
{
1718
	CyStringList lTextures;
1719
 
1720
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1721
	{
1722
		C_File *f = node->Data();
1723
		if ( f->GetFileType() != FILETYPE_SHIPMODEL )
1724
			continue;
1725
 
1726
		// cant do these yet
1727
		if ( f->CheckFileExt("pbb") || f->CheckFileExt("bob") )
1728
		{
1729
			if ( !f->BobDecompile() )
1730
				continue;
1731
		}
1732
 
1733
		if ( !f->GetData() )
1734
		{
1735
			if ( !f->ReadFromFile() )
1736
				continue;
1737
		}
1738
 
1739
		unsigned char *data = NULL;
1740
		size_t size;
1741
 
1742
		if ( f->CheckFileExt("pbb") || f->CheckFileExt("pbd") )
1743
			data = f->UnPCKFile(&size);
1744
		else
1745
		{
1746
			data = f->GetData();
1747
			size = f->GetDataSize();
1748
		}
1749
 
1750
		this->GetTextureList(&lTextures, data, size);
1751
	}
1752
 
1753
	for ( SStringList *node = lTextures.Head(); node; node = node->next )
1754
	{
35 cycrow 1755
		if ( CFileIO(node->str).CheckFileExtension("dds") )
1756
			pVfs->extractGameFileToPackage(this, "dds\\" + Utils::String(node->str.ToString()), FILETYPE_SHIPOTHER);
1757
		else 
1758
			pVfs->extractGameFileToPackage(this, "textures\\" + Utils::String(node->str.ToString()), FILETYPE_SHIPOTHER);
1 cycrow 1759
	}
1760
}
1761
 
39 cycrow 1762
bool CXspFile::AddTextFromFile(const Utils::String &sFile, int textId)
1 cycrow 1763
{
39 cycrow 1764
	Utils::String file = sFile;
1765
 
1 cycrow 1766
	bool remove = false;
1767
	if ( CFileIO(file).CheckFileExtension("pck") )
1768
	{
39 cycrow 1769
		C_File F;
1770
		F.SetFilename(CyString(file));
1 cycrow 1771
		F.UnPCKFile();
79 cycrow 1772
		if ( F.WriteToFile(CPackages::tempDirectory() + "tmp.dat") )
1 cycrow 1773
		{
1774
			remove = true;
79 cycrow 1775
			file = CPackages::tempDirectory() + "tmp.dat";
1 cycrow 1776
		}
1777
	}
1778
 
78 cycrow 1779
	/*
68 cycrow 1780
	std::wfstream fileStream(file.c_str());
1781
	if ( fileStream.is_open() ) {
1782
		while(!fileStream.eof()) {
1783
			std::wstring line;
1784
			std::getline(fileStream, line);
1785
			int i =0;
1786
		}
1787
		fileStream.close();
1788
	}
78 cycrow 1789
	*/
68 cycrow 1790
 
1 cycrow 1791
	FILE *fid = fopen(file.c_str(), "r");
1792
	if ( fid )
1793
	{
1794
		bool ret = this->AddTextFromFile(fid, textId);
1795
		fclose(fid);
1796
 
52 cycrow 1797
		if ( remove ) CFileIO::Remove(file);
50 cycrow 1798
		_changed();
1 cycrow 1799
		return ret;
1800
	}
1801
 
1802
	return false;
1803
}
1804
 
39 cycrow 1805
bool CXspFile::ImportBodies(CyStringList *sceneModels, const Utils::String &filename)
1 cycrow 1806
{
1807
	CFileIO File(filename);
52 cycrow 1808
	if ( File.exists() )
1 cycrow 1809
	{
39 cycrow 1810
		Utils::String sSection;
1 cycrow 1811
		int section = 0;
1812
		CyStringList *lines = File.ReadLinesStr();
1813
		for ( SStringList *node = lines->Head(); node; node = node->next )
1814
		{
1815
			node->str.RemoveChar(9);
1816
			node->str.RemoveChar('\r');
1817
			node->str.RemoveFirstSpace();
1818
			if ( node->str.Empty() )
1819
				continue;
1820
			if ( node->str[0] == '/' )
1821
				continue;
1822
 
1823
			// are we looking for a section
1824
			if ( section <= 0 )
1825
			{
39 cycrow 1826
				sSection = node->str.GetToken(";", 1, 1).ToString();
1 cycrow 1827
				section = node->str.GetToken(";", 2, 2).ToInt();
1828
			}
1829
			else
1830
			{
1831
				int max;
1832
				CyString *strs = node->str.SplitToken(";", &max);
1833
				if ( strs && max )
1834
				{
1835
					for ( int i = 0; i < max; i++ )
1836
					{
1837
						strs[i].RemoveSpaces();
1838
						if (strs[i].Empty() )
1839
							continue;
1840
						if ( sceneModels->FindString(strs[i]) )
39 cycrow 1841
							this->AddBody(sSection, strs[i].ToString());
1 cycrow 1842
						--section;
1843
					}
1844
				}
1845
				CLEANSPLIT(strs, max)
1846
			}
1847
		}
1848
		delete lines;
1849
		return true;
1850
	}
1851
 
1852
	return false;
1853
}
1854
 
39 cycrow 1855
bool CXspFile::ImportCockpits(const Utils::String &filename)
1 cycrow 1856
{
1857
	CFileIO File(filename);
52 cycrow 1858
	if ( File.exists() )
1 cycrow 1859
	{
1860
		CyStringList *lines = File.ReadLinesStr();
1861
		int entries = 0;
1862
		for ( SStringList *node = lines->Head(); node; node = node->next )
1863
		{
1864
			node->str.RemoveChar(9);
1865
			node->str.RemoveChar('\r');
1866
			node->str.RemoveFirstSpace();
1867
			if ( node->str.Empty() )
1868
				node->remove = true;
1869
			else if ( node->str[0] == '/' )
1870
				node->remove = true;
1871
			else if ( !entries )
1872
			{
1873
				entries = node->str.GetToken(";", 2, 2).ToInt();
1874
				node->remove = true;
1875
			}
1876
		}
1877
		lines->RemoveMarked();
1878
 
1879
		// now get all the entries from TShips
1880
		for ( int i = 0; i < 6; i++ )
1881
		{
14 cycrow 1882
			int idx = m_sData.token(";", 32 + (i * 2));
1 cycrow 1883
			if ( idx < lines->Count() && idx )
1884
			{
39 cycrow 1885
				Utils::String turret = lines->GetAt(idx)->str.ToString();
1 cycrow 1886
				int pos = -1;
14 cycrow 1887
				Utils::String id;
39 cycrow 1888
				while ( id.empty() && pos > -100 ) id = turret.token(";", pos--);
14 cycrow 1889
				m_sData = m_sData.replaceToken(";", 32 + (i * 2), id + "(" + (long)idx + ")");
1 cycrow 1890
 
1891
				this->AddCockpit(turret, 0);
1892
			}
1893
		}
1894
 
1895
		delete lines;
1896
		return true;
1897
	}
1898
	return false;
1899
}
1900
 
35 cycrow 1901
bool CXspFile::extractCockpits(CVirtualFileSystem *pVfs)
1 cycrow 1902
{
79 cycrow 1903
	if ( !pVfs->ExtractGameFile("types/TCockpits.pck", CPackages::tempDirectory() + "tmp.dat").empty() ) {
1904
		bool ret = this->ImportCockpits(CPackages::tempDirectory() + "tmp.dat");
1905
		CFileIO::Remove(CPackages::tempDirectory() + "tmp.dat");
1 cycrow 1906
 
1907
		return ret;
1908
	}
1909
 
1910
	return false;
1911
}
1912
 
35 cycrow 1913
bool CXspFile::extractBodies(CVirtualFileSystem *pVfs, CyStringList *sceneModels)
1 cycrow 1914
{
1915
	if ( !sceneModels ) return false;
31 cycrow 1916
 
79 cycrow 1917
	if ( !pVfs->ExtractGameFile("types/Bodies.pck", CPackages::tempDirectory() + "tmp.dat").empty() ) {
1918
		bool ret = this->ImportBodies(sceneModels, CPackages::tempDirectory() + "tmp.dat");
1919
		CFileIO::Remove(CPackages::tempDirectory() + "tmp.dat");
1 cycrow 1920
 
1921
		return ret;
1922
	}
1923
 
1924
	return false;
1925
}
1926
 
1927
bool CXspFile::AddTextFromFile(FILE *id, int textId)
1928
{
14 cycrow 1929
	if ( textId == -1 && !m_sData.empty() )
1930
		textId = m_sData.token(";", 7);
1 cycrow 1931
 
1932
	if ( textId <= 0 )
1933
		return false;
1934
 
39 cycrow 1935
	Utils::String line;
1 cycrow 1936
	if ( !id )
1937
		return false;
1938
 
1939
	bool added = false;
1940
 
39 cycrow 1941
	Utils::String shipName;
1942
	Utils::String shipDesc;
1 cycrow 1943
 
68 cycrow 1944
	int lastAddedGameID = 0;
1945
	int currentGameID = 0;
1 cycrow 1946
	int lang = 0;
1947
	bool inpage = false;
1948
	while ( !feof(id) )
1949
	{
39 cycrow 1950
		if ( !shipName.empty() && !shipDesc.empty() )
1 cycrow 1951
		{
1952
			added = true;
1953
			break;
1954
		}
1955
 
39 cycrow 1956
		line.readToEndOfLine(id, 0, false);
1957
		line.removeChar(9);
1958
		line.removeChar('\r');
1959
		line.removeFirstSpace();
1 cycrow 1960
 
1961
		if ( inpage )
1962
		{
68 cycrow 1963
			if ( line.left(6).Compare("</page") ) {
1964
				inpage = false;
1965
				continue;
1966
			}
1 cycrow 1967
 
1968
			// find matching id
39 cycrow 1969
			if ( line.left(6).Compare("<t id=") )
1 cycrow 1970
			{
39 cycrow 1971
				int pos = line.findPos("id=\"", 0);
1 cycrow 1972
				if ( pos != -1 )
1973
				{
68 cycrow 1974
					pos += 4;
1975
					int endpos = line.findPos("\"", pos);
1 cycrow 1976
					if ( endpos != -1 )
1977
					{
68 cycrow 1978
						int id = line.mid(pos, endpos);
1 cycrow 1979
						if ( id == textId || id == (textId + 1) )
1980
						{
39 cycrow 1981
							pos = line.findPos(">", endpos);
1 cycrow 1982
							if ( pos != -1 )
1983
							{
39 cycrow 1984
								endpos = line.findPos("</t>", pos);
1 cycrow 1985
								if ( endpos != -1 )
1986
								{
1987
									if ( id == textId )
68 cycrow 1988
										shipName = line.mid(pos + 1, endpos);
1 cycrow 1989
									else
68 cycrow 1990
										shipDesc = line.mid(pos + 1, endpos);
1991
									lastAddedGameID = currentGameID;
1 cycrow 1992
								}
1993
							}
1994
						}
1995
					}
1996
				}
1997
			}
1998
		}
1999
		else if ( lang ) // search for page 17
2000
		{
39 cycrow 2001
			if ( line.left(8).Compare("<page id") )
1 cycrow 2002
			{
39 cycrow 2003
				int pos = line.findPos("id=\"");
1 cycrow 2004
				if ( pos != -1 )
2005
				{
68 cycrow 2006
					pos += 4;
2007
					int endpos = line.findPos("\"", pos);
1 cycrow 2008
					if ( endpos != -1 )
2009
					{
68 cycrow 2010
						Utils::String sId = line.mid(pos, endpos);
39 cycrow 2011
						int id = sId;
68 cycrow 2012
						if ( sId.length() > 4 ) {
2013
							id = sId.right(4);
2014
							currentGameID = sId.left(sId.length() - 4);
2015
						}
2016
 
2017
						if ( currentGameID >= lastAddedGameID && id == 17 )
1 cycrow 2018
							inpage = true;
2019
					}
2020
				}
2021
			}
2022
		}
39 cycrow 2023
		else if ( line.left(12).Compare("<language id") )
1 cycrow 2024
		{
39 cycrow 2025
			int pos = line.findPos("id=\"");
1 cycrow 2026
			if ( pos != -1 )
2027
			{
68 cycrow 2028
				// move past the id=
2029
				pos += 4;
2030
 
2031
				Utils::String s = line.right(-pos);
2032
				Utils::String s2 = line.mid(pos, -1);
2033
				int endpos = line.findPos("\"", pos);
1 cycrow 2034
				if ( endpos != -1 )
68 cycrow 2035
					lang = line.mid(pos, endpos);
1 cycrow 2036
			}
2037
		}
2038
	}
2039
 
2040
	// incase we only found the shipname
39 cycrow 2041
	if ( !shipName.empty() )
1 cycrow 2042
		added = true;
2043
 
2044
	if ( added )
2045
	{
50 cycrow 2046
		if ( lang == 44 || this->name().empty())
1 cycrow 2047
		{
50 cycrow 2048
			this->setName(shipName);
48 cycrow 2049
			this->setDescription(shipDesc.findReplace("&amp", "&"));
1 cycrow 2050
		}
2051
		this->AddText(lang, shipName, shipDesc);
2052
		return true;	
2053
	}
2054
 
2055
	return false;
2056
}
2057
 
31 cycrow 2058
void CXspFile::ExtractTexts(CCatFile *catFile, CCatFile *secondCatFile, int textId)
1 cycrow 2059
{
2060
	for ( CListNode<SInCatFile> *node = catFile->GetFiles()->Front(); node; node = node->next() )
2061
	{
2062
		SInCatFile *f = node->Data();
2063
		if ( !f->sFile.Left(2).Compare("t\\") && !f->sFile.Left(2).Compare("t/") )
2064
			continue;
2065
 
2066
		// extract the text file and read in the data
79 cycrow 2067
		bool extracted = catFile->ExtractFile(f->sFile, CPackages::GetTempDirectory() + "tmp.dat");
2068
		if ( !extracted && secondCatFile ) extracted = secondCatFile->ExtractFile(f->sFile, CPackages::GetTempDirectory() + "tmp.dat");
31 cycrow 2069
		if ( extracted ) {
79 cycrow 2070
			this->AddTextFromFile(CPackages::tempDirectory() + "tmp.dat", textId);
2071
			CFileIO::Remove(CPackages::tempDirectory() + "tmp.dat");
1 cycrow 2072
		}
2073
	}
2074
}
2075
 
35 cycrow 2076
bool CXspFile::processSceneFileSection(int section, CVirtualFileSystem *pVfs, CyStringList *lModels, CProgressInfo *progress)
1 cycrow 2077
{
2078
	if ( progress ) progress->UpdateStatus(section);
2079
 
2080
	switch ( section )
2081
	{
2082
		case IMPORTSHIP_COMPONANT:
2083
			if ( !lModels ) return false;
35 cycrow 2084
			this->extractComponants(pVfs, lModels);
1 cycrow 2085
			break;
2086
 
2087
		case IMPORTSHIP_MODELS:
2088
			{
2089
				if ( !lModels ) return false;
2090
				for ( SStringList *node = lModels->Head(); node; node = node->next )
2091
				{
2092
					if ( node->str.IsNumber() ) // count be componants or dummy
2093
						continue;
35 cycrow 2094
					if ( pVfs->extractGameFileToPackage(this, "objects\\" + Utils::String(node->str.ToString()) + ".pbb", FILETYPE_SHIPMODEL, "objects\\" + Utils::String(node->str.ToString()) + ".bob") )
1 cycrow 2095
						continue;
35 cycrow 2096
					if ( pVfs->extractGameFileToPackage(this, "objects\\" + Utils::String(node->str.ToString()) + ".pbd", FILETYPE_SHIPMODEL, "objects\\" + Utils::String(node->str.ToString()) + ".bod") )
1 cycrow 2097
						continue;
2098
				}
2099
			}
2100
			break;
2101
 
2102
		case IMPORTSHIP_DUMMIES:
2103
			if ( !lModels ) return false;
35 cycrow 2104
			this->extractDummies(pVfs, lModels, true);
42 cycrow 2105
			this->extractCutData(pVfs, lModels, true);
1 cycrow 2106
			break;
2107
 
2108
		// extract the textures
2109
		case IMPORTSHIP_TEXTURES:
35 cycrow 2110
			this->extractTextures(pVfs);
1 cycrow 2111
			break;
2112
 
2113
		case IMPORTSHIP_TEXTS:
2114
			// extract the text file entries
35 cycrow 2115
			pVfs->extractTexts(this, m_sData.token(";", 7));
1 cycrow 2116
			break;
2117
 
2118
		case IMPORTSHIP_BODIES:
2119
			// extract the bodies entries
2120
			if ( !lModels ) return false;
35 cycrow 2121
			this->extractBodies(pVfs, lModels);
1 cycrow 2122
			break;
2123
 
2124
		case IMPORTSHIP_COCKPITS:
2125
			// extract the cockpit entries
35 cycrow 2126
			this->extractCockpits(pVfs);
1 cycrow 2127
			break;
2128
	}
2129
 
2130
	return true;
2131
}
2132
 
35 cycrow 2133
bool CXspFile::processSceneFiles(CVirtualFileSystem *pVfs, CProgressInfo *progress)
1 cycrow 2134
{
2135
	// now lets parse our files
2136
	if ( progress ) progress->UpdateStatus(IMPORTSHIP_EXTRACTSCENE);
2137
	CyStringList *lModels = this->ReadSceneModels();
2138
	if ( !lModels )
2139
		return false;
2140
 
2141
	// extract componants, and add extra items to list
35 cycrow 2142
	if ( !this->processSceneFileSection(IMPORTSHIP_COMPONANT, pVfs, lModels, progress) )
1 cycrow 2143
		return false;
2144
 
2145
	//lets first find any model files
35 cycrow 2146
	if ( !this->processSceneFileSection(IMPORTSHIP_MODELS, pVfs, lModels, progress) )
1 cycrow 2147
		return false;
2148
 
2149
	// extract the dummies
35 cycrow 2150
	if ( !this->processSceneFileSection(IMPORTSHIP_DUMMIES, pVfs, lModels, progress) )
1 cycrow 2151
		return false;
2152
 
2153
	// extract the textures
35 cycrow 2154
	if ( !this->processSceneFileSection(IMPORTSHIP_TEXTURES, pVfs, lModels, progress) )
1 cycrow 2155
		return false;
2156
 
2157
	// extract the text file entries
35 cycrow 2158
	if ( !this->processSceneFileSection(IMPORTSHIP_TEXTS, pVfs, lModels, progress) )
1 cycrow 2159
		return false;
2160
 
2161
	// extract the bodies entries
35 cycrow 2162
	if ( !this->processSceneFileSection(IMPORTSHIP_BODIES, pVfs, lModels, progress) )
1 cycrow 2163
		return false;
2164
 
2165
	// extract the cockpit entries
35 cycrow 2166
	if ( !this->processSceneFileSection(IMPORTSHIP_COCKPITS, pVfs, lModels, progress) )
1 cycrow 2167
		return false;
2168
 
2169
	delete lModels;
2170
 
2171
	return true;
2172
}
2173
 
2174
 
2175
void CXspFile::PackAllFiles()
2176
{
2177
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2178
	{
2179
		C_File *f = node->Data();
2180
		if ( f->GetFileType() == FILETYPE_SHIPSCENE || f->GetFileType() == FILETYPE_COCKPITSCENE || f->GetFileType() == FILETYPE_SHIPMODEL || f->GetFileType() == FILETYPE_SHIPOTHER )
41 cycrow 2181
		{	
2182
			/*
1 cycrow 2183
			if ( f->CheckFileExt("bod") )
2184
			{
2185
				if ( f->PCKFile() )
2186
					f->ChangeFileExt("pbd");
41 cycrow 2187
			}	
42 cycrow 2188
 
2189
			else */if ( f->CheckFileExt("bob") )
1 cycrow 2190
			{
2191
				if ( f->PCKFile() )
2192
					f->ChangeFileExt("pbb");
42 cycrow 2193
			}
1 cycrow 2194
		}
2195
	}
2196
}
2197
 
2198
void CXspFile::AdjustCockpits()
2199
{
2200
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
2201
	{
2202
		SCockpit *c = node->Data();
2203
		if ( c->iIndex < 0 )
2204
			continue;
2205
 
39 cycrow 2206
		Utils::String id = c->sCockpit.token(";", 19);
1 cycrow 2207
 
2208
		for ( int i = 0; i < 6; i++ )
2209
		{
39 cycrow 2210
			Utils::String tId = m_sData.token(";", 32 + (i * 2));
2211
			if ( tId.isNumber() && ((int)tId) == c->iIndex )
50 cycrow 2212
				m_sData = m_sData.replaceToken(";", 32 + (i * 2), (id + "(" + Utils::String::Number(c->iIndex) + ")").c_str());
1 cycrow 2213
		}
2214
	}
2215
}
2216
 
39 cycrow 2217
Utils::String CXspFile::FormatShipData(CyStringList *cockpits, int *text, int game)
1 cycrow 2218
{
39 cycrow 2219
	Utils::String data = (game == GAME_X3) ? this->GetX3ShipData() : this->GetTCShipData();
1 cycrow 2220
	// do turrets
2221
	for ( int t = 0; t < 6; t++ )
2222
	{
2223
		int oldPos = 0;
39 cycrow 2224
		Utils::String turret = data.token(";", 32 + (t * 2));
2225
		if ( !turret.isNumber() )
1 cycrow 2226
		{
39 cycrow 2227
			if ( turret.isin("(") )
1 cycrow 2228
			{
39 cycrow 2229
				oldPos = turret.tokens("(", 2).token(")", 1);
2230
				turret = turret.token("(", 1);
1 cycrow 2231
			}
2232
			int pos = cockpits->FindStringPos(turret);
2233
			if ( pos < 0 )	pos = oldPos;
39 cycrow 2234
			if ( pos >= cockpits->Count() ) pos = 0;
2235
			data = data.replaceToken(";", 32 + (t * 2), (long)pos);
1 cycrow 2236
		}
2237
	}
2238
	// adjust the weapons
2239
	int mask = this->GetLaserMask(game - 1);
2240
	if ( mask != -1 )
39 cycrow 2241
		data = data.replaceToken(";", 19, (long)mask);
1 cycrow 2242
	mask = this->GetMissileMask(game - 1);
2243
	if ( mask != -1 )
39 cycrow 2244
		data = data.replaceToken(";", 25, (long)mask);
1 cycrow 2245
 
2246
	// fix the ship text
2247
	if ( m_iOrgDesc > 0 )
2248
		(*text) = m_iOrgDesc;
39 cycrow 2249
	data = data.replaceToken(";", 7, (long)*text);
1 cycrow 2250
 
2251
	// add the ware id
39 cycrow 2252
	data.removeChar(9);
2253
	data.removeEndSpace();
1 cycrow 2254
	// remove the end ;
39 cycrow 2255
	while ( data.right(1) == ";" ) data.truncate(-1);
2256
	data = data.replaceToken(";", data.countToken(";"), this->GetShipID());
2257
	if ( data.right(1) != ";" )
1 cycrow 2258
		data += ";";
2259
 
2260
	return data;
35 cycrow 2261
}
2262