00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "terraintype.h"
00020 #include "gameoptions.h"
00021 #include "graphicset.h"
00022 #include "sgstream.h"
00023 #include "textfileparser.h"
00024 #include "textfiletags.h"
00025 #include "textfile_evaluation.h"
00026 #include "overviewmapimage.h"
00027 #include "graphics/blitter.h"
00028 #include "fieldimageloader.h"
00029
00030 const char* terrainProperty[terrainPropertyNum+1] = {"shallow water" ,
00031 "normal lowland",
00032 "swamp",
00033 "forest",
00034 "high mountains",
00035 "road",
00036 "railroad",
00037 "entry of building (not to be used for terrain)" ,
00038 "harbour",
00039 "runway" ,
00040 "pipeline",
00041 "buried pipeline",
00042 "water",
00043 "deep water",
00044 "hard sand",
00045 "soft sand",
00046 "track possible",
00047 "small rocks",
00048 "mud",
00049 "snow",
00050 "deep snow",
00051 "mountains",
00052 "very shallow water",
00053 "large rocks",
00054 "lava",
00055 "ditch",
00056 "hillside",
00057 "turret foundation",
00058 "morass",
00059 "Installation",
00060 "pack ice",
00061 "river",
00062 "frozen water",
00063 "bridge",
00064 "lava barrier",
00065 "spaceport",
00066 "beacon",
00067 "fire",
00068 NULL };
00069
00070
00071
00072
00073 void TerrainAccess::read ( tnstream& stream ) {
00074 terrain.read ( stream );
00075 terrain.reset( 7 );
00076 terrainreq.read ( stream );
00077 terrainnot.read ( stream );
00078 terrainnot.reset( 7 );
00079 terrainkill.read ( stream );
00080
00081 for ( int a = 0; a < 10; a++ )
00082 stream.readInt( );
00083 };
00084
00085 void TerrainAccess::write ( tnstream& stream ) const {
00086 terrain.write ( stream );
00087 terrainreq.write ( stream );
00088 terrainnot.write ( stream );
00089 terrainkill.write ( stream );
00090
00091 for ( int a = 0; a < 10; a++ )
00092 stream.writeInt( 0 );
00093 };
00094
00095 void TerrainAccess::runTextIO ( PropertyContainer& pc )
00096 {
00097 pc.addTagArray ( "terrain_any", terrain, terrainPropertyNum, terrainProperties );
00098 pc.addTagArray ( "terrain_all", terrainreq, terrainPropertyNum, terrainProperties );
00099 pc.addTagArray ( "terrain_not", terrainnot, terrainPropertyNum, terrainProperties );
00100 pc.addTagArray ( "terrain_kill", terrainkill, terrainPropertyNum, terrainProperties );
00101 }
00102
00103 void TerrainBits::appendToString( ASCString& text ) const
00104 {
00105 for (int i = 0; i < terrainPropertyNum ; i++) {
00106 TerrainBits bts;
00107 bts.set ( i );
00108
00109 if ( (*this & bts).any() ) {
00110 text += "- " ;
00111 text += terrainProperty[i];
00112 text += "\n";
00113 }
00114 }
00115 }
00116
00117
00118
00119
00120 TerrainType::MoveMalus::MoveMalus()
00121 {
00122 resize( cmovemalitypenum);
00123 for ( int i = 0; i < cmovemalitypenum; i++ )
00124 at(i) = 100;
00125 }
00126
00127 TerrainType::TerrainType()
00128 {
00129 id = -1;
00130 for ( int i = 0; i < cwettertypennum; i++ )
00131 weather[i] = NULL;
00132
00133 }
00134
00135
00136 void TerrainType::Weather::paint ( Surface& s, SPoint pos )
00137 {
00138 Surface* img;
00139 if ( bi_pict == -1 )
00140 img = ℑ
00141 else
00142 img = &GraphicSetManager::Instance().getPic( bi_pict);
00143
00144 megaBlitter<ColorTransform_None,
00145 ColorMerger_AlphaOverwrite,
00146 SourcePixelSelector_Plain,
00147 TargetPixelSelector_All>
00148 (*img,s,pos,nullParam,nullParam,nullParam,nullParam);
00149 }
00150
00151
00152 const OverviewMapImage* TerrainType::Weather::getQuickView()
00153 {
00154 if ( bi_pict >= 0 ) {
00155 return GraphicSetManager::Instance().getQuickView( bi_pict );
00156 } else {
00157 if (!quickView ) {
00158 quickView = new OverviewMapImage( image );
00159 }
00160 return quickView;
00161 }
00162 }
00163
00164 TerrainType::Weather::~Weather()
00165 {
00166 delete quickView;
00167 }
00168
00169
00170 const int terrain_version = 6;
00171
00172
00173 void TerrainType::MoveMalus::read( tnstream& stream, int defaultValue, int moveMalusCount )
00174 {
00175 clear();
00176
00177 int version;
00178 if ( moveMalusCount <= 0 ) {
00179 version = stream.readInt();
00180 moveMalusCount = stream.readInt();
00181 } else
00182 version = 0;
00183
00184 #ifndef converter
00185 int mmcount = moveMalusCount;
00186 if (mmcount < moveMalusCount )
00187 mmcount = moveMalusCount;
00188 #else
00189 int mmcount = moveMalusCount ;
00190 #endif
00191
00192 for ( int j=0; j< mmcount ; j++ ) {
00193 if (j < moveMalusCount ) {
00194 int i;
00195 if ( version < 2 )
00196 i = stream.readChar();
00197 else
00198 i = stream.readInt();
00199 push_back ( i );
00200 } else
00201 if ( j == 0 )
00202 push_back ( defaultValue );
00203 else
00204 push_back ( at(0) );
00205 }
00206 }
00207
00208 void TerrainType::MoveMalus::write ( tnstream& stream ) const
00209 {
00210 stream.writeInt(2);
00211 stream.writeInt( size() );
00212 for ( int m = 0; m < size(); m++ )
00213 stream.writeInt ( at(m) );
00214 }
00215
00216 void TerrainType::Weather::read ( tnstream& stream )
00217 {
00218 read( stream, terrain_version );
00219 }
00220
00221
00222 void TerrainType::Weather::read ( tnstream& stream, int version )
00223 {
00224 bool loadImage = true;
00225 if (version <=2 ) {
00226 loadImage = stream.readInt();
00227
00228 for ( int j = 1; j < 8; j++ )
00229 stream.readInt();
00230
00231 for ( int j = 0; j < 8; j++ )
00232 stream.readInt();
00233 }
00234
00235 if ( version == 1 ) {
00236 stream.readInt();
00237 defensebonus = stream.readWord();
00238 attackbonus = stream.readWord();
00239 basicjamming = stream.readChar();
00240 } else {
00241 defensebonus = stream.readInt();
00242 attackbonus = stream.readInt();
00243 basicjamming = stream.readInt();
00244 }
00245 int move_maluscount = stream.readChar();
00246 stream.readInt();
00247 stream.readInt();
00248 stream.readInt();
00249
00250 art.read ( stream );
00251
00252 bi_pict = stream.readInt();
00253 for ( int j = 1; j < 6; j++ )
00254 stream.readInt();
00255
00256 move_malus.read( stream, minmalq, move_maluscount );
00257
00258 if ( version >= 5 )
00259 originalImageFilename = stream.readString();
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 if ( loadImage )
00274 if ( bi_pict == -1 )
00275 image.read ( stream );
00276 }
00277
00278 void TerrainType::Weather::write ( tnstream& stream ) const
00279 {
00280 stream.writeInt ( defensebonus );
00281 stream.writeInt ( attackbonus );
00282 stream.writeInt ( basicjamming );
00283 stream.writeChar ( 0 );
00284 stream.writeInt ( 1 );
00285 stream.writeInt ( 1 );
00286 stream.writeInt ( 0);
00287 art.write ( stream );
00288
00289
00290 stream.writeInt ( bi_pict );
00291 for ( int m = 1; m< 6; m++ )
00292 stream.writeInt ( -1 );
00293
00294 move_malus.write ( stream );
00295
00296 stream.writeString( originalImageFilename );
00297
00298 if ( bi_pict == -1 )
00299 image.write ( stream );
00300 }
00301
00302
00303 void TerrainType::read( tnstream& stream )
00304 {
00305 int version = stream.readInt();
00306 if ( version > terrain_version || (version < 5 && version !=1) )
00307 throw tinvalidversion ( stream.getDeviceName(), terrain_version, version );
00308
00309 stream.readInt();
00310 id = stream.readInt();
00311
00312 bool ___loadWeather[cwettertypennum];
00313 for ( int ww = 0; ww < cwettertypennum; ww++ )
00314 ___loadWeather[ww] = stream.readInt();
00315
00316 for ( int nf = 0; nf < 8; nf++ )
00317 stream.readInt();
00318
00319 name = stream.readString();
00320
00321 for ( int i=0; i<cwettertypennum ;i++ ) {
00322 if ( ___loadWeather[i] ) {
00323 weather[i] = new TerrainType::Weather ( this );
00324 weather[i]->read( stream, version );
00325 } else
00326 weather[i] = NULL;
00327
00328 }
00329
00330 if ( version >= 6 )
00331 readClassContainer( secondaryIDs, stream );
00332 }
00333
00334
00335 void TerrainType::write ( tnstream& stream ) const
00336 {
00337 stream.writeInt ( terrain_version );
00338 stream.writeInt ( !name.empty() );
00339 stream.writeInt ( id );
00340 for ( int m = 0; m < cwettertypennum; m++ )
00341 stream.writeInt ( weather[m] != NULL );
00342
00343 for ( int m = 0; m < 8; m++ )
00344 stream.writeInt ( 0 );
00345
00346 stream.writeString( name );
00347 for ( int i = 0; i < cwettertypennum ; i++ )
00348 if ( weather[i] )
00349 weather[i]->write( stream );
00350
00351 writeClassContainer( secondaryIDs, stream );
00352
00353
00354
00355
00356
00357 }
00358
00359
00360 int TerrainType::getMemoryFootprint() const
00361 {
00362 int size = sizeof(*this);
00363
00364 for ( int w = 0; w < cwettertypennum; ++w )
00365 if ( weather[w] )
00366 size += weather[w]->getMemoryFootprint();
00367
00368 return size;
00369 }
00370
00371 int TerrainType::Weather::getMemoryFootprint() const
00372 {
00373 int size = sizeof(*this);
00374 size += image.getMemoryFootprint();
00375 if ( quickView )
00376 size += quickView->getMemoryFootprint();
00377 return size;
00378 }
00379
00380
00381 TerrainType::~TerrainType()
00382 {
00383 for ( int i = 0; i< cwettertypennum; ++i) {
00384 delete weather[i];
00385 weather[i] = NULL;
00386 }
00387 }
00388
00389
00390 TerrainAccess :: TerrainAccess ( void )
00391 {
00392 terrain.flip();
00393 }
00394
00395 int TerrainAccess :: accessible ( const TerrainBits& bts ) const
00396 {
00397 if ( (terrain & bts).any()
00398 && (terrainreq & bts) == terrainreq
00399 && (terrainnot & bts ).none()
00400 ) return 1;
00401 else
00402 if ( (terrainkill & bts).any() )
00403 return -1;
00404 else
00405 return 0;
00406 }
00407
00408
00409 void TerrainBits::setInt ( int terrain1, int terrain2 )
00410 {
00411 reset();
00412 for ( int i = 0; i < 32; i++ )
00413 if ( terrain1 & ( 1 << i ))
00414 set(i);
00415
00416 for ( int i = 0; i < 32; i++ )
00417 if ( terrain2 & ( 1 << i ))
00418 set(32+i);
00419 }
00420
00421 void TerrainBits::read ( tnstream& stream )
00422 {
00423 int terrain1 = stream.readInt();
00424 int terrain2 = stream.readInt();
00425 setInt ( terrain1, terrain2 );
00426 };
00427
00428 void TerrainBits::write ( tnstream& stream ) const
00429 {
00430 int terrain1 = 0;
00431 int terrain2 = 0;
00432 for ( int i = 0; i < 32; i++ )
00433 if ( test(i) )
00434 terrain1 |= 1 << i ;
00435
00436 for ( int i = 0; i < 32; i++ )
00437 if ( test(32+i) )
00438 terrain2 |= 1 << i ;
00439
00440 stream.writeInt( terrain1 );
00441 stream.writeInt( terrain2 );
00442 }
00443
00444
00445
00446
00447 void TerrainType :: runTextIO ( PropertyContainer& pc )
00448 {
00449 pc.addBreakpoint();
00450
00451
00452 BitSet weatherBits;
00453 for ( int i = 0; i < cwettertypennum; i++ )
00454 if ( weather[i] )
00455 weatherBits.set(i);
00456
00457 pc.addString( "Name", name );
00458 pc.addInteger( "ID", id );
00459
00460 if ( pc.find( "SecondaryIDs") || !pc.isReading())
00461 pc.addIntegerArray("SecondaryIDs", secondaryIDs );
00462
00463
00464 pc.addTagArray( "Weather", weatherBits, cwettertypennum, weatherTags );
00465
00466 for ( int i = 0; i < cwettertypennum; i++ )
00467 if ( weatherBits.test(i) ) {
00468
00469 if ( pc.isReading() )
00470 weather[i] = new TerrainType::Weather ( this );
00471
00472 pc.openBracket ( weatherTags[i] );
00473 weather[i]->runTextIO ( pc );
00474 pc.closeBracket ( );
00475 }
00476
00477 }
00478
00479 void TerrainType::Weather::runTextIO ( PropertyContainer& pc )
00480 {
00481 bool bi3pics = false;
00482
00483 if ( !pc.isReading() )
00484 if ( bi_pict >= 0 )
00485 bi3pics = true;
00486
00487 pc.addBool ( "UseGFXpics", bi3pics, false );
00488 if ( !bi3pics ) {
00489 bi_pict = -1;
00490 int w = cwettertypennum-1;
00491 for ( int i = 0; i < cwettertypennum-1; i++ )
00492 if ( terraintype->weather[i] == this )
00493 w = i;
00494
00495 ASCString s = extractFileName_withoutSuffix ( terraintype->filename );
00496 if ( s.empty() ) {
00497 s = "terrain";
00498 s += strrr(terraintype->id);
00499 }
00500 s += weatherAbbrev[w];
00501 pc.addImage ( "picture", image, s, true );
00502
00503 if ( pc.isReading() ) {
00504 originalImageFilename = s;
00505 } else {
00506 pc.addString( "OriginalImageFilename", originalImageFilename );
00507 }
00508
00509
00510
00511 if ( pc.isReading() ) {
00512 int operations;
00513 pc.addNamedInteger("GraphicOperations", operations, graphicOperationNum, graphicOperations, 0 );
00514 if ( operations == 1 )
00515 snowify( image );
00516 else
00517 if ( operations == 2 )
00518 snowify( image, false );
00519 }
00520
00521 } else {
00522 pc.addInteger ( "GFX_Picture", bi_pict );
00523 if ( bi_pict < 0 )
00524 fatalError ( "invalid BI-image " );
00525 }
00526
00527 pc.addInteger ( "DefenseBonus", defensebonus, 0 );
00528 pc.addInteger ( "AttackBonus", attackbonus, 0 );
00529 pc.addInteger ( "BasicJamming", basicjamming, 0 );
00530 pc.addDFloatArray ( "MoveMalus", move_malus );
00531 while ( move_malus.size() < cmovemalitypenum )
00532 if ( move_malus.size() == 0 )
00533 move_malus.push_back ( minmalq );
00534 else
00535 move_malus.push_back ( move_malus[0] );
00536
00537
00538 pc.addTagArray ( "TerrainProperties", art, terrainPropertyNum, terrainProperties );
00539 }
00540
00541
00542
00543
00544 TerrainBits getTerrainBitType ( TerrainBitTypes tbt )
00545 {
00546 TerrainBits tb;
00547 switch ( tbt ) {
00548 case cbwater0 : tb.setInt( 1<<22 ); break;
00549 case cbwater1 : tb.setInt( 1 ); break;
00550 case cbwater2 : tb.setInt( 4096 ); break;
00551 case cbwater3 : tb.setInt( 8192 ); break;
00552 case cbwater : tb.setInt ( (1<<22)
00553 | (1<< 0)
00554 | (1<<12)
00555 | (1<<13)
00556 | (1<<31)
00557 ); break;
00558 case cbstreet : tb.setInt ( 32, 0 ); break;
00559 case cbrailroad : tb.setInt ( 64, 0 ); break;
00560 case cbbuildingentry : tb.setInt ( 128, 0 ); break;
00561 case cbharbour : tb.setInt ( 256, 0 ); break;
00562 case cbrunway : tb.setInt ( 512, 0 ); break;
00563 case cbpipeline : tb.setInt ( 1024, 0 ); break;
00564 case cbpowerline : tb.setInt ( 2048, 0 ); break;
00565 case cbfahrspur : tb.setInt ( 1<<16, 0 ); break;
00566 case cbfestland : tb.flip(); tb ^= getTerrainBitType( cbwater ); break;
00567 case cbsnow1 : tb.setInt ( 1<<19, 0 ); break;
00568 case cbsnow2 : tb.setInt ( 1<<20, 0 ); break;
00569 case cbhillside : tb.setInt ( 1<<26, 0 ); break;
00570 case cbsmallrocks : tb.setInt ( 1<<17, 0 ); break;
00571 case cblargerocks : tb.setInt ( 1<<23, 0 ); break;
00572 case cbfrozenwater : tb.setInt ( 0, 1 ); break;
00573 case cbicebreaking : tb |= getTerrainBitType( cbfrozenwater )
00574 | getTerrainBitType( cbsnow1 )
00575 | getTerrainBitType(cbsnow2 );
00576 case cbriver : tb.setInt( 1 << 31, 0 ); break;
00577
00578 };
00579 return tb;
00580 }
00581
00582
00583 ASCString TerrainAccess :: toString( bool brief ) const
00584 {
00585 ASCString text;
00586
00587 text += "Terrain properties of which one must be available:\n" ;
00588 terrain.appendToString( text );
00589
00590 if ( !( brief && terrainreq.none() )) {
00591 text += "\n\nTerrain properties that must all be set:\n" ;
00592 terrainreq.appendToString( text );
00593 }
00594
00595 if ( !( brief && terrainnot.none() )) {
00596 text += "\n\nTerrain properties that must not be set:\n" ;
00597 terrainnot.appendToString( text );
00598 }
00599
00600 if ( !( brief && terrainkill.none() )) {
00601 text += "\n\nTerrain properties that are fatal:\n" ;
00602 terrainkill.appendToString( text );
00603 }
00604
00605 return text;
00606 }