Subversion Repositories spk

Rev

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