Subversion Repositories spk

Rev

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