Subversion Repositories spk

Rev

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

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