Subversion Repositories spk

Rev

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