170 }; |
170 }; |
171 |
171 |
172 int launchDemo (QString path) |
172 int launchDemo (QString path) |
173 { |
173 { |
174 QFile f (path); |
174 QFile f (path); |
175 |
175 |
176 if (not f.open (QIODevice::ReadOnly)) |
176 if (not f.open (QIODevice::ReadOnly)) |
177 { |
177 { |
178 error (tr ("Couldn't open '%1' for reading: %2").arg (path).arg (strerror (errno))); |
178 error (tr ("Couldn't open '%1' for reading: %2").arg (path).arg (strerror (errno))); |
179 return 1; |
179 return 1; |
180 } |
180 } |
181 |
181 |
182 QDataStream stream (&f); |
182 QDataStream stream (&f); |
183 stream.setByteOrder (QDataStream::LittleEndian); |
183 stream.setByteOrder (QDataStream::LittleEndian); |
184 |
184 |
185 DemoHeaders headers; |
185 DemoHeaders headers; |
186 uint32 length; |
186 uint32 length; |
187 uint16 zanversionID, numWads; |
187 uint16 zanversionID, numWads; |
188 uint32 longSink; |
188 uint32 longSink; |
189 QString zanversion; |
189 QString zanversion; |
215 // The remaining headers are variable and relative to the length header. |
215 // The remaining headers are variable and relative to the length header. |
216 headers.version = headers.length + 1; |
216 headers.version = headers.length + 1; |
217 headers.userInfo = headers.length + 3, |
217 headers.userInfo = headers.length + 3, |
218 headers.bodyStart = headers.length + 4; |
218 headers.bodyStart = headers.length + 4; |
219 headers.wads = headers.length + 10; |
219 headers.wads = headers.length + 10; |
220 |
220 |
221 // Read the demo header and get data |
221 // Read the demo header and get data |
222 for (;;) |
222 for (;;) |
223 { |
223 { |
224 uint8 header; |
224 uint8 header; |
225 stream >> header; |
225 stream >> header; |
226 |
226 |
227 if (header == headers.bodyStart) |
227 if (header == headers.bodyStart) |
228 { |
228 { |
229 ready = true; |
229 ready = true; |
230 break; |
230 break; |
231 } |
231 } |
264 } |
264 } |
265 else if (header == headers.wads) |
265 else if (header == headers.wads) |
266 { |
266 { |
267 QString sink; |
267 QString sink; |
268 stream >> numWads; |
268 stream >> numWads; |
269 |
269 |
270 for (uint8 i = 0; i < numWads; ++i) |
270 for (uint8 i = 0; i < numWads; ++i) |
271 { |
271 { |
272 QString wad = readString (stream); |
272 QString wad = readString (stream); |
273 wads << wad; |
273 wads << wad; |
274 } |
274 } |
275 |
275 |
276 // The demo has two checksum strings. We're not interested in them, though. |
276 // The demo has two checksum strings. We're not interested in them, though. |
277 (sink = readString (stream)) = readString (stream); |
277 (sink = readString (stream)) = readString (stream); |
278 } |
278 } |
279 else |
279 else |
280 { |
280 { |
296 QDialog* prompt = new UnknownVersionPrompt (path, zanversion, (buildID == ReleaseBuild)); |
296 QDialog* prompt = new UnknownVersionPrompt (path, zanversion, (buildID == ReleaseBuild)); |
297 |
297 |
298 if (not prompt->exec()) |
298 if (not prompt->exec()) |
299 return 1; |
299 return 1; |
300 } |
300 } |
301 |
301 |
302 QString iwadpath; |
302 QString iwadpath; |
303 QStringList pwadpaths; |
303 QStringList pwadpaths; |
304 |
304 |
305 // Find the WADs |
305 // Find the WADs |
306 for (const QString& wad : wads) |
306 for (const QString& wad : wads) |
307 { |
307 { |
308 QString path = findWAD (wad); |
308 QString path = findWAD (wad); |
309 |
309 |
310 // WAD names are case-sensitive under non-Windows and they can appear in uppercase |
310 // WAD names are case-sensitive under non-Windows and they can appear in uppercase |
311 // so we need to test that too. |
311 // so we need to test that too. |
312 if (path.isEmpty()) |
312 if (path.isEmpty()) |
313 path = findWAD (wad.toUpper()); |
313 path = findWAD (wad.toUpper()); |
314 |
314 |
315 if (path.isEmpty()) |
315 if (path.isEmpty()) |
316 { |
316 { |
317 error (tr ("Couldn't find %1!").arg (wad)); |
317 error (tr ("Couldn't find %1!").arg (wad)); |
318 return 1; |
318 return 1; |
319 } |
319 } |
321 if (&wad == &wads.first()) |
321 if (&wad == &wads.first()) |
322 iwadpath = path; |
322 iwadpath = path; |
323 else |
323 else |
324 pwadpaths << path; |
324 pwadpaths << path; |
325 } |
325 } |
326 |
326 |
327 if (not Config::get ("noprompt").toBool()) |
327 if (not Config::get ("noprompt").toBool()) |
328 { |
328 { |
329 QString pwadtext; |
329 QString pwadtext; |
330 |
330 |
331 for (const QString& wad : wads) |
331 for (const QString& wad : wads) |
332 { |
332 { |
333 if (&wad == &wads.first()) |
333 if (&wad == &wads.first()) |
334 continue; // skip the IWAD |
334 continue; // skip the IWAD |
335 |
335 |
336 if (not pwadtext.isEmpty()) |
336 if (not pwadtext.isEmpty()) |
337 pwadtext += "<br />"; |
337 pwadtext += "<br />"; |
338 |
338 |
339 pwadtext += wad; |
339 pwadtext += wad; |
340 } |
340 } |
341 |
341 |
342 QDialog* dlg = new QDialog; |
342 QDialog* dlg = new QDialog; |
343 Ui_DemoPrompt ui; |
343 Ui_DemoPrompt ui; |
344 ui.setupUi (dlg); |
344 ui.setupUi (dlg); |
345 ui.demoNameLabel->setText (basename (path)); |
345 ui.demoNameLabel->setText (basename (path)); |
346 ui.demoRecorder->setText (uncolorize (userinfo.netname)); |
346 ui.demoRecorder->setText (uncolorize (userinfo.netname)); |
347 ui.versionLabel->setText (zanversion); |
347 ui.versionLabel->setText (zanversion); |
348 ui.iwadLabel->setText (wads[0]); |
348 ui.iwadLabel->setText (wads[0]); |
349 ui.pwadsLabel->setText (pwadtext); |
349 ui.pwadsLabel->setText (pwadtext); |
350 dlg->setWindowTitle (versionSignature()); |
350 dlg->setWindowTitle (versionSignature()); |
351 |
351 |
352 if (not dlg->exec()) |
352 if (not dlg->exec()) |
353 return 0; |
353 return 0; |
354 } |
354 } |
355 |
355 |
356 QStringList cmdlineList; |
356 QStringList cmdlineList; |