PageRenderTime 76ms CodeModel.GetById 38ms RepoModel.GetById 0ms app.codeStats 0ms

/source/loaders.cpp

https://bitbucket.org/val_haris/asc-ai
C++ | 1725 lines | 1131 code | 506 blank | 88 comment | 255 complexity | c33e58084270498addf38c6c4cad6ba5 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
  1. /*! \file loaders.cpp
  2. \brief procedure for loading and writing savegames, maps etc.
  3. IO for basic types like vehicletype, buildingtype etc which are also used by the small editors are found in sgstream
  4. */
  5. /*
  6. This file is part of Advanced Strategic Command; http://www.asc-hq.de
  7. Copyright (C) 1994-2010 Martin Bickel and Marc Schellenberger
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2 of the License, or
  11. (at your option) any later version.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program; see the file COPYING. If not, write to the
  18. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  19. Boston, MA 02111-1307 USA
  20. */
  21. #include <algorithm>
  22. #include <cstring>
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include "typen.h"
  26. #include "misc.h"
  27. #include "buildingtype.h"
  28. #include "vehicletype.h"
  29. #include "spfst.h"
  30. #include "loaders.h"
  31. #include "dlg_box.h"
  32. #include "dlg_box.h"
  33. #include "dialog.h"
  34. #include "sgstream.h"
  35. #include "attack.h"
  36. #include "errors.h"
  37. #include "strtmesg.h"
  38. #include "textfileparser.h"
  39. #include "itemrepository.h"
  40. #include "prehistoricevents.h"
  41. #include "gamemap.h"
  42. #include "gameeventsystem.h"
  43. #include "graphicset.h"
  44. #include "gameoptions.h"
  45. #include "lua/luarunner.h"
  46. #include "lua/luastate.h"
  47. #include "packagemanager.h"
  48. #include "i18n.h"
  49. #include "mapimageexport.h"
  50. #ifdef sgmain
  51. # include "ai/ai.h"
  52. #endif
  53. const int actsavegameversion = 0xff63;
  54. const int minsavegameversion = 0xff31;
  55. const int actmapversion = 0xfe51;
  56. const int minmapversion = 0xfe24;
  57. const int actnetworkversion = 0x0032;
  58. const int minnetworkversion = 0x0004;
  59. const int actreplayversion = 0x0003;
  60. const int minreplayversion = 0x0001;
  61. const int fileterminator = 0xa01a;
  62. const char* savegameextension = "*.sav";
  63. const char* mapextension = "*.map";
  64. const char* tournamentextension = ".ascpbm";
  65. bool suppressMapTriggerExecution = true;
  66. void seteventtriggers( GameMap* actmap )
  67. {
  68. if ( !suppressMapTriggerExecution )
  69. for ( GameMap::Events::iterator i = actmap->events.begin(); i != actmap->events.end(); ++i )
  70. (*i)->arm();
  71. for ( int i = 0; i < 8; i++ )
  72. actmap->player[i].queuedEvents = 1;
  73. }
  74. #define csm_typid32 1 /* b1 */
  75. #define csm_direction 2 /* b1 */
  76. #define csm_vehicle 4 /* b1 */
  77. #define csm_building 8 /* b1 */
  78. #define csm_height 32 /* b1 */
  79. #define csm_cnt2 64 /* b1 */
  80. #define csm_b3 128 /* b1 */
  81. #define csm_material 1 /* b3 */
  82. #define csm_fuel 2 /* b3 */
  83. #define csm_visible 4 /* b3 */
  84. #define csm_weather 16 /* b3 */
  85. #define csm_object 64 /* b3 */
  86. #define csm_b4 128 /* b3 */
  87. #define csm_resources 1 /* b4 */
  88. #define csm_connection 2 // b4
  89. #define csm_newobject 4 // b4
  90. /**************************************************************/
  91. /* sezierungen schreiben / lesen */
  92. /**************************************************************/
  93. void tspfldloaders::readdissections ( void )
  94. {
  95. for (int i = 0; i < 8; i ++ ) {
  96. if ( spfld->player[ i ].__dissectionsToLoad ) {
  97. int k;
  98. do {
  99. Player::Dissection du;
  100. stream->readInt(); // dummy;
  101. stream->readInt(); // dummy;
  102. du.orgpoints = stream->readInt();
  103. du.points = stream->readInt();
  104. du.num = stream->readInt();
  105. k = stream->readInt();
  106. int j = stream->readInt();
  107. du.fzt = vehicleTypeRepository.getObject_byID ( j );
  108. if ( !du.fzt )
  109. throw InvalidID ( "vehicle", j );
  110. j = stream->readInt();
  111. du.tech = technologyRepository.getObject_byID ( j );
  112. if ( !du.tech )
  113. throw InvalidID ( "technology", j );
  114. spfld->player[ i ].dissections.push_back ( du );
  115. } while ( k );
  116. }
  117. } /* endfor */
  118. }
  119. void tspfldloaders::writedissections ( void )
  120. {
  121. for (int i = 0; i < 8; i ++ ) {
  122. Player::DissectionContainer::iterator di = spfld->player[i].dissections.begin();
  123. while ( di != spfld->player[i].dissections.end() ) {
  124. stream->writeInt ( 1 ); // dummy
  125. stream->writeInt ( 1 ); // dummy
  126. stream->writeInt ( di->orgpoints );
  127. stream->writeInt ( di->points );
  128. stream->writeInt ( di->num );
  129. di++;
  130. if ( di != spfld->player[i].dissections.end() )
  131. stream->writeInt ( 1 );
  132. else
  133. stream->writeInt ( 0 );
  134. stream->writeInt ( di->fzt->id );
  135. stream->writeInt ( di->tech->id );
  136. }
  137. }
  138. }
  139. /**************************************************************/
  140. /* Messages schreiben / lesen */
  141. /**************************************************************/
  142. const int messageVersion = 0xabcdf1;
  143. const int messageMinVersion = 0xabcdef;
  144. void tspfldloaders:: writemessages ( void )
  145. {
  146. stream->writeInt ( messageVersion );
  147. int id = 0;
  148. for ( MessageContainer::iterator mi = spfld->messages.begin(); mi != spfld->messages.end(); ) {
  149. id++;
  150. (*mi)->id = id;
  151. stream->writeInt ( (*mi)->from );
  152. stream->writeInt ( (*mi)->to );
  153. stream->writeInt ( (*mi)->cc );
  154. stream->writeInt ( (unsigned int) (*mi)->time );
  155. stream->writeInt ( 1 );
  156. stream->writeInt ( (*mi)->id );
  157. stream->writeInt ( (*mi)->gametime.turn() );
  158. stream->writeInt ( (*mi)->gametime.move() );
  159. stream->writeInt( (*mi)->reminder );
  160. ASCString& t = (*mi)->text;
  161. mi++;
  162. stream->writeInt ( mi != spfld->messages.end() ? 1 : 0 );
  163. stream->writeString ( t );
  164. }
  165. for ( int i = 0; i < 8; i++ )
  166. writemessagelist ( spfld->player[ i ].oldmessage );
  167. for ( int i = 0; i < 8; i++ )
  168. writemessagelist ( spfld->player[ i ].unreadmessage );
  169. for ( int i = 0; i < 8; i++ )
  170. writemessagelist ( spfld->player[ i ].sentmessage );
  171. writemessagelist ( spfld->unsentmessage );
  172. stream->writeInt ( messageVersion );
  173. stream->writeString ( spfld->gameJournal );
  174. stream->writeString ( spfld->newJournal );
  175. }
  176. void tspfldloaders:: writemessagelist( MessagePntrContainer& lst )
  177. {
  178. for ( MessagePntrContainer::iterator i = lst.begin(); i != lst.end(); i++ )
  179. stream->writeInt ( (*i)->id );
  180. stream->writeInt ( 0 );
  181. }
  182. /*
  183. class MessageIDequals : public unary_function<Message*,bool>{
  184. int id;
  185. public:
  186. MessageIDequals ( int _id ) { id == _id; };
  187. bool operator() ( const Message* m ) { return m->id == id; };
  188. };
  189. */
  190. void tspfldloaders:: readmessagelist( MessagePntrContainer& lst )
  191. {
  192. int i = stream->readInt();
  193. while ( i ) {
  194. // MessageContainer::iterator mi = find ( spfld->messages.begin(), spfld->messages.end(), MessageIDequals ( i ));
  195. MessageContainer::iterator mi = spfld->messages.end();
  196. for ( MessageContainer::iterator mi2 = spfld->messages.begin(); mi2 != spfld->messages.end(); mi2++ )
  197. if ( (*mi2)->id == i )
  198. mi = mi2;
  199. if ( mi == spfld->messages.end())
  200. warningMessage( "message list corrupted !\nplease report this bug!\nthe game will continue, but some messages will probably be missing\nand other instabilities may occur.");
  201. lst.push_back ( *mi );
  202. i = stream->readInt();
  203. }
  204. }
  205. void tspfldloaders:: readmessages ( void )
  206. {
  207. int magic = stream->readInt();
  208. assertOrThrow( magic >= messageMinVersion && magic <= messageVersion );
  209. while ( spfld->__loadmessages ) {
  210. Message* msg = new Message ( spfld );
  211. msg->from = stream->readInt();
  212. msg->to = stream->readInt();
  213. if ( magic >= 0xabcdf0 )
  214. msg->cc = stream->readInt();
  215. else
  216. msg->cc = 0;
  217. msg->time = stream->readInt();
  218. bool msgtext = stream->readInt();
  219. msg->id = stream->readInt();
  220. int t = stream->readInt();
  221. int m = stream->readInt();
  222. msg->gametime.set ( t, m );
  223. if ( magic >= 0xabcdf1 )
  224. msg->reminder = stream->readInt();
  225. else
  226. msg->reminder = false;
  227. spfld->__loadmessages = stream->readInt();
  228. if ( msgtext )
  229. msg->text = stream->readString( true );
  230. }
  231. for ( int i = 0; i < 8; i++ )
  232. if ( spfld->player[ i ].__loadoldmessage )
  233. readmessagelist ( spfld->player[ i ].oldmessage );
  234. for ( int i = 0; i < 8; i++ )
  235. if ( spfld->player[ i ].__loadunreadmessage )
  236. readmessagelist ( spfld->player[ i ].unreadmessage );
  237. for ( int i = 0; i < 8; i++ )
  238. if ( spfld->player[ i ].__loadsentmessage )
  239. readmessagelist ( spfld->player[ i ].sentmessage );
  240. if ( spfld->__loadunsentmessage )
  241. readmessagelist ( spfld->unsentmessage );
  242. stream->readInt(); // magic
  243. if ( spfld->___loadJournal )
  244. spfld->gameJournal = stream->readString();
  245. if ( spfld->___loadNewJournal )
  246. spfld->newJournal = stream->readString();
  247. }
  248. void tspfldloaders::readoldevents ( void )
  249. {
  250. if ( spfld->loadOldEvents ) {
  251. int num = stream->readInt();
  252. while ( num ) {
  253. for ( int i = 0; i < num; i++ )
  254. stream->readInt();
  255. for ( int i = 0; i < num; i++ )
  256. stream->readInt();
  257. num = stream->readInt();
  258. }
  259. }
  260. }
  261. void checkForUniqueUnitIDs( GameMap* gamemap )
  262. {
  263. map<int,int> units;
  264. for ( int p = 0; p < gamemap->getPlayerCount(); ++p )
  265. for ( Player::VehicleList::iterator i = gamemap->getPlayer(p).vehicleList.begin(); i != gamemap->getPlayer(p).vehicleList.end(); ++i )
  266. if ( units[(*i)->networkid]++ > 0 ) {
  267. warningMessage("unit with duplicate network ids: " + ASCString::toString( (*i)->networkid ) + "\nThis will lead to replay errors during the next turn." );
  268. (*i)->networkid = gamemap->idManager.getNewNetworkID();;
  269. }
  270. }
  271. /**************************************************************/
  272. /* map schreiben / lesen / initialisieren */
  273. /**************************************************************/
  274. void tspfldloaders::writemap ( void )
  275. {
  276. checkForUniqueUnitIDs( spfld );
  277. if ( !spfld )
  278. displaymessage ( "tspfldloaders::writemap ; no map to write ! ",2);
  279. spfld->write ( *stream );
  280. }
  281. void tmaploaders::initmap ( void )
  282. {
  283. spfld->game_parameter = NULL;
  284. }
  285. void tgameloaders::initmap ( void )
  286. {
  287. spfld->game_parameter = NULL;
  288. }
  289. void tspfldloaders::readmap ( void )
  290. {
  291. spfld = new GameMap;
  292. spfld->read ( *stream );
  293. }
  294. void tgameloaders :: writeAI ( )
  295. {
  296. #ifdef sgmain
  297. int a = 0;
  298. for ( int i = 0; i< 8; i++ )
  299. if ( spfld->player[i].ai )
  300. a += 1 << i;
  301. stream->writeInt ( a );
  302. for ( int i = 0; i < 8; i++ )
  303. if ( spfld->player[i].ai )
  304. spfld->player[i].ai->write( *stream );
  305. #else
  306. stream->writeInt(0);
  307. #endif
  308. }
  309. void tgameloaders :: readAI ( )
  310. {
  311. #ifdef sgmain
  312. int a = stream->readInt();
  313. for ( int i = 0; i< 8; i++ )
  314. if ( a & ( 1 << i ) ) {
  315. AI* ai = new AI ( spfld, i );
  316. ai->read ( *stream );
  317. spfld->player[i].ai = ai;
  318. } else {
  319. spfld->player[i].ai = NULL;
  320. }
  321. #else
  322. for ( int i = 0; i< 9; i++ )
  323. spfld->player[i].ai = NULL;
  324. #endif
  325. }
  326. /**************************************************************/
  327. /* Network schreiben / lesen */
  328. /**************************************************************/
  329. extern void readLegacyNetworkData ( tnstream& stream );
  330. void tspfldloaders::readLegacyNetwork ( void )
  331. {
  332. if ( spfld->___loadLegacyNetwork )
  333. readLegacyNetworkData( *stream );
  334. }
  335. /**************************************************************/
  336. /* fielder schreiben / lesen */
  337. /**************************************************************/
  338. const int objectstreamversion = 4;
  339. void tspfldloaders::writefields ( void )
  340. {
  341. int l = 0;
  342. int cnt1 = spfld->xsize * spfld->ysize;
  343. int cnt2;
  344. do {
  345. cnt2 = 0;
  346. MapField* fld = &spfld->field[l];
  347. /*
  348. RLE encoding not supported any more, since tfield is becomming too complex
  349. if (l + 2 < cnt1) {
  350. l2 = l + 1;
  351. fld2 = &spfld->field[l2];
  352. asfasfdasfd
  353. while ((l2 + 2 < cnt1) && ( memcmp(fld2, fld, sizeof(*fld2)) == 0) ) {
  354. cnt2++;
  355. l2++;
  356. fld2 = &spfld->field[l2];
  357. }
  358. }
  359. */
  360. char b1 = 0;
  361. char b3 = 0;
  362. char b4 = 0;
  363. if (fld->typ->terraintype->id > 255)
  364. b1 |= csm_typid32;
  365. if (fld->vehicle != NULL)
  366. b1 |= csm_vehicle;
  367. if ( (fld->bdt & getTerrainBitType( cbbuildingentry )).any() )
  368. b1 |= csm_building;
  369. if (cnt2 > 0)
  370. b1 |= csm_cnt2;
  371. if (fld->material > 0)
  372. b3 |= csm_material;
  373. if (fld->fuel > 0)
  374. b3 |= csm_fuel;
  375. if (fld->typ != fld->typ->terraintype->weather[0])
  376. b3 |= csm_weather;
  377. if (fld->visible)
  378. b3 |= csm_visible;
  379. if ( !fld->objects.empty() || !fld->mines.empty() )
  380. b4 |= csm_newobject;
  381. if ( fld->resourceview )
  382. b4 |= csm_resources;
  383. if ( fld->connection )
  384. b4 |= csm_connection;
  385. if ( b4 )
  386. b3 |= csm_b4;
  387. if ( b3 )
  388. b1 |= csm_b3;
  389. stream->writeChar( b1 );
  390. if (b1 & csm_b3 )
  391. stream->writeChar ( b3 );
  392. if (b3 & csm_b4 )
  393. stream->writeChar ( b4 );
  394. if (b1 & csm_cnt2 )
  395. stream->writeInt ( cnt2 );
  396. if (b3 & csm_weather ) {
  397. int k = 1;
  398. while ( fld->typ != fld->typ->terraintype->weather[k] && k < cwettertypennum ) {
  399. k++;
  400. } /* endwhile */
  401. if ( k == cwettertypennum ) {
  402. k = 0;
  403. displaymessage ( "invalid terrain ( weather not found ) at position %d \n",1,l );
  404. }
  405. stream->writeInt ( k );
  406. }
  407. if (b1 & csm_typid32 )
  408. stream->writeInt ( fld->typ->terraintype->id );
  409. else
  410. stream->writeChar ( fld->typ->terraintype->id );
  411. if (b1 & csm_vehicle )
  412. fld->vehicle->write ( *stream );
  413. if (b1 & csm_building )
  414. fld->building->write ( *stream );
  415. if (b3 & csm_material )
  416. stream->writeChar ( fld->material );
  417. if (b3 & csm_fuel )
  418. stream->writeChar ( fld->fuel );
  419. if (b3 & csm_visible )
  420. stream->writeWord ( fld->visible );
  421. if ( b4 & csm_newobject ) {
  422. stream->writeInt ( objectstreamversion );
  423. stream->writeInt ( fld->mines.size() );
  424. for ( MapField::MineContainer::iterator m = fld->mines.begin(); m != fld->mines.end(); m++ ) {
  425. stream->writeInt ( m->type );
  426. stream->writeInt ( m->strength );
  427. stream->writeInt ( m->lifetimer );
  428. stream->writeInt ( m->player );
  429. stream->writeInt ( m->identifier );
  430. }
  431. stream->writeInt ( fld->objects.size() );
  432. for ( MapField::ObjectContainer::iterator o = fld->objects.begin(); o != fld->objects.end(); o++ ) {
  433. stream->writeInt ( 1 ); // was: pointer to type
  434. stream->writeInt ( o->damage );
  435. stream->writeInt ( o->dir );
  436. stream->writeInt ( o->lifetimer );
  437. for ( int i = 0; i < 4; i++ )
  438. stream->writeInt ( 0 ); // dummy
  439. stream->writeInt ( o->typ->id );
  440. stream->writeInt( o->remainingGrowthTime );
  441. }
  442. }
  443. if (b4 & csm_resources ) {
  444. stream->writeChar ( fld->resourceview->visible );
  445. for ( int i = 0; i < 8; i++ )
  446. stream->writeChar ( fld->resourceview->fuelvisible[i] );
  447. for ( int i = 0; i < 8; i++ )
  448. stream->writeChar ( fld->resourceview->materialvisible[i] );
  449. }
  450. if ( b4 & csm_connection )
  451. stream->writeInt ( fld->connection );
  452. l += 1 + cnt2;
  453. } while (l < cnt1);
  454. }
  455. void tspfldloaders::readfields ( void )
  456. {
  457. int cnt2 = 0;
  458. int cnt1 = spfld->xsize * spfld->ysize;
  459. assertOrThrow( cnt1 > 0 );
  460. assertOrThrow( spfld->xsize > 0 );
  461. assertOrThrow( spfld->ysize > 0 );
  462. spfld->allocateFields ( spfld->xsize , spfld->ysize );
  463. if (spfld->field == NULL)
  464. displaymessage ( "Could not allocate memory for map ",2);
  465. int l = 0;
  466. MapField* lfld = NULL;
  467. do {
  468. MapField* fld2;
  469. if (cnt2 == 0) {
  470. fld2 = & spfld->field[l];
  471. fld2->bdt.setInt ( 0 , 0 );
  472. char b1, b3, b4;
  473. b1 = stream->readChar();
  474. if (b1 & csm_b3 )
  475. b3 = stream->readChar();
  476. else
  477. b3 = 0;
  478. if (b3 & csm_b4 )
  479. b4 = stream->readChar();
  480. else
  481. b4 = 0;
  482. if (b1 & csm_cnt2 )
  483. cnt2 = stream->readInt();
  484. else
  485. cnt2 = 0;
  486. int weather;
  487. if (b3 & csm_weather )
  488. weather = stream->readInt();
  489. else
  490. weather = 0;
  491. assertOrThrow( weather >= 0 && weather < cwettertypennum );
  492. int k;
  493. if (b1 & csm_typid32 )
  494. k = stream->readInt();
  495. else
  496. k = stream->readChar();
  497. pterraintype trn = terrainTypeRepository.getObject_byID ( k );
  498. if ( !trn )
  499. throw InvalidID ( "terrain", k );
  500. fld2->typ = trn->weather[weather];
  501. if ( !fld2->typ ) {
  502. fld2->typ = trn->weather[0];
  503. if ( !fld2->typ )
  504. throw InvalidID ( "terrain", k );
  505. }
  506. if (b1 & csm_direction )
  507. stream->readChar(); // fld2->direction = 0;
  508. if (b1 & csm_vehicle ) {
  509. fld2->vehicle = Vehicle::newFromStream ( spfld, *stream );
  510. fld2->vehicle->setnewposition ( l%spfld->xsize, l/spfld->xsize );
  511. }
  512. if (b1 & csm_building ) {
  513. fld2->building = Building::newFromStream ( spfld, *stream );
  514. fld2->bdt |= getTerrainBitType(cbbuildingentry);
  515. }
  516. if (b3 & csm_material)
  517. fld2->material = stream->readChar();
  518. else
  519. fld2->material = 0;
  520. if (b3 & csm_fuel)
  521. fld2->fuel = stream->readChar();
  522. else
  523. fld2->fuel = 0;
  524. if (b3 & csm_visible)
  525. fld2->visible = stream->readWord();
  526. else
  527. fld2->visible = 0;
  528. int tempobjectNum = 0;
  529. if (b3 & csm_object ) {
  530. char minetype = stream->readChar();
  531. char minestrength = stream->readChar();
  532. if ( minetype >> 4 ) {
  533. Mine m( MineTypes((minetype >> 1) & 7), minestrength, minetype >> 4, spfld );
  534. fld2->mines.push_back ( m );
  535. }
  536. tempobjectNum = stream->readInt();
  537. for ( int i = 0; i < 16; i++ )
  538. stream->readInt();
  539. }
  540. int objectversion = 1;
  541. if ( b4 & csm_newobject ) {
  542. objectversion = stream->readInt();
  543. if ( objectversion < 1 || objectversion > objectstreamversion )
  544. throw tinvalidversion ( "object", objectstreamversion, objectversion );
  545. int minenum = stream->readInt();
  546. for ( int i = 0; i < minenum; i++ ) {
  547. MineTypes type = MineTypes(stream->readInt());
  548. int strength = stream->readInt();
  549. int minetime = stream->readInt();
  550. int player = stream->readInt();
  551. if ( player < 0 || player > 7 )
  552. player = 0;
  553. assertOrThrow( strength >= 0 );
  554. assertOrThrow( type > 0 && type <= 4 );
  555. int id;
  556. if ( objectversion >= 4 )
  557. id = stream->readInt();
  558. else
  559. id = spfld->idManager.getNewNetworkID();
  560. Mine m ( type, strength, player, spfld, id );
  561. if ( objectversion == 1 ) {
  562. int endtime = minetime;
  563. int lifetime = spfld->getgameparameter( GameParameter(cgp_antipersonnelmine_lifetime + m.type - 1));
  564. if ( lifetime > 0 && endtime > 0 )
  565. m.lifetimer = endtime - spfld->time.turn() + spfld->getgameparameter( GameParameter(cgp_antipersonnelmine_lifetime + m.type - 1));
  566. else if ( lifetime > 0 )
  567. m.lifetimer = lifetime;
  568. else
  569. m.lifetimer = -1;
  570. } else
  571. m.lifetimer = minetime;
  572. fld2->mines.push_back ( m );
  573. }
  574. tempobjectNum = stream->readInt();
  575. }
  576. if ( (b3 & csm_object) || (b4 & csm_newobject )) {
  577. for ( int n = 0; n < tempobjectNum; n++ ) {
  578. Object o;
  579. stream->readInt(); // was: type
  580. o.damage = stream->readInt();
  581. assertOrThrow( o.damage >= 0 );
  582. o.dir = stream->readInt();
  583. if ( objectversion >= 2 )
  584. o.lifetimer = stream->readInt();
  585. else
  586. stream->readInt();
  587. for ( int i = 0; i < 4; i++ )
  588. stream->readInt(); // dummy
  589. int id = stream->readInt();
  590. o.typ = objectTypeRepository.getObject_byID ( id );
  591. if ( !o.typ )
  592. throw InvalidID ( "object", id );
  593. if ( objectversion >= 3 )
  594. o.remainingGrowthTime = stream->readInt();
  595. if ( objectversion == 1 )
  596. o.lifetimer = o.typ->lifetime;
  597. fld2->objects.push_back ( o );
  598. }
  599. fld2->sortobjects();
  600. }
  601. if (b4 & csm_resources ) {
  602. fld2->resourceview = new MapField::Resourceview;
  603. fld2->resourceview->visible = stream->readChar();
  604. for ( int i = 0; i < 8; i++ )
  605. fld2->resourceview->fuelvisible[i] = stream->readChar();
  606. for ( int i = 0; i < 8; i++ )
  607. fld2->resourceview->materialvisible[i] = stream->readChar();
  608. }
  609. if ( b4 & csm_connection )
  610. fld2->connection = stream->readInt();
  611. if (b1 & csm_cnt2 )
  612. lfld = fld2;
  613. } else {
  614. spfld->field[l].typ = lfld->typ;
  615. spfld->field[l].fuel = lfld->material;
  616. spfld->field[l].visible = lfld->visible;
  617. spfld->field[l].tempw = 0;
  618. spfld->field[l].connection = lfld->connection;
  619. for ( int i = 0; i < 8; i++ )
  620. spfld->field[l].view[i] = lfld->view[i];
  621. cnt2--;
  622. }
  623. l++ ;
  624. } while (l < cnt1);
  625. spfld->overviewMapHolder.connect();
  626. }
  627. /**************************************************************/
  628. /* Chain Items */
  629. /**************************************************************/
  630. void tspfldloaders::chainitems ( GameMap* actmap )
  631. {
  632. int i = 0;
  633. for (int y = 0; y < actmap->ysize; y++)
  634. for (int x = 0; x < actmap->xsize; x++) {
  635. MapField* fld = &actmap->field[i];
  636. fld->setparams();
  637. i++;
  638. }
  639. }
  640. /**************************************************************/
  641. /* Set Player Existencies */
  642. /**************************************************************/
  643. SigC::Signal1<void,GameMap*> tspfldloaders::mapLoaded;
  644. tspfldloaders::tspfldloaders ( void )
  645. {
  646. spfld = NULL;
  647. }
  648. tspfldloaders::~tspfldloaders ( void )
  649. {
  650. delete spfld;
  651. spfld = NULL;
  652. }
  653. int tmaploaders::savemap( const ASCString& name, GameMap* gamemap )
  654. {
  655. #ifdef logging
  656. logtofile ( "loaders / tmaploaders::savemap / started " );
  657. #endif
  658. tnfilestream filestream ( name, tnstream::writing );
  659. stream = &filestream;
  660. spfld = gamemap;
  661. /********************************************************************************/
  662. /* Stream initialisieren, Dateiinfo schreiben , map schreiben */
  663. /********************************************************************************/
  664. {
  665. stream->writepchar ( getFullVersionString() ); // description is not used any more
  666. stream->writeWord ( fileterminator );
  667. stream->writeInt ( actmapversion );
  668. writemap ( );
  669. }
  670. writefields ();
  671. #ifdef WEATHERGENERATOR
  672. spfld->weatherSystem->write(filestream);
  673. #endif
  674. stream->writeInt ( actmapversion );
  675. spfld = NULL;
  676. return 0;
  677. }
  678. void weatherSystemRequired()
  679. {
  680. throw ASCmsgException( "This file can not be loaded, since it contains data of the discontinued weather generator");
  681. }
  682. GameMap* tmaploaders::_loadmap( const ASCString& name )
  683. {
  684. displayLogMessage ( 4, "loading map %s ... ", name.c_str() );
  685. tnfilestream filestream ( name, tnstream::reading);
  686. stream = &filestream;
  687. char* description = NULL;
  688. stream->readpchar ( &description );
  689. delete[] description;
  690. int w = stream->readWord();
  691. if ( w != fileterminator )
  692. throw tinvalidversion ( name, fileterminator, w );
  693. int version = stream->readInt();
  694. if ( version > actmapversion || version < minmapversion )
  695. throw tinvalidversion ( name, actmapversion, version );
  696. displayLogMessage ( 8, "map, ");
  697. readmap ();
  698. if ( version <= 0xfe27 ) {
  699. displayLogMessage ( 8, "eventsToCome, ");
  700. readOldEventLists ( stream, false, spfld );
  701. }
  702. displayLogMessage ( 8, "fields, ");
  703. readfields ();
  704. if(version == 0xfe50)
  705. weatherSystemRequired();
  706. version = stream->readInt();
  707. if (version > actmapversion || version < minmapversion )
  708. throw tinvalidversion ( name, actmapversion, version );
  709. displayLogMessage ( 8, "chainItems, ");
  710. chainitems ( spfld );
  711. for ( int sp = spfld->getPlayerCount()-1; sp >= 0; sp--)
  712. if ( spfld->player[sp].exist() )
  713. spfld->actplayer = sp;
  714. displayLogMessage ( 8, "setEventTriggers, ");
  715. seteventtriggers( spfld );
  716. displayLogMessage ( 8, "calculateallobjects ");
  717. calculateallobjects( spfld );
  718. displayLogMessage ( 8, "init for playing, ");
  719. spfld->time.set ( 1, 0 );
  720. spfld->levelfinished = false;
  721. spfld->preferredFileNames.mapname[0] = name ;
  722. checkForUniqueUnitIDs( spfld );
  723. spfld->startGame();
  724. displayLogMessage ( 4, "done\n");
  725. GameMap* m = spfld;
  726. spfld = NULL;
  727. mapLoaded( m );
  728. return m;
  729. }
  730. GameMap* eventLocalizationMap = NULL;
  731. void loadLocalizedMessageFile( GameMap* map, const ASCString& filename )
  732. {
  733. eventLocalizationMap = map;
  734. LuaState state;
  735. LuaRunner runner( state );
  736. runner.runFile( filename );
  737. if ( !runner.getErrors().empty() )
  738. errorMessage( runner.getErrors() );
  739. eventLocalizationMap = NULL;
  740. }
  741. void loadLocalizedMessages( GameMap* map, const ASCString& name )
  742. {
  743. Locale locale;
  744. ASCString filename = locale.getLocalizedFile( name );
  745. if( !filename.empty() && exist( filename ) )
  746. loadLocalizedMessageFile( map, filename );
  747. }
  748. GameMap* tmaploaders::loadmap ( const ASCString& name )
  749. {
  750. tmaploaders gl;
  751. GameMap* map = gl._loadmap ( name );
  752. #ifdef sgmain
  753. loadLocalizedMessages( map, name );
  754. #endif
  755. return map;
  756. }
  757. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  758. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  759. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  760. void tsavegameloaders::savegame( tnstream* strm, GameMap* gamemap, bool writeReplays )
  761. {
  762. PackageManager::storeData( gamemap );
  763. stream = strm;
  764. spfld = gamemap;
  765. stream->writepchar( getFullVersionString() );
  766. stream->writeWord( fileterminator );
  767. stream->writeInt( actsavegameversion );
  768. //An Image of the Map will now be saved to the file.
  769. writemaptostream( spfld , 100, 100, *stream);
  770. stream->writeString( gamemap->maptitle );
  771. stream->writeString( gamemap->getCurrentPlayer().getName() );
  772. stream->writeInt( gamemap->time.turn() );
  773. writemap ();
  774. writemessages();
  775. writefields ( );
  776. writedissections();
  777. if ( writeReplays && spfld->replayinfo ) {
  778. stream->writeInt( 1 );
  779. spfld->replayinfo->write(*stream);
  780. } else
  781. stream->writeInt( 0 );
  782. writeAI();
  783. stream->writeInt( actsavegameversion );
  784. spfld = NULL;
  785. }
  786. void tsavegameloaders::savegame( GameMap* gamemap, const ASCString& name)
  787. {
  788. tnfilestream filestream ( name, tnstream::writing );
  789. savegame ( &filestream, gamemap, true );
  790. }
  791. GameFileInformation tsavegameloaders::loadMapimageFromFile( const ASCString& filename )
  792. {
  793. GameFileInformation gfi;
  794. try {
  795. tnfilestream stream( filename, tnstream::reading );
  796. stream.readString(); // was: description
  797. int w = stream.readWord();
  798. if ( w != fileterminator )
  799. throw tinvalidversion ( stream.getDeviceName(), fileterminator, w );
  800. int version = stream.readInt();
  801. if ( version >= 0xff63 ) {
  802. gfi.image = loadmapfromstream( stream );
  803. gfi.maptitle = stream.readString();
  804. gfi.playername = stream.readString();
  805. gfi.turn = stream.readInt();
  806. }
  807. } catch(...) {
  808. }
  809. return gfi;
  810. }
  811. GameMap* tsavegameloaders::loadGameFromFile( const ASCString& filename )
  812. {
  813. tnfilestream filestream( filename, tnstream::reading );
  814. tsavegameloaders gl;
  815. return gl.loadgame( &filestream );
  816. }
  817. GameMap* tsavegameloaders::loadgame( tnstream* strm )
  818. {
  819. stream = strm;
  820. stream->readString(); // was: description
  821. int w = stream->readWord();
  822. if ( w != fileterminator )
  823. throw tinvalidversion ( strm->getDeviceName(), fileterminator, w );
  824. int version = stream->readInt();
  825. if (version > actsavegameversion || version < minsavegameversion )
  826. throw tinvalidversion ( strm->getDeviceName(), actsavegameversion, version );
  827. if ( version >= 0xff62 ) {
  828. // ignoring the map image
  829. loadmapfromstream( *stream );
  830. }
  831. if ( version >= 0xff63 ) {
  832. // ignoring the map information
  833. stream->readString();
  834. stream->readString();
  835. stream->readInt();
  836. }
  837. readmap ();
  838. readLegacyNetwork ();
  839. if ( version <= 0xff39 )
  840. for ( int i = 0; i < 8; i++ )
  841. spfld->player[i].research.read_techs ( *stream );
  842. readmessages();
  843. if ( version <= 0xff37 ) {
  844. readOldEventLists ( stream, true, spfld );
  845. readoldevents ();
  846. }
  847. readfields ( );
  848. if(version == 0xff60)
  849. weatherSystemRequired();
  850. readdissections();
  851. bool loadReplay = true;
  852. if ( version >= 0xff35 )
  853. if ( !stream->readInt() )
  854. loadReplay = false;
  855. if ( loadReplay ) {
  856. spfld->replayinfo = new GameMap::ReplayInfo;
  857. spfld->replayinfo->read ( *stream );
  858. } else
  859. spfld->replayinfo = NULL;
  860. if ( version >= 0xff34 )
  861. readAI ();
  862. version = stream->readInt();
  863. if (version > actsavegameversion || version < minsavegameversion )
  864. throw tinvalidversion ( strm->getDeviceName(), actsavegameversion, version );
  865. chainitems ( spfld );
  866. seteventtriggers( spfld );
  867. calculateallobjects( spfld );
  868. checkForUniqueUnitIDs( spfld );
  869. mapLoaded( spfld );
  870. GameMap* s = spfld;
  871. spfld = NULL; // to avoid that is is deleted by the destructor of tsavegameloaders
  872. return s;
  873. }
  874. /*****************************************************************************************************/
  875. /* Netzwerk */
  876. /*****************************************************************************************************/
  877. int tnetworkloaders::savenwgame( tnstream* strm, const GameMap* gamemap )
  878. {
  879. PackageManager::storeData( gamemap );
  880. spfld = const_cast<GameMap*>(gamemap); // yes, this is bad, but spfld can't be made constant because it is also used for loading
  881. stream = strm;
  882. stream->writepchar ( getFullVersionString() ); // description is not used any more
  883. stream->writeWord ( fileterminator );
  884. stream->writeInt ( actnetworkversion );
  885. writemap ();
  886. writemessages();
  887. stream->writeInt ( actnetworkversion );
  888. writefields ( );
  889. writedissections();
  890. if ( spfld->replayinfo )
  891. spfld->replayinfo->write ( *stream );
  892. // the AI must be the last data of the file
  893. writeAI();
  894. stream->writeInt ( actnetworkversion );
  895. spfld = NULL;
  896. return 0;
  897. }
  898. GameMap* tnetworkloaders::loadnwgame( tnstream* strm )
  899. {
  900. const char* name = "network game";
  901. stream = strm;
  902. char* description = NULL;
  903. stream->readpchar ( &description );
  904. delete[] description;
  905. int w = stream->readWord();
  906. if ( w != fileterminator )
  907. throw tinvalidversion ( name, fileterminator, (int) w );
  908. int version = stream->readInt();
  909. if (version > actnetworkversion || version < minnetworkversion )
  910. throw tinvalidversion ( name, actnetworkversion, version );
  911. readmap ();
  912. if ( version <= 0x11 )
  913. for ( int i = 0; i < 8; i++ )
  914. spfld->player[i].research.read_techs ( *stream );
  915. //NEW SaveData Weather
  916. if(version == 0x0030)
  917. weatherSystemRequired();
  918. /*if(version > 0xfe28){ //Vielleicht minus 1
  919. actmap->weatherSystem->read(*stream);
  920. }*/
  921. readmessages();
  922. readLegacyNetwork ();
  923. version = stream->readInt();
  924. if (version > actnetworkversion || version < minnetworkversion )
  925. throw tinvalidversion ( name, actnetworkversion, version );
  926. if ( version < 10 ) {
  927. readOldEventLists ( stream, true, spfld );
  928. readoldevents ();
  929. }
  930. readfields ( );
  931. readdissections();
  932. if ( spfld->__loadreplayinfo ) {
  933. spfld->replayinfo = new GameMap::ReplayInfo;
  934. spfld->replayinfo->read ( *stream );
  935. }
  936. if ( version > 8 )
  937. readAI();
  938. #ifdef sgmain
  939. version = stream->readInt();
  940. if (version > actnetworkversion || version < minnetworkversion )
  941. throw tinvalidversion ( name, actnetworkversion, version );
  942. #endif
  943. chainitems ( spfld );
  944. seteventtriggers( spfld );
  945. calculateallobjects( spfld );
  946. checkForUniqueUnitIDs( spfld );
  947. spfld->levelfinished = false;
  948. // there was a bug that made the ammo amount underflow
  949. for ( int i = 0; i < 8; ++i)
  950. for ( Player::BuildingList::iterator b = spfld->player[i].buildingList.begin(); b != spfld->player[i].buildingList.end(); ++b )
  951. for ( int a = 0; a < waffenanzahl; ++a )
  952. if ( (*b)->ammo[a] > 32000 ) {
  953. ASCString s;
  954. s.format( "Player %s had %d ammo of type %s in the building at %d/%d", spfld->player[i].getName().c_str(), (*b)->ammo[a], cwaffentypen[a], (*b)->getEntry().x, (*b)->getEntry().y );
  955. new Message( s, spfld, 1 );
  956. (*b)->ammo[a] = 0;
  957. }
  958. GameMap* spfldcopy = spfld;
  959. spfld = NULL;
  960. mapLoaded( spfldcopy );
  961. return spfldcopy;
  962. }
  963. ASCString getLuaQuote( bool open, int n )
  964. {
  965. ASCString s = open? "[[" : "]]";
  966. for ( int i =0; i < n; ++i )
  967. s.insert(1, "=" );
  968. return s;
  969. }
  970. ASCString luaQuote( const ASCString& text )
  971. {
  972. int count = 0;
  973. while( text.find_first_of( getLuaQuote( true, count )) != ASCString::npos ||
  974. text.find_first_of( getLuaQuote( false, count )) != ASCString::npos )
  975. ++count;
  976. return getLuaQuote( true, count) + text + getLuaQuote( false, count );
  977. }
  978. void writeMessageFile( GameMap* gamemap, tnstream& stream )
  979. {
  980. stream.writeString( "map = asc.getLoadingMap() \n", false);
  981. for ( GameMap::Events::const_iterator i = gamemap->events.begin(); i != gamemap->events.end(); ++i ) {
  982. ASCString s = (*i)->action->getLocalizationString();
  983. if ( !s.empty() ) {
  984. stream.writeString ( "--- ===== Event " + ASCString::toString((*i)->id) + " ======= \n", false );
  985. stream.writeString ( "message = " + luaQuote( s ) + "\n", false );
  986. stream.writeString ( "asc.setLocalizedEventMessage( map, " + ASCString::toString((*i)->id) + ", message )\n\n", false);
  987. }
  988. }
  989. for ( int p = 0; p <= gamemap->getPlayerCount(); ++p ) {
  990. Player& player = gamemap->getPlayer(p);
  991. for ( Player::BuildingList::const_iterator b = player.buildingList.begin(); b != player.buildingList.end(); ++b ) {
  992. if ( !(*b)->name.empty() ) {
  993. stream.writeString ( "--- ===== Building " + ASCString::toString((*b)->getIdentification()) + " ======= \n", false );
  994. ASCString f;
  995. f.format( "asc.setLocalizedContainerName( map, asc.MapCoordinate( %d, %d ), %s ) \n", (*b)->getPosition().x, (*b)->getPosition().y, + luaQuote( (*b)->name ).c_str() );
  996. stream.writeString ( f, false );
  997. }
  998. }
  999. }
  1000. }
  1001. void savemap( const ASCString& name, GameMap* gamemap )
  1002. {
  1003. #ifdef logging
  1004. logtofile ( "loaders / savemap / started " );
  1005. #endif
  1006. try {
  1007. tmaploaders gl;
  1008. gl.savemap ( name, gamemap );
  1009. if ( CGameOptions::Instance()->saveEventMessagesExternal && gamemap->nativeMessageLanguage.length() ) {
  1010. tn_file_buf_stream messages ( name + "." + gamemap->nativeMessageLanguage, tnstream::writing );
  1011. writeMessageFile( gamemap, messages );
  1012. }
  1013. } /* endtry */
  1014. catch ( const tfileerror& err ) {
  1015. displaymessage( "file error writing map to filename %s ", 1, err.getFileName().c_str() );
  1016. } /* endcatch */
  1017. catch ( const ASCexception& ) {
  1018. displaymessage( "error writing map ", 1 );
  1019. } /* endcatch */
  1020. }
  1021. void savegame( const ASCString& name, GameMap* gamemap)
  1022. {
  1023. try {
  1024. tsavegameloaders gl;
  1025. gl.savegame ( gamemap, name);
  1026. } catch ( const tfileerror& err) {
  1027. displaymessage( "error writing map to filename %s ", 1, err.getFileName().c_str() );
  1028. } /* endcatch */
  1029. catch ( const ASCexception& ) {
  1030. displaymessage( "error writing map ", 1 );
  1031. } /* endcatch */
  1032. }
  1033. void savereplay( GameMap* gamemap, int num )
  1034. {
  1035. try {
  1036. if ( !gamemap->replayinfo )
  1037. fatalError ( "treplayloaders :: savereplay ; No replay activated !");
  1038. if ( gamemap->replayinfo->map[num] ) {
  1039. delete gamemap->replayinfo->map[num];
  1040. gamemap->replayinfo->map[num] = NULL;
  1041. }
  1042. gamemap->replayinfo->map[num] = new MemoryStreamStorage;
  1043. MemoryStream memstream ( gamemap->replayinfo->map[num], tnstream::writing );
  1044. memstream.writeInt( actreplayversion );
  1045. tsavegameloaders sgl;
  1046. sgl.savegame ( &memstream, gamemap, false );
  1047. memstream.writeInt ( actreplayversion );
  1048. } catch ( const ASCexception & ) {
  1049. displaymessage( "error saving replay information", 1 );
  1050. } /* endcatch */
  1051. }
  1052. GameMap* loadreplay( MemoryStreamStorage* streambuf )
  1053. {
  1054. GameMap* replaymap = NULL;
  1055. try {
  1056. const char* name = "memorystream actmap->replayinfo";
  1057. MemoryStream memstream ( streambuf, tnstream::reading );
  1058. int version = memstream.readInt();
  1059. if (version > actreplayversion || version < minreplayversion )
  1060. throw tinvalidversion ( name, actreplayversion, version );
  1061. tsavegameloaders sgl;
  1062. replaymap = sgl.loadgame ( &memstream );
  1063. version = memstream.readInt();
  1064. if (version > actreplayversion || version < minreplayversion ) {
  1065. delete replaymap;
  1066. throw tinvalidversion ( name, actreplayversion, version );
  1067. }
  1068. } catch ( const InvalidID & err ) {
  1069. displaymessage( err.getMessage().c_str(), 1 );
  1070. replaymap = NULL;
  1071. } /* endcatch */
  1072. catch ( const tinvalidversion & err ) {
  1073. displaymessage( err.getMessage().c_str(), 1 );
  1074. replaymap = NULL;
  1075. } /* endcatch */
  1076. catch ( const tfileerror & err) {
  1077. displaymessage( "error reading map filename %s ", 1, err.getFileName().c_str() );
  1078. replaymap = NULL;
  1079. } /* endcatch */
  1080. catch ( const ASCexception & ) {
  1081. displaymessage( "error loading replay", 1 );
  1082. replaymap = NULL;
  1083. } /* endcatch */
  1084. return replaymap;
  1085. }
  1086. GameMap* mapLoadingExceptionChecker( const ASCString& filename, MapLoadingFunction loader )
  1087. {
  1088. GameMap* m = NULL;
  1089. try {
  1090. m = loader( filename );
  1091. } catch ( const InvalidID & err ) {
  1092. displaymessage( err.getMessage().c_str(), 1 );
  1093. return NULL;
  1094. } /* endcatch */
  1095. catch ( const tinvalidversion & err ) {
  1096. displaymessage( err.getMessage().c_str(), 1 );
  1097. return NULL;
  1098. } /* endcatch */
  1099. catch ( const StreamCompressionError & err ) {
  1100. displaymessage( "The file %s is corrupted.\nPlease obtain a new copy of that file", 1, filename.c_str() );
  1101. return NULL;
  1102. } catch ( const tfileerror & err) {
  1103. displaymessage( "error reading map filename %s ", 1, err.getFileName().c_str() );
  1104. return NULL;
  1105. } /* endcatch */
  1106. catch ( const ASCmsgException & msg ) {
  1107. displaymessage( "error loading file\n" + msg.getMessage() , 1 );
  1108. return NULL;
  1109. } /* endcatch */
  1110. catch ( const ASCexception & ) {
  1111. displaymessage( "error loading file", 1 );
  1112. return NULL;
  1113. } /* endcatch */
  1114. return m;
  1115. }
  1116. bool validatemapfile ( const ASCString& filename )
  1117. {
  1118. char* description = NULL;
  1119. try {
  1120. tnfilestream stream ( filename, tnstream::reading );
  1121. stream.readpchar ( &description, 200 );
  1122. if ( description ) {
  1123. delete[] description ;
  1124. description = NULL;
  1125. }
  1126. int w = stream.readWord();
  1127. if ( w != fileterminator )
  1128. throw tinvalidversion ( filename, fileterminator, (int) w );
  1129. int version = stream.readInt();
  1130. if (version > actmapversion || version < minmapversion )
  1131. throw tinvalidversion ( filename, actmapversion, version );
  1132. } /* endtry */
  1133. catch ( ... ) {
  1134. return false;
  1135. } /* endcatch */
  1136. return true;
  1137. }
  1138. bool validateemlfile ( const ASCString& filename )
  1139. {
  1140. char* description = NULL;
  1141. try {
  1142. tnfilestream stream ( filename, tnstream::reading );
  1143. stream.readpchar ( &description, 200 );
  1144. if ( description ) {
  1145. delete[] description ;
  1146. description = NULL;
  1147. }
  1148. int w = stream.readWord();
  1149. if ( w != fileterminator )
  1150. throw tinvalidversion ( filename, fileterminator, (int) w );
  1151. int version = stream.readInt();
  1152. if (version > actnetworkversion || version < minnetworkversion )
  1153. throw tinvalidversion ( filename, actnetworkversion, version );
  1154. } /* endtry */
  1155. catch ( const ASCexception & ) {
  1156. return false;
  1157. } /* endcatch */
  1158. return true;
  1159. }
  1160. bool validatesavfile ( const ASCString& filename )
  1161. {
  1162. char* description = NULL;
  1163. try {
  1164. tnfilestream stream ( filename, tnstream::reading );
  1165. stream.readpchar ( &description, 200 );
  1166. if ( description ) {
  1167. delete[] description ;
  1168. description = NULL;
  1169. }
  1170. int w = stream.readWord();
  1171. if ( w != fileterminator )
  1172. throw tinvalidversion ( filename, fileterminator, w );
  1173. int version = stream.readInt();
  1174. if (version > actsavegameversion || version < minsavegameversion )
  1175. throw tinvalidversion ( filename, actsavegameversion, version );
  1176. } /* endtry */
  1177. catch ( const ASCexception & ) {
  1178. return false;
  1179. } /* endcatch */
  1180. return true;
  1181. }
  1182. MapConinuationInfo findNextCampaignMap( int id )
  1183. {
  1184. MapConinuationInfo mi;
  1185. tfindfile ff ( mapextension );
  1186. ASCString filename = ff.getnextname();
  1187. while( !filename.empty() ) {
  1188. try {
  1189. tnfilestream filestream ( filename, tnstream::reading );
  1190. tmaploaders spfldloader;
  1191. spfldloader.stream = &filestream;
  1192. CharBuf description;
  1193. spfldloader.stream->readpchar ( &description.buf );
  1194. int w = spfldloader.stream->readWord();
  1195. if ( w != fileterminator )
  1196. throw tinvalidversion ( filename.c_str(), w, fileterminator );
  1197. int version = spfldloader.stream->readInt();
  1198. if (version > actmapversion || version < minmapversion )
  1199. throw tinvalidversion ( filename.c_str(), version, actmapversion );
  1200. spfldloader.readmap ();
  1201. if ( spfldloader.spfld->campaign.avail && spfldloader.spfld->campaign.id == id ) {
  1202. mi.title = spfldloader.spfld->maptitle;
  1203. mi.codeword = spfldloader.spfld->codeWord;
  1204. mi.filename = filename;
  1205. return mi;
  1206. }
  1207. } catch ( ... ) {
  1208. } /* endcatch */
  1209. filename = ff.getnextname();
  1210. }
  1211. return mi;
  1212. }