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