00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <algorithm>
00020 #include <set>
00021
00022 #include "objecttype.h"
00023 #include "graphicset.h"
00024 #include "textfileparser.h"
00025 #include "textfiletags.h"
00026 #include "sgstream.h"
00027 #include "textfile_evaluation.h"
00028 #include "mapalgorithms.h"
00029 #include "graphics/blitter.h"
00030 #include "graphics/drawing.h"
00031 #include "fieldimageloader.h"
00032 #include "memsize_interface.h"
00033 #include "iconrepository.h"
00034
00035
00036 #ifndef converter
00037 #include "gamemap.h"
00038 #endif
00039
00040
00041
00042 ObjectType :: FieldModification::FieldModification()
00043 {
00044 terrain_and.flip();
00045 }
00046
00047 ObjectType :: ObjectType ( void ) : rotateImage(false)
00048 {
00049 namingMethod = AddToTerrain;
00050 groupID = -1;
00051
00052 displayMethod = 0;
00053 canExistBeneathBuildings = false;
00054 netBehaviour = 0;
00055 viewbonus_abs = -1;
00056 viewbonus_plus = 0;
00057 imageHeight = 0;
00058 physicalHeight = 0;
00059 growthRate = 0;
00060 growOnUnits = false;
00061 lifetime = -1;
00062 growthDuration = -1;
00063 }
00064
00065 const int ObjectType::namingMethodNum = 3;
00066
00067 const char* ObjectType::namingMethodNames[namingMethodNum+1] = { "ReplaceTerrain", "AddToTerrain", "UnNamed", NULL };
00068
00069
00070
00071
00072 const ObjectType::FieldModification& ObjectType::getFieldModification ( int weather ) const
00073 {
00074 return fieldModification[getWeather(weather)];
00075 }
00076
00077 bool ObjectType :: buildable ( MapField* fld ) const
00078 {
00079 #ifndef converter
00080 if ( fld->building && !growOnUnits )
00081 return false;
00082
00083 if ( getFieldModification( fld->getWeather() ).terrainaccess.accessible ( fld->bdt ) <= 0 )
00084 return false;
00085
00086 #endif
00087 return true;
00088 }
00089
00090 int ObjectType :: getEffectiveHeight() const
00091 {
00092 return 1 << physicalHeight;
00093 }
00094
00095
00096 int ObjectType :: getWeather( int weather ) const
00097 {
00098 while ( !this->weather.test(weather) ) {
00099 if ( weather == 5 )
00100 weather = 4;
00101 else
00102 if ( weather == 2 )
00103 weather = 1;
00104 else
00105 weather = 0;
00106 }
00107 return weather;
00108 }
00109
00110
00111 const OverviewMapImage* ObjectType :: getOverviewMapImage( int picnum, int weather ) const
00112 {
00113 weather = getWeather(weather);
00114
00115 if ( weatherPicture[weather].images.size() <= picnum )
00116 picnum = 0;
00117
00118 if ( weatherPicture[weather].bi3pic[picnum] > 0 )
00119 return GraphicSetManager::Instance().getQuickView( weatherPicture[weather].bi3pic[picnum] );
00120 else {
00121 if ( weatherPicture[weather].overviewMapImage.size() <= picnum )
00122 weatherPicture[weather].overviewMapImage.resize( picnum+1 );
00123
00124 if ( !weatherPicture[weather].overviewMapImage[picnum].valid() )
00125 weatherPicture[weather].overviewMapImage[picnum].create( weatherPicture[weather].images[picnum] );
00126
00127 return &weatherPicture[weather].overviewMapImage[picnum];
00128 }
00129 }
00130
00131
00132 const Surface& ObjectType :: getPicture ( int i, int w ) const
00133 {
00134 w = getWeather(w);
00135
00136 if ( weatherPicture[w].images.size() <= i ) {
00137 if ( i >= 64 && weatherPicture[w].images.size() > 34 )
00138 i = 34;
00139 else
00140 i = 0;
00141 }
00142
00143 if ( weatherPicture[w].bi3pic[i] > 0 )
00144 return GraphicSetManager::Instance().getPic(weatherPicture[w].bi3pic[i]);
00145 else {
00146 const Surface& s = weatherPicture[w].images[i];
00147 if ( s.valid() )
00148 return s;
00149 else {
00150 if ( i < 65 && weatherPicture[w].images.size() >= 66 ) {
00151 const Surface& s2 = weatherPicture[w].images[65];
00152 if ( s2.valid())
00153 return s2;
00154 }
00155 if ( i < 64 && weatherPicture[w].images.size() >= 65 ) {
00156 const Surface& s2 = weatherPicture[w].images[64];
00157 if ( s2.valid())
00158 return s2;
00159 }
00160 return IconRepository::getIcon("red-x-field.png");
00161 }
00162 }
00163 }
00164
00165
00166 void ObjectType :: display ( Surface& surface, const SPoint& pos, int dir, int weather ) const
00167 {
00168 weather = getWeather(weather);
00169
00170 if ( id == 4 ) {
00171 switch ( dir ) {
00172 case 68 : realDisplay( surface, pos, 9, weather ); break;
00173 case 34 : realDisplay( surface, pos, 10, weather ); break;
00174 case 17 : realDisplay( surface, pos, 11, weather ); break;
00175 case 136 : realDisplay( surface, pos, 12, weather ); break;
00176 case 0 : realDisplay( surface, pos, 0, weather ); break;
00177 default : {
00178 for (int i = 0; i <= 7; i++)
00179 if ( dir & (1 << i))
00180 realDisplay( surface, pos, i+1, weather );
00181 }
00182 }
00183 } else
00184 realDisplay( surface, pos, dir, weather );
00185
00186 }
00187
00188
00189 template<
00190 int BytesPerSourcePixel,
00191 int BytesPerTargetPixel
00192 >
00193 class ColorConverter_PassThrough
00194 {
00195 public:
00196 typedef typename PixelSize2Type<BytesPerTargetPixel>::PixelType SourcePixelType;
00197 typedef typename PixelSize2Type<BytesPerTargetPixel>::PixelType TargetPixelType;
00198 private:
00199 SourcePixelType srcColorKey;
00200 TargetPixelType destColorKey;
00201 public:
00202 ColorConverter_PassThrough( const Surface& sourceSurface, Surface& targetSurface )
00203 {}
00204 ;
00205 TargetPixelType convert ( SourcePixelType sp )
00206 {
00207 return sp;
00208 };
00209 };
00210
00211
00212
00213 void ObjectType::realDisplay ( Surface& surface, const SPoint& pos, int dir, int weather ) const
00214 {
00215 int flip = 0;
00216 if ( dir < weatherPicture[weather].flip.size() )
00217 flip = weatherPicture[weather].flip[dir];
00218
00219 if ( displayMethod==1 ) {
00220 const Surface& s = getPicture( dir, weather);
00221 if ( dir != 0 && rotateImage ) {
00222 megaBlitter<ColorTransform_None, ColorMerger_AlphaLighter, SourcePixelSelector_CacheRotation,TargetPixelSelector_All>(s, surface, pos, nullParam,0.7,make_pair(&s,directionangle[dir%6]),nullParam);
00223 } else {
00224 megaBlitter<ColorTransform_None, ColorMerger_AlphaLighter, SourcePixelSelector_DirectFlip,TargetPixelSelector_All>(s, surface, pos, nullParam, 0.7, flip, nullParam);
00225 }
00226 } else
00227 if ( displayMethod == 2 ) {
00228 const Surface& s = getPicture( dir, weather);
00229 if ( !s.valid() )
00230 return;
00231
00232 if ( s.GetPixelFormat().BitsPerPixel() == 8 ) {
00233 MegaBlitter< 1,4,
00234 ColorTransform_None,
00235 ColorMerger_Alpha_XLAT_TableShifter,
00236 SourcePixelSelector_DirectFlip,
00237 TargetPixelSelector_All,
00238 ColorConverter_PassThrough
00239 >
00240 blitter;
00241 blitter.setFlipping( flip & 1, flip & 2 );
00242 blitter.blit( s, surface, pos );
00243 }
00244
00245 } else
00246 if ( displayMethod == 4 ) {
00247 const Surface& s = getPicture( dir, weather);
00248 if ( !s.valid() )
00249 return;
00250
00251 if ( dir != 0 && rotateImage ) {
00252 megaBlitter<ColorTransform_None, ColorMerger_AlphaMixer, SourcePixelSelector_CacheRotation ,TargetPixelSelector_All>(s, surface, pos, nullParam,nullParam,make_pair(&s,directionangle[dir%6]),nullParam);
00253 } else {
00254 megaBlitter<ColorTransform_None, ColorMerger_AlphaMixer, SourcePixelSelector_DirectFlip, TargetPixelSelector_All>(s, surface, pos, nullParam,nullParam, flip, nullParam);
00255 }
00256 } else {
00257 bool disp = true;
00258 #ifndef karteneditor
00259 if ( displayMethod == 3 )
00260 disp = false;
00261 #endif
00262 if ( disp ) {
00263 const Surface& s = getPicture( dir, weather);
00264 if ( !s.valid() )
00265 return;
00266 if ( flip ) {
00267
00268 megaBlitter<ColorTransform_None, ColorMerger_AlphaMerge, SourcePixelSelector_DirectFlip,TargetPixelSelector_All>(s, surface, pos, nullParam,nullParam, flip, nullParam);
00269
00270
00271 } else {
00272 if ( dir != 0 && rotateImage ) {
00273
00274 megaBlitter<ColorTransform_None, ColorMerger_AlphaMerge, SourcePixelSelector_CacheRotation ,TargetPixelSelector_All>(s, surface, pos, nullParam,nullParam,make_pair(&s,directionangle[dir%6]),nullParam);
00275
00276
00277 } else {
00278
00279 megaBlitter<ColorTransform_None, ColorMerger_AlphaMerge, SourcePixelSelector_Plain,TargetPixelSelector_All>(s, surface, pos, nullParam,nullParam,nullParam,nullParam);
00280
00281
00282 }
00283 }
00284 }
00285 }
00286 }
00287
00288
00289 void ObjectType :: display ( Surface& surface, const SPoint& pos ) const
00290 {
00291 display ( surface, pos, rotateImage? 0 : 64, 0 );
00292 }
00293
00294
00295
00296
00297 #ifndef converter
00298
00299 namespace ForestCalculation {
00300
00301
00302
00303
00304
00305
00306
00307 const int woodformnum = 28;
00308 int woodform[ woodformnum ] = { 63,30,60,39,51,28,35,48,6,57,15,14,56,7,49,47,59,31,61,60,55, -1,-1,-1,-1,-1,-1,-1 };
00309
00310
00311 int SmoothTreesData0[] = {
00312 4, 7, 10,101,
00313 1,0x0001,243,
00314 1,0x0115,243,
00315 30,0x3F, 30,243,0x3F, 60,243,0x3F, 39,243,0x3F, 51,243,
00316 0x3F, 28,243,0x3F, 35,243,0x3F, 48,243,0x3F, 6,243,
00317 0x3F, 57,243,0x3F, 15,243,0x3F, 14,243,0x3F, 56,243,
00318 0x3F, 7,243,0x3F, 49,243,0x3F, 47,243,0x3F, 59,243,
00319 0x3F, 31,243,0x3F, 61,243,0x3F, 62,243,0x3F, 55,243,
00320 0x3F, 23,243,0x3F, 46,243,0x3F, 29,243,0x3F, 58,243,
00321 0x3F, 53,243,0x3F, 43,243,0x3F, 22,243,0x3F, 38,243,
00322 0x3F, 50,243,0x3F, 52,243,
00323 7,264,265,266,267,268,269,270
00324 };
00325
00326 int SmoothTreesData[] = {
00327 4, 7, 10,101,
00328 1,0x0001,243,
00329 1,0x0115,243,
00330 30,0x3F, 30,244,0x3F, 60,245,0x3F, 39,246,0x3F, 51,247,
00331 0x3F, 28,248,0x3F, 29,248,0x3F, 35,249,0x3F, 43,249,
00332 0x3F, 48,250,0x3F, 50,250,0x3F, 52,250,0x3F, 6,251,
00333 0x3F, 22,251,0x3F, 38,251,0x3F, 57,252,0x3F, 15,253,
00334 0x3F, 14,254,0x3F, 46,254,0x3F, 56,255,0x3F, 58,255,
00335 0x3F, 7,256,0x3F, 23,256,0x3F, 49,257,0x3F, 53,257,
00336 0x3F, 47,258,0x3F, 59,259,0x3F, 31,260,0x3F, 61,261,
00337 0x3F, 62,262,0x3F, 55,263,
00338 7,264,265,266,267,268,269,270
00339 };
00340
00341 int UnSmoothTreesData[] = {
00342 4, 7, 8, 9,
00343 1,0x011C,243,
00344 0,
00345 0,
00346 1,243
00347 };
00348
00349
00350
00351
00352 int SmoothBanksData [] = {
00353 4, 7, 16, 77,
00354 1, 0x0103, 95,
00355 4, 0x010F, 95,
00356 0x010E, 0,
00357 0x0109,110,
00358 0x0107,121,
00359 20,0x3F,59, 98, 0x3F,51, 98, 0x3F,47, 99, 0x3F,39, 99,
00360 0x3F,31,100, 0x3F,30,100, 0x3F,61,101, 0x3F,60,101,
00361 0x3F,55,102, 0x3F,62,103, 0x3F,35,104, 0x3F,28,105,
00362 0x3F,56,106, 0x3F,48,106, 0x3F,49,106, 0x3F,57,106,
00363 0x3F,14,107, 0x3F,15,107, 0x3F, 7,107, 0x3F, 6,107,
00364 0
00365 };
00366
00367 int UnSmoothBanksData [] = {
00368 4, 7, 8, 9,
00369 1, 0x010C, 98,
00370 0,
00371 0,
00372 1, 95
00373 };
00374
00375
00376 int SmoothDarkBanksData [] = {
00377 4, 7, 16, 77,
00378 1,0x0103,385,
00379 4,0x0103,385,
00380 0x010A,373,
00381 0x0104,449,
00382 0x0104,463,
00383 20,0x3F,59,373, 0x3F,51,373, 0x3F,47,374, 0x3F,39,374,
00384 0x3F,31,375, 0x3F,30,375, 0x3F,61,376, 0x3F,60,376,
00385 0x3F,55,377, 0x3F,62,378, 0x3F,35,379, 0x3F,28,380,
00386 0x3F,56,381, 0x3F,48,381, 0x3F,49,381, 0x3F,57,381,
00387 0x3F,14,382, 0x3F,15,382, 0x3F, 7,382, 0x3F, 6,382,
00388 0
00389 };
00390
00391 int UnSmoothDarkBanksData [] = {
00392 4, 7, 8, 9,
00393 1,0x010A,373,
00394 0,
00395 0,
00396 1,385
00397 };
00398
00399
00400
00401 class Smoothing {
00402 GameMap* actmap;
00403 public:
00404 Smoothing ( GameMap* gamemap ) : actmap ( gamemap ) {};
00405 MapField* getfield ( int x, int y )
00406 {
00407 return actmap->getField ( x, y );
00408 }
00409
00410 int IsInSetOfWord( int Wert, int* A )
00411 {
00412 int Pos = 0;
00413 int Anz1 = A[Pos];
00414 Pos++;
00415 int res = 0;
00416 int Anz2;
00417 while ( Anz1 > 0 ) {
00418 int W = A[Pos];
00419 Pos++;
00420 Anz2 = W & 0xff;
00421
00422 if ( W & 0x100 ) {
00423 if (( Wert>= A[Pos]) && (Wert< A[Pos]+Anz2))
00424 res = 1;
00425 Pos++;
00426 } else {
00427 while ( Anz2 > 0) {
00428 if ( Wert == A[Pos] )
00429 res = 1;
00430 Pos++;
00431 Anz2--;
00432 }
00433 }
00434
00435 Anz1--;
00436 }
00437
00438 return res;
00439 };
00440
00441
00442 int GetNeighbourMask( int x, int y, int* Arr, ObjectType* o )
00443 {
00444 int res = 0;
00445 for ( int d = 0; d < sidenum; d++ ) {
00446 int x1 = x;
00447 int y1 = y;
00448 getnextfield ( x1, y1, d );
00449 MapField* fld = getfield ( x1, y1 );
00450 if ( fld ) {
00451
00452 Object* obj = fld->checkForObject ( o );
00453 if ( obj )
00454 if ( obj->typ->weather.test(0) )
00455 if ( IsInSetOfWord ( obj->typ->weatherPicture[0].bi3pic[ obj->dir ], Arr ))
00456 res += 1 << d;
00457
00458
00459
00460 } else
00461 res += 1 << d;
00462
00463 }
00464 return res;
00465 };
00466
00467 int GetNeighbourMask( int x, int y, int* Arr )
00468 {
00469 int res = 0;
00470 for ( int d = 0; d < sidenum; d++ ) {
00471 int x1 = x;
00472 int y1 = y;
00473 getnextfield ( x1, y1, d );
00474 MapField* fld = getfield ( x1, y1 );
00475 if ( fld ) {
00476
00477 if ( IsInSetOfWord ( fld->typ->bi_pict, Arr ))
00478 res += 1 << d;
00479
00480 } else
00481 res += 1 << d;
00482
00483 }
00484 return res;
00485 };
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 int SearchAndGetInt( int Wert, int* Arr, int* Res )
00504 {
00505 int Anz = Arr[0];
00506 int Pos = 1;
00507 while ( Anz> 0 ) {
00508 if (( Wert & Arr[Pos]) == Arr[Pos+1] ) {
00509 *Res = Arr[Pos+2];
00510 return Anz > 0;
00511 }
00512 Pos += 3;
00513 Anz--;
00514 }
00515 return Anz> 0;
00516 };
00517
00518
00519 int SmoothIt( ObjectType* TerObj, int* SmoothData )
00520 {
00521 int P0 = SmoothData[0];
00522 int P1 = SmoothData[1];
00523 int P2 = SmoothData[2];
00524 int P3 = SmoothData[3];
00525 int Res = 0;
00526 for ( int Y = 0 ; Y < actmap->ysize; Y++ )
00527 for ( int X = 0; X < actmap->xsize; X++ ) {
00528 if ( TerObj ) {
00529 Object* obj = getfield ( X, Y )-> checkForObject ( TerObj );
00530 if ( obj && obj->typ->weather.test(0) ) {
00531 int Old = obj->dir;
00532
00533
00534 if ( IsInSetOfWord( obj->typ->weatherPicture[0].bi3pic[ obj->dir ], &SmoothData[P0] )) {
00535 int Mask = GetNeighbourMask( X, Y, &SmoothData[P1], TerObj );
00536 if ( Mask < 63 ) {
00537 int nw;
00538 if ( !SearchAndGetInt(Mask, &SmoothData[P2], &nw) ) {
00539 if ( SmoothData[P3] == 0 || SmoothData[P3] == 1 )
00540 nw = SmoothData[P3+ 1];
00541 else
00542 nw = SmoothData[P3+ 1 ];
00543 }
00544 for ( int i = 0; i < TerObj->weatherPicture[0].bi3pic.size(); i++ )
00545 if ( TerObj->weatherPicture[0].bi3pic[ i ] == nw )
00546 obj->dir = i;
00547 }
00548 }
00549 if ( Old != obj->dir )
00550 Res = 1;
00551 }
00552 } else {
00553 MapField* fld = getfield ( X, Y );
00554 TerrainType::Weather* old = fld->typ;
00555
00556
00557 if ( IsInSetOfWord( fld->typ->bi_pict, &SmoothData[P0] )) {
00558 int Mask = GetNeighbourMask( X, Y, &SmoothData[P1] );
00559 if ( Mask < 63 ) {
00560 int nw;
00561 if ( !SearchAndGetInt(Mask, &SmoothData[P2], &nw) ) {
00562 if ( SmoothData[P3] == 0 || SmoothData[P3] == 1 )
00563 nw = SmoothData[P3+ 1];
00564 else
00565 nw = SmoothData[P3+ 1 ];
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582 }
00583 }
00584 if ( old != fld->typ )
00585 Res = 1;
00586
00587 }
00588 }
00589 return Res;
00590 };
00591
00592
00593
00594 void smooth ( int what, ObjectType* woodObj )
00595 {
00596 int ShowAgain = 0;
00597 if ( what & 2 ) {
00598 if ( SmoothIt( NULL, UnSmoothBanksData) )
00599 ShowAgain = 1;
00600 if ( SmoothIt( NULL, UnSmoothDarkBanksData) )
00601 ShowAgain = 1;
00602 if ( SmoothIt( NULL, SmoothBanksData) )
00603 ShowAgain = 1;
00604 if ( SmoothIt( NULL, SmoothDarkBanksData) )
00605 ShowAgain = 1;
00606 }
00607
00608 if ( what & 1 ) {
00609 if ( woodObj ) {
00610 int count = 0;
00611 while ( SmoothIt ( woodObj, SmoothTreesData0 ) && count < 20 ) {
00612 ShowAgain = 1;
00613 count++;
00614 }
00615 if ( SmoothIt ( woodObj, SmoothTreesData) )
00616 ShowAgain = 1;
00617 }
00618 }
00619
00620
00621
00622
00623
00624
00625 };
00626
00627 };
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753 void smooth ( int what, GameMap* gamemap, ObjectType* woodObj )
00754 {
00755 Smoothing s ( gamemap );
00756 s.smooth ( what, woodObj );
00757 }
00758
00759
00760 void calculateforest( GameMap* actmap, ObjectType* woodObj )
00761 {
00762 for ( int y = 0; y < actmap->ysize ; y++)
00763 for ( int x = 0; x < actmap->xsize ; x++) {
00764 MapField* fld = actmap->getField(x,y);
00765
00766 for ( MapField::ObjectContainer::iterator i = fld->objects.begin(); i != fld->objects.end(); i++ )
00767 if ( i->typ == woodObj )
00768 i->dir = 0;
00769 }
00770
00771 Smoothing s ( actmap );
00772 s.smooth( 1, woodObj );
00773 return;
00774
00775 int run = 0;
00776 int changed ;
00777 do {
00778 changed = 0;
00779 for ( int y = 0; y < actmap->ysize ; y++)
00780 for ( int x = 0; x < actmap->xsize ; x++) {
00781 MapField* fld = actmap->getField(x,y);
00782
00783 for ( MapField::ObjectContainer::iterator o = fld->objects.begin(); o != fld->objects.end(); o++ )
00784 if ( o->typ == woodObj ) {
00785 int c = 0;
00786 for ( int i = 0; i < sidenum; i++) {
00787 int a = x;
00788 int b = y;
00789 getnextfield( a, b, i );
00790 MapField* fld2 = actmap->getField(a,b);
00791
00792 if ( fld2 ) {
00793 Object* oi = fld2->checkForObject ( o->typ );
00794 if ( oi )
00795 if ( oi->dir <= 20 || run == 0 )
00796 c |= 1 << i ;
00797 }
00798 }
00799
00800
00801 int dr;
00802 for ( int j = 0; j < woodformnum; j++ )
00803 if ( woodform[j] == c ) {
00804 dr = j;
00805
00806 }
00807
00808
00809
00810
00811 if ( o->dir != dr && !(o->dir >= 21 && dr >= 21)) {
00812 o->dir = dr;
00813 fld->setparams();
00814 changed = 1;
00815 }
00816 }
00817 }
00818 run++;
00819 } while ( changed );
00820 }
00821
00822 }
00823
00824
00825 #else // ifdef converter
00826
00827
00828
00829 #endif
00830
00831
00832 int ObjectType :: getMemoryFootprint() const
00833 {
00834 int size = sizeof( *this );
00835 for ( int ww = 0; ww < cwettertypennum; ww++ ) {
00836 size += for_each( weatherPicture[ww].images.begin(), weatherPicture[ww].images.end(), MemorySum<Surface>() ).size;
00837 size += for_each( weatherPicture[ww].overviewMapImage.begin(), weatherPicture[ww].overviewMapImage.end(), MemorySum<OverviewMapImage>() ).size;
00838 }
00839
00840 return size;
00841 }
00842
00843
00844
00845 const int object_version = 22;
00846
00847 void ObjectType :: read ( tnstream& stream )
00848 {
00849 int version = stream.readInt();
00850
00851 if ( version < 9 )
00852 fatalError ( "sorry, the old file format for objects cannot be loaded any more" );
00853
00854 if ( version <= object_version && version >= 9 ) {
00855
00856 id = stream.readInt();
00857 groupID = stream.readInt();
00858
00859 int ___weather = stream.readInt();
00860 weather.reset();
00861 for ( int i = 0; i < cwettertypennum; i++ )
00862 if ( ___weather & ( 1 << i ))
00863 weather.set ( i );
00864
00865 visibleago = stream.readInt();
00866
00867 if ( version <= 20 ) {
00868 vector<int> IDs;
00869 readClassContainer( IDs, stream );
00870 linkableObjects.clear();
00871 for ( int i = 0; i < IDs.size(); ++i )
00872 linkableObjects.push_back( IntRange(IDs[i]));
00873
00874 readClassContainer( IDs, stream );
00875 linkableTerrain.clear();
00876 for ( int i = 0; i < IDs.size(); ++i )
00877 linkableTerrain.push_back( IntRange(IDs[i]));
00878 } else {
00879 readClassContainer( linkableObjects, stream );
00880 readClassContainer( linkableTerrain, stream );
00881 }
00882 armor = stream.readInt();
00883
00884 for ( int i = 0; i < cwettertypennum; ++i ) {
00885 fieldModification[i].terrainaccess.read( stream );
00886 fieldModification[i].terrain_and.read ( stream );
00887 fieldModification[i].terrain_or.read ( stream );
00888 fieldModification[i].movemalus_plus.read ( stream, 0 );
00889 fieldModification[i].movemalus_abs.read ( stream, -1 );
00890 }
00891
00892
00893 attackbonus_plus = stream.readInt();
00894 attackbonus_abs = stream.readInt();
00895
00896 defensebonus_plus = stream.readInt();
00897 defensebonus_abs = stream.readInt();
00898
00899 basicjamming_plus = stream.readInt();
00900 basicjamming_abs = stream.readInt();
00901
00902 if ( version >= 10 ) {
00903 viewbonus_plus = stream.readInt();
00904 viewbonus_abs = stream.readInt();
00905 }
00906
00907 if ( version <= 10 ) {
00908 imageHeight = stream.readInt();
00909 physicalHeight = imageHeight / 30;
00910 } else {
00911 imageHeight = stream.readInt();
00912 physicalHeight = stream.readInt();
00913 }
00914
00915
00916 buildcost.read( stream );
00917 removecost.read ( stream );
00918 build_movecost = stream.readInt();
00919 remove_movecost = stream.readInt();
00920
00921 canExistBeneathBuildings = stream.readInt();
00922
00923 name = stream.readString();
00924
00925 netBehaviour = stream.readInt();
00926
00927 displayMethod = stream.readInt();
00928
00929 if ( version < 15 ) {
00930 Surface s;
00931 s.read( stream );
00932 s.read( stream );
00933 }
00934
00935 techDependency.read ( stream );
00936
00937 if ( version >= 12 )
00938 growthRate = stream.readFloat();
00939 else
00940 growthRate = 0;
00941
00942 if ( version >= 13 )
00943 lifetime = stream.readInt();
00944 else
00945 lifetime = -1;
00946
00947
00948 for ( int ww = 0; ww < cwettertypennum; ww++ )
00949 if ( weather.test ( ww ) ) {
00950
00951 int pictnum = stream.readInt();
00952 stream.readInt( );
00953
00954 weatherPicture[ww].bi3pic.resize( pictnum );
00955 weatherPicture[ww].flip.resize( pictnum );
00956 weatherPicture[ww].images.resize( pictnum );
00957
00958 for ( int n = 0; n < pictnum; n++ ) {
00959 int bi3 = stream.readInt();
00960 if ( bi3 == 1 ) {
00961 weatherPicture[ww].bi3pic[n] = stream.readInt();
00962 weatherPicture[ww].flip[n] = stream.readInt();
00963 } else {
00964 weatherPicture[ww].bi3pic[n] = -1;
00965 weatherPicture[ww].images[n].read ( stream );
00966 if ( object_version >= 13 )
00967 weatherPicture[ww].flip[n] = stream.readInt();
00968 else
00969 weatherPicture[ww].flip[n] = 0;
00970 }
00971 }
00972 if ( version >= 22 )
00973 weatherPicture[ww].originalFilename = stream.readString();
00974 }
00975
00976 if ( version >= 16 )
00977 namingMethod = NamingMethod( stream.readInt() );
00978
00979 if ( version >= 17 )
00980 growthDuration = stream.readInt();
00981
00982 if ( version >= 18 )
00983 rotateImage = stream.readInt();
00984
00985 if ( version >= 19 )
00986 growOnUnits = stream.readInt();
00987
00988 if ( version >= 20 )
00989 readClassContainer( secondaryIDs, stream );
00990
00991 } else
00992 throw tinvalidversion ( stream.getLocation(), object_version, version );
00993 }
00994
00995
00996 void ObjectType :: write ( tnstream& stream ) const
00997 {
00998 stream.writeInt ( object_version );
00999
01000 stream.writeInt ( id );
01001 stream.writeInt ( groupID );
01002
01003 int ___weather = 0;
01004 for ( int i = 0; i < cwettertypennum; i++ )
01005 if ( weather.test ( i ))
01006 ___weather |= 1 << i;
01007 stream.writeInt ( ___weather );
01008 stream.writeInt ( visibleago );
01009
01010 writeClassContainer ( linkableObjects, stream );
01011 writeClassContainer ( linkableTerrain, stream );
01012
01013 stream.writeInt ( armor );
01014
01015 for ( int i = 0; i < cwettertypennum; i++ ) {
01016 fieldModification[i].terrainaccess.write( stream );
01017 fieldModification[i].terrain_and.write ( stream );
01018 fieldModification[i].terrain_or.write ( stream );
01019 fieldModification[i].movemalus_plus.write ( stream );
01020 fieldModification[i].movemalus_abs.write ( stream );
01021 }
01022
01023
01024 stream.writeInt ( attackbonus_plus );
01025 stream.writeInt ( attackbonus_abs );
01026 stream.writeInt ( defensebonus_plus );
01027 stream.writeInt ( defensebonus_abs );
01028
01029 stream.writeInt ( basicjamming_plus );
01030 stream.writeInt ( basicjamming_abs );
01031
01032 stream.writeInt ( viewbonus_plus );
01033 stream.writeInt ( viewbonus_abs );
01034
01035
01036 stream.writeInt ( imageHeight );
01037 stream.writeInt ( physicalHeight );
01038
01039 buildcost.write( stream );
01040 removecost.write ( stream );
01041 stream.writeInt( build_movecost );
01042 stream.writeInt( remove_movecost );
01043
01044 stream.writeInt( canExistBeneathBuildings );
01045
01046 stream.writeString ( name );
01047
01048 stream.writeInt ( netBehaviour );
01049
01050 stream.writeInt ( displayMethod );
01051
01052 techDependency.write ( stream );
01053
01054 stream.writeFloat( growthRate );
01055 stream.writeInt( lifetime );
01056
01057
01058 for ( int ww = 0; ww < cwettertypennum; ww++ )
01059 if ( weather.test( ww ) ) {
01060 stream.writeInt( weatherPicture[ww].images.size() );
01061 stream.writeInt( 0 );
01062
01063 for ( int l = 0; l < weatherPicture[ww].images.size(); l++ ) {
01064 if ( weatherPicture[ww].bi3pic[l] >= 0 ) {
01065 stream.writeInt ( 1 );
01066 stream.writeInt ( weatherPicture[ww].bi3pic[l] );
01067 } else {
01068 stream.writeInt ( 2 );
01069 weatherPicture[ww].images[l].write( stream );
01070 }
01071 stream.writeInt ( weatherPicture[ww].flip.at(l) );
01072 }
01073 stream.writeString( weatherPicture[ww].originalFilename );
01074 }
01075
01076 stream.writeInt( namingMethod );
01077 stream.writeInt( growthDuration );
01078 stream.writeInt( rotateImage );
01079 stream.writeInt( growOnUnits );
01080
01081 writeClassContainer( secondaryIDs, stream );
01082
01083 }
01084
01085
01086 void ObjectType :: FieldModification :: runTextIO ( PropertyContainer& pc )
01087 {
01088 pc.addDFloatArray ( "Movemalus_plus", movemalus_plus );
01089 size_t mm = movemalus_plus.size();
01090 movemalus_plus.resize( cmovemalitypenum );
01091 for ( size_t i = mm; i < cmovemalitypenum; i++ ) {
01092 if ( i == 0 )
01093 movemalus_plus[i] = 0;
01094 else
01095 movemalus_plus[i] = movemalus_plus[0];
01096 }
01097
01098
01099 pc.addDFloatArray ( "Movemalus_abs", movemalus_abs );
01100 mm = movemalus_abs.size();
01101 movemalus_abs.resize( cmovemalitypenum );
01102 for ( size_t i = mm; i < cmovemalitypenum; i++ ) {
01103 if ( i == 0 )
01104 movemalus_abs[i] = -1;
01105 else
01106 movemalus_abs[i] = movemalus_abs[0];
01107 }
01108
01109 pc.openBracket ( "TerrainAccess" );
01110 terrainaccess.runTextIO ( pc );
01111 pc.closeBracket ();
01112
01113 pc.addTagArray ( "TerrainProperties_Filter", terrain_and, terrainPropertyNum, terrainProperties, true );
01114 pc.addTagArray ( "TerrainProperties_Add", terrain_or, terrainPropertyNum, terrainProperties );
01115 }
01116
01117 void ObjectType :: runTextIO ( PropertyContainer& pc )
01118 {
01119 pc.addBreakpoint();
01120
01121 pc.addInteger ( "ID", id );
01122
01123 if ( pc.find( "SecondaryIDs") || !pc.isReading())
01124 pc.addIntegerArray("SecondaryIDs", secondaryIDs );
01125
01126 pc.addInteger ( "GroupID", groupID, -1 );
01127 pc.addTagArray ( "Weather", weather, cwettertypennum, weatherTags );
01128 pc.addBool ( "visible_in_fogOfWar", visibleago );
01129 pc.addIntRangeArray ( "LinkableObjects", linkableObjects );
01130 if ( pc.find ( "LinkableTerrain" ) || !pc.isReading() )
01131 pc.addIntRangeArray ( "LinkableTerrain", linkableTerrain );
01132
01133 pc.addBool ( "canExistBeneathBuildings", canExistBeneathBuildings, false );
01134
01135 pc.addInteger ( "Armor", armor );
01136
01137 bool oldWeatherSpecification;
01138
01139 if ( pc.find ( "Movemalus_plus" )) {
01140 oldWeatherSpecification = true;
01141
01142 fieldModification[0].runTextIO ( pc );
01143
01144 for ( int i = 1; i < cwettertypennum; ++i )
01145 fieldModification[i] = fieldModification[0];
01146
01147 } else
01148 oldWeatherSpecification= false;
01149
01150
01151 pc.addInteger ( "AttackBonus_abs", attackbonus_abs );
01152 pc.addInteger ( "AttackBonus_plus", attackbonus_plus );
01153 pc.addInteger ( "DefenseBonus_abs", defensebonus_abs );
01154 pc.addInteger ( "DefenseBonus_plus", defensebonus_plus );
01155 pc.addInteger ( "Jamming_abs", basicjamming_abs );
01156
01157 if ( pc.find( "Jammming_plus"))
01158 pc.addInteger ( "Jammming_plus", basicjamming_plus );
01159 else
01160 pc.addInteger ( "Jamming_plus", basicjamming_plus );
01161
01162 pc.addInteger ( "Height", imageHeight );
01163 if ( pc.find ( "PhysicalHeight" ) || !pc.isReading() ) {
01164 pc.addInteger ( "PhysicalHeight", physicalHeight );
01165 } else
01166 physicalHeight = imageHeight / 30;
01167
01168 pc.addInteger ( "ViewBonus_abs", viewbonus_abs, -1 );
01169 pc.addInteger ( "ViewBonus_plus", viewbonus_plus, 0 );
01170
01171 pc.openBracket ( "ConstructionCost" );
01172 buildcost.runTextIO ( pc );
01173 pc.addInteger ( "Movement", build_movecost );
01174 pc.closeBracket ();
01175
01176 pc.openBracket ( "RemovalCost" );
01177 removecost.runTextIO ( pc );
01178 pc.addInteger ( "Movement", remove_movecost );
01179 pc.closeBracket ();
01180
01181 pc.addString( "Name", name );
01182 pc.addTagInteger ( "NamingMethod", namingMethod, namingMethodNum, namingMethodNames, int(0) );
01183
01184 pc.addDFloat( "GrowthRate", growthRate, 0 );
01185 pc.addInteger( "MaxChildSpawnNumber", growthDuration, -1 );
01186 pc.addInteger( "LifeTime", lifetime, -1 );
01187 pc.addBool( "GrowOnUnits", growOnUnits, false );
01188
01189
01190 pc.addTagInteger ( "NetBehaviour", netBehaviour, netBehaviourNum, objectNetMethod, int(NetToSelf) );
01191
01192 if ( pc.isReading() && pc.find ( "NoSelfChaining" )) {
01193 bool no_autonet;
01194 pc.addBool ( "NoSelfChaining", no_autonet );
01195 if ( !no_autonet )
01196 netBehaviour |= NetToSelf;
01197 }
01198
01199
01200 for ( int i = 0; i < cwettertypennum; i++ )
01201 if ( weather.test(i) ) {
01202
01203 pc.openBracket ( weatherTags[i] );
01204 bool bi3pics = false;
01205
01206 if ( !pc.isReading() )
01207 for ( int j = 0; j < weatherPicture[i].bi3pic.size(); j++ )
01208 if ( weatherPicture[i].bi3pic[j] >= 0 )
01209 bi3pics = true;
01210
01211 pc.addBool ( "UseGFXpics", bi3pics );
01212 if ( bi3pics ) {
01213 pc.addIntegerArray ( "GFXpictures", weatherPicture[i].bi3pic );
01214 pc.addIntegerArray ( "FlipPictures", weatherPicture[i].flip );
01215
01216 weatherPicture[i].flip.resize( weatherPicture[i].bi3pic.size() );
01217 weatherPicture[i].images.resize( weatherPicture[i].bi3pic.size() );
01218 } else {
01219 ASCString s = extractFileName_withoutSuffix( filename );
01220 if ( s.empty() ) {
01221 s = "object";
01222 s += strrr(id);
01223 }
01224 ASCString filename = s + weatherAbbrev[i];
01225 pc.addImageArray ( "picture", weatherPicture[i].images, filename );
01226 if ( pc.isReading() )
01227 weatherPicture[i].originalFilename = filename;
01228 else
01229 pc.addString( "OriginalImageFilename", weatherPicture[i].originalFilename );
01230
01231 weatherPicture[i].bi3pic.resize( weatherPicture[i].images.size() );
01232 weatherPicture[i].flip.resize( weatherPicture[i].images.size() );
01233
01234 if ( pc.find ( "FlipPictures" ) || !pc.isReading() ) {
01235 vector<int> imgReferences;
01236 imgReferences.resize ( weatherPicture[i].images.size() );
01237
01238 if ( pc.isReading() )
01239 for ( int j = 0; j < weatherPicture[i].images.size(); j++ ) {
01240 weatherPicture[i].bi3pic[j] = -1;
01241 weatherPicture[i].flip[j] = 0;
01242 imgReferences[j] = -1;
01243 }
01244
01245 pc.addIntegerArray ( "FlipPictures", weatherPicture[i].flip );
01246 pc.addIntegerArray ( "ImageReference", imgReferences );
01247
01248 if ( pc.isReading() ) {
01249 for ( int j = 0; j < weatherPicture[i].images.size(); j++ )
01250 if ( j < imgReferences.size() && imgReferences[j] >= 0 && imgReferences[j] < weatherPicture[i].images.size() )
01251 weatherPicture[i].images[j] = weatherPicture[i].images[imgReferences[j]];
01252
01253 while ( weatherPicture[i].flip.size() < weatherPicture[i].images.size() )
01254 weatherPicture[i].flip.push_back(0);
01255 }
01256 } else {
01257 for ( int u = 0; u < weatherPicture[i].images.size(); u++ ) {
01258 weatherPicture[i].bi3pic[u] = -1;
01259 weatherPicture[i].flip[u] = 0;
01260 }
01261 }
01262
01263 if ( pc.isReading() ) {
01264 int operations;
01265 std::set<void*> processedImages;
01266 pc.addNamedInteger("GraphicOperations", operations, graphicOperationNum, graphicOperations, 0 );
01267 if ( operations == 1 ) {
01268 for ( int j = 0; j < weatherPicture[i].images.size(); j++ )
01269 if ( processedImages.find( weatherPicture[i].images[j].getBaseSurface() ) == processedImages.end() ) {
01270 snowify( weatherPicture[i].images[j] );
01271 processedImages.insert( weatherPicture[i].images[j].getBaseSurface() ) ;
01272 }
01273 } else
01274 if ( operations == 2 ) {
01275 for ( int j = 0; j < weatherPicture[i].images.size(); j++ )
01276 if ( processedImages.find( weatherPicture[i].images[j].getBaseSurface() ) == processedImages.end() ) {
01277 snowify( weatherPicture[i].images[j], false );
01278 processedImages.insert( weatherPicture[i].images[j].getBaseSurface() ) ;
01279 }
01280
01281 }
01282 }
01283
01284 }
01285
01286 if ( pc.find ( "DisplayMethod" ) || !pc.isReading() ) {
01287 pc.addNamedInteger( "DisplayMethod", displayMethod, objectDisplayingMethodNum, objectDisplayingMethodTags );
01288 if ( displayMethod == 2 && pc.isReading() && weatherPicture[i].images[0].GetPixelFormat().BitsPerPixel() != 8 )
01289 pc.error("Error parsing object " + name + " (ID=" + ASCString::toString(id)+"): invalid image; displaymethod=translation is only a available for 8 Bit images");
01290
01291 } else
01292 displayMethod = 0;
01293
01294
01295 if ( !oldWeatherSpecification ) {
01296 fieldModification[i].runTextIO( pc );
01297 }
01298 pc.closeBracket ( );
01299 }
01300
01301 techDependency.runTextIO( pc );
01302
01303 if ( weatherPicture[0].images.size() == 1 && (netBehaviour&KeepOrientation) )
01304 rotateImage = true;
01305
01306
01307
01308 }