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 TerrainType::MoveMalus::MoveMalus()
00104 {
00105 resize( cmovemalitypenum);
00106 for ( int i = 0; i < cmovemalitypenum; i++ )
00107 at(i) = 100;
00108 }
00109
00110 TerrainType::TerrainType()
00111 {
00112 id = -1;
00113 for ( int i = 0; i < cwettertypennum; i++ )
00114 weather[i] = NULL;
00115
00116 }
00117
00118
00119 void TerrainType::Weather::paint ( Surface& s, SPoint pos )
00120 {
00121 Surface* img;
00122 if ( bi_pict == -1 )
00123 img = ℑ
00124 else
00125 img = &GraphicSetManager::Instance().getPic( bi_pict);
00126
00127 megaBlitter<ColorTransform_None,
00128 ColorMerger_AlphaOverwrite,
00129 SourcePixelSelector_Plain,
00130 TargetPixelSelector_All>
00131 (*img,s,pos,nullParam,nullParam,nullParam,nullParam);
00132 }
00133
00134
00135 const OverviewMapImage* TerrainType::Weather::getQuickView()
00136 {
00137 if ( bi_pict >= 0 ) {
00138 return GraphicSetManager::Instance().getQuickView( bi_pict );
00139 } else {
00140 if (!quickView ) {
00141 quickView = new OverviewMapImage( image );
00142 }
00143 return quickView;
00144 }
00145 }
00146
00147 TerrainType::Weather::~Weather()
00148 {
00149 delete quickView;
00150 }
00151
00152
00153 const int terrain_version = 4;
00154
00155
00156 void TerrainType::MoveMalus::read( tnstream& stream, int defaultValue, int moveMalusCount )
00157 {
00158 clear();
00159
00160 int version;
00161 if ( moveMalusCount <= 0 ) {
00162 version = stream.readInt();
00163 moveMalusCount = stream.readInt();
00164 } else
00165 version = 0;
00166
00167 #ifndef converter
00168 int mmcount = moveMalusCount;
00169 if (mmcount < moveMalusCount )
00170 mmcount = moveMalusCount;
00171 #else
00172 int mmcount = moveMalusCount ;
00173 #endif
00174
00175 for ( int j=0; j< mmcount ; j++ ) {
00176 if (j < moveMalusCount ) {
00177 int i;
00178 if ( version < 2 )
00179 i = stream.readChar();
00180 else
00181 i = stream.readInt();
00182 push_back ( i );
00183 } else
00184 if ( j == 0 )
00185 push_back ( defaultValue );
00186 else
00187 push_back ( at(0) );
00188 }
00189 }
00190
00191 void TerrainType::MoveMalus::write ( tnstream& stream ) const
00192 {
00193 stream.writeInt(2);
00194 stream.writeInt( size() );
00195 for ( int m = 0; m < size(); m++ )
00196 stream.writeInt ( at(m) );
00197 }
00198
00199 void TerrainType::Weather::read ( tnstream& stream )
00200 {
00201 read( stream, terrain_version );
00202 }
00203
00204
00205 void TerrainType::Weather::read ( tnstream& stream, int version )
00206 {
00207 bool loadImage = true;
00208 if (version <=2 ) {
00209 loadImage = stream.readInt();
00210
00211 for ( int j = 1; j < 8; j++ )
00212 stream.readInt();
00213
00214 for ( int j = 0; j < 8; j++ )
00215 stream.readInt();
00216 }
00217
00218 if ( version == 1 ) {
00219 stream.readInt();
00220 defensebonus = stream.readWord();
00221 attackbonus = stream.readWord();
00222 basicjamming = stream.readChar();
00223 } else {
00224 defensebonus = stream.readInt();
00225 attackbonus = stream.readInt();
00226 basicjamming = stream.readInt();
00227 }
00228 int move_maluscount = stream.readChar();
00229 stream.readInt();
00230 stream.readInt();
00231 stream.readInt();
00232
00233 art.read ( stream );
00234
00235 bi_pict = stream.readInt();
00236 for ( int j = 1; j < 6; j++ )
00237 stream.readInt();
00238
00239 move_malus.read( stream, minmalq, move_maluscount );
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 if ( loadImage )
00254 if ( bi_pict == -1 )
00255 image.read ( stream );
00256 }
00257
00258 void TerrainType::Weather::write ( tnstream& stream ) const
00259 {
00260 stream.writeInt ( defensebonus );
00261 stream.writeInt ( attackbonus );
00262 stream.writeInt ( basicjamming );
00263 stream.writeChar ( 0 );
00264 stream.writeInt ( 1 );
00265 stream.writeInt ( 1 );
00266 stream.writeInt ( 0);
00267 art.write ( stream );
00268
00269
00270 stream.writeInt ( bi_pict );
00271 for ( int m = 1; m< 6; m++ )
00272 stream.writeInt ( -1 );
00273
00274 move_malus.write ( stream );
00275
00276 if ( bi_pict == -1 )
00277 image.write ( stream );
00278 }
00279
00280
00281 void TerrainType::read( tnstream& stream )
00282 {
00283 int version = stream.readInt();
00284 if ( version == terrain_version || version == 1) {
00285
00286 stream.readInt();
00287 id = stream.readInt();
00288
00289 bool ___loadWeather[cwettertypennum];
00290 for ( int ww = 0; ww < cwettertypennum; ww++ )
00291 ___loadWeather[ww] = stream.readInt();
00292
00293 for ( int nf = 0; nf < 8; nf++ )
00294 stream.readInt();
00295
00296 name = stream.readString();
00297
00298 for ( int i=0; i<cwettertypennum ;i++ ) {
00299 if ( ___loadWeather[i] ) {
00300 weather[i] = new TerrainType::Weather ( this );
00301 weather[i]->read( stream, version );
00302 } else
00303 weather[i] = NULL;
00304
00305 }
00306
00307 } else
00308 throw tinvalidversion ( stream.getDeviceName(), terrain_version, version );
00309
00310
00311
00312
00313
00314
00315
00316 }
00317
00318
00319 void TerrainType::write ( tnstream& stream ) const
00320 {
00321 stream.writeInt ( terrain_version );
00322 stream.writeInt ( !name.empty() );
00323 stream.writeInt ( id );
00324 for ( int m = 0; m < cwettertypennum; m++ )
00325 stream.writeInt ( weather[m] != NULL );
00326
00327 for ( int m = 0; m < 8; m++ )
00328 stream.writeInt ( 0 );
00329
00330 stream.writeString( name );
00331 for ( int i = 0; i < cwettertypennum ; i++ )
00332 if ( weather[i] )
00333 weather[i]->write( stream );
00334
00335
00336
00337
00338
00339 }
00340
00341
00342 int TerrainType::getMemoryFootprint() const
00343 {
00344 int size = sizeof(*this);
00345
00346 for ( int w = 0; w < cwettertypennum; ++w )
00347 if ( weather[w] )
00348 size += weather[w]->getMemoryFootprint();
00349
00350 return size;
00351 }
00352
00353 int TerrainType::Weather::getMemoryFootprint() const
00354 {
00355 int size = sizeof(*this);
00356 size += image.getMemoryFootprint();
00357 if ( quickView )
00358 size += quickView->getMemoryFootprint();
00359 return size;
00360 }
00361
00362
00363 TerrainType::~TerrainType()
00364 {
00365 for ( int i = 0; i< cwettertypennum; ++i) {
00366 delete weather[i];
00367 weather[i] = NULL;
00368 }
00369 }
00370
00371
00372 TerrainAccess :: TerrainAccess ( void )
00373 {
00374 terrain.flip();
00375 }
00376
00377 int TerrainAccess :: accessible ( const TerrainBits& bts ) const
00378 {
00379 if ( (terrain & bts).any()
00380 && (terrainreq & bts) == terrainreq
00381 && (terrainnot & bts ).none()
00382 ) return 1;
00383 else
00384 if ( (terrainkill & bts).any() )
00385 return -1;
00386 else
00387 return 0;
00388 }
00389
00390
00391 void TerrainBits::setInt ( int terrain1, int terrain2 )
00392 {
00393 reset();
00394 for ( int i = 0; i < 32; i++ )
00395 if ( terrain1 & ( 1 << i ))
00396 set(i);
00397
00398 for ( int i = 0; i < 32; i++ )
00399 if ( terrain2 & ( 1 << i ))
00400 set(32+i);
00401 }
00402
00403 void TerrainBits::read ( tnstream& stream )
00404 {
00405 int terrain1 = stream.readInt();
00406 int terrain2 = stream.readInt();
00407 setInt ( terrain1, terrain2 );
00408 };
00409
00410 void TerrainBits::write ( tnstream& stream ) const
00411 {
00412 int terrain1 = 0;
00413 int terrain2 = 0;
00414 for ( int i = 0; i < 32; i++ )
00415 if ( test(i) )
00416 terrain1 |= 1 << i ;
00417
00418 for ( int i = 0; i < 32; i++ )
00419 if ( test(32+i) )
00420 terrain2 |= 1 << i ;
00421
00422 stream.writeInt( terrain1 );
00423 stream.writeInt( terrain2 );
00424 }
00425
00426
00427 void TerrainType :: runTextIO ( PropertyContainer& pc )
00428 {
00429 pc.addBreakpoint();
00430
00431
00432 BitSet weatherBits;
00433 for ( int i = 0; i < cwettertypennum; i++ )
00434 if ( weather[i] )
00435 weatherBits.set(i);
00436
00437 pc.addString( "Name", name );
00438 pc.addInteger( "ID", id );
00439
00440 if ( pc.find( "SecondaryIDs") || !pc.isReading())
00441 pc.addIntegerArray("SecondaryIDs", secondaryIDs );
00442
00443
00444 pc.addTagArray( "Weather", weatherBits, cwettertypennum, weatherTags );
00445
00446 for ( int i = 0; i < cwettertypennum; i++ )
00447 if ( weatherBits.test(i) ) {
00448
00449 if ( pc.isReading() )
00450 weather[i] = new TerrainType::Weather ( this );
00451
00452 pc.openBracket ( weatherTags[i] );
00453 weather[i]->runTextIO ( pc );
00454 pc.closeBracket ( );
00455 }
00456
00457 }
00458
00459 void TerrainType::Weather::runTextIO ( PropertyContainer& pc )
00460 {
00461 bool bi3pics = false;
00462
00463 if ( !pc.isReading() )
00464 if ( bi_pict >= 0 )
00465 bi3pics = true;
00466
00467 pc.addBool ( "UseGFXpics", bi3pics, false );
00468 if ( !bi3pics ) {
00469 bi_pict = -1;
00470 int w = cwettertypennum-1;
00471 for ( int i = 0; i < cwettertypennum-1; i++ )
00472 if ( terraintype->weather[i] == this )
00473 w = i;
00474
00475 ASCString s = extractFileName_withoutSuffix ( terraintype->filename );
00476 if ( s.empty() ) {
00477 s = "terrain";
00478 s += strrr(terraintype->id);
00479 }
00480 pc.addImage ( "picture", image, s + weatherAbbrev[w], true );
00481
00482
00483 if ( pc.isReading() ) {
00484 int operations;
00485 pc.addNamedInteger("GraphicOperations", operations, graphicOperationNum, graphicOperations, 0 );
00486 if ( operations == 1 )
00487 snowify( image );
00488 else
00489 if ( operations == 2 )
00490 snowify( image, false );
00491 }
00492
00493 } else {
00494 pc.addInteger ( "GFX_Picture", bi_pict );
00495 if ( bi_pict < 0 )
00496 fatalError ( "invalid BI-image " );
00497 }
00498
00499 pc.addInteger ( "DefenseBonus", defensebonus, 0 );
00500 pc.addInteger ( "AttackBonus", attackbonus, 0 );
00501 pc.addInteger ( "BasicJamming", basicjamming, 0 );
00502 pc.addDFloatArray ( "MoveMalus", move_malus );
00503 while ( move_malus.size() < cmovemalitypenum )
00504 if ( move_malus.size() == 0 )
00505 move_malus.push_back ( minmalq );
00506 else
00507 move_malus.push_back ( move_malus[0] );
00508
00509
00510 pc.addTagArray ( "TerrainProperties", art, terrainPropertyNum, terrainProperties );
00511 }
00512
00513
00514
00515
00516 TerrainBits getTerrainBitType ( TerrainBitTypes tbt )
00517 {
00518 TerrainBits tb;
00519 switch ( tbt ) {
00520 case cbwater0 : tb.setInt( 1<<22 ); break;
00521 case cbwater1 : tb.setInt( 1 ); break;
00522 case cbwater2 : tb.setInt( 4096 ); break;
00523 case cbwater3 : tb.setInt( 8192 ); break;
00524 case cbwater : tb.setInt ( (1<<22)
00525 | (1<< 0)
00526 | (1<<12)
00527 | (1<<13)
00528 | (1<<31)
00529 ); break;
00530 case cbstreet : tb.setInt ( 32, 0 ); break;
00531 case cbrailroad : tb.setInt ( 64, 0 ); break;
00532 case cbbuildingentry : tb.setInt ( 128, 0 ); break;
00533 case cbharbour : tb.setInt ( 256, 0 ); break;
00534 case cbrunway : tb.setInt ( 512, 0 ); break;
00535 case cbpipeline : tb.setInt ( 1024, 0 ); break;
00536 case cbpowerline : tb.setInt ( 2048, 0 ); break;
00537 case cbfahrspur : tb.setInt ( 1<<16, 0 ); break;
00538 case cbfestland : tb.flip(); tb ^= getTerrainBitType( cbwater ); break;
00539 case cbsnow1 : tb.setInt ( 1<<19, 0 ); break;
00540 case cbsnow2 : tb.setInt ( 1<<20, 0 ); break;
00541 case cbhillside : tb.setInt ( 1<<26, 0 ); break;
00542 case cbsmallrocks : tb.setInt ( 1<<17, 0 ); break;
00543 case cblargerocks : tb.setInt ( 1<<23, 0 ); break;
00544 case cbfrozenwater : tb.setInt ( 0, 1 ); break;
00545 case cbicebreaking : tb |= getTerrainBitType( cbfrozenwater )
00546 | getTerrainBitType( cbsnow1 )
00547 | getTerrainBitType(cbsnow2 );
00548 case cbriver : tb.setInt( 1 << 31, 0 ); break;
00549
00550 };
00551 return tb;
00552 }
00553
00554