Subversion Repositories spk

Rev

Rev 48 | Rev 50 | 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
 
65
	m_bChanged = true; 
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
		{
74
			m_bChanged = true; 
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
 
92
	m_bChanged = true; 
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
 
107
	m_bChanged = true; 
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;
132
	m_bChanged = true; 
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;
156
	m_bChanged = true; 
157
}
158
 
159
bool CXspFile::IsValid ()
160
{
161
	if ( m_sName.Empty() )
162
		return false;
163
	if ( m_sAuthor.Empty() )
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);
1 cycrow 394
			m_pSceneFile = this->AddFile(CFileIO(file).GetFilename(), CFileIO(file).GetDir(), 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);
1 cycrow 403
			m_pCockpitFile = this->AddFile(CFileIO(file).GetFilename(), CFileIO(file).GetDir(), 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);
1 cycrow 412
			C_File *newFile= this->AddFile(CFileIO(file).GetFilename(), CFileIO(file).GetDir(), 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
			{
441
				newFile = this->AddFile(CFileIO(file).GetFilename(), CFileIO(file).GetDir(), 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
 
672
bool CXspFile::WriteHeader(FILE *id, int valueheader, int valueComprLen)
673
{
674
	fprintf ( id, "XSPCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen );
675
	if ( ferror(id) )
676
		return false;
677
	return true;
678
}
679
 
14 cycrow 680
bool CXspFile::CheckHeader(const Utils::String header) const
1 cycrow 681
{
682
	if ( header.Compare("XSPCycrow") )
683
		return true;
684
	return false;
685
}
686
 
687
void CXspFile::SetLaserMask(int game, int mask)
688
{
689
	for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
690
	{
691
		SWeaponMask *m = node->Data();
692
		if ( m->iGame == game )
693
		{
694
			m->iMask = mask;
695
			return;
696
		}
697
	}
698
 
699
	// no found, need to add it
700
	this->AddWeaponMask(game, mask);
701
}
702
 
703
void CXspFile::SetMissileMask(int game, int mask)
704
{
705
	for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
706
	{
707
		SWeaponMask *m = node->Data();
708
		if ( m->iGame == game )
709
		{
710
			m->iMask = mask;
711
			return;
712
		}
713
	}
714
 
715
	// no found, need to add it
716
	this->AddMissileMask(game, mask);
717
}
718
int CXspFile::GetLaserMask(int game, bool getOnly)
719
{
720
	int mask = -1;
721
	for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
722
	{
723
		SWeaponMask *m = node->Data();
724
		if ( m->iGame == game )
725
			return m->iMask;
726
 
727
		if ( !mask && !getOnly )
728
			mask = m->iMask;
729
	}
730
 
731
	return mask;
732
}
733
 
734
int CXspFile::GetMissileMask(int game, bool getOnly)
735
{
736
	int mask = -1;
737
	for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
738
	{
739
		SWeaponMask *m = node->Data();
740
		if ( m->iGame == game )
741
			return m->iMask;
742
 
743
		if ( !mask && !getOnly )
744
			mask = m->iMask;
745
	}
746
 
747
	return mask;
748
}
749
 
39 cycrow 750
Utils::String CXspFile::GetShipClass()
1 cycrow 751
{
14 cycrow 752
	if ( !m_sData.empty() )
753
		return m_sData.token(";", TSHIPPOS_CLASS);
1 cycrow 754
	return "OBJ_SHIP_M5";
755
}
756
 
757
bool CXspFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile)
758
{
759
	if ( !CBaseFile::GeneratePackagerScript(wildcard, list, datafile) )
760
		return false;
761
 
762
	if ( m_iShipyard )
763
	{
764
		list->PushBack("# Shipyards, Set which shipyards to add ships for sale to");
765
		for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 )
766
		{
767
			if ( this->IsShipyard(i) )
768
				list->PushBack(CyString("Shipyard: ") + GetShipyardName(i));
769
		}
770
		list->PushBack("");
771
	}
772
 
773
	if ( m_iOrgDesc > 0 )
774
	{
775
		list->PushBack("# Use Original Description, overrides text entrys to use one of the built in text");
776
		list->PushBack(CyString("OriginalDescription: ") + (long)m_iOrgDesc);
777
		list->PushBack("");
778
	}
779
 
14 cycrow 780
	if ( !m_sID.empty() )
1 cycrow 781
	{
782
		list->PushBack("# Ship ID, the ship id to identify the ship as");
783
		list->PushBack(CyString("ShipID: ") + m_sID);
784
	}
785
 
14 cycrow 786
	if ( !m_sData.empty() )
1 cycrow 787
	{
788
		list->PushBack("# Ship Data, the TShip data entry to add to the game (parts of this are adjusted and auto generated by the installer)");
789
		list->PushBack(CyString("ShipData: ") + m_sData);
790
		list->PushBack("");
791
	}
792
 
793
	if ( m_bExistingShip )
794
	{
795
		list->PushBack("# Existing Ship, replaces an existing ship in the game with ship package instead of creating a new entry");
796
		list->PushBack("ExistingShip");
797
		list->PushBack("");
798
	}
799
 
800
	if ( !datafile )
801
	{
802
		if ( !CBaseFile::GeneratePackagerScriptFile(wildcard, list) )
803
			return false;
804
	}
805
 
806
	return true;
807
}
808
 
14 cycrow 809
bool CXspFile::LoadPackageData(const Utils::String &sFirst, const Utils::String &sRest)
1 cycrow 810
{
14 cycrow 811
	if ( sFirst.Compare("Shipyard") )
1 cycrow 812
	{
813
		for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 )
814
		{
39 cycrow 815
			if ( sRest.Compare(GetShipyardName(i)) )
1 cycrow 816
			{
817
				this->AddShipyard(i);
818
				break;
819
			}
820
		}
821
	}
14 cycrow 822
	else if ( sFirst.Compare("OriginalDescription") )
823
		m_iOrgDesc = sRest;
824
	else if ( sFirst.Compare("ShipData") )
825
		m_sData = sRest;
826
	else if ( sFirst.Compare("ReadData") ) // read data from a tships file
1 cycrow 827
	{
828
		CPackages p;
14 cycrow 829
		m_sData = p.ReadShipData(sRest.tokens(" ", 2), sRest.token(" ", 1)).ToString();
1 cycrow 830
	}
14 cycrow 831
	else if ( sFirst.Compare("ExistingShip") )
1 cycrow 832
		m_bExistingShip = true;
14 cycrow 833
	else if ( sFirst.Compare("ShipID") )
834
		m_sID = sRest;
835
	else if ( !CBaseFile::LoadPackageData(sFirst, sRest) )
1 cycrow 836
	{
837
		return false;
838
	}
839
 
840
	return true;
841
}
842
 
843
 
39 cycrow 844
Utils::String CXspFile::GetX3ShipData()
1 cycrow 845
{
39 cycrow 846
	Utils::String data = m_sData;
1 cycrow 847
 
848
	// change the ship subtype, Reunion uses number, TC uses a define
39 cycrow 849
	Utils::String sSubType = data.token(";", 6);
850
	if ( !((long)sSubType) && sSubType != "0" )
851
		data = data.replaceToken(";", 6, (long)CShipData::ConvertShipSubType(CyString(sSubType)));
1 cycrow 852
 
39 cycrow 853
	Utils::String sClass = data.token(";", TSHIPPOS_CLASS);
854
	if ( !((long)sClass) && sClass != "0" )
1 cycrow 855
	{
856
		int num = 0;
857
		for ( int i = 0; i < OBJ_SHIP_MAX; i++ )
858
		{
39 cycrow 859
			if ( sClass.Compare(CShipData::ConvertShipClass(CShipData::GetShipClassFromNum(i)).ToString()) )
1 cycrow 860
			{
861
				num = i;
862
				break;
863
			}
864
		}
865
 
39 cycrow 866
		data = data.replaceToken(";", TSHIPPOS_CLASS, (long)num);
1 cycrow 867
	}
868
 
869
	return data;
870
}
871
 
39 cycrow 872
Utils::String CXspFile::GetTCShipData()
1 cycrow 873
{
39 cycrow 874
	Utils::String data = m_sData;
1 cycrow 875
 
39 cycrow 876
	Utils::String sSubType = data.token(";", 6);
877
	if ( ((long)sSubType) || sSubType == "0" )
878
		data = data.replaceToken(";", 6, CShipData::ConvertShipSubType((long)sSubType).ToString());
1 cycrow 879
 
39 cycrow 880
	Utils::String sClass = data.token(";", TSHIPPOS_CLASS);
881
	if ( ((long)sClass) || sClass == "0" )
882
		data = data.replaceToken(";", TSHIPPOS_CLASS, CShipData::ConvertShipClass((long)sClass).ToString());
1 cycrow 883
 
884
	return data;
885
}
886
 
39 cycrow 887
bool CXspFile::RemoveCockpit(const Utils::String &sCockpitId)
1 cycrow 888
{
39 cycrow 889
	Utils::String cockpitid = sCockpitId;
1 cycrow 890
	// if its a whole line, just get the end
39 cycrow 891
	if ( cockpitid.isin(";") )
1 cycrow 892
	{
39 cycrow 893
		cockpitid = cockpitid.tokens(";", -2);
894
		while ( cockpitid.right(1) == ";" )
895
			cockpitid.truncate(-1);
1 cycrow 896
	}
897
 
898
	bool ret = false;
899
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
900
	{
39 cycrow 901
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 902
		if ( id.Compare(cockpitid) )
903
		{
904
			node->DeleteData();
905
			ret = true;
906
			break;
907
		}
908
	}
909
 
910
	m_lCockpit.RemoveEmpty();
911
 
912
	return ret;
913
}
914
 
39 cycrow 915
bool CXspFile::RemoveComponent(const Utils::String &section1, const Utils::String &section2, const Utils::String &data)
1 cycrow 916
{
917
	bool ret = false;
918
	for ( CListNode<SComponent> *node = m_lComponent.Front(); node; node = node->next() )
919
	{
920
		if ( node->Data()->sSection.Compare(section1) && node->Data()->sSection2.Compare(section2) && node->Data()->sData.Compare(data) )
921
		{
922
			ret = true;
923
			node->DeleteData();
924
			break;
925
		}
926
	}
927
	m_lComponent.RemoveEmpty();
928
	return ret;
929
}
930
 
39 cycrow 931
bool CXspFile::RemoveDummy(const Utils::String &section, const Utils::String &data)
1 cycrow 932
{
933
	bool ret = false;
934
	for ( CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next() )
935
	{
936
		if ( node->Data()->sSection.Compare(section) && node->Data()->sData.Compare(data) )
937
		{
938
			ret = true;
939
			node->DeleteData();
940
			break;
941
		}
942
	}
943
	m_lDummy.RemoveEmpty();
944
 
945
	return ret;
946
}
947
 
39 cycrow 948
Utils::String CXspFile::GetCockpitData(const Utils::String &cid)
1 cycrow 949
{
950
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
951
	{
39 cycrow 952
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 953
		if ( id.Compare(cid) )
954
			return node->Data()->sCockpit;
955
	}
956
 
39 cycrow 957
	return "";
1 cycrow 958
}
959
 
39 cycrow 960
SCockpit *CXspFile::FindCockpit(const Utils::String &cid)
1 cycrow 961
{
962
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
963
	{
39 cycrow 964
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 965
		if ( id.Compare(cid) )
966
			return node->Data();
967
	}
968
 
969
	return NULL;
970
}
971
 
39 cycrow 972
void CXspFile::EditCockpit(const Utils::String &cid, const Utils::String &cockpit)
1 cycrow 973
{
974
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
975
	{
39 cycrow 976
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 977
		if ( id.Compare(cid) )
978
		{
979
			node->Data()->sCockpit = cockpit;
980
			break;
981
		}
982
	}
983
}
984
 
39 cycrow 985
void CXspFile::EditCockpit(const Utils::String &cid, const Utils::String &scene, int mask)
1 cycrow 986
{
987
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
988
	{
39 cycrow 989
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 990
		if ( id.Compare(cid) )
991
		{
39 cycrow 992
			Utils::String cockpit = node->Data()->sCockpit;
993
			cockpit = cockpit.replaceToken(";", 8, scene);
994
			cockpit = cockpit.replaceToken(";", 9, (long)mask);
1 cycrow 995
			node->Data()->sCockpit = cockpit;
996
			break;
997
		}
998
	}
999
}
39 cycrow 1000
void CXspFile::NewCockpit(const Utils::String &id, const Utils::String &scene, int mask)
1 cycrow 1001
{
39 cycrow 1002
	Utils::String cockpit = "0;0;0;0;0;0;0;";
1 cycrow 1003
	cockpit += scene + ";";
39 cycrow 1004
	cockpit += (long)mask;
1 cycrow 1005
	cockpit += ";0;0;0;0;0;0;-100000;0;0;";
1006
	cockpit += id + ";";
1007
	this->AddCockpit(cockpit, -1);
1008
}
1009
 
39 cycrow 1010
bool CXspFile::RemoveCutData(const Utils::String &cut)
1 cycrow 1011
{
1012
	bool ret = false;
1013
	for ( SStringList *str = m_lCutData.Head(); str; str = str->next )
1014
	{
39 cycrow 1015
		if ( str->str.GetToken(";", 1, 1).Compare(CyString(cut.token(";", 1))) )
1 cycrow 1016
		{
1017
			ret = true;
1018
			str->remove = true;
1019
			break;
1020
		}
1021
	}
1022
 
1023
	m_lCutData.RemoveMarked();
1024
 
1025
	return ret;
1026
}
1027
 
39 cycrow 1028
bool CXspFile::RemoveBodies(const Utils::String &cut)
1 cycrow 1029
{
1030
	bool ret = false;
1031
	for ( SStringList *str = m_lBodies.Head(); str; str = str->next )
1032
	{
39 cycrow 1033
		if ( str->str.Remove(' ').Compare(CyString(cut.remove(' '))) )
1 cycrow 1034
		{
1035
			ret = true;
1036
			str->remove = true;
1037
			break;
1038
		}
1039
	}
1040
 
1041
	m_lBodies.RemoveMarked();
1042
 
1043
	return ret;
1044
}
1045
 
39 cycrow 1046
bool CXspFile::RemoveAnimation(const Utils::String &cut)
1 cycrow 1047
{
1048
	bool ret = false;
1049
	for ( SStringList *str = m_lAnimations.Head(); str; str = str->next )
1050
	{
39 cycrow 1051
		if ( str->str.Remove(' ').Remove('\n').Compare(CyString(cut.remove(' ').remove('\n'))) )
1 cycrow 1052
		{
1053
			ret = true;
1054
			str->remove = true;
1055
			break;
1056
		}
1057
	}
1058
 
1059
	m_lAnimations.RemoveMarked();
1060
 
1061
	return ret;
1062
}
1063
 
39 cycrow 1064
void CXspFile::AddCockpit(const Utils::String &cockpit, int game, int mask, int index)
1 cycrow 1065
{
1066
	SCockpit *pCockpit = NULL;
1067
 
1068
	// first search for the cockpit entry
39 cycrow 1069
	Utils::String cid = cockpit.token(";", 19);
1 cycrow 1070
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1071
	{
39 cycrow 1072
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 1073
		if ( id.Compare(cid) )
1074
		{
1075
			pCockpit = node->Data();
1076
			break;
1077
		}
1078
	}
1079
 
1080
	if ( !pCockpit )
1081
	{
1082
		pCockpit = new SCockpit;
1083
		pCockpit->sCockpit = cockpit;
1084
		pCockpit->iIndex = index;
1085
		m_lCockpit.push_back(pCockpit);
1086
	}
1087
	if ( index != -1 )
1088
		pCockpit->iIndex = index;
1089
 
1090
	// now add the game mask
1091
	if ( game > 0 )
1092
	{
1093
		// search if the game mask already exists
1094
		SWeaponMask *wm = NULL;
1095
		for ( CListNode<SWeaponMask> *node = pCockpit->lWeaponMask.Front(); node; node = node->next() )
1096
		{
1097
			if ( node->Data()->iGame == game )
1098
			{
1099
				wm = node->Data();
1100
				break;
1101
			}
1102
		}
1103
 
1104
		if ( !wm )
1105
		{
1106
			wm = new SWeaponMask;
1107
			pCockpit->lWeaponMask.push_back(wm);
1108
		}
1109
 
1110
		wm->iGame = game;
1111
		if ( mask == -1 )
39 cycrow 1112
			wm->iMask = cockpit.token(";", 9);
1 cycrow 1113
		else
1114
			wm->iMask = mask;
1115
	}
1116
	m_bChanged = true; 
1117
}
1118
 
39 cycrow 1119
void CXspFile::AddBody(const Utils::String &section, const Utils::String &data)
1 cycrow 1120
{
1121
	this->AddBodies(section + ";" + data);
1122
	m_bChanged = true; 
1123
}
39 cycrow 1124
void CXspFile::AddBodies(const Utils::String &sData)
1 cycrow 1125
{
39 cycrow 1126
	Utils::String data = sData;
1127
	if ( !data.isNumber() )
1 cycrow 1128
	{
39 cycrow 1129
		if ( data[(int)(data.length() - 5)] == '.' )
1130
			data = data.left(-5);
1131
		else if ( data[(int)(data.length() - 4)] == '.' )
1132
			data = data.left(-4);
1133
		if ( data.right(1) != ";" )
1 cycrow 1134
			data += ";";
1135
	}
39 cycrow 1136
	m_lBodies.PushBack(CyString(data), true);
1 cycrow 1137
	m_bChanged = true; 
1138
}
1139
 
39 cycrow 1140
int CXspFile::GetAnimationType(const Utils::String &type)
1 cycrow 1141
{
1142
	if ( type.Compare("TAT_TAGSINGLESTEP") )
1143
		return TAT_SINGLE;
1144
	else if ( type.Compare("TAT_TAGONESHOT") 
1145
				|| type.Compare("TAT_TAGONESHOT_REINIT") 
1146
				|| type.Compare("TAT_PINGPONG")
1147
				|| type.Compare("TAT_TAGLOOP") )
1148
		return TAT_3;
1149
 
1150
	return TAT_NONE;
1151
}
1152
 
1153
bool CXspFile::ReadAnimations(CyStringList *lIn, CyStringList *lOut, int startRecord)
1154
{
39 cycrow 1155
	Utils::String lastComment;
1156
	Utils::String addEntry;
1 cycrow 1157
	int remaining = 0;
39 cycrow 1158
	Utils::String lastType;
1 cycrow 1159
	int newEntries = 0;
1160
	int entries = -1;
1161
	for ( SStringList *strNode = lIn->Head(); strNode; strNode = strNode->next )
1162
	{
39 cycrow 1163
		Utils::String line = strNode->str.ToString();
1164
		line.removeChar('\r');
1165
		line.removeChar(9);
1166
		if ( line.empty() || line[0] == '/' )
1 cycrow 1167
			continue;
1168
		if ( entries == -1)
1169
		{
39 cycrow 1170
			entries	= line.token(";", 1);
1 cycrow 1171
			newEntries = entries - startRecord;
1172
		}
1173
		else
1174
		{
1175
			// remove comments, endspaces and last ;
39 cycrow 1176
			Utils::String sStriped = line;
1177
			if ( sStriped.isin("//") )
1 cycrow 1178
			{
1179
				if ( entries <= newEntries )
39 cycrow 1180
					lastComment = "//" + sStriped.tokens("//", 2);
1181
				sStriped = sStriped.token("//", 1);
1 cycrow 1182
			}
39 cycrow 1183
			sStriped.removeEndSpace();
1184
			if ( sStriped.right(1) == ";" )
1185
				sStriped.truncate(-1);
1 cycrow 1186
 
39 cycrow 1187
			Utils::String sRemainingLeft;
1 cycrow 1188
			if ( remaining > 0 )
1189
				sRemainingLeft = sStriped;
1190
			else
1191
			{
1192
				// each line should be a new entry, with some exceptions
1193
				// potection for new lines
39 cycrow 1194
				lastType = sStriped.token(";", 1);
1 cycrow 1195
 
1196
				switch (CXspFile::GetAnimationType(lastType))
1197
				{
1198
					case TAT_SINGLE:
39 cycrow 1199
						remaining = (long)sStriped.token(";", 5) + 1;
1200
						sRemainingLeft = sStriped.tokens(";", 6);
1 cycrow 1201
						if ( entries <= newEntries )
39 cycrow 1202
							addEntry = sStriped.tokens(";", 1, 5) + ";";
1 cycrow 1203
						break;
1204
					case TAT_3:
39 cycrow 1205
						remaining = (long)sStriped.token(";", 5) + 1;
1206
						sRemainingLeft = sStriped.tokens(";", 6);
1 cycrow 1207
						if ( entries <= newEntries )
39 cycrow 1208
							addEntry = sStriped.tokens(";", 1, 5) + ";";
1 cycrow 1209
						break;
1210
 
1211
					default:
1212
						remaining = 0;
1213
						if ( entries <= newEntries )
1214
							addEntry = sStriped;
1215
 
1216
				}
1217
			}
1218
 
39 cycrow 1219
			if ( !sRemainingLeft.empty() )
1 cycrow 1220
			{
1221
				int tatType = CXspFile::GetAnimationType(lastType);
1222
				if ( tatType == TAT_SINGLE )
1223
				{
39 cycrow 1224
					if ( sRemainingLeft.isin(";") )
1225
						remaining -= sRemainingLeft.countToken(";");
1226
					else if ( !sRemainingLeft.empty() )
1 cycrow 1227
						--remaining;
1228
 
1229
					if ( entries <= newEntries )
1230
						addEntry += sRemainingLeft + ";";
1231
				}
1232
				else if ( tatType == TAT_3 )
1233
				{
1234
					// last entry
1235
					if ( remaining == 1 )
1236
						--remaining;
39 cycrow 1237
					else if ( sRemainingLeft.isin(";") )
1 cycrow 1238
					{
39 cycrow 1239
						if ( !sRemainingLeft.isin("TATF_COORDS") )
1 cycrow 1240
						{
39 cycrow 1241
							int amt = sRemainingLeft.countToken(";") / 3;
1 cycrow 1242
							remaining -= amt;
39 cycrow 1243
							if ( remaining == 1 && (sRemainingLeft.countToken(";") - (amt * 3)) == 1 )
1 cycrow 1244
								--remaining;
1245
						}
1246
						else
1247
						{
39 cycrow 1248
							int iRem = sRemainingLeft.countToken(";");
1 cycrow 1249
							int iPos = 1;
1250
							while ( iPos < iRem )
1251
							{
39 cycrow 1252
								Utils::String first = sRemainingLeft.token(";", iPos);
1253
								if ( first.isin("TATF_COORDS") )
1 cycrow 1254
									iPos += 5;
1255
								else
1256
									iPos += 3;
1257
								--remaining;
1258
							}
1259
 
1260
							if ( remaining == 1 && iPos == iRem )
1261
								--remaining;
1262
						}
1263
					}
1264
 
1265
					if ( entries <= newEntries )
1266
						addEntry += sRemainingLeft + ";";
1267
				}
1268
			}
1269
 
1270
			if ( remaining <= 0 )
1271
			{
39 cycrow 1272
				if ( entries <= newEntries && !addEntry.empty())
1 cycrow 1273
				{
39 cycrow 1274
					if ( addEntry[(int)addEntry.length() - 1] != ';' )
1 cycrow 1275
						addEntry += ";";
39 cycrow 1276
					lOut->PushBack(CyString(addEntry + lastComment));
1 cycrow 1277
				}
1278
				--entries;
1279
			}
1280
		}
1281
	}
1282
 
1283
	return !lOut->Empty();
1284
}
1285
 
1286
void CXspFile::AddAnimation(CyStringList *list)
1287
{
1288
	for ( SStringList *strNode = list->Head(); strNode; strNode = strNode->next )
39 cycrow 1289
		this->AddAnimation(strNode->str.ToString());
1 cycrow 1290
	m_bChanged = true; 
1291
}
1292
 
1293
SText *CXspFile::FindShipText(int lang)
1294
{
1295
	if ( m_lText.empty() )
1296
		return NULL;
1297
 
1298
	SText *english = NULL;
1299
	SText *german = NULL;
1300
	SText *found = NULL;
1301
	for ( CListNode<SText> *node = m_lText.Front(); node; node = node->next() )
1302
	{
1303
		SText *text = node->Data();
1304
		// matched language
1305
		if ( text->iId == lang )
1306
			return text;
1307
		else if ( text->iId == 44 )
1308
			english = text;
1309
		else if ( text->iId == 49 )
1310
			german = text;
1311
		else if ( !found )
1312
			found = text;
1313
	}
1314
 
1315
	// if we've found an english version, use that
1316
	if ( english )
1317
		return english;
1318
	// otherwise try a german
1319
	if ( german )
1320
		return german;
1321
	// otherwise use any we've found (usually first one)
1322
	return found;
1323
}
1324
 
39 cycrow 1325
Utils::String CXspFile::GetTextName(int lang)
1 cycrow 1326
{
1327
	SText *t = FindShipText(lang);
1328
	if ( t )
1329
	{
1330
		// return the correct language text
39 cycrow 1331
		if ( !t->sName.empty() )
1 cycrow 1332
			return t->sName;
1333
		// we have found a text, but there is no ship name ??
1334
		else if ( lang != 44 )
1335
		{
1336
			// reget the english one
1337
			t = FindShipText(44);
39 cycrow 1338
			if ( t && !t->sName.empty() )
1 cycrow 1339
				return t->sName;
1340
		}
1341
	}
1342
 
1343
	// still not found one, return the ships name
1344
	return this->GetShipName(lang);
1345
}
1346
 
39 cycrow 1347
Utils::String CXspFile::GetTextDescription(int lang)
1 cycrow 1348
{
1349
	SText *t = FindShipText(lang);
1350
	if ( t )
1351
	{
1352
		// return the correct language text
39 cycrow 1353
		if ( !t->sDesc.empty() )
1 cycrow 1354
			return t->sDesc;
1355
		// we have found a text, but there is no ship name ??
1356
		else if ( lang != 44 )
1357
		{
1358
			// reget the english one
1359
			t = FindShipText(44);
39 cycrow 1360
			if ( t && !t->sDesc.empty() )
1 cycrow 1361
				return t->sDesc;
1362
		}
1363
	}
1364
 
1365
	// still not found one, return the ships name
48 cycrow 1366
	if ( !this->description().empty() ) return this->description();
1 cycrow 1367
	return this->GetShipName(lang);
1368
}
1369
 
35 cycrow 1370
bool CXspFile::startExtractShip(CVirtualFileSystem *pVfs, const Utils::String &sId, CProgressInfo *pProgress)
1 cycrow 1371
{
39 cycrow 1372
	m_sID = sId.remove('\r');
35 cycrow 1373
	while ( m_sID.right(1) == ";" )
1374
		m_sID.truncate(-1);
1 cycrow 1375
 
35 cycrow 1376
	m_sData = pVfs->getTShipsEntry(m_sID);
1377
 
1 cycrow 1378
	// get scene files
35 cycrow 1379
	if ( pProgress ) pProgress->UpdateStatus(IMPORTSHIP_SCENE);
1380
	if ( !this->extractSceneFiles(pVfs) )
1 cycrow 1381
		return false;
1382
 
1383
	return true;
1384
}
1385
 
35 cycrow 1386
bool CXspFile::extractShip(CVirtualFileSystem *pVfs, const Utils::String &sId, CProgressInfo *progress)
1 cycrow 1387
{
35 cycrow 1388
	if ( !this->startExtractShip(pVfs, sId, progress) )
1 cycrow 1389
		return false;
1390
 
1391
	// read the scene file and get the files list
35 cycrow 1392
	if ( !this->processSceneFiles(pVfs, progress) )
1 cycrow 1393
		return false;
1394
 
1395
	// pack all the ship files
1396
	this->PackAllFiles();
1397
 
1398
	return true;
1399
}
1400
 
35 cycrow 1401
bool CXspFile::extractSceneFiles(CVirtualFileSystem *pVfs)
1 cycrow 1402
{
35 cycrow 1403
	m_pSceneFile = pVfs->extractGameFileToPackage(this, "objects\\" + m_sData.token(";", 17) + ".pbd", FILETYPE_SHIPSCENE, "objects\\" + m_sData.token(";", 17) + ".bod");
1404
	if ( !m_pSceneFile ) return false;
1405
	m_pCockpitFile = pVfs->extractGameFileToPackage(this, "objects\\" + m_sData.token(";", 18) + ".pbd", FILETYPE_COCKPITSCENE, "objects\\" + m_sData.token(";", 18) + ".bod");
1 cycrow 1406
 
1407
	return true;
1408
}
1409
 
1410
CyStringList *CXspFile::ReadSceneModels()
1411
{
1412
	// read the scene file
1413
	if ( !m_pSceneFile )
1414
		m_pSceneFile = this->GetFirstFile(FILETYPE_SHIPSCENE);
1415
 
1416
	if ( !m_pSceneFile )
1417
		return NULL;
1418
 
1419
	// check if its packed
1420
	size_t datasize;
1421
	unsigned char *data = m_pSceneFile->UncompressData((long *)&datasize, 0);
1422
 
1423
	// if data wasn't compressed, then copy it itself as we are editing it
1424
	bool deleteData = false;
1425
	if ( data == m_pSceneFile->GetData() )
1426
	{
1427
		data = new unsigned char[m_pSceneFile->GetDataSize()];
1428
		memcpy(data, m_pSceneFile->GetData(), m_pSceneFile->GetDataSize());
1429
		deleteData = true;
1430
	}
1431
 
1432
	if ( data && datasize )
1433
	{
1434
		if ( m_pSceneFile->CheckPackedExtension() )
1435
			data = UnPCKData(data, datasize, &datasize);
1436
	}
1437
 
1438
	if ( !data || !datasize )
1439
		return NULL;
1440
 
1441
	CyStringList *lModels = new CyStringList;
1442
 
1443
	size_t pos = 0;
1444
	bool newline = true;
1445
	bool online = false;
1446
	while ( pos < datasize )
1447
	{
1448
		char c = data[pos];
1449
		++pos;
1450
 
1451
		// skip until next line
1452
		if ( !newline && !online )
1453
		{
1454
			if ( c == '\n' )
1455
				newline = true;
1456
			continue;
1457
		}
1458
 
1459
		if ( newline )
1460
		{
1461
			if ( c == ' ' || c == 9 || c == '\n' || c == '\r' )
1462
				continue;
1463
 
1464
			newline = false;
1465
 
1466
			if ( c == 'P' || c == 'p' )
1467
			{
1468
				while ( data[pos] == ' ' ) pos++;
1469
				unsigned char *line = (data + pos);
1470
				while ( data[pos] != ' ' && data[pos] != ';' ) pos++;
1471
				data[pos] = '\0';
1472
				if ( atoi((const char *)line) == lModels->Count() )
1473
					online = true;
1474
			}
1475
		}
1476
		// this line is out model
1477
		else if ( online )
1478
		{
1479
			if ( c == 'B' || c == 'b' )
1480
			{
1481
				while(data[pos] == ' ') pos++;
1482
				unsigned char *line = (data + pos);
1483
				while(data[pos] != ';') pos++;
1484
				data[pos] = '\0';
1485
 
1486
				lModels->PushBack((char *)line);
1487
				online = false;
1488
			}
1489
		}
1490
	}
1491
 
1492
	if ( deleteData )
1493
		delete data;
1494
 
1495
	return lModels;
1496
}
1497
 
42 cycrow 1498
void CXspFile::extractCutData(CVirtualFileSystem *pVfs, CyStringList *sceneModels, bool add)
1499
{
1500
	std::vector<int> cuts;
1501
	for ( CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next() ) {
1502
		Utils::String data = node->Data()->sData;
1503
		int states = data.token(";", 3);
1504
		for ( int i = 0; i < states; i++ ) {
1505
			int cutid = data.token(";", (i * 2) + 5);
1506
			if ( !cutid ) continue;
1507
			cuts.push_back(cutid);
1508
		}
1509
	}
1510
 
1511
	if ( cuts.empty() ) return;
1512
 
1513
	if ( !pVfs->ExtractGameFile("types/CutData.pck", "tmp") ) return;
1514
 
1515
	CFileIO File("tmp");
1516
	if ( !File.Exists() ) return;
1517
 
1518
	CyStringList *lines = File.ReadLinesStr();
1519
	int count = -1;
1520
	for ( SStringList *node = lines->Head(); node; node = node->next ) {
1521
		Utils::String line = node->str.ToString();
1522
		line.removeChar('\r');
1523
		line.removeChar(' ');
1524
		line.removeFirstSpace();
1525
		if ( line[0] == '/' ) continue;
1526
		if ( count == -1 ) count = line.token(";", 1);
1527
		else {
1528
			int max;
1529
			Utils::String *words = line.tokenise(";", &max);
1530
			if ( words && max ) {
1531
				for ( int i = 0; i < max; i += 2 ) {
1532
					int cutid = words[i];
1533
					if ( !cutid ) continue;
1534
					for ( std::vector<int>::iterator itr = cuts.begin(); itr != cuts.end(); itr++ ) {
1535
						if ( (*itr) == cutid ) {
1536
							this->AddCutData(words[i] + ";" + words[i + 1] + ";");
1537
							if ( add ) {
1538
								sceneModels->PushBack(CyString(words[i + 1]));
1539
							}
1540
							break;
1541
						}
1542
					}
1543
				}
1544
				CLEANSPLIT(words, max);
1545
			}
1546
		}
1547
	}
1548
}
1549
 
35 cycrow 1550
void CXspFile::extractDummies(CVirtualFileSystem *pVfs, CyStringList *sceneModels, bool add)
1 cycrow 1551
{
1552
	if ( !sceneModels ) return;
31 cycrow 1553
 
1554
	bool extracted = false;
35 cycrow 1555
	if ( pVfs->ExtractGameFile("types/dummies.pck", "tmp") ) {
1 cycrow 1556
		CFileIO File("tmp");
1557
		if ( File.Exists() )
1558
		{
39 cycrow 1559
			Utils::String section;
1 cycrow 1560
			int secCount = 0;
1561
			CyStringList *lines = File.ReadLinesStr();
1562
			for ( SStringList *node = lines->Head(); node; node = node->next )
1563
			{
1564
				node->str.RemoveFirstSpace();
1565
				node->str.RemoveChar(9);
1566
				node->str.RemoveChar('\r');
1567
				if ( node->str.Empty() )
1568
					continue;
1569
				if ( node->str[0] == '/' )
1570
					continue;
1571
 
1572
				// not in a section yet
1573
				if ( secCount <= 0 )
1574
				{
39 cycrow 1575
					section = node->str.GetToken(";", 1, 1).ToString();
1 cycrow 1576
					secCount = node->str.GetToken(";", 2, 2).ToInt();
1577
				}
1578
				else
1579
				{
39 cycrow 1580
					Utils::String first = node->str.GetToken(";", 1, 1).ToString();
1 cycrow 1581
					if ( sceneModels->FindString(first) )
1582
					{
39 cycrow 1583
						this->AddDummy(section, node->str.ToString());
1 cycrow 1584
 
1585
						if ( add )
1586
						{
1587
							int pos = 4;
1588
							int scene = node->str.GetToken(";", 3, 3).ToInt();
1589
							for ( int i = 0; i < scene; i++ )
1590
							{
1591
								sceneModels->PushBack(node->str.GetToken(";", 5 + (i * 2), 5 + (i * 2)));
1592
								pos += 2;
1593
							}
1594
 
1595
							int model = node->str.GetToken(";", pos, pos).ToInt();
1596
							for ( int i = 0; i < model; i++ )
1597
								sceneModels->PushBack(node->str.GetToken(";", pos + (i * 2) + 1, pos + (i * 2) + 1));
1598
						}
1599
					}
1600
					--secCount;
1601
 
1602
				}
1603
			}
1604
 
1605
			delete lines;
1606
			File.Remove();
1607
		}
1608
	}
1609
}
1610
 
35 cycrow 1611
void CXspFile::extractComponants(CVirtualFileSystem *pVfs, CyStringList *sceneModels)
1 cycrow 1612
{
1613
	if ( !sceneModels ) return;
35 cycrow 1614
	if ( pVfs->ExtractGameFile("types/components.pck", "tmp") )
1 cycrow 1615
	{
1616
		CFileIO File("tmp");
1617
		if ( File.Exists() )
1618
		{
39 cycrow 1619
			Utils::String file;
1620
			Utils::String section;
1 cycrow 1621
			int secCount = 0;
1622
			int secCount2 = 0;
1623
			CyStringList *lines = File.ReadLinesStr();
1624
			for ( SStringList *node = lines->Head(); node; node = node->next )
1625
			{
1626
				node->str.RemoveFirstSpace();
1627
				node->str.RemoveChar(9);
1628
				node->str.RemoveChar('\r');
1629
				if ( node->str.Empty() )
1630
					continue;
1631
				if ( node->str[0] == '/' )
1632
					continue;
1633
 
1634
				// not in a section yet
1635
				if ( secCount2 )
1636
				{
1637
					if ( sceneModels->FindString(file) )
39 cycrow 1638
						this->AddComponent(section, file, node->str.ToString());
1 cycrow 1639
					--secCount2;
1640
				}
1641
				else if ( secCount <= 0 )
1642
				{
39 cycrow 1643
					section = node->str.GetToken(";", 1, 1).ToString();
1 cycrow 1644
					secCount = node->str.GetToken(";", 2, 2).ToInt();
1645
				}
1646
				else
1647
				{
39 cycrow 1648
					file = node->str.GetToken(";", 1, 1).ToString();
1 cycrow 1649
					secCount2 = node->str.GetToken(";", 2, 2).ToInt();
1650
					--secCount;
1651
				}
1652
			}
1653
 
1654
			delete lines;
1655
			File.Remove();
1656
		}
1657
	}
1658
}
1659
 
1660
bool CXspFile::GetTextureList(CyStringList *list, const unsigned char *olddata, size_t size)
1661
{
1662
	if ( !olddata || !size )
1663
		return false;
1664
 
1665
	size_t startLine = 0;
1666
	CyString line;
1667
	size_t pos = 0;
1668
 
1669
	unsigned char *data = new unsigned char[size];
1670
	memcpy(data, olddata, size);
1671
 
1672
	while ( (pos++) < size )
1673
	{
1674
		if ( data[pos] == '\n' )
1675
		{
1676
			data[pos] = '\0';
1677
			line = (char *)(data + startLine);
1678
			line.RemoveChar(9);
1679
			line.RemoveChar('\r');
1680
			line.RemoveFirstSpace();
1681
 
1682
			if ( !line.Empty() && line[0] != '/' )
1683
			{
1684
				CyString first = line.GetToken(":", 1, 1);
1685
				if ( first.Compare("MATERIAL6") )
1686
				{
1687
					int max;
1688
					CyString *strs = line.GetToken(":", 2).SplitToken("; ", &max);
1689
 
1690
					if ( strs && max >= 2)
1691
					{
1692
						for ( int i = 2; i < max; i++ )
1693
						{
1694
							CyString s = strs[i];
1695
							if ( s.IsIn(";") )
1696
								s = s.GetToken(";", 1, 1);
1697
							if ( !s.IsNumber() && !s.Compare("NULL") && s.IsIn(".") )
1698
								list->PushBack(s, "", true);
1699
						}
1700
					}
1701
 
1702
					CLEANSPLIT(strs, max)
1703
				}
1704
			}
1705
 
1706
			startLine = pos + 1;
1707
		}
1708
	}
1709
 
1710
	delete [] data;
1711
 
1712
	return true;
1713
}
1714
 
35 cycrow 1715
void CXspFile::extractTextures(CVirtualFileSystem *pVfs)
1 cycrow 1716
{
1717
	CyStringList lTextures;
1718
 
1719
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1720
	{
1721
		C_File *f = node->Data();
1722
		if ( f->GetFileType() != FILETYPE_SHIPMODEL )
1723
			continue;
1724
 
1725
		// cant do these yet
1726
		if ( f->CheckFileExt("pbb") || f->CheckFileExt("bob") )
1727
		{
1728
			if ( !f->BobDecompile() )
1729
				continue;
1730
		}
1731
 
1732
		if ( !f->GetData() )
1733
		{
1734
			if ( !f->ReadFromFile() )
1735
				continue;
1736
		}
1737
 
1738
		unsigned char *data = NULL;
1739
		size_t size;
1740
 
1741
		if ( f->CheckFileExt("pbb") || f->CheckFileExt("pbd") )
1742
			data = f->UnPCKFile(&size);
1743
		else
1744
		{
1745
			data = f->GetData();
1746
			size = f->GetDataSize();
1747
		}
1748
 
1749
		this->GetTextureList(&lTextures, data, size);
1750
	}
1751
 
1752
	for ( SStringList *node = lTextures.Head(); node; node = node->next )
1753
	{
35 cycrow 1754
		if ( CFileIO(node->str).CheckFileExtension("dds") )
1755
			pVfs->extractGameFileToPackage(this, "dds\\" + Utils::String(node->str.ToString()), FILETYPE_SHIPOTHER);
1756
		else 
1757
			pVfs->extractGameFileToPackage(this, "textures\\" + Utils::String(node->str.ToString()), FILETYPE_SHIPOTHER);
1 cycrow 1758
	}
1759
}
1760
 
39 cycrow 1761
bool CXspFile::AddTextFromFile(const Utils::String &sFile, int textId)
1 cycrow 1762
{
39 cycrow 1763
	Utils::String file = sFile;
1764
 
1 cycrow 1765
	bool remove = false;
1766
	if ( CFileIO(file).CheckFileExtension("pck") )
1767
	{
39 cycrow 1768
		C_File F;
1769
		F.SetFilename(CyString(file));
1 cycrow 1770
		F.UnPCKFile();
1771
		if ( F.WriteToFile("tmp") )
1772
		{
1773
			remove = true;
1774
			file = "tmp";
1775
		}
1776
	}
1777
 
1778
	FILE *fid = fopen(file.c_str(), "r");
1779
	if ( fid )
1780
	{
1781
		bool ret = this->AddTextFromFile(fid, textId);
1782
		fclose(fid);
1783
 
1784
		if ( remove )
1785
			CFileIO(file).Remove();
1786
		m_bChanged = true; 
1787
		return ret;
1788
	}
1789
 
1790
	return false;
1791
}
1792
 
39 cycrow 1793
bool CXspFile::ImportBodies(CyStringList *sceneModels, const Utils::String &filename)
1 cycrow 1794
{
1795
	CFileIO File(filename);
1796
	if ( File.Exists() )
1797
	{
39 cycrow 1798
		Utils::String sSection;
1 cycrow 1799
		int section = 0;
1800
		CyStringList *lines = File.ReadLinesStr();
1801
		for ( SStringList *node = lines->Head(); node; node = node->next )
1802
		{
1803
			node->str.RemoveChar(9);
1804
			node->str.RemoveChar('\r');
1805
			node->str.RemoveFirstSpace();
1806
			if ( node->str.Empty() )
1807
				continue;
1808
			if ( node->str[0] == '/' )
1809
				continue;
1810
 
1811
			// are we looking for a section
1812
			if ( section <= 0 )
1813
			{
39 cycrow 1814
				sSection = node->str.GetToken(";", 1, 1).ToString();
1 cycrow 1815
				section = node->str.GetToken(";", 2, 2).ToInt();
1816
			}
1817
			else
1818
			{
1819
				int max;
1820
				CyString *strs = node->str.SplitToken(";", &max);
1821
				if ( strs && max )
1822
				{
1823
					for ( int i = 0; i < max; i++ )
1824
					{
1825
						strs[i].RemoveSpaces();
1826
						if (strs[i].Empty() )
1827
							continue;
1828
						if ( sceneModels->FindString(strs[i]) )
39 cycrow 1829
							this->AddBody(sSection, strs[i].ToString());
1 cycrow 1830
						--section;
1831
					}
1832
				}
1833
				CLEANSPLIT(strs, max)
1834
			}
1835
		}
1836
		delete lines;
1837
		return true;
1838
	}
1839
 
1840
	return false;
1841
}
1842
 
39 cycrow 1843
bool CXspFile::ImportCockpits(const Utils::String &filename)
1 cycrow 1844
{
1845
	CFileIO File(filename);
1846
	if ( File.Exists() )
1847
	{
1848
		CyStringList *lines = File.ReadLinesStr();
1849
		int entries = 0;
1850
		for ( SStringList *node = lines->Head(); node; node = node->next )
1851
		{
1852
			node->str.RemoveChar(9);
1853
			node->str.RemoveChar('\r');
1854
			node->str.RemoveFirstSpace();
1855
			if ( node->str.Empty() )
1856
				node->remove = true;
1857
			else if ( node->str[0] == '/' )
1858
				node->remove = true;
1859
			else if ( !entries )
1860
			{
1861
				entries = node->str.GetToken(";", 2, 2).ToInt();
1862
				node->remove = true;
1863
			}
1864
		}
1865
		lines->RemoveMarked();
1866
 
1867
		// now get all the entries from TShips
1868
		for ( int i = 0; i < 6; i++ )
1869
		{
14 cycrow 1870
			int idx = m_sData.token(";", 32 + (i * 2));
1 cycrow 1871
			if ( idx < lines->Count() && idx )
1872
			{
39 cycrow 1873
				Utils::String turret = lines->GetAt(idx)->str.ToString();
1 cycrow 1874
				int pos = -1;
14 cycrow 1875
				Utils::String id;
39 cycrow 1876
				while ( id.empty() && pos > -100 ) id = turret.token(";", pos--);
14 cycrow 1877
				m_sData = m_sData.replaceToken(";", 32 + (i * 2), id + "(" + (long)idx + ")");
1 cycrow 1878
 
1879
				this->AddCockpit(turret, 0);
1880
			}
1881
		}
1882
 
1883
		delete lines;
1884
		return true;
1885
	}
1886
	return false;
1887
}
1888
 
35 cycrow 1889
bool CXspFile::extractCockpits(CVirtualFileSystem *pVfs)
1 cycrow 1890
{
35 cycrow 1891
	if ( pVfs->ExtractGameFile("types/TCockpits.pck", "tmp") ) {
1 cycrow 1892
		bool ret = this->ImportCockpits("tmp");
1893
		CFileIO("tmp").Remove();
1894
 
1895
		return ret;
1896
	}
1897
 
1898
	return false;
1899
}
1900
 
35 cycrow 1901
bool CXspFile::extractBodies(CVirtualFileSystem *pVfs, CyStringList *sceneModels)
1 cycrow 1902
{
1903
	if ( !sceneModels ) return false;
31 cycrow 1904
 
35 cycrow 1905
	if ( pVfs->ExtractGameFile("types/Bodies.pck", "tmp") ) {
1 cycrow 1906
		bool ret = this->ImportBodies(sceneModels, "tmp");
1907
		CFileIO("tmp").Remove();
1908
 
1909
		return ret;
1910
	}
1911
 
1912
	return false;
1913
}
1914
 
1915
bool CXspFile::AddTextFromFile(FILE *id, int textId)
1916
{
14 cycrow 1917
	if ( textId == -1 && !m_sData.empty() )
1918
		textId = m_sData.token(";", 7);
1 cycrow 1919
 
1920
	if ( textId <= 0 )
1921
		return false;
1922
 
39 cycrow 1923
	Utils::String line;
1 cycrow 1924
	if ( !id )
1925
		return false;
1926
 
1927
	bool added = false;
1928
 
39 cycrow 1929
	Utils::String shipName;
1930
	Utils::String shipDesc;
1 cycrow 1931
 
1932
	int lang = 0;
1933
	bool inpage = false;
1934
	while ( !feof(id) )
1935
	{
39 cycrow 1936
		if ( !shipName.empty() && !shipDesc.empty() )
1 cycrow 1937
		{
1938
			added = true;
1939
			break;
1940
		}
1941
 
39 cycrow 1942
		line.readToEndOfLine(id, 0, false);
1943
		line.removeChar(9);
1944
		line.removeChar('\r');
1945
		line.removeFirstSpace();
1 cycrow 1946
 
1947
		if ( inpage )
1948
		{
39 cycrow 1949
			if ( line.left(6).Compare("</page") )
1 cycrow 1950
				break;
1951
 
1952
			// find matching id
39 cycrow 1953
			if ( line.left(6).Compare("<t id=") )
1 cycrow 1954
			{
39 cycrow 1955
				int pos = line.findPos("id=\"", 0);
1 cycrow 1956
				if ( pos != -1 )
1957
				{
39 cycrow 1958
					int endpos = line.findPos("\"", pos + 5);
1 cycrow 1959
					if ( endpos != -1 )
1960
					{
39 cycrow 1961
						int id = line.mid(pos + 5, endpos);
1 cycrow 1962
						if ( id == textId || id == (textId + 1) )
1963
						{
39 cycrow 1964
							pos = line.findPos(">", endpos);
1 cycrow 1965
							if ( pos != -1 )
1966
							{
39 cycrow 1967
								endpos = line.findPos("</t>", pos);
1 cycrow 1968
								if ( endpos != -1 )
1969
								{
1970
									if ( id == textId )
39 cycrow 1971
										shipName = line.mid(pos + 2, endpos - (pos + 1));
1 cycrow 1972
									else
39 cycrow 1973
										shipDesc = line.mid(pos + 2, endpos - (pos + 1));
1 cycrow 1974
								}
1975
							}
1976
						}
1977
					}
1978
				}
1979
			}
1980
		}
1981
		else if ( lang ) // search for page 17
1982
		{
39 cycrow 1983
			if ( line.left(8).Compare("<page id") )
1 cycrow 1984
			{
39 cycrow 1985
				int pos = line.findPos("id=\"");
1 cycrow 1986
				if ( pos != -1 )
1987
				{
39 cycrow 1988
					int endpos = line.findPos("\"", pos + 5);
1 cycrow 1989
					if ( endpos != -1 )
1990
					{
39 cycrow 1991
						Utils::String sId = line.mid(pos + 5, endpos - (pos + 4));
1992
						int id = sId;
1993
						if ( id == 17 || ((int)sId.right(4)) == 17 )
1 cycrow 1994
							inpage = true;
1995
					}
1996
				}
1997
			}
1998
		}
39 cycrow 1999
		else if ( line.left(12).Compare("<language id") )
1 cycrow 2000
		{
39 cycrow 2001
			int pos = line.findPos("id=\"");
1 cycrow 2002
			if ( pos != -1 )
2003
			{
39 cycrow 2004
				int endpos = line.findPos("\"", pos + 5);
1 cycrow 2005
				if ( endpos != -1 )
39 cycrow 2006
					lang = line.mid(pos + 5, endpos - (pos + 4));
1 cycrow 2007
			}
2008
		}
2009
	}
2010
 
2011
	// incase we only found the shipname
39 cycrow 2012
	if ( !shipName.empty() )
1 cycrow 2013
		added = true;
2014
 
2015
	if ( added )
2016
	{
2017
		if ( lang == 44 || m_sName.Empty())
2018
		{
2019
			m_sName = shipName;
48 cycrow 2020
			this->setDescription(shipDesc.findReplace("&amp", "&"));
1 cycrow 2021
		}
2022
		this->AddText(lang, shipName, shipDesc);
2023
		return true;	
2024
	}
2025
 
2026
	return false;
2027
}
2028
 
31 cycrow 2029
void CXspFile::ExtractTexts(CCatFile *catFile, CCatFile *secondCatFile, int textId)
1 cycrow 2030
{
2031
	for ( CListNode<SInCatFile> *node = catFile->GetFiles()->Front(); node; node = node->next() )
2032
	{
2033
		SInCatFile *f = node->Data();
2034
		if ( !f->sFile.Left(2).Compare("t\\") && !f->sFile.Left(2).Compare("t/") )
2035
			continue;
2036
 
2037
		// extract the text file and read in the data
31 cycrow 2038
		bool extracted = catFile->ExtractFile(f->sFile, "tmp");
2039
		if ( !extracted && secondCatFile ) extracted = secondCatFile->ExtractFile(f->sFile, "tmp");
2040
		if ( extracted ) {
1 cycrow 2041
			this->AddTextFromFile("tmp", textId);
2042
			CFileIO("tmp").Remove();
2043
		}
2044
	}
2045
}
2046
 
35 cycrow 2047
bool CXspFile::processSceneFileSection(int section, CVirtualFileSystem *pVfs, CyStringList *lModels, CProgressInfo *progress)
1 cycrow 2048
{
2049
	if ( progress ) progress->UpdateStatus(section);
2050
 
2051
	switch ( section )
2052
	{
2053
		case IMPORTSHIP_COMPONANT:
2054
			if ( !lModels ) return false;
35 cycrow 2055
			this->extractComponants(pVfs, lModels);
1 cycrow 2056
			break;
2057
 
2058
		case IMPORTSHIP_MODELS:
2059
			{
2060
				if ( !lModels ) return false;
2061
				for ( SStringList *node = lModels->Head(); node; node = node->next )
2062
				{
2063
					if ( node->str.IsNumber() ) // count be componants or dummy
2064
						continue;
35 cycrow 2065
					if ( pVfs->extractGameFileToPackage(this, "objects\\" + Utils::String(node->str.ToString()) + ".pbb", FILETYPE_SHIPMODEL, "objects\\" + Utils::String(node->str.ToString()) + ".bob") )
1 cycrow 2066
						continue;
35 cycrow 2067
					if ( pVfs->extractGameFileToPackage(this, "objects\\" + Utils::String(node->str.ToString()) + ".pbd", FILETYPE_SHIPMODEL, "objects\\" + Utils::String(node->str.ToString()) + ".bod") )
1 cycrow 2068
						continue;
2069
				}
2070
			}
2071
			break;
2072
 
2073
		case IMPORTSHIP_DUMMIES:
2074
			if ( !lModels ) return false;
35 cycrow 2075
			this->extractDummies(pVfs, lModels, true);
42 cycrow 2076
			this->extractCutData(pVfs, lModels, true);
1 cycrow 2077
			break;
2078
 
2079
		// extract the textures
2080
		case IMPORTSHIP_TEXTURES:
35 cycrow 2081
			this->extractTextures(pVfs);
1 cycrow 2082
			break;
2083
 
2084
		case IMPORTSHIP_TEXTS:
2085
			// extract the text file entries
35 cycrow 2086
			pVfs->extractTexts(this, m_sData.token(";", 7));
1 cycrow 2087
			break;
2088
 
2089
		case IMPORTSHIP_BODIES:
2090
			// extract the bodies entries
2091
			if ( !lModels ) return false;
35 cycrow 2092
			this->extractBodies(pVfs, lModels);
1 cycrow 2093
			break;
2094
 
2095
		case IMPORTSHIP_COCKPITS:
2096
			// extract the cockpit entries
35 cycrow 2097
			this->extractCockpits(pVfs);
1 cycrow 2098
			break;
2099
	}
2100
 
2101
	return true;
2102
}
2103
 
35 cycrow 2104
bool CXspFile::processSceneFiles(CVirtualFileSystem *pVfs, CProgressInfo *progress)
1 cycrow 2105
{
2106
	// now lets parse our files
2107
	if ( progress ) progress->UpdateStatus(IMPORTSHIP_EXTRACTSCENE);
2108
	CyStringList *lModels = this->ReadSceneModels();
2109
	if ( !lModels )
2110
		return false;
2111
 
2112
	// extract componants, and add extra items to list
35 cycrow 2113
	if ( !this->processSceneFileSection(IMPORTSHIP_COMPONANT, pVfs, lModels, progress) )
1 cycrow 2114
		return false;
2115
 
2116
	//lets first find any model files
35 cycrow 2117
	if ( !this->processSceneFileSection(IMPORTSHIP_MODELS, pVfs, lModels, progress) )
1 cycrow 2118
		return false;
2119
 
2120
	// extract the dummies
35 cycrow 2121
	if ( !this->processSceneFileSection(IMPORTSHIP_DUMMIES, pVfs, lModels, progress) )
1 cycrow 2122
		return false;
2123
 
2124
	// extract the textures
35 cycrow 2125
	if ( !this->processSceneFileSection(IMPORTSHIP_TEXTURES, pVfs, lModels, progress) )
1 cycrow 2126
		return false;
2127
 
2128
	// extract the text file entries
35 cycrow 2129
	if ( !this->processSceneFileSection(IMPORTSHIP_TEXTS, pVfs, lModels, progress) )
1 cycrow 2130
		return false;
2131
 
2132
	// extract the bodies entries
35 cycrow 2133
	if ( !this->processSceneFileSection(IMPORTSHIP_BODIES, pVfs, lModels, progress) )
1 cycrow 2134
		return false;
2135
 
2136
	// extract the cockpit entries
35 cycrow 2137
	if ( !this->processSceneFileSection(IMPORTSHIP_COCKPITS, pVfs, lModels, progress) )
1 cycrow 2138
		return false;
2139
 
2140
	delete lModels;
2141
 
2142
	return true;
2143
}
2144
 
2145
 
2146
void CXspFile::PackAllFiles()
2147
{
2148
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2149
	{
2150
		C_File *f = node->Data();
2151
		if ( f->GetFileType() == FILETYPE_SHIPSCENE || f->GetFileType() == FILETYPE_COCKPITSCENE || f->GetFileType() == FILETYPE_SHIPMODEL || f->GetFileType() == FILETYPE_SHIPOTHER )
41 cycrow 2152
		{	
2153
			/*
1 cycrow 2154
			if ( f->CheckFileExt("bod") )
2155
			{
2156
				if ( f->PCKFile() )
2157
					f->ChangeFileExt("pbd");
41 cycrow 2158
			}	
42 cycrow 2159
 
2160
			else */if ( f->CheckFileExt("bob") )
1 cycrow 2161
			{
2162
				if ( f->PCKFile() )
2163
					f->ChangeFileExt("pbb");
42 cycrow 2164
			}
1 cycrow 2165
		}
2166
	}
2167
}
2168
 
2169
void CXspFile::AdjustCockpits()
2170
{
2171
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
2172
	{
2173
		SCockpit *c = node->Data();
2174
		if ( c->iIndex < 0 )
2175
			continue;
2176
 
39 cycrow 2177
		Utils::String id = c->sCockpit.token(";", 19);
1 cycrow 2178
 
2179
		for ( int i = 0; i < 6; i++ )
2180
		{
39 cycrow 2181
			Utils::String tId = m_sData.token(";", 32 + (i * 2));
2182
			if ( tId.isNumber() && ((int)tId) == c->iIndex )
2183
				m_sData = m_sData.replaceToken(";", 32 + (i * 2), (id + "(" + Utils::String::number(c->iIndex) + ")").c_str());
1 cycrow 2184
		}
2185
	}
2186
}
2187
 
39 cycrow 2188
Utils::String CXspFile::FormatShipData(CyStringList *cockpits, int *text, int game)
1 cycrow 2189
{
39 cycrow 2190
	Utils::String data = (game == GAME_X3) ? this->GetX3ShipData() : this->GetTCShipData();
1 cycrow 2191
	// do turrets
2192
	for ( int t = 0; t < 6; t++ )
2193
	{
2194
		int oldPos = 0;
39 cycrow 2195
		Utils::String turret = data.token(";", 32 + (t * 2));
2196
		if ( !turret.isNumber() )
1 cycrow 2197
		{
39 cycrow 2198
			if ( turret.isin("(") )
1 cycrow 2199
			{
39 cycrow 2200
				oldPos = turret.tokens("(", 2).token(")", 1);
2201
				turret = turret.token("(", 1);
1 cycrow 2202
			}
2203
			int pos = cockpits->FindStringPos(turret);
2204
			if ( pos < 0 )	pos = oldPos;
39 cycrow 2205
			if ( pos >= cockpits->Count() ) pos = 0;
2206
			data = data.replaceToken(";", 32 + (t * 2), (long)pos);
1 cycrow 2207
		}
2208
	}
2209
	// adjust the weapons
2210
	int mask = this->GetLaserMask(game - 1);
2211
	if ( mask != -1 )
39 cycrow 2212
		data = data.replaceToken(";", 19, (long)mask);
1 cycrow 2213
	mask = this->GetMissileMask(game - 1);
2214
	if ( mask != -1 )
39 cycrow 2215
		data = data.replaceToken(";", 25, (long)mask);
1 cycrow 2216
 
2217
	// fix the ship text
2218
	if ( m_iOrgDesc > 0 )
2219
		(*text) = m_iOrgDesc;
39 cycrow 2220
	data = data.replaceToken(";", 7, (long)*text);
1 cycrow 2221
 
2222
	// add the ware id
39 cycrow 2223
	data.removeChar(9);
2224
	data.removeEndSpace();
1 cycrow 2225
	// remove the end ;
39 cycrow 2226
	while ( data.right(1) == ";" ) data.truncate(-1);
2227
	data = data.replaceToken(";", data.countToken(";"), this->GetShipID());
2228
	if ( data.right(1) != ";" )
1 cycrow 2229
		data += ";";
2230
 
2231
	return data;
35 cycrow 2232
}
2233