src/demo.cpp

changeset 10
bc1414343e19
parent 8
e8f645d9f28f
child 11
3ddebf76105e
--- a/src/demo.cpp	Wed Jul 17 19:45:19 2013 +0300
+++ b/src/demo.cpp	Sun Aug 11 02:58:55 2013 +0300
@@ -6,49 +6,75 @@
 #include "bytestream.h"
 #include "misc.h"
 #include "ui_demoprompt.h"
+#include "prompts.h"
 
-static const uint32 g_demoSignature = makeByteID( 'Z', 'C', 'L', 'D' );
+static const uint32 g_demoSignature = makeByteID ('Z', 'C', 'L', 'D');
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-static str tr( const char* msg ) {
-	return QObject::tr( msg );
+str uncolorize (const str& in) {
+	str out;
+	int skip = 0;
+	
+	for (const qchar& c : in) {
+		if (skip-- > 0)
+			continue;
+		
+		if (c.toAscii() == '\034') {
+			skip = 1;
+			continue;
+		}
+		
+		out += c;
+	}
+	
+	return out;
 }
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-static void error( str msg ) {
-	QMessageBox::critical( null, "Error", msg );
+static str tr (const char* msg) {
+	return QObject::tr (msg);
 }
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-static int getVersionIndex( str ver ) {
-	int i;
-	
-	for( i = 0; i < g_zanVersions.size(); ++i )
-		if( g_zanVersions[i] == ver )
-			return i;
-	
-	return -1;
+static void error (str msg) {
+	QMessageBox::critical (null, "Error", msg);
 }
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-static str findWAD( str name ) {
+static bool isKnownVersion (str ver) {
 	QSettings cfg;
-	list<var> paths = cfg.value( "wads/paths", list<var>() ).toList();
+	list<var> versions = getVersionsList();
+	
+	for (const var& it : versions)
+		if (it.toString() == ver || it.toString() + 'M' == ver)
+			return true;
 	
-	if( paths.size() == 0 ) {
-		error( tr( "No WAD paths configured!" ));
-		exit( 9 );
+	return false;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+static str findWAD (str name) {
+	QSettings cfg;
+	list<var> paths = cfg.value ("wads/paths", list<var>()).toList();
+	
+	if (paths.size() == 0) {
+		error (tr ("No WAD paths configured!"));
+		
+		// Cannot just return an empty string here since that'd trigger
+		// another error prompt - skip ahead and exit.
+		exit (9);
 	}
 	
-	for( var it : paths ) {
-		str fullpath = fmt( "%1/%2", it.toString(), name );
-		QFile f( fullpath );
+	for (const var& it : paths) {
+		str fullpath = fmt ("%1/%2", it.toString(), name);
+		QFile f (fullpath);
 		
-		if( f.exists() )
+		if (f.exists())
 			return fullpath;
 	}
 	
@@ -57,27 +83,27 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-int launchDemo( str path ) {
-	FILE* fp = fopen( path.toStdString().c_str(), "r" );
+int launchDemo (str path) {
+	FILE* fp = fopen (path.toStdString().c_str(), "r");
 	
-	if( !fp ) {
-		error( fmt( tr( "Couldn't open '%1' for reading: %2" ), path, strerror( errno )));
+	if (!fp) {
+		error (fmt (tr ("Couldn't open '%1' for reading: %2"), path, strerror (errno)));
 		return 1;
 	}
 	
-	fseek( fp, 0, SEEK_END );
-	const size_t fsize = ftell( fp );
-	rewind( fp );
+	fseek (fp, 0, SEEK_END);
+	const size_t fsize = ftell (fp);
+	rewind (fp);
 	
 	char* buf = new char[fsize];
 	
-	if( fread( buf, 1, fsize, fp ) != fsize ) {
-		error( tr( "I/O error" ));
+	if (fread (buf, 1, fsize, fp) != fsize) {
+		error (tr ("I/O error"));
 		delete[] buf;
 		return 2;
 	}
-	
-	Bytestream s( buf, fsize );
+
+	Bytestream s (buf, fsize);
 	delete[] buf;
 	
 	uint8 offset;
@@ -93,8 +119,8 @@
 	{
 		uint32 sig;
 		
-		if( !s.readLong( sig ) || sig != g_demoSignature ) {
-			error( fmt( tr( "'%1' is not a Zandronum demo file!" ), path ));
+		if (!s.readLong (sig) || sig != g_demoSignature) {
+			error (fmt (tr ("'%1' is not a Zandronum demo file!"), path));
 			return 3;
 		}
 	}
@@ -102,108 +128,123 @@
 	// Zandronum stores CLD_DEMOLENGTH after the signature. This is also the
 	// first demo enumerator, so we can determine the offset (which is variable!)
 	// from this byte
-	s.readByte( offset );
-	s.readLong( length );
-	
+	s.readByte (offset);
+	s.readLong (length);
+
 	uint16 zanversionID, numWads;
 	uint32 longSink;
 	str zanversion;
 	list<str> wads;
 	bool ready = false;
+	uint8 buildID;
 	
-	for( ;; ) {
+	// Read the demo header and get data
+	for (;;) {
 		uint8 header;
-		if( !s.readByte( header ))
+		
+		if (!s.readByte (header))
 			break;
 		
-		if( header == DemoBodyStart + offset ) {
+		if (header == DemoBodyStart + offset) {
 			ready = true;
 			break;
-		} elif( header == DemoVersion + offset ) {
-			s.readShort( zanversionID );
-			s.readString( zanversion );
-			s.readLong( longSink ); // rng seed - we don't need it
-		} elif( header == DemoUserInfo + offset ) {
-			s.readString( userinfo.netname );
-			s.readByte( userinfo.gender );
-			s.readLong( userinfo.color );
-			s.readLong( userinfo.aimdist );
-			s.readString( userinfo.skin );
-			s.readLong( userinfo.railcolor );
-			s.readByte( userinfo.handicap );
-			s.readByte( userinfo.unlagged );
-			s.readByte( userinfo.respawnOnFire );
-			s.readByte( userinfo.ticsPerUpdate );
-			s.readByte( userinfo.connectionType );
-			s.readString( userinfo.className );
-		} elif( header == DemoWads + offset ) {
-			s.readShort( numWads );
+		} elif (header == DemoVersion + offset) {
+			s.readShort (zanversionID);
+			s.readString (zanversion);
+			
+			if (zanversion.left (4) != "1.1-" && zanversion.left (6) != "1.1.1-")
+				s.readByte (buildID);
+			else
+				buildID = 1;
 			
-			for( uint8 i = 0; i < numWads; ++i ) {
+			s.readLong (longSink);  // rng seed - we don't need it
+		} elif (header == DemoUserInfo + offset) {
+			s.readString (userinfo.netname);
+			s.readByte (userinfo.gender);
+			s.readLong (userinfo.color);
+			s.readLong (userinfo.aimdist);
+			s.readString (userinfo.skin);
+			s.readLong (userinfo.railcolor);
+			s.readByte (userinfo.handicap);
+			s.readByte (userinfo.unlagged);
+			s.readByte (userinfo.respawnOnFire);
+			s.readByte (userinfo.ticsPerUpdate);
+			s.readByte (userinfo.connectionType);
+			s.readString (userinfo.className);
+		} elif (header == DemoWads + offset) {
+			str sink;
+			s.readShort (numWads);
+			
+			for (uint8 i = 0; i < numWads; ++i) {
 				str wad;
-				s.readString( wad );
+				s.readString (wad);
 				wads << wad;
 			}
 			
 			// The demo has two checksum strings. We're not interested
 			// in them though.
-			str sink;
-			for( int i = 0; i < 2; ++i )
-				s.readString( sink );
+			for (int i = 0; i < 2; ++i)
+				s.readString (sink);
 		} else {
-			error( fmt( tr( "Unknown header %1!\n" ), (int) header ));
-			return 4;
+			error (fmt (tr ("Unknown header %1!\n"), (int) header));
+			return 3;
 		}
 	}
-	
-	if( !ready ) {
-		error( fmt( tr( "Incomplete demo header in '%s'!" ), path ));
-		return 5;
-	}
-	
-	int i = getVersionIndex( zanversion );
-	if( i == -1 ) {
-		error( fmt( tr( "Unknown Zandronum version %1!\n" ), zanversion ));
-		return 6;
+
+	if (!ready) {
+		error (fmt (tr ("Incomplete demo header in '%s'!"), path));
+		return 3;
 	}
 	
+	if (!isKnownVersion (zanversion)) {
+		UnknownVersionPrompt* prompt = new UnknownVersionPrompt (path, zanversion, (buildID == 1));
+		if (!prompt->exec())
+			return 6;
+		
+		if (!isKnownVersion (zanversion)) {
+			error (tr ("Failure in configuration! This shouldn't happen."));
+			return 6;
+		}
+	}
+
 	QSettings cfg;
-	str binarypath = cfg.value( binaryConfigName( zanversion )).toString();
-	
-	if( binarypath.isEmpty() ) {
-		error( fmt( tr( "No binary path specified for Zandronum version %1!\n" ), zanversion ));
+	str binarypath = cfg.value (binaryConfigName (zanversion)).toString();
+
+	if (binarypath.isEmpty()) {
+		error (fmt (tr ("No binary path specified for Zandronum version %1!"), zanversion));
 		return 7;
 	}
-	
-	str iwad, iwadpath;
-	list<str> pwads, pwadpaths;
+
+	str iwadpath;
+	list<str> pwadpaths;
 	
 	// Find the WADs
-	for( const str& wad : wads ) {
-		str path = findWAD( wad );
+	for (const str& wad : wads) {
+		str path = findWAD (wad);
 		
 		// IWAD names can appear in uppercase too. Linux is case-sensitive, so..
-		if( &wad == &wads[0] && path.isEmpty() )
-			path = findWAD( wad.toUpper() );
+		if (&wad == &wads[0] && path.isEmpty())
+			path = findWAD (wad.toUpper());
 		
-		if( path.isEmpty() ) {
-			error( fmt( tr( "Couldn't find %1!\n" ), wad ));
+		if (path.isEmpty()) {
+			error (fmt (tr ("Couldn't find %1!"), wad));
 			return 8;
 		}
 		
-		if( &wad == &wads[0] ) {
+		if (&wad == &wads[0])
 			iwadpath = path;
-			iwad = wad;
-		} else {
+		else
 			pwadpaths << path;
-			pwads << wad;
-		}
 	}
 	
-	if( !cfg.value( "nodemoprompt", false ).toBool() ) {
+	if (!cfg.value ("nodemoprompt", false).toBool()) {
 		str pwadtext;
-		for( const str& pwad : pwads ) {
-			if( !pwadtext.isEmpty() )
+		
+		for (const str& pwad : wads) {
+			if (&pwad == &wads[0])
+				continue; // skip the IWAD
+			
+			if (!pwadtext.isEmpty())
 				pwadtext += "<br />";
 			
 			pwadtext += pwad;
@@ -211,33 +252,31 @@
 		
 		QDialog* dlg = new QDialog;
 		Ui_DemoPrompt ui;
-		ui.setupUi( dlg );
-		ui.demoNameLabel->setText( basename( path ));
-		ui.demoRecorder->setText( userinfo.netname );
-		ui.versionLabel->setText( zanversion );
-		ui.iwadLabel->setText( wads[0] );
-		ui.pwadsLabel->setText( pwadtext );
+		ui.setupUi (dlg);
+		ui.demoNameLabel->setText (basename (path));
+		ui.demoRecorder->setText (uncolorize (userinfo.netname));
+		ui.versionLabel->setText (zanversion);
+		ui.iwadLabel->setText (wads[0]);
+		ui.pwadsLabel->setText (pwadtext);
+		dlg->setWindowTitle (fmt (APPNAME " %1", versionString()));
 		
-		if( !dlg->exec() )
+		if (!dlg->exec())
 			return 1;
 	}
-	
-	print( "binary: %1\n", binarypath );
-	print( "iwad: %1\npwads: %2\n", iwadpath, pwadpaths );
-	
-	QStringList cmdlineList ({
+
+	QStringList cmdlineList ( {
 		"-playdemo", path,
 		"-iwad", iwadpath,
 	});
 	
-	if( pwadpaths.size() > 0 ) {
+	if (pwadpaths.size() > 0) {
 		cmdlineList << "-file";
 		cmdlineList << pwadpaths;
 	}
 	
-	print( "commandline: %1 %2\n", binarypath, cmdlineList.join( " " ));
+	print ("Executing: %1 %2\n", binarypath, cmdlineList.join (" "));
 	QProcess* proc = new QProcess;
-	proc->start( binarypath, cmdlineList );
-	proc->waitForFinished( -1 );
+	proc->start (binarypath, cmdlineList);
+	proc->waitForFinished (-1);
 	return 0;
 }
\ No newline at end of file

mercurial