Subversion Repositories spk

Rev

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

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