00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <algorithm>
00029 #include <cstring>
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032
00033 #include "typen.h"
00034 #include "misc.h"
00035 #include "newfont.h"
00036 #include "buildingtype.h"
00037 #include "vehicletype.h"
00038 #include "spfst.h"
00039 #include "loaders.h"
00040 #include "dlg_box.h"
00041 #include "dlg_box.h"
00042 #include "dialog.h"
00043 #include "sgstream.h"
00044 #include "attack.h"
00045 #include "errors.h"
00046 #include "strtmesg.h"
00047 #include "textfileparser.h"
00048 #include "itemrepository.h"
00049 #include "prehistoricevents.h"
00050 #include "gamemap.h"
00051 #include "gameeventsystem.h"
00052
00053 #ifdef sgmain
00054 # include "ai/ai.h"
00055 #endif
00056
00057
00058
00059 const int actsavegameversion = 0xff61;
00060 const int minsavegameversion = 0xff31;
00061 const int actmapversion = 0xfe51;
00062 const int minmapversion = 0xfe24;
00063 const int actnetworkversion = 0x0032;
00064 const int minnetworkversion = 0x0004;
00065 const int actreplayversion = 0x0003;
00066 const int minreplayversion = 0x0001;
00067
00068
00069 const int fileterminator = 0xa01a;
00070
00071
00072 const char* savegameextension = "*.sav";
00073 const char* mapextension = "*.map";
00074 const char* tournamentextension = ".ascpbm";
00075
00076
00077
00078 void seteventtriggers( GameMap* actmap )
00079 {
00080 #ifdef sgmain
00081 for ( GameMap::Events::iterator i = actmap->events.begin(); i != actmap->events.end(); ++i )
00082 (*i)->arm();
00083
00084 #endif
00085
00086 for ( int i = 0; i < 8; i++ )
00087 actmap->player[i].queuedEvents = 1;
00088 }
00089
00090
00091
00092 #define csm_typid32 1
00093 #define csm_direction 2
00094 #define csm_vehicle 4
00095 #define csm_building 8
00096 #define csm_height 32
00097 #define csm_cnt2 64
00098 #define csm_b3 128
00099
00100 #define csm_material 1
00101 #define csm_fuel 2
00102 #define csm_visible 4
00103
00104 #define csm_weather 16
00105
00106 #define csm_object 64
00107 #define csm_b4 128
00108
00109 #define csm_resources 1
00110 #define csm_connection 2 // b4
00111 #define csm_newobject 4 // b4
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 void tspfldloaders::readdissections ( void )
00125 {
00126 for (int i = 0; i < 8; i ++ ) {
00127 if ( spfld->player[ i ].__dissectionsToLoad ) {
00128 int k;
00129 do {
00130 Player::Dissection du;
00131 stream->readInt();
00132 stream->readInt();
00133
00134 du.orgpoints = stream->readInt();
00135 du.points = stream->readInt();
00136 du.num = stream->readInt();
00137
00138 k = stream->readInt();
00139
00140 int j = stream->readInt();
00141 du.fzt = vehicleTypeRepository.getObject_byID ( j );
00142 if ( !du.fzt )
00143 throw InvalidID ( "vehicle", j );
00144
00145 j = stream->readInt();
00146 du.tech = technologyRepository.getObject_byID ( j );
00147 if ( !du.tech )
00148 throw InvalidID ( "technology", j );
00149
00150 spfld->player[ i ].dissections.push_back ( du );
00151 } while ( k );
00152 }
00153 }
00154 }
00155
00156 void tspfldloaders::writedissections ( void )
00157 {
00158 for (int i = 0; i < 8; i ++ ) {
00159 Player::DissectionContainer::iterator di = spfld->player[i].dissections.begin();
00160 while ( di != spfld->player[i].dissections.end() ) {
00161 stream->writeInt ( 1 );
00162 stream->writeInt ( 1 );
00163 stream->writeInt ( di->orgpoints );
00164 stream->writeInt ( di->points );
00165 stream->writeInt ( di->num );
00166
00167 di++;
00168 if ( di != spfld->player[i].dissections.end() )
00169 stream->writeInt ( 1 );
00170 else
00171 stream->writeInt ( 0 );
00172
00173 stream->writeInt ( di->fzt->id );
00174 stream->writeInt ( di->tech->id );
00175 }
00176 }
00177 }
00178
00179
00180
00181
00182
00183
00184
00185 const int messageVersion = 0xabcdf1;
00186 const int messageMinVersion = 0xabcdef;
00187
00188 void tspfldloaders:: writemessages ( void )
00189 {
00190 stream->writeInt ( messageVersion );
00191
00192 int id = 0;
00193 for ( MessageContainer::iterator mi = spfld->messages.begin(); mi != spfld->messages.end(); ) {
00194 id++;
00195 (*mi)->id = id;
00196
00197 stream->writeInt ( (*mi)->from );
00198 stream->writeInt ( (*mi)->to );
00199 stream->writeInt ( (*mi)->cc );
00200 stream->writeInt ( (unsigned int) (*mi)->time );
00201 stream->writeInt ( 1 );
00202 stream->writeInt ( (*mi)->id );
00203 stream->writeInt ( (*mi)->gametime.turn() );
00204 stream->writeInt ( (*mi)->gametime.move() );
00205 stream->writeInt( (*mi)->reminder );
00206
00207
00208 ASCString& t = (*mi)->text;
00209
00210 mi++;
00211 stream->writeInt ( mi != spfld->messages.end() ? 1 : 0 );
00212
00213 stream->writeString ( t );
00214 }
00215
00216 for ( int i = 0; i < 8; i++ )
00217 writemessagelist ( spfld->player[ i ].oldmessage );
00218
00219 for ( int i = 0; i < 8; i++ )
00220 writemessagelist ( spfld->player[ i ].unreadmessage );
00221
00222 for ( int i = 0; i < 8; i++ )
00223 writemessagelist ( spfld->player[ i ].sentmessage );
00224
00225 writemessagelist ( spfld->unsentmessage );
00226
00227 stream->writeInt ( messageVersion );
00228
00229 stream->writeString ( spfld->gameJournal );
00230 stream->writeString ( spfld->newJournal );
00231 }
00232
00233
00234 void tspfldloaders:: writemessagelist( MessagePntrContainer& lst )
00235 {
00236 for ( MessagePntrContainer::iterator i = lst.begin(); i != lst.end(); i++ )
00237 stream->writeInt ( (*i)->id );
00238 stream->writeInt ( 0 );
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 void tspfldloaders:: readmessagelist( MessagePntrContainer& lst )
00252 {
00253 int i = stream->readInt();
00254
00255 while ( i ) {
00256
00257 MessageContainer::iterator mi = spfld->messages.end();
00258 for ( MessageContainer::iterator mi2 = spfld->messages.begin(); mi2 != spfld->messages.end(); mi2++ )
00259 if ( (*mi2)->id == i )
00260 mi = mi2;
00261
00262 if ( mi == spfld->messages.end())
00263 warning( "message list corrupted !\nplease report this bug!\nthe game will continue, but some messages will probably be missing\nand other instabilities may occur.");
00264 lst.push_back ( *mi );
00265 i = stream->readInt();
00266 }
00267 }
00268
00269
00270 void tspfldloaders:: readmessages ( void )
00271 {
00272 int magic = stream->readInt();
00273 assertOrThrow( magic >= messageMinVersion && magic <= messageVersion );
00274
00275 while ( spfld->__loadmessages ) {
00276 Message* msg = new Message ( spfld );
00277
00278 msg->from = stream->readInt();
00279 msg->to = stream->readInt();
00280 if ( magic >= 0xabcdf0 )
00281 msg->cc = stream->readInt();
00282 else
00283 msg->cc = 0;
00284
00285 msg->time = stream->readInt();
00286 bool msgtext = stream->readInt();
00287 msg->id = stream->readInt();
00288 int t = stream->readInt();
00289 int m = stream->readInt();
00290 msg->gametime.set ( t, m );
00291
00292 if ( magic >= 0xabcdf1 )
00293 msg->reminder = stream->readInt();
00294 else
00295 msg->reminder = false;
00296
00297 spfld->__loadmessages = stream->readInt();
00298
00299 if ( msgtext )
00300 msg->text = stream->readString( true );
00301
00302 }
00303
00304 for ( int i = 0; i < 8; i++ )
00305 if ( spfld->player[ i ].__loadoldmessage )
00306 readmessagelist ( spfld->player[ i ].oldmessage );
00307
00308 for ( int i = 0; i < 8; i++ )
00309 if ( spfld->player[ i ].__loadunreadmessage )
00310 readmessagelist ( spfld->player[ i ].unreadmessage );
00311
00312 for ( int i = 0; i < 8; i++ )
00313 if ( spfld->player[ i ].__loadsentmessage )
00314 readmessagelist ( spfld->player[ i ].sentmessage );
00315
00316 if ( spfld->__loadunsentmessage )
00317 readmessagelist ( spfld->unsentmessage );
00318
00319 stream->readInt();
00320
00321 if ( spfld->___loadJournal )
00322 spfld->gameJournal = stream->readString();
00323
00324 if ( spfld->___loadNewJournal )
00325 spfld->newJournal = stream->readString();
00326 }
00327
00328
00329
00330
00331
00332
00333 void tspfldloaders::readoldevents ( void )
00334 {
00335 if ( spfld->loadOldEvents ) {
00336 int num = stream->readInt();
00337 while ( num ) {
00338 for ( int i = 0;i < num; i++ )
00339 stream->readInt();
00340 for ( int i = 0;i < num; i++ )
00341 stream->readInt();
00342
00343 num = stream->readInt();
00344 }
00345 }
00346 }
00347
00348 void checkForUniqueUnitIDs( GameMap* gamemap )
00349 {
00350 map<int,int> units;
00351 for ( int p = 0; p < gamemap->getPlayerCount(); ++p )
00352 for ( Player::VehicleList::iterator i = gamemap->getPlayer(p).vehicleList.begin(); i != gamemap->getPlayer(p).vehicleList.end(); ++i )
00353 if ( units[(*i)->networkid]++ > 0 ) {
00354 warning("unit with duplicate network ids: " + ASCString::toString( (*i)->networkid ) + "\nThis will lead to replay errors during the next turn." );
00355 (*i)->networkid = gamemap->getNewNetworkID();;
00356 }
00357 }
00358
00359
00360
00361
00362
00363 void tspfldloaders::writemap ( void )
00364 {
00365 checkForUniqueUnitIDs( spfld );
00366 if ( !spfld )
00367 displaymessage ( "tspfldloaders::writemap ; no map to write ! ",2);
00368
00369 spfld->write ( *stream );
00370 }
00371
00372
00373 void tmaploaders::initmap ( void )
00374 {
00375 spfld->game_parameter = NULL;
00376 }
00377
00378
00379 void tgameloaders::initmap ( void )
00380 {
00381 spfld->game_parameter = NULL;
00382 }
00383
00384
00385 void tspfldloaders::readmap ( void )
00386 {
00387 spfld = new GameMap;
00388
00389 spfld->read ( *stream );
00390 }
00391
00392
00393
00394 void tgameloaders :: writeAI ( )
00395 {
00396 #ifdef sgmain
00397 int a = 0;
00398 for ( int i = 0; i< 8; i++ )
00399 if ( spfld->player[i].ai )
00400 a += 1 << i;
00401
00402 stream->writeInt ( a );
00403
00404 for ( int i = 0; i < 8; i++ )
00405 if ( spfld->player[i].ai )
00406 spfld->player[i].ai->write( *stream );
00407 #else
00408 stream->writeInt(0);
00409 #endif
00410 }
00411
00412 void tgameloaders :: readAI ( )
00413 {
00414 #ifdef sgmain
00415 int a = stream->readInt();
00416 for ( int i = 0; i< 8; i++ )
00417 if ( a & ( 1 << i ) ) {
00418 AI* ai = new AI ( spfld, i );
00419 ai->read ( *stream );
00420 spfld->player[i].ai = ai;
00421 } else {
00422 spfld->player[i].ai = NULL;
00423 }
00424 #else
00425 for ( int i = 0; i< 9; i++ )
00426 spfld->player[i].ai = NULL;
00427 #endif
00428 }
00429
00430
00431
00432
00433
00434
00435 extern void readLegacyNetworkData ( tnstream& stream );
00436
00437
00438 void tspfldloaders::readLegacyNetwork ( void )
00439 {
00440 if ( spfld->___loadLegacyNetwork )
00441 readLegacyNetworkData( *stream );
00442 }
00443
00444
00445
00446
00447
00448
00449
00450
00451 const int objectstreamversion = 3;
00452
00453 void tspfldloaders::writefields ( void )
00454 {
00455 int l = 0;
00456 int cnt1 = spfld->xsize * spfld->ysize;
00457 int cnt2;
00458
00459 do {
00460 cnt2 = 0;
00461 tfield* fld = &spfld->field[l];
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 char b1 = 0;
00480 char b3 = 0;
00481 char b4 = 0;
00482
00483 if (fld->typ->terraintype->id > 255)
00484 b1 |= csm_typid32;
00485 if (fld->vehicle != NULL)
00486 b1 |= csm_vehicle;
00487 if ( (fld->bdt & getTerrainBitType( cbbuildingentry )).any() )
00488 b1 |= csm_building;
00489
00490
00491 if (cnt2 > 0)
00492 b1 |= csm_cnt2;
00493
00494 if (fld->material > 0)
00495 b3 |= csm_material;
00496 if (fld->fuel > 0)
00497 b3 |= csm_fuel;
00498
00499 if (fld->typ != fld->typ->terraintype->weather[0])
00500 b3 |= csm_weather;
00501 if (fld->visible)
00502 b3 |= csm_visible;
00503 if ( !fld->objects.empty() || !fld->mines.empty() )
00504 b4 |= csm_newobject;
00505
00506 if ( fld->resourceview )
00507 b4 |= csm_resources;
00508
00509 if ( fld->connection )
00510 b4 |= csm_connection;
00511
00512 if ( b4 )
00513 b3 |= csm_b4;
00514
00515 if ( b3 )
00516 b1 |= csm_b3;
00517
00518 stream->writeChar( b1 );
00519
00520 if (b1 & csm_b3 )
00521 stream->writeChar ( b3 );
00522
00523 if (b3 & csm_b4 )
00524 stream->writeChar ( b4 );
00525
00526 if (b1 & csm_cnt2 )
00527 stream->writeInt ( cnt2 );
00528
00529 if (b3 & csm_weather ) {
00530 int k = 1;
00531 while ( fld->typ != fld->typ->terraintype->weather[k] && k < cwettertypennum ) {
00532 k++;
00533 }
00534
00535 if ( k == cwettertypennum ) {
00536 k = 0;
00537 displaymessage ( "invalid terrain ( weather not found ) at position %d \n",1,l );
00538 }
00539 stream->writeInt ( k );
00540 }
00541
00542 if (b1 & csm_typid32 )
00543 stream->writeInt ( fld->typ->terraintype->id );
00544 else
00545 stream->writeChar ( fld->typ->terraintype->id );
00546
00547 if (b1 & csm_vehicle )
00548 fld->vehicle->write ( *stream );
00549
00550
00551 if (b1 & csm_building )
00552 fld->building->write ( *stream );
00553
00554 if (b3 & csm_material )
00555 stream->writeChar ( fld->material );
00556
00557 if (b3 & csm_fuel )
00558 stream->writeChar ( fld->fuel );
00559
00560 if (b3 & csm_visible )
00561 stream->writeWord ( fld->visible );
00562
00563 if ( b4 & csm_newobject ) {
00564 stream->writeInt ( objectstreamversion );
00565
00566 stream->writeInt ( fld->mines.size() );
00567 for ( tfield::MineContainer::iterator m = fld->mines.begin(); m != fld->mines.end(); m++ ) {
00568 stream->writeInt ( m->type );
00569 stream->writeInt ( m->strength );
00570 stream->writeInt ( m->lifetimer );
00571 stream->writeInt ( m->player );
00572 }
00573
00574 stream->writeInt ( fld->objects.size() );
00575
00576 for ( tfield::ObjectContainer::iterator o = fld->objects.begin(); o != fld->objects.end(); o++ ) {
00577 stream->writeInt ( 1 );
00578 stream->writeInt ( o->damage );
00579 stream->writeInt ( o->dir );
00580 stream->writeInt ( o->lifetimer );
00581 for ( int i = 0; i < 4; i++ )
00582 stream->writeInt ( 0 );
00583 stream->writeInt ( o->typ->id );
00584 stream->writeInt( o->remainingGrowthTime );
00585 }
00586 }
00587
00588 if (b4 & csm_resources ) {
00589 stream->writeChar ( fld->resourceview->visible );
00590 for ( int i = 0; i < 8; i++ )
00591 stream->writeChar ( fld->resourceview->fuelvisible[i] );
00592 for ( int i = 0; i < 8; i++ )
00593 stream->writeChar ( fld->resourceview->materialvisible[i] );
00594 }
00595
00596 if ( b4 & csm_connection )
00597 stream->writeInt ( fld->connection );
00598
00599 l += 1 + cnt2;
00600 } while (l < cnt1);
00601 }
00602
00603
00604
00605
00606
00607 void tspfldloaders::readfields ( void )
00608 {
00609 int cnt2 = 0;
00610 int cnt1 = spfld->xsize * spfld->ysize;
00611
00612 assertOrThrow( cnt1 > 0 );
00613 assertOrThrow( spfld->xsize > 0 );
00614 assertOrThrow( spfld->ysize > 0 );
00615
00616 spfld->allocateFields ( spfld->xsize , spfld->ysize );
00617
00618 if (spfld->field == NULL)
00619 displaymessage ( "Could not allocate memory for map ",2);
00620
00621 int l = 0;
00622 tfield* lfld = NULL;
00623
00624 do {
00625 tfield* fld2;
00626
00627 if (cnt2 == 0) {
00628
00629 fld2 = & spfld->field[l];
00630
00631 fld2->bdt.setInt ( 0 , 0 );
00632
00633 char b1, b3, b4;
00634 b1 = stream->readChar();
00635
00636 if (b1 & csm_b3 )
00637 b3 = stream->readChar();
00638 else
00639 b3 = 0;
00640
00641 if (b3 & csm_b4 )
00642 b4 = stream->readChar();
00643 else
00644 b4 = 0;
00645
00646 if (b1 & csm_cnt2 )
00647 cnt2 = stream->readInt();
00648 else
00649 cnt2 = 0;
00650
00651 int weather;
00652 if (b3 & csm_weather )
00653 weather = stream->readInt();
00654 else
00655 weather = 0;
00656
00657
00658 int k;
00659
00660 if (b1 & csm_typid32 )
00661 k = stream->readInt();
00662 else
00663 k = stream->readChar();
00664
00665 pterraintype trn = terrainTypeRepository.getObject_byID ( k );
00666 if ( !trn )
00667 throw InvalidID ( "terrain", k );
00668
00669 fld2->typ = trn->weather[weather];
00670 if ( !fld2->typ ) {
00671 fld2->typ = trn->weather[0];
00672 if ( !fld2->typ )
00673 throw InvalidID ( "terrain", k );
00674 }
00675
00676 if (b1 & csm_direction )
00677 stream->readChar();
00678
00679
00680 if (b1 & csm_vehicle ) {
00681 fld2->vehicle = Vehicle::newFromStream ( spfld, *stream );
00682 fld2->vehicle->setnewposition ( l%spfld->xsize, l/spfld->xsize );
00683 }
00684
00685 if (b1 & csm_building ) {
00686 fld2->building = Building::newFromStream ( spfld, *stream );
00687 fld2->bdt |= getTerrainBitType(cbbuildingentry);
00688 }
00689
00690 if (b3 & csm_material)
00691 fld2->material = stream->readChar();
00692 else
00693 fld2->material = 0;
00694
00695 if (b3 & csm_fuel)
00696 fld2->fuel = stream->readChar();
00697 else
00698 fld2->fuel = 0;
00699
00700 if (b3 & csm_visible)
00701 fld2->visible = stream->readWord();
00702 else
00703 fld2->visible = 0;
00704
00705 bool tempobjects[16];
00706 int tempobjectNum = 0;
00707
00708 if (b3 & csm_object ) {
00709
00710 char minetype = stream->readChar();
00711 char minestrength = stream->readChar();
00712 if ( minetype >> 4 ) {
00713 Mine m( MineTypes((minetype >> 1) & 7), minestrength, minetype >> 4, spfld );
00714 fld2->mines.push_back ( m );
00715 }
00716
00717 tempobjectNum = stream->readInt();
00718
00719 for ( int i = 0; i < 16; i++ )
00720 tempobjects[i] = stream->readInt();
00721 }
00722
00723 int objectversion = 1;
00724 if ( b4 & csm_newobject ) {
00725 objectversion = stream->readInt();
00726
00727 if ( objectversion < 1 || objectversion > objectstreamversion )
00728 throw tinvalidversion ( "object", objectstreamversion, objectversion );
00729
00730 int minenum = stream->readInt();
00731
00732 for ( int i = 0; i < minenum; i++ ) {
00733 MineTypes type = MineTypes(stream->readInt());
00734 int strength = stream->readInt();
00735 int minetime = stream->readInt();
00736 int player = stream->readInt();
00737 if ( player < 0 || player > 7 )
00738 player = 0;
00739
00740 assertOrThrow( strength >= 0 );
00741 assertOrThrow( type > 0 && type <= 4 );
00742
00743 Mine m ( type, strength, player, spfld );
00744 if ( objectversion == 1 ) {
00745 int endtime = minetime;
00746 int lifetime = spfld->getgameparameter( GameParameter(cgp_antipersonnelmine_lifetime + m.type - 1));
00747 if ( lifetime > 0 && endtime > 0 )
00748 m.lifetimer = endtime - spfld->time.turn() + spfld->getgameparameter( GameParameter(cgp_antipersonnelmine_lifetime + m.type - 1));
00749 else
00750 if ( lifetime > 0 )
00751 m.lifetimer = lifetime;
00752 else
00753 m.lifetimer = -1;
00754 } else
00755 m.lifetimer = minetime;
00756 fld2->mines.push_back ( m );
00757 }
00758
00759 tempobjectNum = stream->readInt();
00760 }
00761
00762 if ( (b3 & csm_object) || (b4 & csm_newobject )) {
00763 for ( int n = 0; n < tempobjectNum; n++ ) {
00764 Object o;
00765 stream->readInt();
00766 o.damage = stream->readInt();
00767 assertOrThrow( o.damage >= 0 );
00768 o.dir = stream->readInt();
00769 if ( objectversion >= 2 )
00770 o.lifetimer = stream->readInt();
00771 else
00772 stream->readInt();
00773
00774 for ( int i = 0; i < 4; i++ )
00775 stream->readInt();
00776
00777 int id = stream->readInt();
00778 o.typ = objectTypeRepository.getObject_byID ( id );
00779
00780 if ( !o.typ )
00781 throw InvalidID ( "object", id );
00782
00783 if ( objectversion >= 3 )
00784 o.remainingGrowthTime = stream->readInt();
00785
00786 if ( objectversion == 1 )
00787 o.lifetimer = o.typ->lifetime;
00788
00789
00790 fld2->objects.push_back ( o );
00791 }
00792 fld2->sortobjects();
00793 }
00794
00795 if (b4 & csm_resources ) {
00796 fld2->resourceview = new tfield::Resourceview;
00797 fld2->resourceview->visible = stream->readChar();
00798 for ( int i = 0; i < 8; i++ )
00799 fld2->resourceview->fuelvisible[i] = stream->readChar();
00800 for ( int i = 0; i < 8; i++ )
00801 fld2->resourceview->materialvisible[i] = stream->readChar();
00802 }
00803
00804 if ( b4 & csm_connection )
00805 fld2->connection = stream->readInt();
00806
00807 if (b1 & csm_cnt2 )
00808 lfld = fld2;
00809
00810 }
00811 else {
00812 spfld->field[l].typ = lfld->typ;
00813 spfld->field[l].fuel = lfld->material;
00814 spfld->field[l].visible = lfld->visible;
00815 spfld->field[l].tempw = 0;
00816 spfld->field[l].connection = lfld->connection;
00817 for ( int i = 0; i < 8; i++ )
00818 spfld->field[l].view[i] = lfld->view[i];
00819 cnt2--;
00820 }
00821 l++ ;
00822 } while (l < cnt1);
00823
00824 spfld->overviewMapHolder.connect();
00825
00826 }
00827
00828
00829
00830
00831
00832
00833
00834 void tspfldloaders::chainitems ( GameMap* actmap )
00835 {
00836 int i = 0;
00837 for (int y = 0; y < actmap->ysize; y++)
00838 for (int x = 0; x < actmap->xsize; x++) {
00839 tfield* fld = &actmap->field[i];
00840 fld->setparams();
00841 i++;
00842 }
00843 }
00844
00845
00846
00847
00848
00849
00850
00851 SigC::Signal1<void,GameMap*> tspfldloaders::mapLoaded;
00852
00853
00854 tspfldloaders::tspfldloaders ( void )
00855 {
00856 spfld = NULL;
00857 }
00858
00859
00860 tspfldloaders::~tspfldloaders ( void )
00861 {
00862 delete spfld;
00863 spfld = NULL;
00864 }
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883 int tmaploaders::savemap( const ASCString& name, GameMap* gamemap )
00884 {
00885 #ifdef logging
00886 logtofile ( "loaders / tmaploaders::savemap / started " );
00887 #endif
00888
00889 tnfilestream filestream ( name, tnstream::writing );
00890
00891 stream = &filestream;
00892
00893 spfld = gamemap;
00894
00895
00896
00897
00898
00899 {
00900 stream->writepchar ( getFullVersionString() );
00901 stream->writeWord ( fileterminator );
00902 stream->writeInt ( actmapversion );
00903
00904 writemap ( );
00905 }
00906
00907 writefields ();
00908 #ifdef WEATHERGENERATOR
00909 spfld->weatherSystem->write(filestream);
00910 #endif
00911 stream->writeInt ( actmapversion );
00912
00913 spfld = NULL;
00914
00915 return 0;
00916 }
00917
00918
00919
00920 void weatherSystemRequired()
00921 {
00922 throw ASCmsgException( "This file can not be loaded, since it contains data of the discontinued weather generator");
00923 }
00924
00925
00926 GameMap* tmaploaders::_loadmap( const ASCString& name )
00927 {
00928 displayLogMessage ( 4, "loading map %s ... ", name.c_str() );
00929
00930 tnfilestream filestream ( name, tnstream::reading);
00931
00932 stream = &filestream;
00933
00934 char* description = NULL;
00935
00936 stream->readpchar ( &description );
00937 delete[] description;
00938
00939 int w = stream->readWord();
00940
00941 if ( w != fileterminator )
00942 throw tinvalidversion ( name, fileterminator, w );
00943
00944
00945 int version = stream->readInt();
00946
00947 if ( version > actmapversion || version < minmapversion )
00948 throw tinvalidversion ( name, actmapversion, version );
00949
00950
00951 displayLogMessage ( 8, "map, ");
00952 readmap ();
00953
00954 if ( version <= 0xfe27 ) {
00955 displayLogMessage ( 8, "eventsToCome, ");
00956 readOldEventLists ( stream, false, spfld );
00957 }
00958
00959 displayLogMessage ( 8, "fields, ");
00960 readfields ();
00961
00962
00963 if(version == 0xfe50)
00964 weatherSystemRequired();
00965
00966 version = stream->readInt();
00967 if (version > actmapversion || version < minmapversion )
00968 throw tinvalidversion ( name, actmapversion, version );
00969
00970
00971 displayLogMessage ( 8, "chainItems, ");
00972 chainitems ( spfld );
00973
00974 for ( int sp = spfld->getPlayerCount()-1; sp >= 0; sp--)
00975 if ( spfld->player[sp].exist() )
00976 spfld->actplayer = sp;
00977
00978 displayLogMessage ( 8, "setEventTriggers, ");
00979 seteventtriggers( spfld );
00980
00981 displayLogMessage ( 8, "calculateallobjects ");
00982 calculateallobjects( spfld );
00983
00984
00985 displayLogMessage ( 8, "init for playing, ");
00986
00987 spfld->time.set ( 1, 0 );
00988 spfld->levelfinished = false;
00989 spfld->preferredFileNames.mapname[0] = name ;
00990 checkForUniqueUnitIDs( spfld );
00991 spfld->startGame();
00992
00993 displayLogMessage ( 4, "done\n");
00994
00995 GameMap* m = spfld;
00996 spfld = NULL;
00997
00998 mapLoaded( m );
00999
01000 return m;
01001 }
01002
01003
01004 GameMap* tmaploaders::loadmap ( const ASCString& name )
01005 {
01006 tmaploaders gl;
01007 return gl._loadmap ( name );
01008 }
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025 void tsavegameloaders::savegame( pnstream strm, GameMap* gamemap, bool writeReplays )
01026 {
01027 stream = strm;
01028 spfld = gamemap;
01029
01030 stream->writepchar( getFullVersionString() );
01031 stream->writeWord( fileterminator );
01032
01033 stream->writeInt( actsavegameversion );
01034 writemap ();
01035
01036 writemessages();
01037
01038 writefields ( );
01039
01040 writedissections();
01041
01042 if ( writeReplays && spfld->replayinfo ) {
01043 stream->writeInt( 1 );
01044 spfld->replayinfo->write(*stream);
01045 } else
01046 stream->writeInt( 0 );
01047
01048 writeAI();
01049
01050 stream->writeInt( actsavegameversion );
01051
01052 spfld = NULL;
01053 }
01054
01055
01056 void tsavegameloaders::savegame( const ASCString& name)
01057 {
01058 tnfilestream filestream ( name, tnstream::writing );
01059 savegame ( &filestream, actmap, true );
01060 }
01061
01062
01063
01064 GameMap* tsavegameloaders::loadGameFromFile( const ASCString& filename )
01065 {
01066 tnfilestream filestream ( filename, tnstream::reading );
01067 tsavegameloaders gl;
01068 return gl.loadgame( &filestream );
01069 }
01070
01071 GameMap* tsavegameloaders::loadgame( pnstream strm )
01072 {
01073 stream = strm;
01074
01075 stream->readString();
01076
01077 int w = stream->readWord();
01078
01079 if ( w != fileterminator )
01080 throw tinvalidversion ( strm->getDeviceName(), fileterminator, w );
01081
01082 int version = stream->readInt();
01083
01084 if (version > actsavegameversion || version < minsavegameversion )
01085 throw tinvalidversion ( strm->getDeviceName(), actsavegameversion, version );
01086
01087
01088 readmap ();
01089
01090 readLegacyNetwork ();
01091
01092 if ( version <= 0xff39 )
01093 for ( int i = 0; i < 8; i++ )
01094 spfld->player[i].research.read_techs ( *stream );
01095
01096 readmessages();
01097
01098 if ( version <= 0xff37 ) {
01099 readOldEventLists ( stream, true, spfld );
01100 readoldevents ();
01101 }
01102
01103 readfields ( );
01104
01105 if(version == 0xff60)
01106 weatherSystemRequired();
01107
01108 readdissections();
01109
01110 bool loadReplay = true;
01111 if ( version >= 0xff35 )
01112 if ( !stream->readInt() )
01113 loadReplay = false;
01114
01115 if ( loadReplay ) {
01116 spfld->replayinfo = new GameMap::ReplayInfo;
01117 spfld->replayinfo->read ( *stream );
01118 } else
01119 spfld->replayinfo = NULL;
01120
01121
01122 if ( version >= 0xff34 )
01123 readAI ();
01124
01125 version = stream->readInt();
01126 if (version > actsavegameversion || version < minsavegameversion )
01127 throw tinvalidversion ( strm->getDeviceName(), actsavegameversion, version );
01128
01129 chainitems ( spfld );
01130
01131 seteventtriggers( spfld );
01132
01133 calculateallobjects( spfld );
01134 checkForUniqueUnitIDs( spfld );
01135
01136 mapLoaded( spfld );
01137
01138 GameMap* s = spfld;
01139 spfld = NULL;
01140 return s;
01141 }
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152 int tnetworkloaders::savenwgame( pnstream strm, const GameMap* gamemap )
01153 {
01154 spfld = const_cast<GameMap*>(gamemap);
01155
01156 stream = strm;
01157
01158 stream->writepchar ( getFullVersionString() );
01159 stream->writeWord ( fileterminator );
01160
01161 stream->writeInt ( actnetworkversion );
01162
01163 writemap ();
01164
01165 writemessages();
01166
01167 stream->writeInt ( actnetworkversion );
01168
01169 writefields ( );
01170
01171 writedissections();
01172
01173 if ( spfld->replayinfo )
01174 spfld->replayinfo->write ( *stream );
01175
01176
01177 writeAI();
01178
01179 stream->writeInt ( actnetworkversion );
01180
01181 spfld = NULL;
01182
01183 return 0;
01184 }
01185
01186
01187
01188
01189
01190 GameMap* tnetworkloaders::loadnwgame( pnstream strm )
01191 {
01192 const char* name = "network game";
01193
01194 stream = strm;
01195
01196
01197 char* description = NULL;
01198 stream->readpchar ( &description );
01199 delete[] description;
01200
01201 int w = stream->readWord();
01202
01203 if ( w != fileterminator )
01204 throw tinvalidversion ( name, fileterminator, (int) w );
01205
01206
01207 int version = stream->readInt();
01208
01209 if (version > actnetworkversion || version < minnetworkversion )
01210 throw tinvalidversion ( name, actnetworkversion, version );
01211
01212 readmap ();
01213
01214 if ( version <= 0x11 )
01215 for ( int i = 0; i < 8; i++ )
01216 spfld->player[i].research.read_techs ( *stream );
01217
01218
01219
01220 if(version == 0x0030)
01221 weatherSystemRequired();
01222
01223
01224
01225
01226 readmessages();
01227 readLegacyNetwork ();
01228
01229 version = stream->readInt();
01230
01231 if (version > actnetworkversion || version < minnetworkversion )
01232 throw tinvalidversion ( name, actnetworkversion, version );
01233
01234
01235
01236 if ( version < 10 ) {
01237 readOldEventLists ( stream, true, spfld );
01238 readoldevents ();
01239 }
01240
01241 readfields ( );
01242
01243 readdissections();
01244
01245 if ( spfld->__loadreplayinfo ) {
01246 spfld->replayinfo = new GameMap::ReplayInfo;
01247 spfld->replayinfo->read ( *stream );
01248 }
01249
01250 if ( version > 8 )
01251 readAI();
01252
01253 #ifdef sgmain
01254 version = stream->readInt();
01255 if (version > actnetworkversion || version < minnetworkversion )
01256 throw tinvalidversion ( name, actnetworkversion, version );
01257 #endif
01258
01259 chainitems ( spfld );
01260
01261 seteventtriggers( spfld );
01262
01263 calculateallobjects( spfld );
01264
01265 checkForUniqueUnitIDs( spfld );
01266
01267 spfld->levelfinished = false;
01268
01269
01270 for ( int i = 0; i < 8; ++i)
01271 for ( Player::BuildingList::iterator b = spfld->player[i].buildingList.begin(); b != spfld->player[i].buildingList.end(); ++b )
01272 for ( int a = 0; a < waffenanzahl; ++a )
01273 if ( (*b)->ammo[a] > 32000 ) {
01274 ASCString s;
01275 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 );
01276 new Message( s, spfld, 1 );
01277 (*b)->ammo[a] = 0;
01278 }
01279
01280
01281 GameMap* spfldcopy = spfld;
01282 spfld = NULL;
01283
01284 mapLoaded( spfldcopy );
01285
01286
01287 return spfldcopy;
01288
01289 }
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304 void savemap( const char * name, GameMap* gamemap )
01305 {
01306
01307 #ifdef logging
01308 logtofile ( "loaders / savemap / started " );
01309 #endif
01310
01311 try {
01312 tmaploaders gl;
01313 gl.savemap ( name, gamemap );
01314 }
01315
01316 catch ( tfileerror err ) {
01317 displaymessage( "file error writing map to filename %s ", 1, err.getFileName().c_str() );
01318 }
01319 catch ( ASCexception err) {
01320 displaymessage( "error writing map ", 1 );
01321 }
01322
01323 }
01324
01325
01326 void savegame( const ASCString& name )
01327 {
01328 try {
01329 tsavegameloaders gl;
01330 gl.savegame ( name );
01331 }
01332 catch ( tfileerror err) {
01333 displaymessage( "error writing map to filename %s ", 1, err.getFileName().c_str() );
01334 }
01335 catch ( ASCexception err) {
01336 displaymessage( "error writing map ", 1 );
01337 }
01338 }
01339
01340
01341 void savereplay( GameMap* gamemap, int num )
01342 {
01343 try {
01344 if ( !gamemap->replayinfo )
01345 fatalError ( "treplayloaders :: savereplay ; No replay activated !");
01346
01347 if ( gamemap->replayinfo->map[num] ) {
01348 delete gamemap->replayinfo->map[num];
01349 gamemap->replayinfo->map[num] = NULL;
01350 }
01351
01352 gamemap->replayinfo->map[num] = new tmemorystreambuf;
01353 tmemorystream memstream ( gamemap->replayinfo->map[num], tnstream::writing );
01354
01355 memstream.writeInt( actreplayversion );
01356
01357 tsavegameloaders sgl;
01358 sgl.savegame ( &memstream, gamemap, false );
01359
01360 memstream.writeInt ( actreplayversion );
01361 }
01362 catch ( ASCexception err ) {
01363 displaymessage( "error saving replay information", 1 );
01364 }
01365 }
01366
01367 GameMap* loadreplay( tmemorystreambuf* streambuf )
01368 {
01369 GameMap* replaymap = NULL;
01370
01371 try {
01372 const char* name = "memorystream actmap->replayinfo";
01373 tmemorystream memstream ( streambuf, tnstream::reading );
01374
01375 int version = memstream.readInt();
01376 if (version > actreplayversion || version < minreplayversion )
01377 throw tinvalidversion ( name, actreplayversion, version );
01378
01379 tsavegameloaders sgl;
01380 replaymap = sgl.loadgame ( &memstream );
01381
01382 version = memstream.readInt();
01383 if (version > actreplayversion || version < minreplayversion ) {
01384 delete replaymap;
01385 throw tinvalidversion ( name, actreplayversion, version );
01386 }
01387
01388 }
01389 catch ( InvalidID err ) {
01390 displaymessage( err.getMessage().c_str(), 1 );
01391 replaymap = NULL;
01392 }
01393 catch ( tinvalidversion err ) {
01394 displaymessage( err.getMessage().c_str(), 1 );
01395 replaymap = NULL;
01396 }
01397 catch ( tfileerror err) {
01398 displaymessage( "error reading map filename %s ", 1, err.getFileName().c_str() );
01399 replaymap = NULL;
01400 }
01401 catch ( ASCexception ) {
01402 displaymessage( "error loading replay", 1 );
01403 replaymap = NULL;
01404 }
01405
01406 return replaymap;
01407 }
01408
01409
01410
01411
01412 GameMap* mapLoadingExceptionChecker( const ASCString& filename, MapLoadingFunction loader )
01413 {
01414 GameMap* m = NULL;
01415 try {
01416 m = loader( filename );
01417 }
01418 catch ( InvalidID err ) {
01419 displaymessage( err.getMessage().c_str(), 1 );
01420 return NULL;
01421 }
01422 catch ( tinvalidversion err ) {
01423 displaymessage( err.getMessage().c_str(), 1 );
01424 return NULL;
01425 }
01426 catch ( tfileerror err) {
01427 displaymessage( "error reading map filename %s ", 1, err.getFileName().c_str() );
01428 return NULL;
01429 }
01430 catch ( ASCmsgException msg ) {
01431 displaymessage( "error loading file\n" + msg.getMessage() , 1 );
01432 return NULL;
01433 }
01434 catch ( ASCexception ) {
01435 displaymessage( "error loading file", 1 );
01436 return NULL;
01437 }
01438
01439 return m;
01440 }
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450 bool validatemapfile ( const ASCString& filename )
01451 {
01452
01453 char* description = NULL;
01454
01455 try {
01456
01457 tnfilestream stream ( filename, tnstream::reading );
01458 stream.readpchar ( &description, 200 );
01459 if ( description ) {
01460 delete[] description ;
01461 description = NULL;
01462 }
01463
01464 int w = stream.readWord();
01465 if ( w != fileterminator )
01466 throw tinvalidversion ( filename, fileterminator, (int) w );
01467
01468 int version = stream.re