Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

gamemap.cpp

Go to the documentation of this file.
00001 
00005 /***************************************************************************
00006                           gamemap.cpp  -  description
00007                              -------------------
00008     begin                : Tue Oct 24 2000
00009     copyright            : (C) 2000 by Martin Bickel
00010     email                : bickel@asc-hq.org
00011  ***************************************************************************/
00012 
00013 /***************************************************************************
00014  *                                                                         *
00015  *   This program is free software; you can redistribute it and/or modify  *
00016  *   it under the terms of the GNU General Public License as published by  *
00017  *   the Free Software Foundation; either version 2 of the License, or     *
00018  *   (at your option) any later version.                                   *
00019  *                                                                         *
00020  ***************************************************************************/
00021 
00022 #include <algorithm>
00023 #include <ctime>
00024 #include <cmath>
00025 
00026 #include "global.h"
00027 #include "misc.h"
00028 #include "typen.h"
00029 #include "vehicletype.h"
00030 #include "buildingtype.h"
00031 #include "gamemap.h"
00032 #include "dialog.h"
00033 #include "itemrepository.h"
00034 #include "strtmesg.h"
00035 // #include "graphics/blitter.h"
00036 #include "overviewmapimage.h"
00037 #include "gameeventsystem.h"
00038 #include "spfst.h"
00039 
00040 
00041 RandomGenerator::RandomGenerator(int seedValue){
00042 
00043 }
00044 
00045 RandomGenerator::~RandomGenerator(){
00046 
00047 
00048 }
00049 
00050 unsigned int RandomGenerator::getPercentage(){
00051   return getRandomValue(100);
00052 }
00053 
00054 unsigned int RandomGenerator::getRandomValue(int limit) {
00055   return getRandomValue(0, limit); 
00056 }
00057 
00058 unsigned int RandomGenerator::getRandomValue (int lowerLimit, int upperLimit){
00059    if(upperLimit == 0) {
00060         return 1;
00061    }
00062    int random_integer = rand();
00063    random_integer = random_integer % upperLimit;
00064    return (lowerLimit + random_integer);
00065 }
00066 
00067 
00068 
00069 
00070 OverviewMapHolder :: OverviewMapHolder( GameMap& gamemap ) : map(gamemap), initialized(false), secondMapReady(false), completed(false), connected(false), x(0),y(0)
00071 {
00072 }
00073 
00074 void OverviewMapHolder :: connect()
00075 {
00076    if ( !connected ) {
00077       idleEvent.connect ( SigC::slot( *this, &OverviewMapHolder::idleHandler ));
00078       connected = true;
00079    }
00080 }
00081 
00082 
00083 SigC::Signal0<void> OverviewMapHolder::generationComplete;
00084 
00085 bool OverviewMapHolder :: idleHandler( )
00086 {
00087    int t = ticker;
00088    while ( !completed && (t + 5 > ticker ))
00089       drawNextField( true );
00090    return true;
00091 }
00092 
00093 
00094 bool OverviewMapHolder::updateField( const MapCoordinate& pos )
00095 {
00096    SPoint imgpos = OverviewMapImage::map2surface( pos );
00097 
00098    tfield* fld = map.getField( pos );
00099    VisibilityStates visi = fieldVisibility( fld, map.getPlayerView(), &map );
00100    if ( visi == visible_not ) {
00101       OverviewMapImage::fill ( overviewMapImage, imgpos, 0xff545454 );
00102    } else {
00103       if ( fld->building && fieldvisiblenow( fld, map.getPlayerView(), &map) )
00104          OverviewMapImage::fill ( overviewMapImage, imgpos, map.player[fld->building->getOwner()].getColor() );
00105       else {
00106 
00107          int w = fld->getweather();
00108          fld->typ->getQuickView()->blit( overviewMapImage, imgpos );
00109          for ( tfield::ObjectContainer::iterator i = fld->objects.begin(); i != fld->objects.end(); ++i )
00110             if ( visi > visible_ago || i->typ->visibleago )
00111                i->getOverviewMapImage( w )->blit( overviewMapImage, imgpos );
00112 
00113          if ( fld->vehicle && fieldvisiblenow( fld, map.getPlayerView()) )
00114             OverviewMapImage::fillCenter ( overviewMapImage, imgpos, map.player[fld->vehicle->getOwner()].getColor() );
00115 
00116          if ( visi == visible_ago )
00117             OverviewMapImage::lighten( overviewMapImage, imgpos, 0.7 ); 
00118 
00119       }
00120 
00121    }
00122    return true;
00123 }
00124 
00125 void OverviewMapHolder::drawNextField( bool signalOnCompletion )
00126 {
00127    if ( !init() )
00128       return;
00129       
00130    if ( x == map.xsize ) {
00131       x = 0;
00132       ++y;
00133    }   
00134    if ( y < map.ysize ) {
00135       if ( !updateField( MapCoordinate(x,y)))
00136          return;
00137       
00138       ++x;
00139    }
00140    if ( y == map.ysize ) {
00141       completed = true;
00142       if ( signalOnCompletion )
00143          generationComplete();
00144 
00145       completedMapImage = overviewMapImage.Duplicate();
00146       secondMapReady = true;
00147    }
00148 }
00149 
00150 Surface OverviewMapHolder::createNewSurface()
00151 {
00152    Surface s;
00153    if ( map.xsize > 0 && map.ysize > 0 ) {
00154       s =  Surface::createSurface( (map.xsize+1) * 6, 4 + map.ysize * 2 , 32, 0 );
00155    }
00156    return s;
00157 }
00158 
00159 bool OverviewMapHolder::init()
00160 {
00161    if ( map.ysize <= 0 || map.xsize <= 0 )
00162       return false;
00163 
00164    if ( !initialized ) {
00165       overviewMapImage = createNewSurface();
00166       initialized = true;
00167    }
00168    return initialized;
00169 }   
00170 
00171 void OverviewMapHolder::resetSize()
00172 {
00173    initialized = false;
00174 }
00175 
00176 
00177 const Surface& OverviewMapHolder::getOverviewMap( bool complete )
00178 {
00179    bool initialized = init();
00180    assert( initialized );
00181    if ( complete )
00182       while ( !completed )
00183          drawNextField( false );
00184 
00185    if(  secondMapReady )
00186       return completedMapImage;
00187    else
00188       return overviewMapImage;
00189 }
00190 
00191 void OverviewMapHolder::startUpdate()
00192 {
00193    completed = false;
00194    x = 0;
00195    y = 0;
00196 }
00197 
00198 void OverviewMapHolder::clear(bool allImages )
00199 {
00200    if ( !initialized )
00201       return;
00202    
00203    overviewMapImage.Fill( Surface::transparent );
00204    if ( allImages ) {
00205       if ( completedMapImage.valid() )
00206          completedMapImage.Fill( Surface::transparent );
00207       secondMapReady = false;
00208    }
00209 
00210    startUpdate();
00211 }
00212 
00213 void OverviewMapHolder::clearmap( GameMap* actmap )
00214 {
00215    if ( actmap )
00216       actmap->overviewMapHolder.clear();
00217 }
00218 
00219 
00220 GameMap :: GameMap ( void )
00221       : overviewMapHolder( *this ), network(NULL)
00222 {
00223    randomSeed = rand();
00224    dialogsHooked = false;
00225 
00226    eventID = 0;
00227 
00228    state = Normal;
00229 
00230    int i;
00231 
00232    xsize = 0;
00233    ysize = 0;
00234    field = NULL;
00235 
00236    actplayer = -1;
00237    time.abstime = 0;
00238 
00239    _resourcemode = 0;
00240 
00241    for ( i = 0; i < 9; ++i ) {
00242       player[i].setParentMap ( this, i );
00243       if ( i == 0 )
00244          player[i].stat = Player::human;
00245       else
00246          player[i].stat = Player::computer;
00247       
00248       player[i].research.chainToMap ( this, i );
00249    }
00250           
00251    unitnetworkid = 0;
00252 
00253    levelfinished = 0;
00254 
00255    messageid = 0;
00256 
00257    continueplaying = false;
00258    replayinfo = NULL;
00259    playerView = 0;
00260    lastjournalchange.abstime = 0;
00261    graphicset = 0;
00262    gameparameter_num = 0;
00263    game_parameter = NULL;
00264    mineralResourcesDisplayed = 0;
00265 
00266    // sigPlayerUserInteractionBegins.connect( SigC::bind( SigC::slot( GameMap::setPlayerMode ), NormalManual));
00267    // sigPlayerUserInteractionEnds.connect( SigC::bind( SigC::slot( GameMap::setPlayerMode ), NormalAuto));
00268 
00269 
00270 #ifdef WEATHERGENERATOR
00271    weatherSystem  = new WeatherSystem(this, 1, 0.03);
00272 #endif
00273    setgameparameter( cgp_objectsDestroyedByTerrain, 1 );
00274 }
00275 
00276 GameMap::Campaign::Campaign()
00277 {
00278    avail = false;
00279    id = 0;
00280    directaccess = true;
00281 }
00282 
00283 void GameMap :: guiHooked()
00284 {
00285    overviewMapHolder.connect();
00286    dialogsHooked = true;
00287 }
00288 
00289 const int tmapversion = 22;
00290 
00291 void GameMap :: read ( tnstream& stream )
00292 {
00293    int version;
00294    int i;
00295 
00296    xsize = stream.readWord();
00297    ysize = stream.readWord();
00298 
00299    if ( xsize == 0xfffe  && ysize == 0xfffc ) {
00300      version = stream.readInt();
00301      if ( version > tmapversion )
00302         throw tinvalidversion ( "GameMap", tmapversion, version );
00303 
00304      xsize = stream.readInt();
00305      ysize = stream.readInt();
00306    } else
00307       version = 1;
00308 
00309    stream.readWord(); // xpos
00310    stream.readWord(); // ypos
00311    stream.readInt(); // dummy
00312    field = NULL;
00313 
00314    if ( version <= 13 ) {
00315       char buf[11]; 
00316       stream.readdata ( buf, 11 );
00317       buf[10] = 0;
00318       codeWord = buf;
00319    } else {
00320       codeWord = stream.readString();
00321    }
00322 
00323    if ( version < 2 )
00324       ___loadtitle = stream.readInt();
00325    else
00326       ___loadtitle = true;
00327 
00328    bool loadCampaign = stream.readInt();
00329    actplayer = stream.readChar();
00330    time.abstime = stream.readInt();   
00331    if(version < 9 || version >= 17){
00332      stream.readChar();
00333      weather.windSpeed = stream.readChar();
00334      weather.windDirection = stream.readChar();
00335    }
00336 
00337    if ( version >= 11 ) 
00338       if ( stream.readInt() != 0x12345678 )
00339          throw ASCmsgException("marker not matched when loading GameMap");
00340    
00341       
00342    for ( int j = 0; j < 4; j++ )
00343       stream.readChar(); // was: different wind in different altitudes
00344    for ( i = 0; i< 12; i++ )
00345       stream.readChar(); // dummy
00346 
00347    _resourcemode = stream.readInt();
00348 
00349    int alliances[8][8];
00350    if ( version <= 10 )
00351       for ( i = 0; i < 8; i++ )
00352          for ( int j = 0; j < 8; j++ )
00353             alliances[j][i] = stream.readChar();
00354 
00355    int dummy_playername[9];
00356    for ( i = 0; i< 9; i++ ) {
00357       player[i].existanceAtBeginOfTurn = stream.readChar();
00358       stream.readInt(); // dummy
00359       stream.readInt(); // dummy
00360       if ( version <= 5 )
00361          player[i].research.read_struct ( stream );
00362       else
00363          player[i].research.read ( stream );
00364 
00365       player[i].ai = (BaseAI*)stream.readInt() ;
00366       player[i].stat = Player::PlayerStatus ( stream.readChar() );
00367       stream.readChar(); // dummy
00368       dummy_playername[i] = stream.readInt();
00369       player[i].passwordcrc.read ( stream );
00370       player[i].__dissectionsToLoad = stream.readInt();
00371       player[i].__loadunreadmessage = stream.readInt();
00372       player[i].__loadoldmessage = stream.readInt();
00373       player[i].__loadsentmessage = stream.readInt();
00374       if ( version >= 3 )
00375          player[i].ASCversion = stream.readInt();
00376       else
00377          player[i].ASCversion = 0;
00378          
00379       if ( version >= 9 )
00380          player[i].cursorPos.read( stream );
00381          
00382       if ( version >= 11 ) 
00383          player[i].diplomacy.read( stream );
00384       else {
00385          if ( i < 8 ) // no alliances for neutral 'player'
00386             for ( int j = 0; j< 8; ++j ) {
00387                if ( alliances[i][j] == 0 ) 
00388                   player[i].diplomacy.setState( j, PEACE, false ); 
00389                else
00390                   player[i].diplomacy.setState( j, WAR, false ); 
00391             }
00392       }
00393       
00394       if ( version >= 12 )
00395          player[i].email = stream.readString();
00396       
00397       if ( version >= 22 )
00398          player[i].read( stream );
00399    }
00400    
00401    if ( version >= 11 ) 
00402       if ( stream.readInt() != 0x12345678 )
00403          throw ASCmsgException("marker not matched when loading GameMap");
00404          
00405 
00406 
00407 
00408    if ( version <= 4 ) {
00410       loadOldEvents = stream.readInt();
00411       stream.readInt(); // int loadeventstocome
00412       stream.readInt(); // int loadeventpassed
00413    }
00414 
00415 
00416    unitnetworkid = stream.readInt();
00417    levelfinished = stream.readChar();
00418    
00419    bool alliance_names_not_used_any_more[8];
00420    if ( version <= 9 ) {
00421       ___loadLegacyNetwork  = stream.readInt();
00422       for ( i = 0; i < 8; i++ )
00423          alliance_names_not_used_any_more[i] = stream.readInt(); // dummy
00424    } else {
00425       ___loadLegacyNetwork = false;
00426       for ( i = 0; i < 8; i++ )
00427          alliance_names_not_used_any_more[i] = 0;
00428    }
00429 
00430    if ( version <= 12 ) {
00431       for ( i = 0; i< 8; i++ ) {
00432          stream.readWord(); // cursorpos.position[i].cx = 
00433          stream.readWord(); // cursorpos.position[i].sx = 
00434          stream.readWord(); // cursorpos.position[i].cy = 
00435          stream.readWord(); // cursorpos.position[i].sy = 
00436       }
00437    }
00438 
00439    if ( version <= 9 )
00440       stream.readInt(); // loadtribute
00441       
00442    __loadunsentmessage = stream.readInt();
00443    __loadmessages = stream.readInt();
00444 
00445    messageid = stream.readInt();
00446 
00447    if(  version < 2 ) {
00448       ___loadJournal = stream.readInt();
00449       ___loadNewJournal = stream.readInt();
00450    } else {
00451       ___loadJournal = true;
00452       ___loadNewJournal = true;
00453    }
00454 
00455    int exist_humanplayername[9];
00456    for ( i = 0; i < 8; i++ )
00457       exist_humanplayername[i] = stream.readInt();
00458    exist_humanplayername[8] = 0;
00459 
00460 
00461    int exist_computerplayername[9];
00462    for ( i = 0; i < 8; i++ )
00463       exist_computerplayername[i] = stream.readInt();
00464    exist_computerplayername[8] = 0;
00465 
00466    supervisorpasswordcrc.read ( stream );
00467 
00468    if ( version <= 10 )
00469       for ( i = 0; i < 8; i++ )
00470          stream.readChar(); // alliances_at_beginofturn[i] = 
00471 
00472    stream.readInt(); // was objectcrc = (Object*containercrcs)
00473    bool load_shareview = false;
00474    if ( version <= 10 )
00475       load_shareview = stream.readInt();
00476 
00477    continueplaying = stream.readInt();
00478    __loadreplayinfo =  stream.readInt();
00479    playerView = stream.readInt();
00480    lastjournalchange.abstime = stream.readInt();
00481 
00482    for ( i = 0; i< 8; i++ )
00483       bi_resource[i].read ( stream );
00484 
00485    int preferredfilenames = stream.readInt();
00486 
00487    bool __loadEllipse = stream.readInt();
00488    graphicset = stream.readInt();
00489    gameparameter_num = stream.readInt();
00490 
00491    stream.readInt(); // dummy
00492    mineralResourcesDisplayed = stream.readInt();
00493    for ( i = 0; i< 9; i++ )
00494        player[i].queuedEvents = stream.readInt();
00495 
00496    for ( i = 0; i < 19; i++ )
00497        stream.readInt();
00498 
00499    int _oldgameparameter[8];
00500    for ( i = 0; i < 8; i++ )
00501        _oldgameparameter[i] = stream.readInt();
00502 
00503    if ( version >= 11 ) 
00504       if ( stream.readInt() != 0x12345678 )
00505          throw ASCmsgException("marker not matched when loading GameMap");
00506 
00508 // Here initmap was called
00510 
00511 
00512 
00513     if ( ___loadtitle )
00514        maptitle = stream.readString();
00515 
00516     if ( loadCampaign ) {
00517        if ( version <= 14 ) {
00518          campaign.id = stream.readWord();
00519          stream.readWord(); // campaign->prevmap 
00520          stream.readChar(); // campaign->player 
00521          campaign.directaccess = stream.readChar();
00522          campaign.avail = true;
00523          for ( int d = 0; d < 21; d++ )
00524             stream.readChar(); // dummy
00525        } else {
00526           campaign.id = stream.readInt();
00527           campaign.directaccess = stream.readChar();
00528           if ( version > 15 )
00529              campaign.avail = stream.readInt();
00530        }
00531     }
00532 
00533     for ( int w=0; w<9 ; w++ ) {
00534        if (dummy_playername[w] )
00535           stream.readString();
00536 
00537        player[w].ai = NULL;
00538 
00539 
00540        if ( exist_humanplayername[w] )
00541           player[w].setName( stream.readString() );
00542 
00543        if ( exist_computerplayername[w] )
00544           stream.readString();
00545 
00546     } /* endfor */
00547 
00548     if ( stream.readInt() )
00549        tribute.read ( stream );
00550 
00551     for ( int aa = 0; aa < 8; aa++ )
00552        if ( alliance_names_not_used_any_more[aa] ) {
00553           char* tempname = NULL;
00554           stream.readpchar ( &tempname );
00555           delete[] tempname;
00556        }
00557 
00558     stream.readInt();
00559 
00560     if ( load_shareview && version <= 10 ) {
00561     
00562       for ( int i = 0; i < 8; i++ )
00563          for ( int j =0; j < 8; j++ ) {
00564             int sv = stream.readChar();
00565             if ( sv )
00566                player[i].diplomacy.setState( j, PEACE_SV, false );
00567          }      
00568                
00569       stream.readInt();
00570     } 
00571 
00572     if ( preferredfilenames ) {
00573        int p;
00574        int mapname[8];
00575        int mapdescription_not_used_any_more[8];
00576        int savegame[8];
00577        int savegamedescription_not_used_any_more[8];
00578        for ( p = 0; p < 8; p++ )
00579           mapname[p] = stream.readInt();
00580        for ( p = 0; p < 8; p++ )
00581           mapdescription_not_used_any_more[p] = stream.readInt();
00582        for ( p = 0; p < 8; p++ )
00583           savegame[p] = stream.readInt();
00584        for ( p = 0; p < 8; p++ )
00585           savegamedescription_not_used_any_more[p] = stream.readInt();
00586 
00587        for ( int i = 0; i < 8; i++ ) {
00588           if ( mapname[i] )
00589              preferredFileNames.mapname[i] = stream.readString ();
00590 
00591           if ( mapdescription_not_used_any_more[i] )
00592              stream.readString(); // dummy
00593 
00594           if ( savegame[i] )
00595              preferredFileNames.savegame[i] = stream.readString ();
00596 
00597           if ( savegamedescription_not_used_any_more[i] )
00598              stream.readString();
00599        }
00600     }
00601 
00602     if ( __loadEllipse ) {
00603        for ( int i = 0; i < 5; ++i )
00604           stream.readInt();
00605        stream.readFloat();
00606        stream.readInt();
00607     }
00608 
00609     int orggpnum = gameparameter_num;
00610     gameparameter_num = 0;
00611     for ( int gp = 0; gp < 8; gp ++ )
00612        setgameparameter ( GameParameter(gp), _oldgameparameter[gp] );
00613 
00614     for ( int ii = 0 ; ii < orggpnum; ii++ ) {
00615        int gpar = stream.readInt();
00616        setgameparameter ( GameParameter(ii), gpar );
00617     }
00618 
00619     if ( version >= 2 ) {
00620        archivalInformation.author = stream.readString();
00621        archivalInformation.description = stream.readString();
00622        archivalInformation.tags = stream.readString();
00623        archivalInformation.requirements = stream.readString();
00624        archivalInformation.modifytime = stream.readInt();
00625     }
00626 
00627     if ( version >= 4 ) {
00628        int num = stream.readInt();
00629        for ( int ii = 0; ii < num; ++ii )
00630           unitProduction.idsAllowed.push_back ( stream.readInt() );
00631 
00632        for ( int ii = 0; ii < 9; ii++ ) {
00633           int num = stream.readInt( );
00634           for ( int i = 0; i < num; i++ ) {
00635              Player::PlayTime pt;
00636              pt.turn = stream.readInt();
00637              pt.date = stream.readInt();
00638              player[ii].playTime.push_back ( pt );
00639           }
00640        }
00641 
00642     }
00643 
00644     if ( version >= 5 ) {
00645        eventID = stream.readInt();
00646 
00647        int num = stream.readInt();
00648        for ( int i = 0; i< num; ++i ) {
00649           Event* ev = new Event ( *this );
00650           ev->read ( stream );
00651           events.push_back ( ev );
00652        }
00653     }
00654 
00655     if ( version >= 8 )
00656        randomSeed = stream.readInt();
00657        
00658     if ( version >= 12 ) {
00659       bool nw = stream.readInt();
00660       if ( nw ) 
00661          network = GameTransferMechanism::read( stream );         
00662     }
00663 }
00664 
00665 
00666 void GameMap :: write ( tnstream& stream )
00667 {
00668    int i;
00669 
00670    stream.writeWord( 0xfffe );
00671    stream.writeWord( 0xfffc );
00672 
00673    stream.writeInt ( tmapversion );
00674    stream.writeInt( xsize );
00675    stream.writeInt( ysize );
00676 
00677    stream.writeWord( 0 );
00678    stream.writeWord( 0 );
00679    stream.writeInt (1); // dummy
00680    stream.writeString ( codeWord );
00681 
00682    
00683    
00684    stream.writeInt( campaign.avail  );
00685    stream.writeChar( actplayer );
00686    stream.writeInt( time.abstime );
00687    
00688    stream.writeChar(0);
00689    stream.writeChar( weather.windSpeed );
00690    stream.writeChar( weather.windDirection );
00691    
00692    stream.writeInt( 0x12345678 );
00693    
00694    for  ( i= 0; i < 4; i++ )
00695       stream.writeChar( 0 );
00696 
00697    for ( i = 0; i< 12; i++ )
00698       stream.writeChar( 0 ); // dummy
00699 
00700    stream.writeInt( _resourcemode );
00701 
00702    for ( i = 0; i< 9; i++ ) {
00703       stream.writeChar( player[i].existanceAtBeginOfTurn );
00704       stream.writeInt( 1 ); // dummy
00705       stream.writeInt( 1 ); // dummy
00706       player[i].research.write ( stream );
00707       stream.writeInt( player[i].ai != NULL );
00708       stream.writeChar( player[i].stat );
00709       stream.writeChar( 0 ); // dummy
00710       stream.writeInt( 0 );
00711       player[i].passwordcrc.write ( stream );
00712       stream.writeInt( !player[i].dissections.empty() );
00713       stream.writeInt( 1 );
00714       stream.writeInt( 1 );
00715       stream.writeInt( 1 );
00716       stream.writeInt ( player[i].ASCversion );
00717       player[i].cursorPos.write( stream );
00718       player[i].diplomacy.write( stream );
00719       stream.writeString ( player[i].email );
00720       player[i].write(stream);
00721    }
00722 
00723    stream.writeInt( 0x12345678 );
00724    
00725    stream.writeInt( unitnetworkid );
00726    stream.writeChar( levelfinished );
00727 
00728    stream.writeInt( 1 );
00729    stream.writeInt( !messages.empty() );
00730 
00731    stream.writeInt( messageid );
00732 
00733    for ( i = 0; i < 8; i++ )
00734       stream.writeInt( 1 );
00735 
00736    for ( i = 0; i < 8; i++ )
00737       stream.writeInt( 0 );
00738 
00739    supervisorpasswordcrc.write ( stream );
00740 
00741    stream.writeInt( 0 );
00742 
00743    stream.writeInt( continueplaying );
00744    stream.writeInt( replayinfo != NULL );
00745    stream.writeInt( playerView );
00746    stream.writeInt( lastjournalchange.abstime );
00747 
00748    for ( i = 0; i< 8; i++ )
00749       bi_resource[i].write ( stream );
00750 
00751    stream.writeInt( 1 );
00752    stream.writeInt( 0 ); // was: ellipse
00753    stream.writeInt( graphicset );
00754    stream.writeInt( gameparameter_num );
00755 
00756    stream.writeInt( game_parameter != NULL );
00757    stream.writeInt( mineralResourcesDisplayed );
00758    for ( i = 0; i< 9; i++ )
00759        stream.writeInt( player[i].queuedEvents );
00760 
00761    for ( i = 0; i < 19; i++ )
00762        stream.writeInt( 0 );
00763 
00764    for ( i = 0; i < 8; i++ )
00765        stream.writeInt( getgameparameter(GameParameter(i)) );
00766 
00767 
00768    stream.writeInt( 0x12345678 );
00769 
00770        
00772 // second part
00774 
00775 
00776 
00777    stream.writeString( maptitle );
00778 
00779    if ( campaign.avail ) {
00780       stream.writeInt( campaign.id );
00781       stream.writeChar( campaign.directaccess );
00782       stream.writeInt( campaign.avail );
00783    }
00784 
00785    for (int w=0; w<8 ; w++ ) 
00786       stream.writeString ( player[w].getName() );
00787 
00788    if ( !tribute.empty() ) {
00789        stream.writeInt ( -1 );
00790        tribute.write ( stream );
00791    } else
00792        stream.writeInt ( 0 );
00793 
00794     stream.writeInt ( 0 );
00795 
00796     int p;
00797     for ( p = 0; p < 8; p++ )
00798        stream.writeInt( 1 );
00799 
00800     for ( p = 0; p < 8; p++ )
00801        stream.writeInt( 0 );
00802 
00803     for ( p = 0; p < 8; p++ )
00804        stream.writeInt( 1 );
00805 
00806     for ( p = 0; p < 8; p++ )
00807        stream.writeInt( 0 );
00808 
00809     for ( int k = 0; k < 8; k++ ) {
00810        stream.writeString ( preferredFileNames.mapname[k] );
00811        stream.writeString ( preferredFileNames.savegame[k] );
00812     }
00813 
00814 
00815     for ( int ii = 0 ; ii < gameparameter_num; ii++ )
00816        stream.writeInt ( game_parameter[ii] );
00817 
00818 
00819     stream.writeString ( archivalInformation.author );
00820     stream.writeString ( archivalInformation.description );
00821     stream.writeString ( archivalInformation.tags );
00822     stream.writeString ( archivalInformation.requirements );
00823     stream.writeInt ( (unsigned int) (::time ( &archivalInformation.modifytime )));
00824 
00825 
00826     stream.writeInt( unitProduction.idsAllowed.size() );
00827     for ( int ii = 0; ii < unitProduction.idsAllowed.size(); ++ii )
00828        stream.writeInt ( unitProduction.idsAllowed[ii] );
00829 
00830 
00831     for ( int ii = 0; ii < 9; ii++ ) {
00832        stream.writeInt( player[ii].playTime.size() );
00833        for ( Player::PlayTimeContainer::iterator i = player[ii].playTime.begin(); i != player[ii].playTime.end(); ++i ) {
00834           stream.writeInt( i->turn );
00835           stream.writeInt( (unsigned int) i->date );
00836        }
00837     }
00838 
00839     stream.writeInt( eventID );
00840 
00841     stream.writeInt ( events.size());
00842     for ( Events::iterator i = events.begin(); i != events.end(); ++i )
00843        (*i)->write( stream );
00844 
00845     stream.writeInt( randomSeed );
00846 
00847     if ( network ) {
00848       stream.writeInt( 1 );
00849       network->write( stream );
00850     } else
00851       stream.writeInt( 0 );
00852 }
00853 
00854 
00855 
00856 
00857 MapCoordinate& GameMap::getCursor()
00858 {
00859    #ifdef sgmain
00860    if ( actplayer >= 0 ) {
00861       if ( !player[actplayer].cursorPos.valid() ) {
00862          bool found = false;
00863          for ( int y = 0; y < ysize && !found; ++y )
00864             for ( int x = 0; x < xsize  && !found; ++x )
00865                if ( getField(x,y)->getContainer() )
00866                   if ( getField(x,y)->getContainer()->getOwner() == actplayer ) {
00867                      player[actplayer].cursorPos = getField(x,y)->getContainer()->getPosition();
00868                      found = true;
00869                   }
00870       }
00871       return player[actplayer].cursorPos;
00872    } else
00873       return player[0].cursorPos;
00874 #else
00875    return player[8].cursorPos;
00876    #endif
00877 }
00878 
00879 
00880 void GameMap :: cleartemps( int b, int value )
00881 {
00882   if ( xsize <= 0 || ysize <= 0)
00883      return;
00884 
00885   int l = 0;
00886   for ( int x = 0; x < xsize ; x++)
00887      for ( int y = 0; y <  ysize ; y++) {
00888 
00889          if (b & 1 )
00890            field[l].a.temp = value;
00891          if (b & 2 )
00892            field[l].a.temp2 = value;
00893          if (b & 4 )
00894            field[l].temp3 = value;
00895          if (b & 8 )
00896            field[l].temp4 = value;
00897 
00898          l++;
00899      }
00900 }
00901 
00902 void GameMap :: allocateFields ( int x, int y, TerrainType::Weather* terrain )
00903 {
00904    field = new tfield[x*y];
00905    for ( int i = 0; i < x*y; i++ ) {
00906       if ( terrain ) {
00907          field[i].typ = terrain;
00908          field[i].setparams();
00909       }
00910       field[i].setMap ( this );
00911    }
00912    xsize = x;
00913    ysize = y;
00914    overviewMapHolder.connect();
00915 }
00916 
00917 
00918 void GameMap :: calculateAllObjects ( void )
00919 {
00920    calculateallobjects();
00921 }
00922 
00923 tfield*  GameMap :: getField(int x, int y)
00924 {
00925    if ((x < 0) || (y < 0) || (x >= xsize) || (y >= ysize))
00926       return NULL;
00927    else
00928       return (   &field[y * xsize + x] );
00929 }
00930 
00931 tfield*  GameMap :: getField(const MapCoordinate& pos )
00932 {
00933    return getField ( pos.x, pos.y );
00934 }
00935 
00936 int   GameMap :: getPlayerView() const
00937 {
00938 #ifdef karteneditor
00939    return -1;
00940 #else
00941    return playerView;
00942 #endif
00943 }
00944 
00945 
00946 void  GameMap :: setPlayerView( int player )
00947 {
00948    playerView = player;
00949 }
00950 
00951 
00952 
00953 bool GameMap :: isResourceGlobal ( int resource )
00954 {
00955    if ( _resourcemode == 1 ) { // BI-Mode
00956       if ( resource == 1 ) // material
00957          return false;
00958       else
00959          if ( resource == 2 )
00960             return getgameparameter(cgp_globalfuel);
00961          else
00962             return true;
00963    } else {
00964       /*
00965       if ( resource == 0 )
00966          return getgameparameter(cgp_globalenergy);
00967       if ( resource == 1 )
00968          return false;
00969       if ( resource == 2 )
00970          return getgameparameter(cgp_globalfuel);
00971       */
00972       return false;
00973    }
00974 }
00975 
00976 int GameMap :: getgameparameter ( GameParameter num ) const
00977 {
00978   if ( game_parameter && num < gameparameter_num ) {
00979      return game_parameter[num];
00980   } else
00981      if ( num < gameparameternum )
00982         return gameParameterSettings[num].defaultValue;
00983      else
00984         return 0;
00985 }
00986 
00987 void GameMap :: setgameparameter ( GameParameter num, int value )
00988 {
00989    if ( game_parameter ) {
00990      if ( num < gameparameter_num )
00991         game_parameter[num] = value;
00992      else {
00993         int* oldparam = game_parameter;
00994         game_parameter = new int[num+1];
00995         for ( int i = 0; i < gameparameter_num; i++ )
00996            game_parameter[i] = oldparam[i];
00997         for ( int j = gameparameter_num; j < num; j++ )
00998            if ( j < gameparameternum )
00999               game_parameter[j] = gameParameterSettings[j].defaultValue;
01000            else
01001               game_parameter[j] = 0;
01002         game_parameter[num] = value;
01003         gameparameter_num = num + 1;
01004         delete[] oldparam;
01005      }
01006    } else {
01007        game_parameter = new int[num+1];
01008        for ( int j = 0; j < num; j++ )
01009           if ( j < gameparameternum )
01010              game_parameter[j] = gameParameterSettings[j].defaultValue;
01011           else
01012              game_parameter[j] = 0;
01013        game_parameter[num] = value;
01014        gameparameter_num = num + 1;
01015    }
01016 }
01017 
01018 void GameMap :: setupResources ( void )
01019 {
01020    for ( int n = 0; n< 8; n++ ) {
01021       bi_resource[n].energy = 0;
01022       bi_resource[n].material = 0;
01023       bi_resource[n].fuel = 0;
01024 
01025      #ifdef sgmain
01026 
01027       for ( Player::BuildingList::iterator i = player[n].buildingList.begin(); i != player[n].buildingList.end(); i++ )
01028          for ( int r = 0; r < 3; r++ )
01029             if ( isResourceGlobal( r )) {
01030                bi_resource[n].resource(r) += (*i)->actstorage.resource(r);
01031                (*i)->actstorage.resource(r) = 0;
01032             }
01033      #endif
01034    }
01035 }
01036 
01037 
01038 
01039 
01040 int GameMap :: eventpassed( int saveas, int action, int mapid )
01041 {
01042    return eventpassed ( (action << 16) | saveas, mapid );
01043 }
01044 
01045 
01046 
01047 int GameMap :: eventpassed( int id, int mapid )
01048 {
01049    return 0;
01050 }
01051 
01052 
01053 void GameMap::registerUnitNetworkID( Vehicle* veh )
01054 {
01055    vehicleLookupCache[veh->networkid] = veh;
01056    if ( unitnetworkid < veh->networkid )
01057       unitnetworkid = veh->networkid;
01058 }
01059 
01060 void GameMap::unregisterUnitNetworkID( Vehicle* veh )
01061 {
01062    VehicleLookupCache::iterator j = vehicleLookupCache.find(veh->networkid);
01063    if ( j != vehicleLookupCache.end() )
01064       vehicleLookupCache.erase(j);
01065 }
01066 
01067 
01068 int GameMap :: getNewNetworkID()
01069 {
01070    ++unitnetworkid;
01071    return unitnetworkid;
01072 }
01073 
01074 Vehicle* GameMap :: getUnit ( Vehicle* eht, int nwid )
01075 {
01076    if ( !eht )
01077       return NULL;
01078    else {
01079       if ( eht->networkid == nwid )
01080          return eht;
01081       else
01082          for ( ContainerBase::Cargo::const_iterator i = eht->getCargo().begin(); i != eht->getCargo().end(); ++i )
01083             if ( *i )  {
01084                if ( (*i)->networkid == nwid )
01085                   return *i;
01086                else {
01087                   Vehicle* ld = getUnit ( *i, nwid );
01088                   if ( ld )
01089                      return ld;
01090                }
01091             }
01092       return NULL;
01093    }
01094 }
01095 
01096 Vehicle* GameMap :: getUnit ( int nwid, bool consistencyCheck )
01097 {
01098    VehicleLookupCache::iterator i = vehicleLookupCache.find( nwid );
01099    if ( i != vehicleLookupCache.end() )
01100       return i->second;
01101 
01102 
01103    if ( consistencyCheck ) 
01104       for ( int p = 0; p < 9; p++ )
01105          for ( Player::VehicleList::iterator i = player[p].vehicleList.begin(); i != player[p].vehicleList.end(); i++ )
01106             if ( (*i)->networkid == nwid ) {
01107                displaymessage("warning: id not registered in VehicleLookupCache!",1);
01108                return *i;
01109             }
01110 
01111    return NULL;
01112 }
01113 
01114 
01115 Vehicle* GameMap :: getUnit ( int x, int y, int nwid )
01116 {
01117    tfield* fld  = getField ( x, y );
01118    if ( !fld )
01119       return NULL;
01120 
01121    if ( fld->vehicle && fld->vehicle->networkid == nwid )
01122          return fld->vehicle;
01123          
01124    if ( fld->getContainer() )
01125       return fld->getContainer()->findUnit( nwid );
01126       
01127    return NULL;
01128      
01129 }
01130 
01131 ContainerBase* GameMap::getContainer ( int nwid )
01132 {
01133    if ( nwid > 0 )
01134       return getUnit(nwid);
01135    else {
01136       int x = (-nwid) & 0xffff;
01137       int y = (-nwid) >> 16;
01138       tfield* fld = getfield(x,y);
01139       if ( !fld )
01140          return NULL;
01141 
01142       return fld->building;
01143    }
01144 }
01145 
01146 
01147 
01148 void GameMap::beginTurn()
01149 {
01150    if ( !player[actplayer].exist() )
01151       if ( replayinfo )
01152          if ( replayinfo->guidata[actplayer] ) {
01153             delete replayinfo->guidata[actplayer];
01154             replayinfo->guidata[actplayer] = NULL;
01155          }
01156             
01157    if ( player[actplayer].exist() && player[actplayer].stat != Player::off ) {
01158       sigPlayerTurnBegins( player[actplayer] );
01159       
01160 //      if ( player[actplayer].stat == Player::human || player[actplayer].stat == Player::supervisor )
01161 //         sigPlayerUserInteractionEnds( player[actplayer] );
01162 
01163    }
01164 }
01165 
01166 
01167 void GameMap::endTurn()
01168 {
01169    player[actplayer].ASCversion = getNumericVersion();
01170    Player::PlayTime pt;
01171    pt.turn = time.turn();
01172    ::time ( &pt.date );
01173    player[actplayer].playTime.push_back ( pt );
01174    
01175    sigPlayerTurnEnds( player[actplayer] );
01176 
01177    for ( int i = 0; i < 9; ++i )
01178      for ( Player::BuildingList::iterator v = player[i].buildingList.begin(); v != player[i].buildingList.end(); ++v ) {
01179          if ( i == actplayer )
01180             (*v)->endOwnTurn();
01181          (*v)->endAnyTurn();
01182      }
01183 
01184 
01185    Player::VehicleList toRemove;
01186    for ( Player::VehicleList::iterator v = player[actplayer].vehicleList.begin(); v != player[actplayer].vehicleList.end(); ++v ) {
01187       Vehicle* actvehicle = *v;
01188 
01189       // Bei Aenderungen hier auch die Windanzeige dashboard.PAINTWIND aktualisieren !!!
01190 
01191       if (( actvehicle->height >= chtieffliegend )   &&  ( actvehicle->height <= chhochfliegend ) && ( getfield(actvehicle->xpos,actvehicle->ypos)->vehicle == actvehicle)) {
01192          if ( getmaxwindspeedforunit ( actvehicle ) < weather.windSpeed*maxwindspeed ){
01193             new Message ( getUnitReference( *v ) + " crashed because of the strong wind", this, 1<<(*v)->getOwner());
01194             toRemove.push_back ( *v );
01195          } else {
01196 
01197             int j = actvehicle->getTank().fuel - UnitHooveringLogic::calcFuelUsage( actvehicle );
01198             if (j < 0) {
01199                new Message ( getUnitReference( *v ) + " crashed due to lack of fuel", this, 1<<(*v)->getOwner());
01200                toRemove.push_back ( *v );
01201                // logtoreplayinfo( rpl_removeunit, actvehicle->getPosition().x, actvehicle->getPosition().y, actvehicle->networkid );
01202             } else {
01203                // logtoreplayinfo( rpl_refuel2, actvehicle->getPosition().x, actvehicle->getPosition().y, actvehicle->networkid, 1002, j, actvehicle->tank.fuel );
01204                actvehicle->getResource( actvehicle->getTank().fuel - j, Resources::Fuel, false);
01205             }
01206          }
01207       }
01208 
01209       if ( actvehicle )
01210          actvehicle->endOwnTurn();
01211 
01212    }
01213 
01214    for ( Player::VehicleList::iterator v = toRemove.begin(); v != toRemove.end(); v++ )
01215       delete *v;
01216 
01217    checkunitsforremoval();
01218 
01219   for ( int i = 0; i < 9; ++i ) 
01220      for ( Player::VehicleList::iterator v = player[i].vehicleList.begin(); v != player[i].vehicleList.end(); ++v ) 
01221          (*v)->endAnyTurn();
01222 
01223  
01224    if ( replayinfo )
01225       replayinfo->closeLogging();
01226       
01227    processJournal();   
01228 
01229    sigPlayerTurnHasEnded( player[actplayer] );
01230    
01231 }
01232 
01233 
01234 void GameMap::endRound()
01235 {
01236     actplayer = 0;
01237     time.set ( time.turn()+1, 0 );
01238 
01239     for ( int y = 0; y < ysize; ++y )
01240        for ( int x = 0; x < xsize; ++x )
01241            getField(x,y)->endRound( time.turn() );
01242 
01243     for (int i = 0; i <= 7; i++) {
01244        if (player[i].exist() && player[i].stat != Player::off ) {
01245 
01246           for ( Player::VehicleList::iterator j = player[i].vehicleList.begin(); j != player[i].vehicleList.end(); j++ )
01247              (*j)->endRound();
01248 
01249           for ( Player::BuildingList::iterator j = player[i].buildingList.begin(); j != player[i].buildingList.end(); j++ )
01250              (*j)->endRound();
01251           
01252           typedef PointerList<ContainerBase::Work*> BuildingWork;
01253           BuildingWork buildingWork;
01254 
01255           for ( Player::BuildingList::iterator j = player[i].buildingList.begin(); j != player[i].buildingList.end(); j++ ) {
01256              ContainerBase::Work* w = (*j)->spawnWorkClasses( false );
01257              if ( w )
01258                 buildingWork.push_back ( w );
01259           }
01260 
01261           for ( Player::VehicleList::iterator j = player[i].vehicleList.begin(); j != player[i].vehicleList.end(); j++ ) {
01262              ContainerBase::Work* w = (*j)->spawnWorkClasses( false );
01263              if ( w )
01264                 buildingWork.push_back ( w );
01265           }
01266           
01267           
01268           bool didSomething;
01269           do {
01270              didSomething = false;
01271              for ( BuildingWork::iterator j = buildingWork.begin(); j != buildingWork.end(); j++ )
01272                 if ( ! (*j)->finished() ) 
01273     //weatherSystem->update(time);
01274                    if ( (*j)->run() )
01275                       didSomething = true;
01276 
01277           } while ( didSomething );
01278           doresearch( this, i );
01279        }
01280     }
01281 
01282     int playerMask = 0;
01283     for ( int i = 0; i < getPlayerCount(); ++i )
01284        if ( !getPlayer(i).exist() )
01285           playerMask |= 1 << i;
01286     tfield::resetView(this,playerMask);
01287 
01288     if ( getgameparameter( cgp_objectGrowthMultiplier) > 0 )
01289        objectGrowth();
01290 }
01291 
01292 #include "libs/rand/rand_r.h"
01293 #include "libs/rand/rand_r.c"
01294 
01295 int GameMap::random( int max )
01296 {
01297    return asc_rand_r( &randomSeed ) % max;
01298 }
01299 
01300 void GameMap::objectGrowth()
01301 {
01302    typedef vector< pair<tfield*,int> > NewObjects;
01303    map<tfield*,int> remainingGrowthTime;
01304 
01305    NewObjects newObjects;
01306    for ( int y = 0; y < ysize; ++y )
01307       for ( int x = 0; x < xsize; ++x ) {
01308           tfield* fld = getField( x, y );
01309           for ( tfield::ObjectContainer::iterator i = fld->objects.begin(); i != fld->objects.end(); ++i)
01310              if ( i->typ->growthRate > 0 && i->remainingGrowthTime != 0 )
01311                 for ( int d = 0; d < 6; ++d ) {
01312                    tfield* fld2 = getField ( getNeighbouringFieldCoordinate( MapCoordinate(x,y), d ));
01313                    if ( fld2 ) 
01314                       if ( i->typ->growOnUnits || ((!fld2->vehicle || fld2->vehicle->height >= chtieffliegend) && !fld2->building ))
01315                         if ( fld2->objects.empty() || getgameparameter( cgp_objectGrowOnOtherObjects ) > 0 ) {
01316                            double d = i->typ->growthRate * getgameparameter( cgp_objectGrowthMultiplier) / 100;
01317                            if ( d > 0 ) {
01318                               if ( d > 0.9 )
01319                                  d = 0.9;
01320 
01321                               int p = static_cast<int>(std::ceil ( double(1) / d));
01322                               if ( p > 1 )
01323                                  if ( random ( p ) == 1 )
01324                                     if ( i->typ->fieldModification[fld2->getweather()].terrainaccess.accessible( fld2->bdt) > 0 ) {
01325                                        newObjects.push_back( make_pair( fld2, i->typ->id ));
01326                                        i->remainingGrowthTime -= 1;
01327                                        remainingGrowthTime[fld2] = i->remainingGrowthTime;
01328                                     }
01329                            }
01330                         }
01331                 }
01332       }
01333 
01334    for ( NewObjects::iterator i = newObjects.begin(); i != newObjects.end(); ++i )
01335       if ( !i->first->checkforobject( getobjecttype_byid( i->second ))) {
01336          if ( i->first->addobject ( getobjecttype_byid( i->second ))) {
01337             Object* o = i->first->checkforobject( getobjecttype_byid( i->second ));
01338             assert(o);
01339             o->remainingGrowthTime = remainingGrowthTime[i->first];
01340          }
01341       }
01342 }
01343 
01344 SigC::Signal1<void,GameMap&> GameMap::sigMapDeletion;
01345 
01346 GameMap :: ~GameMap ()
01347 {
01348    sigMapDeletion( *this );
01349    state = Destruction;
01350 
01351    if ( field )
01352 
01353       for ( int l=0 ;l < xsize * ysize ; l++ ) {
01354          if ( (field[l].bdt & getTerrainBitType(cbbuildingentry)).any() )
01355             delete field[l].building;
01356 
01357 
01358          Vehicle* aktvehicle = field[l].vehicle;
01359          if ( aktvehicle )
01360             delete aktvehicle;
01361 
01362       } /* endfor */
01363 
01364    int i;
01365    for ( i = 0; i <= 8; i++) {
01366       if ( player[i].ai ) {
01367          delete player[i].ai;
01368          player[i].ai = NULL;
01369       }
01370    }
01371 
01372    if ( replayinfo ) {
01373       delete replayinfo;
01374       replayinfo = NULL;
01375    }
01376 
01377    if ( game_parameter ) {
01378       delete[] game_parameter;
01379       game_parameter = NULL;
01380    }
01381    
01382    if ( network ) {
01383       delete network;
01384       network = NULL;
01385    }   
01386       
01387 
01388 #ifdef WEATHERGENERATOR
01389    delete weatherSystem;
01390 #endif
01391 
01392    if ( field ) {
01393       delete[] field;
01394       field = NULL;
01395    }
01396 
01397    if ( actmap == this )
01398       actmap = NULL;
01399 
01400 }
01401 
01402 /*
01403 gamemap :: ResourceTribute :: tresourcetribute ( )
01404 {
01405    for ( int a = 0; a < 3; a++ )
01406       for ( int b = 0; b < 8; b++ )
01407          for ( int c = 0; c < 8; c++ ) {
01408             avail.resource[a][b][c] = 0;
01409             paid.resource[a][b][c] = 0;
01410          }
01411 }
01412 */
01413 
01414 bool GameMap :: ResourceTribute :: empty ( )
01415 {
01416    for (int i = 0; i < 8; i++)
01417       for (int j = 0; j < 8; j++)
01418          for (int k = 0; k < 3; k++) {
01419             if ( avail[i][j].resource(k) )
01420                return false;
01421             if ( paid[i][j].resource(k) )
01422                return false;
01423          }
01424 
01425    return true;
01426 }
01427 
01428 const int tributeVersion = 1;  // we are counting backwards, -2 is newer than -1
01429 
01430 void GameMap :: ResourceTribute :: read ( tnstream& stream )
01431 {
01432    int version = stream.readInt();
01433    bool noVersion;
01434 
01435    if ( -version >= tributeVersion ) {
01436       for ( int a = 0; a < 8; ++a )
01437          for ( int b = 0; b < 8; ++b )
01438             payStatusLastTurn[a][b].read( stream );
01439       noVersion = false;
01440    } else
01441       noVersion = true;
01442 
01443 
01444    for ( int a = 0; a < 3; a++ )
01445       for ( int b = 0; b < 8; b++ )
01446          for ( int c = 0; c < 8; c++ ) {
01447              if ( noVersion ) {
01448                 avail[b][c].resource(a) = version;
01449                 noVersion = false;
01450              } else
01451                 avail[b][c].resource(a) = stream.readInt();
01452           }
01453 
01454    for ( int a = 0; a < 3; a++ )
01455       for ( int b = 0; b < 8; b++ )
01456          for ( int c = 0; c < 8; c++ )
01457              paid[b][c].resource(a) = stream.readInt();
01458 }
01459 
01460 void GameMap :: ResourceTribute :: write ( tnstream& stream )
01461 {
01462    stream.writeInt ( -tributeVersion );
01463    for ( int a = 0; a < 8; a++ )
01464       for ( int b = 0; b < 8; b++ )
01465          payStatusLastTurn[a][b].write( stream );
01466 
01467    for ( int a = 0; a < 3; a++ )
01468       for ( int b = 0; b < 8; b++ )
01469          for ( int c = 0; c < 8; c++ )
01470              stream.writeInt ( avail[b][c].resource(a) );
01471 
01472 
01473    for ( int a = 0; a < 3; a++ )
01474       for ( int b = 0; b < 8; b++ )
01475          for ( int c = 0; c < 8; c++ )
01476              stream.writeInt ( paid[b][c].resource(a) );
01477 }
01478 
01479 
01480 
01481 int  GameMap::resize( int top, int bottom, int left, int right )  // positive: larger
01482 {
01483   if ( !top && !bottom && !left && !right )
01484      return 0;
01485 
01486   if ( -(top + bottom) > ysize )
01487      return 1;
01488 
01489   if ( -(left + right) > xsize )
01490      return 2;
01491 
01492   if ( bottom & 1 || top & 1 )
01493      return 3;
01494 
01495 
01496   int ox1, oy1, ox2, oy2;
01497 
01498   if ( top < 0 ) {
01499      for ( int x = 0; x < xsize; x++ )
01500         for ( int y = 0; y < -top; y++ )
01501            getField(x,y)->deleteeverything();
01502 
01503      oy1 = -top;
01504   } else
01505      oy1 = 0;
01506 
01507   if ( bottom < 0 ) {
01508      for ( int x = 0; x < xsize; x++ )
01509         for ( int y = ysize+bottom; y < ysize; y++ )
01510            getField(x,y)->deleteeverything();
01511 
01512      oy2 = ysize + bottom;
01513   } else
01514      oy2 = ysize;
01515    
01516   if ( left < 0 ) {
01517      for ( int x = 0; x < -left; x++ )
01518         for ( int y = 0; y < ysize; y++ )
01519            getField(x,y)->deleteeverything();
01520      ox1 = -left;
01521   } else
01522      ox1 = 0;
01523 
01524   if ( right < 0 ) {
01525      for ( int x = xsize+right; x < xsize; x++ )
01526         for ( int y = 0; y < ysize; y++ )
01527            getField(x,y)->deleteeverything();
01528      ox2 = xsize + right;
01529   } else
01530      ox2 = xsize;
01531 
01532   for (int s = 0; s < 9; s++)
01533      for ( Player::BuildingList::iterator i = player[s].buildingList.begin(); i != player[s].buildingList.end(); i++ )
01534         (*i)->unchainbuildingfromfield();
01535 
01536 
01537   int newx = xsize + left + right;
01538   int newy = ysize + top + bottom;
01539 
01540   tfield* newfield = new tfield [ newx * newy ];
01541   for ( int i = 0; i < newx * newy; i++ )
01542      newfield[i].setMap ( this );
01543 
01544   int x;
01545   for ( x = ox1; x < ox2; x++ )
01546      for ( int y = oy1; y < oy2; y++ ) {
01547         tfield* org = getField ( x, y );
01548         tfield* dst = &newfield[ (x + left) + ( y + top ) * newx];
01549         *dst = *org;
01550      }
01551 
01552   tfield defaultfield;
01553   defaultfield.setMap ( this );
01554   defaultfield.typ = getterraintype_byid ( 30 )->weather[0];
01555 
01556   for ( x = 0; x < left; x++ )
01557      for ( int y = 0; y < newy; y++ )
01558         newfield[ x + y * newx ] = defaultfield;
01559 
01560   for ( x = xsize + left; x < xsize + left + right; x++ )
01561      for ( int y = 0; y < newy; y++ )
01562         newfield[ x + y * newx ] = defaultfield;
01563 
01564 
01565   int y;
01566   for ( y = 0; y < top; y++ )
01567      for ( int x = 0; x < newx; x++ )
01568         newfield[ x + y * newx ] = defaultfield;
01569 
01570   for ( y = ysize + top; y < ysize + top + bottom; y++ )
01571